LSM Oops 内存错误根因分析与解决( 三 )


此时变量 x 所在地址 &(x) 为需要写入 val 的内存虚拟地址 ffffffffaa6f0210, 可以通过 Crash 查看该虚拟地址各项属性:
crash> vtop ffffffffaa6f0210VIRTUALPHYSICALffffffffaa6f02103faf0210PGD DIRECTORY: ffffffffaa80a000PAGE DIRECTORY: 3fc0e067PUD: 3fc0eff0 => 3fc0f063PMD: 3fc0fa98 => 34367063PTE: 34367780 => 800000003faf0061PAGE: 3faf0000PTEPHYSICALFLAGS800000003faf00613faf0000(PRESENT|ACCESSED|DIRTY|NX)PAGEPHYSICALMAppINGINDEX CNT FLAGSffffe02200febc00 3faf0000001 ffffc000000800 reserved可以看到该虚拟地址所在 PAGE 的 PTE 页表项内容 , 从 FLAGS 可以看出该 PAGE 不具备 R/W 属性 。因而可以确认 , 是由于尝试向只读地址空间写数据 , 从而导致内核报错 。
这里稍作补充 , 上述 PUD/PMD/PTE 信息跟第一节日志中的第二行信息一致:
PGD 3fc0e067 P4D 3fc0e067 PUD 3fc0f063 PMD 34367063 PTE 800000003faf0061知道是在调用 hlist_add_tail_rcu 接口出错后也可以通过查看符号表得到所要写入的地址空间是否是只读的 , 在内核的安全模块中默认配置了 apparmor , 当以 ko 的模式挂载外部的 LSM 钩子时 , 都需要以双链表方式挂在 apparmor 的 LSM 尾部:
$ sudo cat /proc/kallsyms | grep apparmor_hooksffffffffaa6eff40 r apparmor_hooks可以看出此时 apparmor_hooks 所在内存空间是只读的 。
7. 问题解决方案进一步查看到 apparmor_hooks 的定义如下:
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init__lsm_ro_after_init 表示 LSM 架构在完成初始化后所在的内存空间会成只读 。
因此我们提出两种解决方案:

  • 解决方案1: 将 __lsm_ro_after_init 标志位去掉 , 让该 PAGE 可读可写 , 这样修改虽然可行 , 但不确定是否会引入其他问题 。
  • 解决方案2: 可以通过内核配置添加 SECURITY_WRITABLE_HOOKS 选项 , 同样会将该 PAGE 配置成可读可写 。
 

【LSM Oops 内存错误根因分析与解决】


推荐阅读