Linux 设备驱动程序:将字符串从内核复制到用户空间
Linux Device Driver: Copying String from Kernel to UserSpace
我有这样的结构:
typedef struct
{
char* BUFFER;
int Size;
}DataTransfer;
在我的 IOCTL 函数中,我尝试填充结构并传递给用户空间:
case CHAR_DRIVER_IOCQREAD:
printk(KERN_INFO "In CHAR_DRIVER_IOCQREAD");
dataTransfer.BUFFER = kmalloc(strlen_user("Hello") +1, GFP_KERNEL);
dataTransfer.Size = strlen_user("Hello") +1;
error_count = copy_to_user((DataTransfer*) arg, &dataTransfer, sizeof(dataTransfer) );
在用户空间中,我尝试这样接收结构:
DataTransfer dataTransfer;
if(ioctl(fd, CHAR_DRIVER_IOCQREAD, &dataTransfer) < 0)
{
perror("ERROR in ioctl CHAR_DRIVER_IOCQREAD");
}
else
{
printf("Kernel returned size %d \n", dataTransfer.Size);
printf("Kernel returned string %s \n", dataTransfer.BUFFER);
}
正确的做法是什么?
这里有几个问题。首先,您正在将结构复制到用户 space 但不是它指向的字符串。该结构将指向您分配的内核内存,用户 space 无法访问。其次,您正在分配内核内存,但实际上并没有在其中放置任何东西。
这样做的一种方法是让用户 space 为 IOCtl 分配内存以将字符串写入其中,然后将类似 DataTransfer 的结构传递给描述它分配的内存的 IOCtl。内核将使用 copy_from_user 从用户内存中读取结构,然后,如果分配的缓冲区足够大以容纳字符串,则使用 copy_to_user 将其写入结构内部传递给它的地址。
例如(内核端,仅草图):
case CHAR_DRIVER_IOCQREAD:
DataTransfer dataTransfer;
if (copy_from_user(&dataTransfer, arg, sizeof(dataTransfer)))
return -EFAULT;
if (dataTransfer.Size < strlen(myString) + 1)
return -ENOMEM;
if (copy_to_user(dataTransfer.BUFFER, myString, strlen(myString) + 1))
return -EFAULT;
我有这样的结构:
typedef struct
{
char* BUFFER;
int Size;
}DataTransfer;
在我的 IOCTL 函数中,我尝试填充结构并传递给用户空间:
case CHAR_DRIVER_IOCQREAD:
printk(KERN_INFO "In CHAR_DRIVER_IOCQREAD");
dataTransfer.BUFFER = kmalloc(strlen_user("Hello") +1, GFP_KERNEL);
dataTransfer.Size = strlen_user("Hello") +1;
error_count = copy_to_user((DataTransfer*) arg, &dataTransfer, sizeof(dataTransfer) );
在用户空间中,我尝试这样接收结构:
DataTransfer dataTransfer;
if(ioctl(fd, CHAR_DRIVER_IOCQREAD, &dataTransfer) < 0)
{
perror("ERROR in ioctl CHAR_DRIVER_IOCQREAD");
}
else
{
printf("Kernel returned size %d \n", dataTransfer.Size);
printf("Kernel returned string %s \n", dataTransfer.BUFFER);
}
正确的做法是什么?
这里有几个问题。首先,您正在将结构复制到用户 space 但不是它指向的字符串。该结构将指向您分配的内核内存,用户 space 无法访问。其次,您正在分配内核内存,但实际上并没有在其中放置任何东西。
这样做的一种方法是让用户 space 为 IOCtl 分配内存以将字符串写入其中,然后将类似 DataTransfer 的结构传递给描述它分配的内存的 IOCtl。内核将使用 copy_from_user 从用户内存中读取结构,然后,如果分配的缓冲区足够大以容纳字符串,则使用 copy_to_user 将其写入结构内部传递给它的地址。
例如(内核端,仅草图):
case CHAR_DRIVER_IOCQREAD:
DataTransfer dataTransfer;
if (copy_from_user(&dataTransfer, arg, sizeof(dataTransfer)))
return -EFAULT;
if (dataTransfer.Size < strlen(myString) + 1)
return -ENOMEM;
if (copy_to_user(dataTransfer.BUFFER, myString, strlen(myString) + 1))
return -EFAULT;