0%

kernel protect

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