我正在编写一个可以访问特定进程内存的内核模块。我使用do_mmap()
对某些用户空间内存进行了匿名映射:
#define MAP_FLAGS (MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS)
prot = PROT_WRITE;
retval = do_mmap(NULL, vaddr, vsize, prot, MAP_FLAGS, 0);
先前设置了 vaddr
和vsize
,并且呼叫成功。在我从内核模块(通过copy_to_user
)写入该内存块后,我想删除它上的PROT_WRITE
权限(就像我在普通用户空间中使用mprotect
一样)。我似乎无法找到允许这样做的功能。
我试图取消映射该区域并使用正确的保护重新映射它,但是这会将内存块清零,删除我刚刚编写的所有数据;设置MAP_UNINITIALIZED
可能会解决这个问题,但是,可以从手册页中找到:
MAP_UNINITIALIZED(自Linux 2.6.33起)</ p>
不要清除匿名页面。此标志旨在提高嵌入式的性能 设备。只有在使用配置内核配置内核时才会使用此标志 CONFIG_MMAP_ALLOW_UNINITIALIZED选项。由于安全隐患,该选项 通常仅在嵌入式设备(即已完成的设备)上启用 控制用户记忆的内容。)
所以,虽然这可能会做我想要的,但它不会非常便携。有没有一种标准的方法可以实现我的建议?
答案 0 :(得分:1)
经过一些更多的研究,我发现了一个名为get_user_pages()
的函数(我发现的最佳文档是here),它返回一个给定地址的用户空间页面列表,可以映射到内核kmap()
的空格并以这种方式写入(在我的例子中,使用kernel_read()
)。这可以用作copy_to_user()
的替代,因为它允许对检索到的页面强制写入权限。唯一的缺点是你必须逐页编写,而不是一次性写,但它确实解决了我在我的问题中描述的问题。
答案 1 :(得分:0)
在用户空间中,系统调用mprotect
可以修改现有映射上的保护标志。您可能需要遵循该系统调用的实现,或者直接从您的代码中直接调用它。请参阅mm/protect.c
。