C 错误:无法在FFFFFFFFFFFFFF处理内核分页请求

C 错误:无法在FFFFFFFFFFFFFF处理内核分页请求,c,linux-kernel,kernel,ioctl,userspace,C,Linux Kernel,Kernel,Ioctl,Userspace,我的内核驱动程序中有一个ioctl处理程序,可以读取和写入ioctl。我还有一个用户空间应用程序,它使用这个IOCTL来写/读数据 当我在用户空间应用程序中使用此ioctl时,它会导致内核OOPS,出现“错误:无法在ffffffffffffffff处处理内核分页请求” 用户空间片段: typedef struct abc_T { uint8_t size; uint8_t addr; uint8_t data[64]; } abc_T; // Read int abc_

我的内核驱动程序中有一个ioctl处理程序,可以读取和写入ioctl。我还有一个用户空间应用程序,它使用这个IOCTL来写/读数据

当我在用户空间应用程序中使用此ioctl时,它会导致内核OOPS,出现
“错误:无法在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;
}
错误:
错误:无法在FFFFFFFFFFFFFF处理内核分页请求
IP:[]0xFFFFFFFFFFFE
PGD 1e0f067 PUD 1e11067 PMD 0
Oops:0010[#1]抢占式SMP
...
呼叫跟踪:
[] ? vfs_写入+0x198/0x1b0
[] ? 系统ioctl+0x80/0x90
[] ? 系统写入+0x49/0xa0
[] ? 系统调用快速路径+0x16/0x1b
代码:错误的RIP值。
RIP[]0xFFFFFFFFFFFE
...
我不知道这是怎么回事。 有人能帮忙吗

更新:由于abc\T中的数组大小为32,我看不出有问题。但当我将数组大小更改为64时,我看到了问题。任何帮助都将不胜感激


更新2:abc\T中的数组大小为64,如果读/写
大小
为我不能确定这是您的问题,但您的代码中存在一些问题

如果从未设置open FAILES retval,但您返回了它,则该行为在
ABC_ioctl
中未指定,因为您使用了返回值

我们看不到abc_write的结尾,如果open失败,是否返回值

注意:我首先假设你做了memcpy,即使open失败,请注意缩进(我编辑了你的问题以更改它)



请看

我不能确定这是您的问题,但您的代码中有一些问题

如果从未设置open FAILES retval,但您返回了它,则该行为在
ABC_ioctl
中未指定,因为您使用了返回值

我们看不到abc_write的结尾,如果open失败,是否返回值

注意:我首先假设你做了memcpy,即使open失败,请注意缩进(我编辑了你的问题以更改它)


如果有以下更新,可以查看

更新:由于abc\T中的数组大小为32,我看不出有问题。 但当我将数组大小更改为64时,我看到了问题。有什么帮助吗 将不胜感激

更新2:在abc\T中数组大小为64时,如果读/写大小给定这些更新:

更新:由于abc\T中的数组大小为32,我看不出有问题。 但当我将数组大小更改为64时,我看到了问题。有什么帮助吗 将不胜感激



更新2:在abc\T中,数组大小为64,如果读/写大小正常,则这是一个错误。最初我将retval初始化为0。将编辑该部分。@oak1208您的意思是您的真实代码将其初始化为0,所以您给我们的代码不是真实代码?它是真实代码。我只是在输入问题时漏掉了它:)@oak1208好的,所以init不见了。我编辑了我的问题,如果open失败,您是否在
abc\u write
中返回值?我认为这不是问题所在,因为当我打印
fd
的值时,它总是>0。好的,这是一个错误。最初我将retval初始化为0。将编辑该部分。@oak1208您的意思是您的真实代码将其初始化为0,所以您给我们的代码不是真实代码?它是真实代码。我只是在输入问题时漏掉了它:)@oak1208好的,所以init不见了。我编辑了我的问题,如果open失败,您是否在
abc\u write
中返回值?我不认为这是问题所在,因为当我打印
fd
的值时,它总是>0。您能展示一下如何注册chardev吗?(尤其包括结构物)。写函数指针似乎没有正确初始化。
static struct file_operations abc_fops={.owner=THIS_MODULE、.unlocked_ioctl=abc_ioctl、.open=abc_open、.release=abc_release、}``if(alloc_chrdev_region(&abc_dev,0,1,abc_dev)<0){return-1;}if(device_create(dev_class,NULL,abc_dev,NULL,abc_dev)==NULL){注销chrdev region(abc_dev,1);return-1;}cdev init(&abc_cdev,abc_fops);如果(cdev_add(&abc_cdev,abc_dev,1)=-1){device_destroy(dev_class,abc_dev);注销chrdev_region(abc_dev,1);返回-1;}``您可以确定用户空间客户端中的哪个调用触发了故障吗?不要假设,确保在调试之后,我发现如果我将
abc\u t
中的
data
数组大小设置为32,它不会崩溃,而将其更改为64会导致崩溃。但是我需要它大于32:(你能展示一下你是如何注册chardev的吗?(特别是包括结构)。写函数指针似乎没有正确初始化。
static struct file\u operations abc\u fops={.owner=THIS_MODULE、.unlocked_ioctl=ABC_ioctl、.open=ABC_open、.release=ABC_release、};
`if(alloc_chrdev_region(&ABC_dev,0,1,ABC_dev)<0){return-1;}if(设备创建(开发类,NULL,ABC_dev,NULL,ABC_dev)==NULL){注销chrdev_区域(abc_-dev,1);返回-1;}cdev_-init(&abc_-cdev,&abc_-fops);如果(cdev_-add(&abc_-cdev,abc_-dev,1)=-1){设备销毁(开发类,abc_-dev);注销chrdev区域(abc_-dev,1);返回-1}“``您能确定是哪个用户空间客户端调用触发了故障吗?不要假设,请确保在调试之后,我发现如果我在
abc\u t
中的
data
数组大小为32,它不会崩溃,而将其更改为64则会崩溃。但我需要它大于32:(
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
...
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;
}
 abc_T abc = {};
abc_T *abc = kmalloc( sizeof( *abc ), GFP_KERNEL );
kfree( abc );