>Linux slub 分配器上的安全加固学习-系统安全-黑吧安全网 | xxx>Linux slub 分配器上的安全加固学习-系统安全-黑吧安全网 – xxx
菜单

>Linux slub 分配器上的安全加固学习-系统安全-黑吧安全网

三月 9, 2020 - 黑吧安全网

Linux slub 分配器上的安全加固学习

来源:本站整理 作者:佚名 时间:2020-03-10 TAG: 我要投稿

linux 内核默认使用slub分配器来做内存管理,在这篇文章里,我们首先简要交代了slub分配器内存分配的基本流程,然后对其上面的两种安全加固做了分析。
 
slub 分配器简述
slub 的实现具体可以参考这篇文章,这里我们简要说明一下。
slub 是针对内核的小内存分配,和用户态堆一开始会brk分一大块内存,然后再慢慢切割一样
伙伴系统给内存,然后slub分配器把内存切割成特定大小的块,后续的分配就可以用了。
具体来说,内核会预先定义一些kmem_cache 结构体,它保存着要如何分割使用内存页的信息,可以通过cat /proc/slabinfo查看系统当前可用的kmem_cache。
>Linux slub 分配器上的安全加固学习-系统安全-黑吧安全网
内核很多的结构体会频繁的申请和释放内存,用kmem_cache 来管理特定的结构体所需要申请的内存效率上就会比较高,也比较节省内存。默认会创建kmalloc-8k,kmalloc-4k,… ,kmalloc-16,kmalloc-8 这样的cache,这样内核调用kmalloc函数时就可以根据申请的内存大小找到对应的kmalloc-xx,然后在里面找可可用的内存块。内核全局有一个 slab_caches 变量,它是一个链表,系统所有的 kmem_cache 都接在这个链表上。
slab 以页为基本单位切割,然后用单向链表(fd指针)串起来,类似用户态堆的 fastbin,每一个小块我们叫它object
kmem_cache 内部比较重要的结构如下:
kmem_cache
    – kmem_cache_cpu
        – freelist
        – partial
    – kmem_cache_node
        – partial
因为现在的计算机大多是多个cpu的,kmem_cache_cpu相当于一个缓存,kmalloc的时候会现在这里找free的slab, 找不到再到kmem_cache_node 找。partial 保存着之前申请过的没用完的slab
内存分配与释放
slab 其实就类似一个fastbin, 所有的分配都会在kmem_cache_cpu 结构体的 freelist 上找。
刚开始什么都没有,伙伴系统会根据kmem_cache的配置信息给出一块内存,分配好后类似freelist ==> [x]->[x]->[x]->…->0 这样,后面每次分配就到freelist链表上找 ,它指向第一个可用的free object。
然后可能申请太多,free object 用完了,那就会再向伙伴系统要。
已经用满的slab不用去管它,等它里面有object被free之后,它就会被挂到kmem_cache_cpu 的partial链表上。
等下一次 freelist上的slab又用完了,就可以看看partial还有没有可用的,直接拿过来换上,就不用去麻烦伙伴系统了。
kmem_cache_cpu 上的partial 可能挂了很多未满的slab, 超过一个阈值的时候,就会把整个链表拿到kmem_cache_node的partial 链表上,然后再有就又可以放了。
那可能又用多了,kmem_cache_cpu 上的 freelist 和 partial 的slab都用满了,这时就可以到 kmem_cache_node的partial 上拿。
object 的free 是 FIFO的,也就是都会接在freelist 链表头,free 的object 超过一个设定好的阈值时会触发内存回收。
okay, slub 分配器大概就是这样,我们接下来分析一下slub上的两个安全加固是什么样的。
 
环境配置
linux-5.4 版本
 
模块编写
为了方便调试,我们写个模块来帮助我们操作内核的 kmalloc 以及kfree, 可以随便kmalloc和kfree任意地址
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//msleep
MODULE_LICENSE("Dual BSD/GPL");
#define ADD_ANY   0xbeef
#define DEL_ANY   0x2333
struct in_args{
    uint64_t addr;
    uint64_t size;
    char __user *buf;
};
uint64_t g_val = 0;
static long add_any(struct in_args *args){
    long ret = 0;
    char *buffer = kmalloc(args->size,GFP_KERNEL);
    if(buffer == NULL){
        return -ENOMEM;
    }
    if(copy_to_user(args->buf,(void *)&buffer,0x8)){
        return -EINVAL;
    }
    return ret;
}
static long del_any(struct in_args *args){
    long ret = 0;
    kfree((void *)args->addr);
    return ret;
}
static long kpwn_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
    long ret = -EINVAL;
    struct in_args in;
    if(copy_from_user(&in,(void *)arg,sizeof(in))){
        return ret;
    }
    switch(cmd){
        case DEL_ANY:
            ret = del_any(&in);
            break;
        case ADD_ANY:
            ret = add_any(&in);
            break;
        default:
            ret = -1;

[1] [2] [3] [4]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。

上一篇:使用RIDL(Rogue In-Flight Data Load)技术逃逸Chrome沙盒返回黑吧安全网首页】【进入黑吧技术论坛
下一篇:教你一步一步构造CVE-2020-2555 POC


Notice: Undefined variable: canUpdate in /var/www/html/wordpress/wp-content/plugins/wp-autopost-pro/wp-autopost-function.php on line 51