10

我知道copy_to_user/ copy_from_user, get_user/put_user函数就是为此目的。

我的问题是,给定用户空间地址/指针,我一般如何访问内核地址指向的数据?

我可以想象,首先我必须确保包含页面应该在物理内存中(而不是在磁盘中)。

你下一步怎么做?我可以使用指向某些用户空间数据的指针*p在哪里直接引用数据吗?p

还是我必须先调用kmap以将包含的物理页框映射到内核虚拟地址空间?为什么?

4

4 回答 4

6

您可能会发现这很有用。

让我们重复一遍,read 和 write 方法的 buff 参数是一个用户空间指针。因此,它不能被内核代码直接取消引用。这种限制有几个原因:

  • 根据您的驱动程序运行的架构以及内核的配置方式,用户空间指针在内核模式下运行时可能根本无效。该地址可能没有映射,或者它可能指向其他一些随机数据。

  • 即使指针在内核空间中确实表示相同的意思,用户空间内存也是分页的,并且在进行系统调用时,所讨论的内存可能不会驻留在 RAM 中。尝试直接引用用户空间内存可能会产生页面错误,这是内核代码不允许做的事情。结果将是“哎呀”,这将导致进行系统调用的进程死亡。

  • 有问题的指针由用户程序提供,可能是错误的或恶意的。如果您的驱动程序曾经盲目地取消引用用户提供的指针,它提供了一个开放的入口,允许用户空间程序访问或覆盖系统中任何地方的内存。如果您不希望对损害用户系统的安全性负责,则永远不能直接取消引用用户空间指针。

来源: http: //www.makelinux.net/ldd3/chp-3-sect-7

也就是说,我自己很想知道如果用户空间地址确实有效会发生什么,并且上述条件都不适用......

于 2012-05-10T09:42:58.037 回答
4

光有指针是不够的!您需要知道该指针“属于”哪个进程。

当进程被抢占时,指针指向另一个进程的地址空间。地址可能不再映射了,yadda yadda,

如果该进程将是您访问数据时的当前进程,那么您应该使用 copy_to_user/copy_from_user 函数。

如果进程可能被调度,您可以尝试 mlock() RAM 中的页面并找出该页面的物理 RAM 地址。每当您想访问它时,您将该物理页面映射到内核虚拟地址。

笔记:

  • 恶意进程可以 munlock() 页面并诱使您访问错误的 RAM 页面。
  • 我不确定 mlock() 语义是否要求下划线 RAM 页面不得更改。
  • 内核应该能够将页面锁定到 RAM 中,我不熟悉 mm 子系统。
于 2012-05-09T08:17:06.237 回答
3

不同的用户空间应用程序有不同的页表。

  1. 您需要获取用户空间程序 pid。
  2. 在 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);
于 2012-05-09T16:15:17.180 回答
1

您需要follow一个地址来获取相应的page结构(请参阅follow_page的示例)。接下来,获取page结构体,您需要通过kmapor将其映射到内核的地址空间kmap_atomic

于 2012-05-09T23:44:52.180 回答