Linux Kernel: Copy_From_User - Struct with Pointers

copy_to_user a struct that contains an array (pointer)

The user needs to provide enough space for all the data being copied out. Ideally he'll tell you how much space he provided, and you check that everything fits.

The copied-out data should (in general) not include any pointers, since they're "local" to a different "process" (the kernel can be viewed as a separate process, as it were, and kernel / user interactions involve process-to-process IPC, similar to sending stuff over local or even Internet-connected sockets).

Since the kernel has pretty intimate knowledge of a process, you can skirt these rules somewhat, e.g., you could compute what the user's pointer will be, and copy out a copy of the original data, with the pointer modified appropriately. But that's kind of wasteful. Or, you can copy a kernel pointer and just not use it in the user code, but now you're "leaking data" that "bad guys" can sometimes leverage in various ways. In security-people-speak you've left a wide-open "covert channel".

In the end, then, the "right" way to do this tends to be something like this:

struct user_interface_version_of_struct {
int property;
int count;
int data[]; /* of size "count" */
};

The user code mallocs (or otherwise arranges to have sufficient space) the "user interface version" and makes some system call to the kernel (read, receive, rcvmsg, ioctl, whatever, as long as it involves doing a "read"-type operation) and tells the kernel: "here's the memory holding the struct, and here's how big it is" (in bytes, or the maximum count value, or whatever: user and kernel simply need to agree on the protocol). The kernel-side code then verifies the user's values in some appropriate manner, and either does the copy-out however is most convenient, or returns an error.

"Most convenient" is sometimes two separate copy ops, or some put_user calls, e.g., if the kernel side has the data structure you showed, you might do:

/* let's say ulen is the user supplied length in bytes,
and uaddr is the user-supplied address */
struct user_interface_version_of_struct *p;

needed = sizeof(*p) + 3 * sizeof(int);
if (needed > ulen)
return -ENOMEM; /* user did not supply enough space */
p = uaddr;
error = put_user(1024, &p->property);
if (error == 0)
error = put_user(3, &p->count);
if (error == 0 && copy_to_user(&p->data, localArray, 3 * sizeof(int))
error = -EFAULT;

You may have a situation where you must conform to some not-very-nice interface, though.


Edit: if you're adding your own system call (rather than tying in to read or ioctl for instance), you can separate the header and data, as in Adam Rosenfield's answer.

copy_from_user - difficulty in copying double pointer from user space

copy_from_user copies one block of consecutive bytes from user space to kernel space. You'll need to first copy the struct ioctl_node, then copy the pointers to individual nodes, then copy the struct node's in a loop. Be sure to allocate the right amount of memory. Since you know the number of nodes in advance, you can allocate an array of them.

struct node_data {
size_t node_count;
struct nodes *nodes;
};
struct node_data *read_nodes(struct ioctl_node_user_pointer *arg)
{
struct node_data *nd = NULL;
struct ioctl_node kin = {0};
struct node *node_user_pointers = NULL;
int i;
int err;
/* Step 1: retrieve the root node */
nd = kmalloc(sizeof(*nd), GFP_KERNEL);
if (!nd) {
err = -ENOMEM;
goto error;
}
if (copy_from_user(ioctl_node_user_pointer, &kin, sizeof(kin))) {
err = -EFAULT;
goto error;
}
if (kin->count < 0 || kin->count > ((size_t)-1)/sizeof(*nodes)) {
err = -EINVAL;
goto error;
}
nd->node_count = kin.count;
/* Step 2: retrieve the pointers to individual nodes */
node_user_pointers = kmalloc(sizeof(*node_user_pointers) * nd->node_count, GFP_KERNEL);
if (node_user_pointers) {
err = -ENOMEM;
goto error;
}
if (copy_from_user(kin->nodes, node_user_pointers, sizeof(*node_user_pointers) * nd->node_count)) {
err = -EFAULT;
goto error;
}
/* Step 3: retrieve the nodes themselves */
nd->nodes = kmalloc(sizeof(*nodes) * nd->node_count, GFP_KERNEL);
if (!nd->nodes) {
err = -ENOMEM;
goto error;
}
for (i = 0; i < head.count; i++) {
if (copy_from_user(node_user_pointers[i], nd->nodes + i, sizeof(nd->nodes[0]))) {
err = -EFAULT;
goto error;
}
}
kfree(node_user_pointers);
return nd;
error:
if (nd) {
kfree(nd->nodes);
kfree(nd);
}
kfree(node_user_pointers);
return ERR_PTR(err);
}

Successfully de-referenced userspace pointer in kernel space without using copy_from_user()

A possible answer is, this depends on the architecture. As you have seen, on a sane architecture (such as x86 or x86-64) simply dereferencing __user pointers just works. But Linux pretends to support every possible architecture, there are architectures where simple dereference does not work. Otherwise copy_to/from_user won't existed.

Another reason for copy_to/from_user is possibility that usermode side modifies its memory simultaneously with the kernel side (in another thread). You cannot assume that the content of usermode memory is frozen while accessing it from kernel. Rougue usermode code can use this to attack the kernel. For example, you can probe the pointer to output data before executing the work, but when you get to copy the result back to usermode, this pointer is already invalid. Oops. The copy_to_user API ensures (should ensure) that the kernel won't crash during the copy, instead the guilty application will be killed.

A safer approach is to copy the whole usermode data structure into kernel (aka 'capture'), check this copy for consistency.

The bottom line... if this driver is proven to work well on certain architecture, and there are no plans to port it, there's no urgency to change it. But check carefully robustness of the kernel code, if capture of the usermode data is needed, or problem may arise during copying from usermode.

How to have deep copy of pointers send inside structure to kernel?

You have to access the memory of your user-mode process using the pointer addresses you gave to your device driver (from kernel-mode - and then you can copy the data to a kernel-mode buffer) or store the actual integer values within the structure instead of using pointers for it.

Alternatively, if you're attached to your user-mode process from kernel-mode, then you can use the pointer addresses from the structure fields to read/write to the data pointed by them (directly) anyway. There's also NtReadVirtualMemory (if you did a bit of work to find the address via KeServiceDescriptorTable or memory scanning).



Related Topics



Leave a reply



Submit