copy_to_user() and copy_from_user() for basic data type
Asked Answered
A

3

8

I'm writing a linux kernel driver and for every function that sends data up to userspace or reads data from userspace, I am using copy_to_user() and copy_from_user(). My question is: do I need to use these calls if I am just copying a basic data type such as a u32 or an int?

Avelin answered 1/4, 2015 at 17:42 Comment(1)
There's some confusion about just what you're asking. A sample function declaration, showing whether you're passing an int or a pointer to int, would be helpful. The two answers posted so far are based on two different interpretations of your question.Shiau
S
7

If the function receives a pointer to user-space data, you have to use copy_from_user() to copy the pointed-to data from user space into kernel space (and vice versa).

Note that the pointer value itself is passed by value (like all C parameters), so you don't have to do a copy_from_user() to obtain the pointer value before you can copy_from_user() the data it points to.

Numeric arguments work the same way as pointer arguments; in C terms, they're both scalars. You don't have to use copy_from_user() to copy the value of the parameter; that's already been copied. You only have to use it to copy data that's pointed to by a passed pointer.

So if you have a parameter of type int, you can use it directly. If your parameter points to an int, then the int object will be in user space, and you need to use copy_to_user to copy the value of that object into kernel space.

Shiau answered 1/4, 2015 at 17:55 Comment(4)
I disagree with you. suppose a pointer in user space is not page aligned and you have to assemble both parts of the pointer to get it complete? The only thing you receive from the user already as a parameter to the call is the user pointer, but if it points to another user pointer, that pointer must be acquired with user_copy. In 64bit environments, a user pointer is 8 bytes wide, and can be split in a page boundary, so you'll need to acces the virtual page tables to translate it from user space to kernel. Also, user space pages can be swapped out, so be careful with this also.Marquet
When you say the pointer is not page aligned, do you mean that the pointer object itself is misaligned, or the data it points to? Pointers are scalars and are always passed by value. If a system call has, say, a void* parameter, the kernel function that handles the system call receives a copy of the pointer; the alignment of the pointer object on the caller side is irrelevant.Shiau
For pointers of simple data types (like int*), put_user and get_user may also be used.Bugloss
@holgac: Yes -- for the object pointed to by a pointer parameter, not for the pointer itself.itShiau
M
2

When a user passes data to kernel space, this data can be split on several pages, and these pages can be even in swapped out memory. In these cases, you'll have to wait for the kernel to swap in the page and get access to the page where the data is in. In the case of elementary data types (like int or pointers) it is also true that some architectures (notably x86 intel) don't force the user to align the data so even an integer can be split around a page border. You can have access to the first part of you integer, but to wait for the second to get swapped in by the memory manager before the whole thing is accessed.

You can save some roundtrips by putting all user data in a structure whose pointer is passed to the kernel. You can copy_from_user it as a block and save accesses (and running into the risk of being blocked several times)

So, and as a conclusion, use the functions even for basic types, as there are plenty of them. Don't assume anything about where the user data can be when running in kernel mode. You have access to it, but the kernel virtual addresses of user data have nothing to do with the virtual addresses seen in user mode.

Marquet answered 2/4, 2015 at 9:6 Comment(3)
Luis: I think you have mis-interpreted the OP. All the OP is trying to do is pass a single value of a basic data type. The OP is really asking if it is possible to pass a basic data by value instead of by reference. As @Keith was pointing out, normally a pointer is passed in, and this pointer IS passed by value so it may be accessed directly. However if you want to dereference the user pointer, you must use the copy_from_user() or get_user() function when in the kernel.Nightmare
Sorry, but as he says: if I am just copying a basic data type such as a u32 or an int meaning copying, so I supposed the int is passed by reference (to return some value, for example) Of course that if he is passing a value only to the kernel (but not back to user space) he can do like this. I am not thinking on ioctl's that is where this makes sense. Suppose he is trying to int a; write(fc, &a, sizeof a);...Marquet
Of course you can use the pointer passed to kernel space in a write(2) as data, but not much sense on making a driver like this. He says ...and for every function...Marquet
B
0

This is how I do it (works but I'm not sure if this is the right way): First make an array of that datatype, then fill the array with the data, then pass the reference to that array, for example to pass only an integer:

    int *from_user = (int *)kmalloc(sizeof(int), GFP_KERNEL);
    if (copy_from_user(from_user, buff, count))
        return -EFAULT;
    printk(KERN_INFO "The value copied from user =   %d", *from_user);
    return sizeof(buff);

And the code for user space:

    int to_be_passed[1];
    to_be_passed[0] = 4; // 4 is just an example
    int fd = open(DEVICE_NAME, O_RDWR);
    write(fd, to_be_passed, sizeof(to_be_passed));
Bust answered 29/4, 2020 at 16:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.