BUG:无法在ffffffffffffffff处处理内核分页请求

时间:2019-03-05 13:54:57

标签: c linux-kernel kernel ioctl userspace

我的内核驱动程序中有一个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时,看到崩溃。

2 个答案:

答案 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 ,即使打开失败,也请注意缩进(我编辑了您的问题以更改它)


可以看看How to use ioctl to read and write to a chardev?

答案 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 );