Jazzy
Jazzy

Reputation: 344

How is data really exchanged between user and kernel space while copy_from_user() is being executed?

I'm writing my first trivial device driver and got a few questions:

// 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

Answers (1)

stark
stark

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

Related Questions