从内核模块更改用户空间内存保护标志

时间:2012-08-17 00:05:02

标签: memory-management process linux-kernel mmap

我正在编写一个可以访问特定进程内存的内核模块。我使用do_mmap()对某些用户空间内存进行了匿名映射:

#define MAP_FLAGS   (MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS)

prot = PROT_WRITE;
retval = do_mmap(NULL, vaddr, vsize, prot, MAP_FLAGS, 0);
先前设置了

vaddrvsize,并且呼叫成功。在我从内核模块(通过copy_to_user)写入该内存块后,我想删除它上的PROT_WRITE权限(就像我在普通用户空间中使用mprotect一样)。我似乎无法找到允许这样做的功能。

我试图取消映射该区域并使用正确的保护重新映射它,但是这会将内存块清零,删除我刚刚编写的所有数据;设置MAP_UNINITIALIZED可能会解决这个问题,但是,可以从手册页中找到:

  

MAP_UNINITIALIZED(自Linux 2.6.33起)<​​/ p>      

不要清除匿名页面。此标志旨在提高嵌入式的性能   设备。只有在使用配置内核配置内核时才会使用此标志   CONFIG_MMAP_ALLOW_UNINITIALIZED选项。由于安全隐患,该选项   通常仅在嵌入式设备(即已完成的设备)上启用   控制用户记忆的内容。)

所以,虽然这可能会做我想要的,但它不会非常便携。有没有一种标准的方法可以实现我的建议?

2 个答案:

答案 0 :(得分:1)

经过一些更多的研究,我发现了一个名为get_user_pages()的函数(我发现的最佳文档是here),它返回一个给定地址的用户空间页面列表,可以映射到内核kmap()的空格并以这种方式写入(在我的例子中,使用kernel_read())。这可以用作copy_to_user()的替代,因为它允许对检索到的页面强制写入权限。唯一的缺点是你必须逐页编写,而不是一次性写,但它确实解决了我在我的问题中描述的问题。

答案 1 :(得分:0)

在用户空间中,系统调用mprotect可以修改现有映射上的保护标志。您可能需要遵循该系统调用的实现,或者直接从您的代码中直接调用它。请参阅mm/protect.c