copy_from_user抛出无法处理内核分页请求

时间:2016-09-01 08:17:41

标签: c linux memory linux-kernel

我正在尝试使用模块读/写内核内存,到目前为止,读取部分正在工作。 我有一个来自用户空间的程序,它打开我的模块创建的设备,并且可以从x addr(内核内存addr)读取n个字节,这样可以工作(使用copy_to_user)。 我也通过使用gdb读取相同的addr来确认它:

gdb /bin/ls /proc/kcore x/2b [addr]

当我尝试写入相同的内存地址时出现问题。 一旦我尝试这个,我得到:

BUG: unable to handle kernel paging request at [addr] (我正在读的同一个地址) 我必须说我从/ proc / kallsyms中获取了这个地址。

令我感到不安的是,我虽然将物理内存映射到内核内存,这意味着即使我们没有足够的内存来映射我们所有的物理内存,至少映射到内核的范围也是如此内存应该存在,如果我能够从该addr中读取,这意味着实际上这个addr现在就存在了。

这里是代码:

            case IOCTL_WRITE_KERNEL_MEMORY:

            pr_info ("%s: IOCTL_WRITE_KERNEL_MEMORY\n", r2_devname);

            if (data->addr < PAGE_OFFSET) {
                    pr_info ("%s: error - 0x%lx belongs to USERSPACE\n", r2_devname, (unsigned long)data->addr);
                    ret = -EINVAL;
                    return ret;
            }

            pr_info ("%s: addr: 0x%lx\n", r2_devname, (unsigned long)data->addr);

            ret = copy_from_user ((void *)data->addr, data->buff, len);
            if (ret) {
                    pr_info ("error: copy_from_user failed\n");
                    ret = -EINVAL;
                    return ret;
            }
            break;

data-&gt; addr包含addr,data-&gt; buff要读取的内容。这是通过来自用户空间的指针传递的:

            case WRITE_KERNEL_MEMORY:

            if (argc < 4) {
                    printf ("specify bytes to write\n");
                    break;
            }

            unsigned char c = 0xd;
            data.buff = &c;
            data.addr = 0xf8350000;
            data.len = n_bytes;

            printf ("ioctl: going to write: 0x%x\n", c);
            printf ("ioctl: going to write: 0x%x\n", *data.buff);

            ioctl_n = _IOR (R2_TYPE, 0x2, sizeof (struct r2k_data));
            ret = ioctl (fd, ioctl_n, &data);
            break;

和结构:

struct r2k_data {
        unsigned long *addr;
        unsigned long len;
        unsigned char *buff;
};

我认为如果我能从该addr读取,我也应该能够写入,即使我因为写保护而无法使用,我想我应该收到另一条错误信息。

有人有想法吗?

非常感谢

1 个答案:

答案 0 :(得分:0)

你不能只读或写任意地址!无论是读还是写,所有地址都必须&#34;映射&#34;,即内核标记为可用,并具有足够的权限来执行操作。

针对您的特定情况: a)read()有效,因为目标地址&#39; data.buff&#39;已映射并分配给您的usermode进程上下文(正在运行的应用程序)。 b)write()失败,因为: src是

data.addr = 0xf8350000;

这是一个任意内核虚拟地址;你不能只是&#34;只是&#34;访问它! 为此,为什么不分配内核缓冲区(使用kmalloc或vmalloc)并将 it 地址作为目标地址。它现在是一个有效的maped内核内存位置。伪代码:

 to_addr = kmalloc(512, GFP_KERNEL);
  <out of memory check>
 ret = copy_from_user ((void *)to_addr, data->buff, len);
 ...
 kfree(to_addr);