我的内核驱动程序中有一个 ioctl 处理程序,它可以读写 ioctl。我还有一个用户空间应用程序,它使用这个 IOCTL 来写入/读取数据。
当我在我的用户空间应用程序中使用这个 ioctl 时,它会导致内核 OOPS"BUG: unable to handle kernel paging request at ffffffffffffffff"
用户空间片段:
typedef struct abc_T {
uint8_t size;
uint8_t addr;
uint8_t data[64];
} abc_T;
// Read
int abc_read(uint8_t addr, uint8_t size, uint8_t * data) {
abc_T abc = {};
int fd;
int retval = 0;
abc.size = size;
abc.addr = addr;
fd = open("/dev/"ABC_DEV, O_RDWR);
if (fd >=0) {
retval = ioctl(fd, READ_ABC, &abc);
if (retval == 0)
memcpy(data, abc.data, size);
}
close(fd);
return retval;
}
// Write
int abc_write(uint8_t addr, uint8_t size, uint8_t * data) {
abc_T abc = {};
int fd;
int retval = 0;
abc.size = size;
abc.addr = addr;
memcpy(abc.data, data, size);
fd = open("/dev/"ABC_DEV, O_RDWR);
if (fd >=0) {
retval = ioctl(fd, WRITE_ABC, &abc);
}
close(fd);
return retval;
}
核心:
static int ABC_ioctl(struct file * file, uint cmd, ulong arg)
{
ABC_T abc;
int retval;
if (copy_from_user(&abc, (void *)arg,
sizeof(ABC_T)) != 0) {
return -EFAULT;
}
switch(cmd) {
case READ_ABC:
retval = read_func(&abc);
if (retval == 0) {
if (copy_to_user((void *)arg, &abc,
sizeof(ABC_T)) != 0) {
retval = -EFAULT;
} else {
retval = 0;
}
}
break;
case WRITE_ABC:
ret_val = write_func(&abc);
break;
return retval;
}
Error:
BUG: unable to handle kernel paging request at ffffffffffffffff
IP: [<ffffffffffffffff>] 0xfffffffffffffffe
PGD 1e0f067 PUD 1e11067 PMD 0
Oops: 0010 [#1] PREEMPT SMP
...
Call Trace:
[<ffffffff8117a8b8>] ? vfs_write+0x198/0x1b0
[<ffffffff8118ccc0>] ? SyS_ioctl+0x80/0x90
[<ffffffff8117b139>] ? SyS_write+0x49/0xa0
[<ffffffff819af419>] ? system_call_fastpath+0x16/0x1b
Code: Bad RIP value.
RIP [<ffffffffffffffff>] 0xfffffffffffffffe
...
不知道这有什么问题。有人可以帮忙吗?
更新:abc_T 中的数组大小为 32,我没有看到问题。但是当我将数组大小更改为 64 时,我看到了问题。任何帮助,将不胜感激。
更新 2:abc_T 中数组大小为 64,如果 read/write size
<= 32,则没有问题,只有当size
要 read/write 大于 32 时,才会看到 crash。