【问题标题】:How is data really exchanged between user and kernel space while copy_from_user() is being executed?执行 copy_from_user() 时,用户和内核空间之间如何真正交换数据?
【发布时间】:2021-01-17 06:29:05
【问题描述】:

我正在编写我的第一个普通设备驱动程序,但遇到了一些问题:

  • 我正在关注这本书,但在执行copy_(to|from)_user() API(或任何在用户和内核空间之间传输数据的 API)时,它似乎没有详细介绍工作细节。有些东西不是很详细,但是在内核上工作时必须知道的东西。

  • copy_from_user() 的实现到底是什么样的?我遇到了以下 sn-ps,但它只是归结为汇编级别。我可能导航不正确。我已经看到了这个函数的一些引用,看起来如果它返回 0 以外的任何值,就会出错。

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

【问题讨论】:

  • 每个问题一个问题!你真的有 2 个不相关的话题
  • 第一个公告点与标题不匹配所以删除它并单独询问
  • 好的,完成.....

标签: c linux-kernel kernel


【解决方案1】:

在系统调用期间,内核仍然映射进程内存空间,因此可以在大多数现代架构上直接读写。主要工作是验证用户提供的地址和大小。此外,数据可能不是常驻的,因此可以触发正常的页面错误机制。之后它只是一个 memcpy。

大多数宏层和调用都是为了处理特定于架构的差异。例如,ARM 在您的示例代码中有用户访问覆盖 uao,它涉及对用户内存的特权模式访问。

编辑:

在系统调用期间,当前进程没有改变,因此内核在内存映射中同时拥有内核内存和用户进程内存。

地址验证是为了限制对允许的用户进程内存的访问。否则,用户进程可以将内核地址传递给写入,例如,并将内核内存复制到用户文件中。

【讨论】:

  • 内核进程内存映射到用户空间进程内存?通过验证用户提供的地址,您指的是正在使用的字符设备,例如:/dev/<class>?
  • 添加了一些解释。这能回答你的问题吗?
  • 内核和用户空间内存不是分开的,即内核不知道用户空间内存,用户空间内存不知道内核空间内存,不是吗?"
  • 用户空间不能直接访问内核内存没有一些特殊的手段,如/dev/kmem。当用户空间进行系统调用时,它在内核中以特权模式运行,并且可以访问内核内存映射和进程内存映射。
  • 嗯,所以这里的真正要点是系统调用启用内核和用户空间内存之间的通信。另外,您没有回答我关于代码的第二个问题..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
  • 2012-08-25
  • 2015-06-26
  • 1970-01-01
  • 2017-05-17
相关资源
最近更新 更多