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子系统

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

  • 您需要获取用户空间程序pid
  • 在pid的页面表中搜索addree
  • 下面是将用户空间虚拟地址转换为物理地址的示例代码。 它在x86平台上工作

    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,它也可以得到内核地址。