我的内核驱动程序中有一个ioctl处理程序,并且已读写ioctl。我还有一个用户空间应用程序,它使用此IOCTL写入/读取数据。
当我在用户空间应用程序中使用此ioctl时,它会导致"BUG: unable to handle kernel paging request at ffffffffffffffff"
的内核OOPS
用户空间代码段:
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,如果读/写size
为<= 32,则没有问题,仅当要读/写的size
大于32时,看到崩溃。
答案 0 :(得分:0)
我不确定这是您的问题,但是您的代码中有一些问题
在
int abc_read(uint8_t addr, uint8_t size, uint8_t * data) {
abc_T abc = {};
int fd, retval;
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);
}
return retval;
}
如果 open 失败,则永远不会设置 retval ,但是您将其返回,则该行为在ABC_ioctl
中未指定,因为您使用了返回值
我们看不到abc_write
的结尾,如果 open 失败,您是否返回一个值?
P.S。我首先以为您是 memcpy ,即使打开失败,也请注意缩进(我编辑了您的问题以更改它)
答案 1 :(得分:0)
给出以下更新:
更新:在abc_T中数组大小为32,我看不到问题。 但是,当我将数组大小更改为64时,我看到了问题。任何帮助 将不胜感激。
更新2:在abc_T中数组大小为64,如果读/写大小为<= 32, 仅当要读取/写入的大小更大时才有问题 大于32,就会看到崩溃。
您可能会超出分配给内核调用堆栈的空间。
这样的代码
abc_T abc = {};
在调用堆栈上分配一个abc_T
对象,该对象在内核内部被极端限制。您可能应该使用kmalloc()
:
abc_T *abc = kmalloc( sizeof( *abc ), GFP_KERNEL );
您需要检查结果,并释放使用kfree()
分配的所有内存:
kfree( abc );