Memory management 如何从Linux内核访问用户空间内存?
我知道,Memory management 如何从Linux内核访问用户空间内存?,memory-management,linux-kernel,Memory Management,Linux Kernel,我知道,copy\u to\u user/copy\u from\u user,get\u user/put\u user功能就是为了这个目的 我的问题是,给定一个用户空间地址/指针,通常如何从内核访问地址指向的数据 我可以想象,首先我必须确保包含的页面应该在物理内存中(而不是在磁盘中) 下一步是什么?我可以使用*p,其中p是指向某些用户空间数据的指针,直接引用数据吗 或者我必须首先调用kmap将包含的物理页面帧映射到内核虚拟地址空间吗?为什么?单靠指针是不够的!您需要知道指针“属于”哪个进程
copy\u to\u user
/copy\u from\u user
,get\u user
/put\u user
功能就是为了这个目的
我的问题是,给定一个用户空间地址/指针,通常如何从内核访问地址指向的数据
我可以想象,首先我必须确保包含的页面应该在物理内存中(而不是在磁盘中)
下一步是什么?我可以使用*p
,其中p
是指向某些用户空间数据的指针,直接引用数据吗
或者我必须首先调用
kmap
将包含的物理页面帧映射到内核虚拟地址空间吗?为什么?单靠指针是不够的!您需要知道指针“属于”哪个进程
当进程被抢占时,指针指向另一进程的地址空间。地址可能不再映射了,yadda yadda
如果访问数据时该进程将是当前进程,则应使用“复制到用户”/“从用户复制”功能
如果进程可能被调度出去,您可以尝试将页锁定在RAM中,并找出页的物理RAM地址。无论何时您想要访问它,您都可以将该物理页映射到内核虚拟地址
注:
- 恶意进程可能会锁定()页面,并诱使您访问错误的RAM页面
- 我不确定mlock()语义是否要求下划线RAM页面不能更改
- 内核应该能够将页面锁定到RAM中,我不熟悉mm子系统
taskpid=find\u get\u pid(curpid);
任务=pid_任务(任务pid,pid类型_-pid);
mm=获取任务(任务);
向下读取(&mm->mmap\U sem);
start_vaddr=vaddr;
end_vaddr=0xC0000000;
while(启动\u vaddr<结束\u vaddr){
u32端;
end=((开始\u vaddr+PMD\u大小)和PMD\u掩码);
如果(结束end_vaddr)
end=end_vaddr;
ret=步行距离(起点、终点、毫米);
如果(ret!=0){
printk(“ret:%08x\n”,ret);
打破
}
start_vaddr=结束;
}
向上读取(&mm->mmap\U sem);
paddr=ret;
kaddr=uuu va(paddr);
毫米输出(毫米);
您需要按照
地址获得相应的页面
结构(参见示例)。接下来,获取页面
结构,您需要通过kmap
或kmap\u原子
将其映射到内核的地址空间,您可能会发现这很有用
让我们重复读写方法的buff参数是
用户空间指针。因此,它不能被
内核代码。这种限制有几个原因:
- 取决于驱动程序运行的体系结构,以及 配置内核时,用户空间指针可能无效 在内核模式下运行。这可能没有对应关系 地址,也可以指向其他一些随机数据
- 即使指针在内核空间中的含义相同, 用户空间内存已分页,而相关内存可能未分页 系统调用时驻留在RAM中。试图引用 用户空间内存直接会产生一个页面错误,即 内核代码不允许执行的操作。结果将是 一个“oops”,这将导致 系统调用
- 所讨论的指针由用户程序提供,该程序 可能是错误的或恶意的。如果你的司机曾经盲目地取消引用 一个用户提供的指针,它提供了一个开放的门口,允许 用户空间程序,用于访问或覆盖内存中的任何位置 系统。如果您不想对损害客户利益负责 为了确保用户系统的安全性,您不能取消对 直接使用用户空间指针
也就是说,我很想知道如果用户空间地址确实有效,并且上面的条件都不适用,会发生什么情况…这是一个很好的观点,代码逻辑也很好。但是,我想有一些哈希表或类似的数据结构,给定一个虚拟地址,可以帮助您快速定位物理页面。有一个缺陷:kaddr=_va(paddr);这行代码只在paddr位于低内存时有效,对吗?paddr意味着物理地址,所以,总是存在于内存中。kaddr表示内核地址。在Linux内核中,define是
#define u va(x)((void*)((unsigned long)(x)+PAGE_OFFSET))
。内核地址内存映射并不复杂,只是一个页偏移量。(在x86模式下应为0xC0000000)。还有其他方法可以得到地址。用户空间应用程序可以使用/proc//pagemap访问内核地址以获取页面信息。如果可以得到PFN,它也可以得到内核地址。