我正在尝试使用模块读/写内核内存,到目前为止,读取部分正在工作。 我有一个来自用户空间的程序,它打开我的模块创建的设备,并且可以从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读取,我也应该能够写入,即使我因为写保护而无法使用,我想我应该收到另一条错误信息。
有人有想法吗?
非常感谢
答案 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);