slub分配器使用
kmem_cache数据结构
slab分配器的对象单位–>管理自己的kmem_cache–>kmem_cache存在于slab_caches双链表中
kmem_cache里的一些小slab对象–>存在于“kmem_cache_node->partial”中 --> 每个node对应于kmem_cache_node数组项
kmem_cache里的另一部分小slab对象–>存在于“kmem_cache_cpu->partial”中
slab中没有被使用的对象称为空闲对象(free object),同一slab中的所有空闲对象被串成了一个单项链表(freelist),每个空闲对象的首地址 + kmem_cache->offset处会保存下一个空闲对象的地址,这样就形成了一个单链表
分配对象
有了上面的kmem_cache结构体
就可以通过kmem_cache_alloc()
分配对象在分配时有如下情况:
- fast path:直接从本地cpu缓存中的freelist拿到可用object
- slow path:本地cpu缓存中的freelist为NULL,但本地cpu缓存中的partial中有未满的slab
- very slow path:本地cpu缓存中的freelist为NULL,且本地cpu缓存中的partial也无slab可用。
内存管理是按大小块管理的具体可看cat /proc/slainfo
大小相同的会物理相邻
专用高速缓存是由kmem_cache_creat()函数创建的,专门使用与特殊类型的对象
普通高速缓存使用kmalloc()进行分配
释放对象
函数定义:
/*分配一块给某个数据结构使用的缓存描述符
name:对象的名字 size:对象的实际大小 align:对齐要求,通常填0,创建是自动选择。 flags:可选标志位 ctor: 构造函数 */
struct kmem_cache *kmem_cache_create( const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void*));
/*销毁kmem_cache_create分配的kmem_cache*/
int kmem_cache_destroy( struct kmem_cache *cachep);
/*从kmem_cache中分配一个object flags参数:GFP_KERNEL为常用的可睡眠的,GFP_ATOMIC从不睡眠 GFP_NOFS等等等*/
void* kmem_cache_alloc(struct kmem_cache* cachep, gfp_t flags);
/*释放object,把它返还给原先的slab*/
void kmem_cache_free(struct kmem_cache* cachep, void* objp);
常见的pwn题使用kmem_cache_alloc_trace
如下:(ctf linux内核-内存管理slub分配器)
int __cdecl sudrv_init()
{
int v0; // eax
__int64 v1; // rdi
printk("\x016SUCTF 2019 SUDriver\n");
v0 = _register_chrdev(0xE9LL, 0LL, 0x100LL, "meizijiutql", &fops);
v1 = kmalloc_caches[12];
su_fd = v0;
su_buf = (char *)kmem_cache_alloc_trace(v1, 0x480020LL, 0x1000LL);//
// kmem_cache_alloc_trace(cachep, flags,size);
return 0;
}
kmem_cache_alloc_trace
函数就是kmem_cache_create + kmem_cache_alloc
这样就通过slub分配器
分配了一块内存了
参考资料
https://blog.csdn.net/u012489236/article/details/108188375(写的很容易理解)
https://zhuanlan.zhihu.com/p/166649492