从调试信息可以看出,错误位置是:
./include/linux/compiler.h:220 case 8: *(volatile __u64 *)p = *(__u64 *)res; break`
打开文件,可以确认该行:
$ vim include/linux/compiler.h +220
static __always_inline void __write_once_size(volatile void *p, void *res, int size)
{
switch (size) {
case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
default:
barrier();
__builtin_memcpy((void *)p, (const void *)res, size);
barrier();
}
}
当然,您还可以在设置listsize 20之后看到特定的__write_once_size函数。此函数是__always_inline,在编译时嵌入在init_lsm_hooks中。
上述过程也可以通过其他方式快速定位,以供进一步阅读:
6.错误代码的详细分析
上面的__write_once_size接口是内核中所有双链列表操作最终输入的函数。

在错误init_lsm_hooks函数中,通过调用hlist_add_tail_rcu来调用WRITE_ONCE,从而输入__write_once_size,让我们看一下该接口的实现:
#define WRITE_ONCE(x, val) \
({ \
union { typeof(x) __val; char __c[1]; } __u = \
{ .__val = (__force typeof(x)) (val) }; \
__write_once_size(&(x), __u.__c, sizeof(x)); \
__u.__val; \
})
WRITE_ONCE()用于将值写入变量对应的内存中。 x对应于变量,val对应于写入值。该函数首先定义并初始化一个并集,以便__u .__ val的值为参数val,然后调用__write_once_size()函数将数据写入内存。
这时,变量x&(x)的地址是需要写入val的内存虚拟地址ffffffffaa6f0210,可以通过Crash查看虚拟地址的属性:
crash> vtop ffffffffaa6f0210
VIRTUAL PHYSICAL
ffffffffaa6f0210 3faf0210
PGD DIRECTORY: ffffffffaa80a000
PAGE DIRECTORY: 3fc0e067
PUD: 3fc0eff0 => 3fc0f063
PMD: 3fc0fa98 => 34367063
PTE: 34367780 => 800000003faf0061
PAGE: 3faf0000
PTE PHYSICAL FLAGS
800000003faf0061 3faf0000 (PRESENT|ACCESSED|DIRTY|NX)
PAGE PHYSICAL MAPPING INDEX CNT FLAGS
ffffe02200febc00 3faf0000 0 0 1 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_hooks
ffffffffaa6eff40 r apparmor_hooks
可以看出apparmor_hooks所在的存储空间是只读的。
7.问题解决方案
再来看一下apparmor_hooks的定义:
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init
__ lsm_ro_after_init意味着LSM体系结构所在的存储空间在初始化后将变为只读。
因此,我们提出了两种解决方案:
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-321339-2.html
瞪眼说瞎话
那日本完全不能抵挡了
南海那么大航线那么多美国为什么专走12海里这条路