运维开发网

linux-kernel – 内核中映射的fork和用户空间内存的交互

运维开发网 https://www.qedev.com 2020-07-09 08:44 出处:网络
考虑使用get_user_pages(或get_page)来映射来自调用进程的页面的 Linux驱动程序.然后将页面的物理地址传递给硬件设备.进程和设备都可以读取和写入页面,直到各方决定结束通信.特别是,通信可以在调用get_user_pages返
考虑使用get_user_pages(或get_page)来映射来自调用进程的页面的 Linux驱动程序.然后将页面的物理地址传递给硬件设备.进程和设备都可以读取和写入页面,直到各方决定结束通信.特别是,通信可以在调用get_user_pages返回的系统调用之后继续使用页面.系统调用实际上是在进程和硬件设备之间设置共享内存区域.

我担心如果进程调用fork会发生什么(它可能来自另一个线程,并且可能在调用get_user_pages的系统调用正在进行时或之后发生).特别是,如果父进程在fork之后写入共享内存区域,我对底层物理地址有什么了解(可能是由于写时复制而改变)?我想明白:

>内核需要做些什么才能防止可能行为不端的进程(我不想创建安全漏洞!);

>进程需要遵守什么限制,以便我们的驱动程序的功能正常工作(即物理内存仍然映射到父进程中的同一地址).

>理想情况下,我想要一个常见的情况,即子进程根本不使用我们的驱动程序(它可能几乎立即调用exec)来工作.

>理想情况下,父进程在分配内存时不必采取任何特殊步骤,因为我们现有的代码将堆栈分配的缓冲区传递给驱动程序.

>我知道MADV_DONTFORK的madvise,并且可以让内存从子进程的空间中消失,但它不适用于堆栈分配的缓冲区.

>“当你与我们的驱动程序激活连接时不要使用fork”会很烦人,但如果满足第1点,则可以接受作为最后的手段.

我愿意指出文档或源代码.我特别关注Linux Device Drivers,但没有发现这个问题. RTFS应用于内核源代码的相关部分有点压倒性.

内核版本并没有完全修复,但是最新版本(假设≥2.6.26).如果重要的话,我们只针对Arm平台(到目前为止单处理器,但多核只是在拐角处).

fork()不会干扰get_user_pages():get_user_pages()将为您提供结构页面.

在能够访问它之前,您需要kmap()它,并且此映射在内核空间中完成,而不是在用户空间中完成.

编辑:get_user_pages()触摸页面表,但你不应该担心这(它只是确保页面在用户空间中映射),并返回-EFAULT,如果它有任何问题这样做.

如果你fork(),直到执行copy-on-write,孩子将能够看到该页面.

一旦完成写入复制(因为子/驱动程序/父级通过用户空间映射写入页面 – 而不是驱动程序具有的内核kmap()),将不再共享该页面.如果您仍然在页面上(在驱动程序代码中)持有kmap(),您将无法知道您是持有父页面还是子页面.

1)这不是一个安全漏洞,因为一旦你执行了(),所有这一切都消失了.

2)当你fork()时,你希望两个进程都是相同的(它是一个分叉!!).我认为你的设计应该允许父母和孩子访问驱动程序. Execve()将刷新所有内容.

如何在用户空间中添加一些功能,如:

f = open("/dev/your_thing")
 mapping = mmap(f, ...)

在设备上调用mmap()时,使用特殊标志安装内存映射:

http://os1a.cs.columbia.edu/lxr/source/include/Linux/mm.h#071

你有一些有趣的东西,比如:

#define VM_SHARED       0x00000008
#define VM_LOCKED       0x00002000
#define VM_DONTCOPY     0x00020000      /* Do not copy this vma on fork */

VM_SHARED将禁止写入时复制VM_LOCKED将禁用该页面上的交换VM_DONTCOPY会告诉内核不要在fork上复制vma区域,虽然我不认为这是个好主意

0

精彩评论

暂无评论...
验证码 换一张
取 消