【问题标题】:Android MSM kernel: copy_to_user failsAndroid MSM 内核:copy_to_user 失败
【发布时间】:2018-09-01 16:05:19
【问题描述】:

我正在为在 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 使用堆中的缓冲区,内核无法再访问它,这是我无法理解的。

我正在使用来自read 系统调用处理程序的copy_to_user,我还打印了current->pid,这是相同的过程。

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

copy_to_user 函数定义在 arch/arm64/include/asm/uaccess.h 中,__copy_to_user 可以在 arch/arm64/lib/copy_to_user.S 中找到.

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

-- 编辑--

我写了一个小sn-p来获取目标用户空间缓冲区的vm_area_struct并打印出权限,结果如下:

MYLOGGER: buffer belongs to vm_area with permissions rw-p

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

-- 编辑--

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

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

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

【问题讨论】:

  • 使用 simple_read_from_buffer(buf, length, offset, &kbuffer, BUFF_LEN)
  • @AlexHoppus 感谢您的建议,正如您从sources 看到的那样,它只是copy_to_user 的包装。我已经检查了参数并且后续读取工作正常(读取偏移正常)

标签: android linux linux-kernel kernel-module


【解决方案1】:

由于某种原因,如果页面不存在于内存中,内核将获取它。

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

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

我目前的解决方法是使用 get_user_pages 预加载这些页面。

我希望这对其他人有帮助:)

【讨论】:

  • Thus you won't be able to write to userspace unless the pages are already present in memory. - 这绝对是 copy_to_user 的意外行为 - 看起来像一个错误。
【解决方案2】:

问题是我持有spin_lock

copy_{to,from}_user 在持有自旋锁时永远不会被调用。 使用mutex 可以解决问题。

我觉得在这上面浪费了好几天真是太愚蠢了……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    相关资源
    最近更新 更多