如何从Linux内核访问用户空间内存?

时间:2012-05-09 04:27:59

标签: memory-management linux-kernel

我知道copy_to_user / copy_from_userget_user / put_user函数就是为了此目的。

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

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

下一步是什么?我可以使用*p,其中p是指向某些用户空间数据的指针,直接引用数据吗?

或者我是否必须先调用kmap将包含的物理页面框架映射到内核虚拟地址空间?为什么呢?

4 个答案:

答案 0 :(得分:4)

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

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

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

如果可以安排该过程,您可以尝试mlock()RAM中的页面,并找出页面的物理RAM地址。无论何时想要访问它,都要将该物理页面映射到内核虚拟地址。

注:

  • 恶意进程可以封锁()页面并诱骗您访问错误的RAM页面。
  • 我不确定mlock()语义要求下划线RAM页面不得更改。
  • 内核应该能够将页面锁定到RAM中,我不熟悉mm子系统。

答案 1 :(得分:4)

您可能会觉得这很有用。

  

让我们重复一下,读写方法的buff参数是   用户空间指针。因此,它不能被直接解除引用   内核代码。这种限制有几个原因:

     
      
  • 取决于您的驱动程序在哪种架构上运行,以及如何运行   内核已配置,用户空间指针可能无效   完全在内核模式下运行。可能没有映射   地址,或者它可以指向其他一些随机数据。

  •   
  • 即使指针在内核空间中的含义相同,   用户空间内存被分页,有问题的内存可能不是   在进行系统调用时驻留在RAM中。试图参考   用户空间内存直接可以生成页面错误,即   不允许内核代码执行的操作。结果将是   一个“哎呀”,这将导致所造成的过程的死亡   系统调用。

  •   
  • 有问题的指针由用户程序提供   可能是马车或恶意。如果你的司机盲目地解除引用   一个用户提供的指针,它提供了一个开放的门口允许   用户空间程序访问或覆盖内存中的任何内存   系统。如果你不希望自己负责妥协   用户系统的安全性,你永远不能解除引用   用户空间指针直接。

  •   

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

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

答案 2 :(得分:3)

不同的用户空间应用程序有不同的页面表。 1)你需要获得用户空间程序pid。 2)在pid的页面表中搜索addree。

下面是将用户空间虚拟地址转换为物理地址的示例代码。 它适用于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);

答案 3 :(得分:0)

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