首页 > 系统相关 >Linux mem 2.8 Kfence 详解【转】

Linux mem 2.8 Kfence 详解【转】

时间:2023-06-25 14:55:28浏览次数:75  
标签:__ mem free Kfence 2.8 内存 kfence page pool

转自:https://pwl999.blog.csdn.net/article/details/124494958

1. 原理介绍
Kfence (Kernel Electric Fence) 是 Linux 内核引入的一种低开销的内存错误检测机制,因为是低开销的所以它可以在运行的生产环境中开启,同样由于是低开销所以它的功能相比较 KASAN 会偏弱。

Kfence 的基本原理非常简单,它创建了自己的专有检测内存池 kfence_pool。在 data page 的两边加上了 fence page 电子栅栏,利用 MMU 的特性把 fence page 设置成不可访问。如果对 data page 的访问越过了 page 边界, 就会立刻触发异常。

 


Kfence 的主要特点如下:

 

item Kfence KASAN
检测密度 抽样法,默认每 100ms 提供一个可检测的内存 对所有内存访问进行检测
检测粒度 核心的检测粒度为 page 检测粒度为字节
1.1 slub/slab hook
Kfence 把自己 hook 到 slub/slab 的 malloc()/free() 流程当中去。但并不是所有的 slub/slab 内存都会从 kfence_pool 内存池中分配。它规定了两个条件:

1、默认每隔 100 ms,开放从 kfence_pool 内存池中分配一次数据。分配成功后会把 kfence_allocation_gate 加 1,阻止继续从 kfence_pool 的分配。kfence_timer 定时到期以后,又会重新开放一次分配。这相当于一种 抽样法。
2、每次分配都会占用 kfence_pool 中的一个 data page,所以可分配的内存长度最大为 1 page。

 

1.2 out-of-bounds (over data page)
从 kfence_pool 中成功分配一个内存对象 obj,不管 obj 的实际大小有多大,都会占据一个 data page。

 


当原本访问 obj 的操作溢出到相邻的 fence page 时,会立即触发 CPU 异常,通过堆栈回溯揪出异常访问的元凶。

1.3 out-of-bounds (in data page)
大部分情况下 obj 是小于一个 page 的,对于 data page 剩余空间系统使用 canary pattern 进行填充。这种操作是为了检测超出了 obj 但还在 data page 范围内的溢出访问。

 


这种类型的溢出是不能在溢出发生时立刻触发的,它只能在 obj free 时,通过检测 canary pattern 被破坏来检测到有 canary 区域的溢出访问。但是异常访问的元凶却不能直接抓出来。

1.4 use-after-free
在 obj 被 free 以后,对应 data page 也会被设置成不可访问状态。

 


这种状态下,如果有操作继续访问 obj 会立即触发 CPU 异常,通过堆栈回溯揪出异常访问的元凶。

1.5 invalid-free
在 obj free 时会判断记录的 malloc 信息,判断是不是一次异常的 free。

2. 代码解析
分析以下关键的代码流程:

2.1 kfence_protect()
把 fence page 设置成不可访问的核心就是通过 MMU 清除掉 PTE 中的 present 标志位:

kfence_init_pool() → kfence_protect() → kfence_protect_page():
kfence_free() → __kfence_free() → kfence_guarded_free() → kfence_protect() → kfence_protect_page():

linux-5.16.14\arch\riscv\include\asm\kfence.h:

static inline bool kfence_protect_page(unsigned long addr, bool protect)
{
pte_t *pte = virt_to_kpte(addr);

if (protect)
set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT));
else
set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT));

flush_tlb_kernel_range(addr, addr + PAGE_SIZE);

return true;
}
2.2 kfence_alloc_pool()
在系统启动时保留 Kfence 需要用到的内存 Page,默认保留 255 个 data page:

start_kernel() → mm_init() → kfence_alloc_pool():

void __init kfence_alloc_pool(void)
{
if (!kfence_sample_interval)
return;

__kfence_pool = memblock_alloc(KFENCE_POOL_SIZE, PAGE_SIZE);

if (!__kfence_pool)
pr_err("failed to allocate pool\n");
}

#define KFENCE_POOL_SIZE ((CONFIG_KFENCE_NUM_OBJECTS + 1) * 2 * PAGE_SIZE)

config KFENCE_NUM_OBJECTS
int "Number of guarded objects available"
range 1 65535
default 255

2.3 kfence_init()
void __init kfence_init(void)
{
/* Setting kfence_sample_interval to 0 on boot disables KFENCE. */
if (!kfence_sample_interval)
return;

stack_hash_seed = (u32)random_get_entropy();
/* (1) 初始化 kfence pool 内存池 */
if (!kfence_init_pool()) {
pr_err("%s failed\n", __func__);
return;
}

if (!IS_ENABLED(CONFIG_KFENCE_STATIC_KEYS))
static_branch_enable(&kfence_allocation_key);
WRITE_ONCE(kfence_enabled, true);
/* (2) 初始化定时释放 guard 的 timer */
queue_delayed_work(system_unbound_wq, &kfence_timer, 0);
pr_info("initialized - using %lu bytes for %d objects at 0x%p-0x%p\n", KFENCE_POOL_SIZE,
CONFIG_KFENCE_NUM_OBJECTS, (void *)__kfence_pool,
(void *)(__kfence_pool + KFENCE_POOL_SIZE));
}


2.4 kfence_alloc()
内存分配流程:

kmem_cache_alloc() → slab_alloc() → kfence_alloc() → __kfence_alloc() → kfence_guarded_alloc():
1
2.5 kfence_free()
内存释放流程:

kfence_free() → __kfence_free() → kfence_guarded_free():
1
参考文档
1.Linux内存异常检测工具—kfence
2.Kernel Electric-Fence (KFENCE)
3.Linux Kernel Sanitizers
4.Linux开源动态之一种新的内存非法访问检查工具KFence
————————————————
版权声明:本文为CSDN博主「pwl999」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pwl999/article/details/124494958

标签:__,mem,free,Kfence,2.8,内存,kfence,page,pool
From: https://www.cnblogs.com/sky-heaven/p/17502930.html

相关文章

  • dbca -silent -responsefile 建库由于tmpfs太小报错ORA-27102: out of memory
    错误信息:[oracle@db01~]$dbca-silent-responsefiledbca.rspCopyingdatabasefiles1%complete2%complete4%complete12%complete100%completeLookatthelogfile"/DBSoft/oracle/cfgtoollogs/dbca/woo/woo.log"forfurtherdetails.[oracle@db01......
  • Oracle 安装报SGA size can not be greater than maximum shared memory segment size
    问题现象:问题分析:        从问题现象上来看可以比较清晰的看出是因为系统的内核参数调整问题,导致无法分配正确的内存给SGA;那么这种情况通常是由于我们的/etc/sysctl.conf中配置的内存信息和实际内存信息不符合导致。 我们的物理内存的大小为2G,swap内存的大小为4G;[root@d......
  • memcached使用中踩的一些坑
    背景线上启用memcached(以下简称mc)作为热点缓存组件已经多年,其稳定性和性能都经历住了考验,这里记录一下踩过的几个坑。大key存储某年某月某日,观察mysql的读库CPU占比有些异常偏高,去check慢查询log,发现部分应有缓存的慢sql居然存在几秒执行一次情况,不符合缓存数小时的代码逻辑......
  • linux memblock 介绍
    memblock作用内核初始化阶段是用引导内存分配器memblock进行管理,因为内核里面有很多内存结构体,不可能在静态编译阶段就静态初始化所有的这些内存结构体。另外,在系统启动过程中,系统启动后的物理内存分配器本身也需要初始化,如伙伴分配器,那么伙伴分配器如何获取内存来初始化自己......
  • memos折腾记录
    不知道小伙伴们平时有没有写日记的习惯?虽说这年头正经人都不写日记了,但我们每天要处理各种各样的事情,一本备忘录还是有必要的。这类应用其实有很多,我自己也体验过一些。有的集成了许多花里胡哨的功能;有的则是充斥着各种广告。于是我寻思着,那还不如自建一个服务来得直接。项目介......
  • memset 与 fill 函数的区别
    在使用时发现memset和fill函数有异同,为了防止考试的时候挂分,专门了解了一下。memset函数由于memset的底层实现是类似二进制实现的字节赋值,只能赋为\(0\),\(1\),\(INF\)或\(-INF\),有比较大的局限性。举个例子:\(int\)类型有\(4\)个字节,每个字节有\(8\)个数字,一......
  • Delete vector contents and free up memory in C++
     DeletevectorcontentsandfreeupmemoryinC++Thispostwilldiscusshowtodeletethevector’scontentsandfreeupthememoryallocatedbythevectortostoreobjectsinC++.1.Using vector::clear functionWecanusethe vector::clear......
  • Loadrunnber 报错误:Error -- memory violation : Exception ACCESS_VIOLATION receive
    最近写的一个Loadrunner脚本,最后一步是点击“退出”按钮退出登录状态,如下:web_text_link("[退出]","Snapshot=t18.inf",DESCRIPTION,"Text=[退出]",ACTION,"UserAction=Click",LAST);return0;但是会报......
  • 闲话 Day12.8
    一如既往的,没有任何学术题材。果然还是太菜了啊。。。所以今天来点抽象东西。我是这个星球的一员。每天住在工厂,日夜不停的加班工作。周围还有好多好多的员工。他们就和我一样不知疲倦的工作着。我似乎从未考虑过工作的意义。或者说,可能我天天不带脑子吧。当然这也无所谓......
  • Member类
    publicclassMember{privateIntegermemberAccount;privateStringmemberPassword;privateStringmemberName;privateStringmemberGender;privateIntegermemberAge;privateIntegermemberHeight;privateIntegermemberWeight;priv......