Reputation: 344
I'm writing my first trivial device driver and got a few questions:
I'm following this book but doesn't seem like it goes into the details of the working while copy_(to|from)_user()
API (or any APIs that transfer data between the user and kernel space) is executed. Something not super detailed but something one must know while working on kernel.
What's the implementation of copy_from_user()
really like? I came across the following snippets but it just goes down to the assembly level. I might be navigating incorrectly. I have seen some references for this function and looks like if it returns anything other than 0, something went wrong.
// https://elixir.bootlin.com/linux/latest/source/include/linux/uaccess.h#L189
static __always_inline unsigned long __must_check
copy_from_user(void *to, const void __user *from, unsigned long n)
{
if (likely(check_copy_size(to, n, false)))
n = _copy_from_user(to, from, n);
return n;
}
__copy_from_user(void *to, const void __user *from, unsigned long n)
{
might_fault();
if (should_fail_usercopy())
return n;
instrument_copy_from_user(to, from, n);
check_object_size(to, n, false);
return raw_copy_from_user(to, from, n);
}
// https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/uaccess.h#L385
#define raw_copy_from_user(to, from, n) \
({ \
unsigned long __acfu_ret; \
uaccess_enable_not_uao(); \
__acfu_ret = __arch_copy_from_user((to), \
__uaccess_mask_ptr(from), (n)); \
uaccess_disable_not_uao(); \
__acfu_ret; \
})
// https://elixir.bootlin.com/linux/latest/source/arch/nds32/lib/copy_from_user.S#L34
.text
ENTRY(__arch_copy_from_user)
add $r5, $r0, $r2
#include "copy_template.S"
move $r0, $r2
ret
.section .fixup,"ax"
.align 2
9001:
sub $r0, $r5, $r0
ret
.previous
ENDPROC(__arch_copy_from_user)
Upvotes: 2
Views: 896
Reputation: 13189
During a syscall the kernel still has the process memory space mapped, so can directly read and write on most modern architectures. The main work is validating the user-provided address and size. Also, the data may not be resident so the normal page fault mechanism can be triggered. After that its just a memcpy.
Most of the macro layers and calls are there to deal with arch-specific differences. For example, ARM has user-access override, uao in your example code, which involves privileged mode access to user memory.
EDIT:
During the syscall, the current process isn't changed so the kernel has both the kernel memory and the user process memory in the memory map.
Address validation is to limit the access to the allowed user-process memory. Otherwise, the user process could pass a kernel address to a write, for example, and copy kernel memory out to a user file.
Upvotes: 1