copy_from/to_user returns 什么时候是非零值

When does copy_from/to_user returns a non-zero value

我阅读了 copy_from/to_user 函数的源代码。 好像他们总是return0.

static inline int copy_from_user(void *to, const void __user volatile *from,
                 unsigned long n)
{
    __chk_user_ptr(from, n);
    volatile_memcpy(to, from, n);
    return 0;
}

https://github.com/torvalds/linux/blob/6f0d349d922ba44e4348a17a78ea51b7135965b1/tools/virtio/linux/uaccess.h#L37-L51

但是,有如下代码检查 copy_from/to_user 的 returned 值。

    if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
        return -EFAULT;

https://github.com/torvalds/linux/blob/db54615e21419c3cb4d699a0b0aa16cc44d0e9da/net/ipv4/netfilter/ip_tables.c#L1114-L1115

那我有3个问题

  1. return非零的copy_from/to_user的代码定义在哪里?
  2. 是什么导致 copy_from/to_user 变为 return 非零值?
  3. returned 的值是多少?

我敢肯定你看错了文件; tools/* 不是内核的一部分,而是用户空间工具的源代码。这段代码看起来像是用于链接为用户空间程序中的内核 API 编写的代码的存根。

实际的 copy_from/to_user 函数也可能看起来总是 return 0,但据我所知,它们有一些奇特的技巧,链接器部分连接到它们的内联汇编中,因此当cpu 在复制操作期间捕获访问错误,错误处理程序可以使用伪造的 -EFAULT return 值在调用方恢复执行。这些函数的定义是特定于 arch 的,可能可以在 arch/ 树中的某个地方找到。

  1. Where the code of copy_from/to_user which returns non-zero is defined?

在 "include/linux/uaccess.h" 中 Linux 源代码树中。请注意,这些将在调用特定于 arch 的 raw_copy_from/to_user 函数之前进行一些初始检查。

  1. What causes the copy_from/to_user to return a non-zero value?

可能的原因是指定的用户内存范围无效,或者reading/writing指定的用户内存范围出现未处理的故障。

  1. What value is returned?

未复制 字节数 returned。这将介于 0 和指定的长度之间。我们将 return 值称为 "unsuccessful length".

让我们调用指定的长度减去(returned) "unsuccessful length" "successful length".

调用者可以认为"successful length"个字节已经复制成功。

请注意,目标缓冲区中实际覆盖的字节数将介于 "successful length" 和指定长度(含)之间,但只有初始 "successful length" 字节应被视为可用。