代码之家  ›  专栏  ›  技术社区  ›  tux_mind

Android MSM内核:copy\u to\u user失败

  •  0
  • tux_mind  · 技术社区  · 7 年前

    我正在为运行在Android设备(Nexus 5X)上的Linux内核编写一个内核驱动程序。

    我有一个内核缓冲区,我想公开一个设备来读取它。我可以从内核缓冲区读写,但无法写入从 read 系统调用。非常奇怪的是 copy_to_user 仅适用于小于128字节的。。。这对我来说毫无意义。

    代码如下(已截断):

    static ssize_t dev_read(struct file *filep, char __user *buffer, size_t len, loff_t *offset){
        unsigned long sent;
        // ...
        pr_err("MYLOGGER: copying from buffer: head=%d, tail=%d, cnt=%d, sent=%lu, access=%lu\n",
              head, tail, cnt, sent,
              access_ok(VERIFY_WRITE, buffer, sent));
    
       if(sent >= 1) {
           sent -= copy_to_user(buffer, mybuf + tail, sent);
           pr_err("MYLOGGER: sent %lu bytes\n", sent);
           // ...
       }
        // ...
    }
    

    输出如下:

    [   56.476834] MYLOGGER: device opened
    [   56.476861] MYLOGGER: reading from buffer
    [   56.476872] MYLOGGER: copying from buffer: head=5666644, tail=0, cnt=5666644, sent=4096, access=1
    [   56.476882] MYLOGGER: sent 0 bytes
    

    从日志中可以看到 sent 是4096,这里没有整数溢出。 使用时 dd 每次通话我最多可以读取128个字节( dd if=/dev/mylog bs=128 )。我认为当使用超过128个字节时 dd公司 使用堆中的缓冲区,内核无法再访问它,这是我无法理解的。

    我正在使用 将\u复制到\u用户 阅读 系统调用处理程序,我还打印了 current->pid 这是同样的过程。

    可以找到内核源代码 from google android sources

    功能 将\u复制到\u用户 定义于 arch/arm64/include/asm/uaccess。h类 以及 __copy_to_user 可在中找到 arch/arm64/lib/copy\u to\u user。S

    谢谢你的时间,我希望在你宝贵的帮助下摆脱这种疯狂。

    --编辑--

    我写了一个小片段 vm_area_struct 然后打印出权限,结果如下:

    MYLOGGER: buffer belongs to vm_area with permissions rw-p
    

    所以那个地址应该是可写的。。。

    --编辑--

    我编写了更多调试代码,记录了用户空间缓冲区使用的内存页的状态。

    MYLOGGER: page=(0x7e3782d000-0x7e3782e000) present=1
    

    长话短说,当页面存在时,它可以工作,不会导致页面错误。这太奇怪了,页面错误应由虚拟内存分配器管理,该分配器将页面加载到主内存中。。。

    2 回复  |  直到 7 年前
        1
  •  0
  •   tux_mind    7 年前

    出于某种原因,如果页面不在内存中,内核将 把它拿来。

    我的猜测是 __copy_to_user assembly function 异常处理程序,返回未复制的字节数。

    此异常处理程序在虚拟内存页错误回调之前执行。因此,除非页面已经存在于内存中,否则无法写入用户空间。

    我目前的解决方法是使用 get_user_pages

    我希望这能帮助其他人:)

        2
  •  0
  •   tux_mind    7 年前

    问题是我持有 spin_lock

    copy_{to,from}_user 不得在持有自旋锁时调用。 使用 mutex 解决了问题。

    我觉得自己很愚蠢,在这件事上浪费了很多天。。。