如何从 Linux 内核访问用户空间内存?
Posted
技术标签:
【中文标题】如何从 Linux 内核访问用户空间内存?【英文标题】:How to access user space memory from the Linux kernel? 【发布时间】:2012-05-17 14:24:03 【问题描述】:我知道copy_to_user
/copy_from_user
、get_user
/put_user
函数就是为此目的。
我的问题是,给定一个用户空间地址/指针,我一般如何从内核访问该地址所指向的数据?
我可以想象,首先我必须确保包含页面应该在物理内存中(而不是在磁盘中)。
下一步是什么?可以用*p
,其中p
是指向一些用户空间数据的指针,直接引用数据吗?
还是我必须先调用kmap
将包含的物理页框映射到内核虚拟地址空间?为什么?
【问题讨论】:
【参考方案1】:只有指针是不够的!您需要知道该指针“属于”哪个进程。
当进程被抢占时,指针指向另一个进程的地址空间。地址可能不会再映射了,yadda yadda,
如果该进程是您访问数据时的当前进程,那么您应该使用 copy_to_user/copy_from_user 函数。
如果进程可能被调度,您可以尝试 mlock() RAM 中的页面并找出该页面的物理 RAM 地址。每当您想访问它时,您将该物理页面映射到内核虚拟地址。
注意:
恶意进程可以 munlock() 页面并诱骗您访问错误的 RAM 页面。 我不确定 mlock() 语义是否要求下划线 RAM 页面不得更改。 内核应该能够将页面锁定到 RAM,我不熟悉 mm 子系统。【讨论】:
【参考方案2】:不同的用户空间应用有不同的页表。
-
您需要获取用户空间程序 pid。
在 pid 的页表中搜索地址。
以下是将用户空间虚拟地址转换为物理地址的示例代码。 它适用于 x86 平台。
taskpid = find_get_pid(curpid);
task = pid_task(taskpid, PIDTYPE_PID );
mm = get_task_mm(task);
down_read(&mm->mmap_sem);
start_vaddr = vaddr;
end_vaddr = 0xC0000000;
while( start_vaddr < end_vaddr)
u32 end;
end = (( start_vaddr + PMD_SIZE) & PMD_MASK);
if( end < start_vaddr || end > end_vaddr)
end = end_vaddr;
ret = walk_pgd(start_vaddr, end, mm);
if(ret != 0)
printk("ret: %08x \n", ret);
break;
start_vaddr = end;
up_read(&mm->mmap_sem);
paddr = ret;
kaddr = __va(paddr);
mmput(mm);
【讨论】:
好点,代码逻辑很好。但我想有一些哈希表或类似的数据结构,给定一个虚拟地址,可以帮助您快速定位物理页面。有一个缺陷:kaddr = __va(paddr);此行仅在 paddr 驻留在低内存时才有效,对吧? paddr 表示物理地址,所以,一直存在于内存中。 kaddr 表示内核地址。在 Linux 内核中定义为#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
。内核地址内存映射并不复杂,只是一个PAGE_OFFSET。 (在 x86 模式下应为 0xC0000000)。还有其他方法可以获取地址。用户空间应用程序可以通过 /proc/您需要follow
一个地址来获得相应的page
结构(参见follow_page 的示例)。接下来,获取page
结构,您需要通过kmap
或kmap_atomic
将其映射到内核的地址空间。
【讨论】:
【参考方案4】:您可能会发现这很有用。
让我们重复一遍 read 和 write 方法的 buff 参数是 用户空间指针。因此,它不能被直接取消引用 内核代码。这种限制有几个原因:
取决于您的驱动程序在哪个架构上运行,以及 内核已配置,用户空间指针可能无效,而 完全在内核模式下运行。可能没有映射 地址,或者它可以指向其他一些随机数据。
即使指针在内核空间中的含义相同, 用户空间内存被分页,并且有问题的内存可能不是 进行系统调用时驻留在 RAM 中。试图参考 用户空间内存直接会产生页面错误,即 内核代码不允许做的事情。结果将是 “哎呀”,这将导致进程的死亡 系统调用。
有问题的指针由用户程序提供,该程序 可能是错误的或恶意的。如果您的驱动程序曾经盲目地取消引用 用户提供的指针,它提供了一个开放的门口,允许 用户空间程序访问或覆盖内存中的任何位置 系统。如果您不希望对损害 用户系统的安全性,你永远不能取消引用 直接用户空间指针。
来源:http://www.makelinux.net/ldd3/chp-3-sect-7
也就是说,我自己很想知道如果用户空间地址确实有效,并且上述条件都不适用会发生什么......
【讨论】:
以上是关于如何从 Linux 内核访问用户空间内存?的主要内容,如果未能解决你的问题,请参考以下文章