SMEP & SMAP
SMEP(Supervisor Mode Execution Prevention,管理模式执行保护):阻止内核执行用户态传递的代码
SMAP(Supervisor Mode Access Prevention,管理模式访问保护):禁止内核CPU访问用户空间的数据和执行用户空间的代码
CR4 寄存器的第 20/21 位可以查看是否开启 SMEP/SMAP:
KASLR
KASLR(Kernel Address Space Layout Randomization,内核地址空间布局随机化):其实就是针对内核的 ASLR
与 ASLR 不同,KASLR 有几个问题:
- 如果用户在暴力破解找 kernel 的位置,会直接导致机器 crash
- 与电脑的休眠机制不兼容
- 有很多其他的模块需要或者依赖于知道 kernel 的位置,这些都需要谨慎处理:
- 开启
kptr_restrict
系统调用防止内核地址泄露到用户空间(普通用户都无法读取内核符号地址) - 使用
dmesg_restrict
防止dmesg
泄露内核地址(限制非特权用户使用 dmesg 查看内核日志缓冲区中的消息) /var/log/messages
应该设置为只有root
用户能访问(该文件中存放的就是系统的日志信息)
- 开启
KPTI
KPTI(Kernel PageTable Isolation,内核页表隔离):完全分离用户空间与内核空间页表来解决页表泄露
- 如果没有 KPTI,每当执行用户空间代码时,Linux 会在其分页表中保留整个内核内存的映射,并保护其访问,这样做的优点是当应用程序向内核发送系统调用或收到中断时,内核页表始终存在,可以避免绝大多数上下文交换相关的开销(TLB 刷新、页表交换等)
- 开启 KPTI 后,为了彻底防止用户程序获取内核数据,可以令内核地址空间和用户地址空间使用两组页表集
Stack Protector
在内核中也是有 Stack Protector 的,编译内核时设置 CONFIG_CC_STACKPROTECTOR 选项即可
- 每个函数执行前先向栈帧顶部插入一个 canary 值以确保顺序的栈上溢在破坏到父函数栈帧前必须要先破坏 canary
- 每个函数返回之前会检测当前栈帧中的 canary 是否被修改,若被修改则代表发生了溢出,就会替换该函数的返回值为
__stack_chk_fail