集团新闻

    1.内核

    内核是操作系统的核心,目的是为上层提供一个接口,和CPU进行交互,方式就是通过设置各种CPU所需要的结构,让CPU能够提供相应的功能,比如设置虚拟内存所需要的一些结构,使得CPU能够顺利识别,从而提供虚拟内存功能。和操作系统进行交互可以通过系统调用等方式实现。

    2.特权等级

    CPU将指令分为各种特权等级,特权指令就是必须在特定特权下才能够执行的指令,否则会出现错误,intel将特权等级分为ring0ring3,其中ring3特权最低,ring0最高,linux只使用了ring0ring3ring0为内核运行的等级,ring3为用户运行的等级。

    3.内核空间与用户空间

    内核空间就是操作系统自己运行的空间,运行在ring0特权等级,拥有自己的空间,位于内存的高地址,而用户空间则是我们平时应用程序运行的空间,运行在ring3特权等级,使用较低地址。内核拥有自己的栈,和用户空间的栈并不共用。

    4.系统调用

    系统调用是linux内核向用户空间提供功能的方式,通过调用特定的系统调用,用户空间可以获取内核提供的功能。比如read函数事实上就是一个系统调用,通过传入特定的参数,内核可以读取用户输入,并且输入到buf里。

    通过使用系统调用,用户空间用户程序将会转入内核空间去执行,在执行完之后通过特殊方式回到用户空间,中间会涉及到用户空间与内核空间的切换。大致流程如下:

    1) 进入

    i. 通过swapgs切换GS段寄存器,是将GS寄存器值和一个特定位置的值进行交换,目的是保存GS值,同时将该位置的值作为内核执行时的GS值使用。

    ii. 将当前栈顶(用户空间栈顶)记录在CPU独占变量区域里,将CPU独占区域里记录的内核栈顶放入rsp(esp)

    iii. 通过push保存各寄存器值

    iv. 通过汇编指令判断是否是x32_abi(暂时可以忽略这个内容)。

    v. 通过系统调用号,跳到全局变量sys_call_table相应位置继续执行相应系统调用。

    2) 退出

    i. 通过swapgs恢复GS值。

    ii. 通过sysretq或者iretq恢复到用户空间进行执行,如果使用Iretq还需要给出用户空间的一些信息,比如CS值,eflags标志寄存器值,用户栈顶位置等等信息。

    5.slab/slub分配器

    这是一个比较大的内容,内核中也需要使用到内存的分配,类似于用户空间malloc的功能。在内核中没有libc,所以没有malloc,但是需要这样的功能,所以有kmalloc,其实现是使用的slab/slub分配器,现在多见的是slub分配器。这个分配器通过一个多级的结构进行管理。首先有cache层,cache是一个结构,里边通过保存空对象,部分使用的对象和完全使用了对象来管理,对象就是指内存对象,也就是用来分配或者已经分配的一部分内核空间。kmalloc使用了多个cache,一个cache对应一个2的幂大小的一组内存对象。

    slab分配器严格按照cache去区分,不同cache的无法分配在一页内,slub分配器则较为宽松,不同cache如果分配相同大小,可能会在一页内,这个点很重要,之后的exp会用到。

    6. 内核模块/驱动

    这是linux拓展内核功能的一个功能,通过向内核插入内核模块可以动态的加载一些驱动代码,用来负责和硬件进行交互,或者在内核层提供一些软件功能。内核模块运行在内核空间,可以通过设备文件来进行交互,比如/dev/目录下的文件很多就是设备文件,打开设备文件,关闭设备文件等等就是使用openclose函数,这些函数在内核模块里进行定义,然后在加载的时候按照一定的规则进行设置,所以通过这些函数可以调用到内核里的模块的相应设置好的函数,最后在内核完成一系列操作,为用户空间提供功能。

    SMEP是我需要稍微提一下的,这是一个内核的保护机制,目的是避免ret2usr利用方式,ret2usr即从内核空间劫持控制流,使得控制流回到用户空间,以ring 0执行用户空间代码来进行提权。开启了SMEP的时候,CPU将会阻止在ring 0执行用户空间代码。这是一个CPU功能,由CPUCR4寄存器管理,用一个位来标志是否开启SMEP保护。不过,SMEP保护并没有阻止直接从用户空间获取数据,只是阻止执行用户空间代码。