manabinto
manabinto

Reputation: 31

How to copy a structure containing a pointer from user space to kernel

Here is the structure I get :

struct my_struct {
    int size;
    int *buffer;
};

Now, I want to copy a variable from user space to kernel space using copy_from_user but it does not seem to work. What I do is this:

In user space I declare a variable struct my_struct data which I in initialize and pass it onto an ioctl, and in the kernel I call copy_from_user(&mydataInkernel, arg, sizeof(mydataInkernel)) after which I allocate the right memory for the pointer and call again copy_from_user(mydataInkernel.buffer, arg + 4, mydataInkernel.size). I don't know what I am doing wrong but it is not working.

Does the first copy also copy all the data pointed to by mydataInkernel.buffer ?

Is there a way to do this simply using copy_from_user ?

UPDATE 1: For the size of a pointer on my architecture, it is indeed 8 bytes (x86_64). To be more clear I'm writing a device driver and this is for the need to get a data from the user space to kernel space using an ioctl. So here is the code I try to do to get the buffer:

     ret_val = copy_from_user(dma_info, (ioctl_dma *)arg, sizeof(dma_info));
     if (ret_val)
           printk(KERN_WARNING "COPY_FROM_USER failed !");
     else
           ret_val = copy_from_user(dma_info->buffer, (ioctl_dma *)arg->buffer, dma_info->taille);

     if (ret_val)
            printk(KERN_WARNING "COPY_FROM_USER failed !");
     else
     {
       //Do the treatment
     }

And here is the prototype of the ioctl function:

long    pci_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);

So I don't think my second copy_from_user is correct even after the cast.

Nb: dma_info is of type the struct defined above.

Upvotes: 2

Views: 2259

Answers (1)

user4822941
user4822941

Reputation:

if you have the initial struct copied in, why can't you just copy_from(arg->buffer, ....) instead of playing games like arg + 4?

since no code was shown it is hard to say for sure, but most likely the problem is in the above. offset of 'buffer' is not 4 bytes. It is 8 due to alignment requirements, assuming x86_64.

to make it clear:

  1. copy from to a local object
  2. validate that the buffer sizes looks sane (e.g. it's not megabytes in size when you expect only kilobytes)
  3. create another local object. allocate enough memory for the buffer and assign to the local object
  4. take the address of the buffer from the copy made in step one (e.g. localobj->buffer) and copyfrom that.

Upvotes: 3

Related Questions