2017-01-09 8 views
1

У меня есть-структуру, как так:Linux Device Driver: Копирование строки из ядра в 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)); 

В userpace Я пытаюсь получить структуру следующим образом:

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); 
} 

Каков правильный способ сделать это?

+0

Возможный дубликат [копировать данные из пространства ядра в пространство пользователя] (http://stackoverflow.com/questions/34159622/copy-data-from-kernel-space- to-user-space) – levengli

+0

zOMG, откуда у вас этот стиль? – 0andriy

+0

@ 0andriy Я тебя не понимаю? –

ответ

3

Пара проблем здесь. Во-первых, вы копируете структуру в пространство пользователя, но не строку, на которую указывает. Структура будет указывать на выделенную вами память ядра, к которой пользовательское пространство не может получить доступ. Во-вторых, вы выделяете память ядра, но на самом деле ничего там не кладете.

Одним из способов сделать это было бы пространство пользователя для выделения памяти для IOCtl для записи строки в, а затем передать структуру, такую ​​как ваш DataTransfer, в IOCtl, описывающую выделенную память. Ядро прочитало бы структуру из пользовательской памяти с помощью copy_from_user, а затем, если выделенный буфер был достаточно большим для хранения строки, напишите ее там, используя copy_to_user, по адресу, переданному ему внутри структуры.

E.g. (Со стороны ядра, эскиз только):

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; 
+0

Хороший ответ! Я не уверен, что наиболее подходящий код ошибки возвращается, когда 'dataTransfer.Size' слишком мал, чтобы удерживать строку, но, вероятно,' -EOVERFLOW'. –