Linux内核中的copy_from_user如何在内部工作?

San*_*986 15 linux linux-kernel memory-mapping

任何人都可以解释一下copy_from_user函数究竟是如何在内部工作的吗?它是否使用任何缓冲区,或者考虑到内核确实有权访问用户空间mem这一事实,是否有任何内存映射.

caf*_*caf 22

实施copy_from_user()高度依赖于架构.

在x86和x86-64上,它只是直接从用户空间地址读取并写入内核空间地址,同时暂时禁用SMAP(超级用户模式访问保护)(如果已配置).其中棘手的部分是将copy_from_user()代码放入特殊区域,以便页面错误处理程序可以识别其中发生故障的时间.发生的内存保护错误copy_from_user()不会像任何其他进程上下文代码触发那样终止进程,或者像在中断上下文中发生的那样使内核崩溃 - 它只是在代码路径中恢复执行返回-EFAULT给调用者.

  • @ Santi1986:`copy_to_user()`以完全相同的方式工作,除了交换源地址和目标地址 - 它从内核地址读取并写入用户空间地址.两者中唯一的检查是用户空间地址确实*低于内核/用户分割; 不需要检查属于其他用户进程的地址,因为`copy _*_ user()`仅在进程上下文中被调用,这意味着*all*地址是内核地址或属于当前进程. (4认同)

小智 8

关于"自内核传递内核空间地址后如何回复copy_to_user,用户空间进程如何访问它"

用户空间进程可以尝试访问任何地址.但是,如果地址未映射到该进程用户空间(即该进程的页表中),或者如果对只读位置的写入尝试存在访问问题,则会生成页面错误.请注意,至少在x86上,每个进程都将所有内核空间映射到该进程的虚拟地址空间的最低1千兆字节,而4GB总地址空间中的3千兆字节(我在这里使用的是32位经典空间) case)用于过程文本(即代码)和数据.来自用户空间的副本由代表进程执行的内核代码执行,实际上它是在复制期间正在使用的该进程的内存映射(即页表).这是在执行处于内核模式时发生的 - 即x86语言中的特权/管理程序模式.假设用户空间代码已经通过合法的目标位置(即在该进程地址空间中正确映射的地址)以将数据复制到,copy_to_user,从内核上下文运行将能够正常写入该地址/区域w/out问题并且在控制返回给用户之后,用户空间也可以从该位置设置读取进程本身开始.更多有趣的细节可以在了解Linux内核,第3版,作者Daniel P. Bovet,Marco Cesati的第9章和第10章中找到.特别是,access_ok()是必要但不充分的有效性检查.用户仍然可以传递不属于进程地址空间的地址.在这种情况下,内核代码执行副本时将发生页面错误异常.最有趣的部分是内核页面错误处理程序如何确定在这种情况下页面错误不是由于内核代码中的错误而是来自用户的错误地址(特别是如果所讨论的内核代码来自内核模块)加载).