Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how is the correct way to use copy_from_user?

I am trying to copy a value from user space to kernel space with the function:

static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t  *off) 
{

    unsigned long copy=0;
    int desp=0; 

    copy = copy_from_user(&desp, &len, 4);  

    printk(KERN_ALERT "copy: %lx\n", copy);      
    printk(KERN_ALERT "desp: %d\n", desp);
}

where "len" is the variable that exists in the user space, and I want to copy it to "desp" in the kernel space

the function call I make from the user space is (write is device_write according to file_operations struct):

 write (fd,buffer,8, &off);

when I print the value that should be stored in "desp" is always 0 (should be 8). What is the problem in my code? I've been seeing several examples and I implemented many variations but none works.

like image 729
eduardosufan Avatar asked Jul 05 '13 13:07

eduardosufan


People also ask

Why should Copy_from_user is needed?

The copy_from_user function copies a block of data from user space into a kernel buffer. it accepts a destination buffer (in kernel space), a source buffer (from user space), and a length defined in bytes.

What does Copy_from_user return?

Returns number of bytes that could not be copied. On success, this will be zero. If some data could not be copied, this function will pad the copied data to the requested size using zero bytes. An alternate version - __copy_from_user_inatomic - may be called from atomic context and will fail rather than sleep.

How do I copy data from user space to kernel space?

You can use the copy_from_user() and copy_to_user() functions to move data between kernel space and user space.


2 Answers

The write function prototype in the manual is:

ssize_t write(int fd, const void *buf, size_t count);

So you only need to pass 3 values to write, namely: the file descriptor fd, buffer where your data lies, and count of bytes you want to write.

This regarding the user space. Now let's move to the kernel space write function, i.e. your device_write.

The argument buf to this function is the one which contains data which you want to write from user space, count is the length of data sent to be written by the kernel. So you are supposed to copy data from buf pointer and not len.

So, the correct way would be:

char *desp;  //allocate memory for this in kernel using malloc
copy_from_user (desp, buff, len);

This should do.

like image 113
Pramod Gurav Avatar answered Oct 03 '22 22:10

Pramod Gurav


len does not exist in user-space. It is passed by value, so len is accessible as a normal variable in kernel-space. desp = (int)len is all you need. Note, however, that size_t is not the same as int, and on 64-bit platforms size_t is 8 bytes.

copy_from_user() is for the buffer you're trying to write (called buffer in your user-space code, and buff in your kernel-space argument list). What's passed is a pointer to a memory address which only exists in user-space, so copy_from_user() copies that buffer to a kernel-space buffer.

like image 40
Peter Avatar answered Oct 03 '22 23:10

Peter