unix 套接字错误 14:EFAULT(错误地址)

发布于 2025-01-04 16:11:27 字数 271 浏览 7 评论 0原文

我有一个非常简单的问题,但整个周末我都没有找到任何答案。我正在使用 sendto() 函数,它返回错误代码 14:EFAULT。手册页将其描述为:

"An invalid user space address was specified for an argument."

我确信这是在谈论我指定的 IP 地址,但现在我怀疑它可能是它所引用的消息缓冲区的内存地址 - I在任何地方都找不到对此的任何澄清,有人可以澄清吗?

I have a very simple question, but I have not managed to find any answers to it all weekend. I am using the sendto() function and it is returning error code 14: EFAULT. The man pages describe it as:

"An invalid user space address was specified for an argument."

I was convinced that this was talking about the IP address I was specifying, but now I suspect it may be the memory address of the message buffer that it is referring to - I can't find any clarification on this anywhere, can anyone clear this up?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

那一片橙海, 2025-01-11 16:11:27

EFAULT 如果传递给 sendto(或更一般地说,任何系统调用)的某个参数的内存地址无效,就会发生这种情况。将其视为内核空间中与系统调用相关的一种SIGSEGV。例如,如果您传递一个空或无效的缓冲区指针(用于读取、写入、发送、接收...),您会得到该信息

请参阅 errno(3), sendto(2) 等等...手册页。

EFAULT 与 IP 地址完全无关。

EFAULT It happen if the memory address of some argument passed to sendto (or more generally to any system call) is invalid. Think of it as a sort of SIGSEGV in kernel land regarding your syscall. For instance, if you pass a null or invalid buffer pointer (for reading, writing, sending, recieving...), you get that

See errno(3), sendto(2) etc... man pages.

EFAULT is not related to IP addresses at all.

帥小哥 2025-01-11 16:11:27

使用getcpu的最小可运行示例

为了让事情更具体,我们可以看一下getcpu系统调用,它非常容易理解,并显示相同的 EFAULT 行为。

man getcpu我们看到签名是:

int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);

cpu指向的内存将包含系统调用后进程正在运行的当前CPU的ID,唯一可能的错误是:

ERRORS
       EFAULT Arguments point outside the calling process's address space.

因此我们可以使用以下命令对其进行测试:

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>

int main(void) {
    int err, ret;
    unsigned cpu;

    /* Correct operation. */
    assert(syscall(SYS_getcpu, &cpu, NULL, NULL) == 0);
    printf("%u\n", cpu);

    /* Bad trash address == 1. */
    ret = syscall(SYS_getcpu, 1, NULL, NULL);
    err = errno;
    assert(ret == -1);
    printf("%d\n", err);
    perror("getcpu");

    return EXIT_SUCCESS;
}

编译并运行:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

示例输出:

cpu 3
errno 14
getcpu: Bad address

因此我们看到垃圾地址为 1 的错误调用返回了 14,从内核代码中可以看出这是 EFAULT:https://stackoverflow.com/a/53958705/895245

请记住,系统调用本身返回 -14 ,然后 syscall C 包装器检测到由于负数而导致错误,返回 -1 并设置errno 为实际的精确错误代码。

由于系统调用非常简单,我们也可以从内核 5.4 实现中确认这一点 kernel/sys.c

SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
        struct getcpu_cache __user *, unused)
{
    int err = 0;
    int cpu = raw_smp_processor_id();

    if (cpup)
        err |= put_user(cpu, cpup);
    if (nodep)
        err |= put_user(cpu_to_node(cpu), nodep);
    return err ? -EFAULT : 0;
}

我们清楚地看到,如果出现问题,就会返回 -EFAULT put_user

值得一提的是,我的 glibc 在 sched.h 中也有一个 getcpu 包装器,但是在地址错误的情况下该实现会出现段错误,这有点令人困惑:<一个href="https://stackoverflow.com/questions/23224607/how-do-i-include-linux-header-files-like-linux-getcpu-h/61774312#61774312">如何包含 Linux 头文件,例如linux/getcpu.h? 但这并不是实际的系统调用对进程所做的事情,而是 glibc 对该地址所做的事情。

在 Ubuntu 20.04、Linux 5.4 上测试。

Minimal runnable example with getcpu

Just to make things more concrete, we can have a look at the getcpu system call, which is very simple to understand, and shows the same EFAULT behaviour.

From man getcpu we see that the signature is:

int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);

and the memory pointed to by the cpu will contain the ID of the current CPU the process is running on after the syscall, the only possible error being:

ERRORS
       EFAULT Arguments point outside the calling process's address space.

So we can test it out with:

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>

int main(void) {
    int err, ret;
    unsigned cpu;

    /* Correct operation. */
    assert(syscall(SYS_getcpu, &cpu, NULL, NULL) == 0);
    printf("%u\n", cpu);

    /* Bad trash address == 1. */
    ret = syscall(SYS_getcpu, 1, NULL, NULL);
    err = errno;
    assert(ret == -1);
    printf("%d\n", err);
    perror("getcpu");

    return EXIT_SUCCESS;
}

compile and run:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

Sample output:

cpu 3
errno 14
getcpu: Bad address

so we see that the bad call with a trash address of 1 returned 14, which is EFAULT as seen from kernel code: https://stackoverflow.com/a/53958705/895245

Remember that the syscall itself returns -14, and then the syscall C wrapper detects that it is an error due to being negative, returns -1, and sets errno to the actual precise error code.

And since the syscall is so simple, we can confirm this from the kernel 5.4 implementation as well at kernel/sys.c:

SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
        struct getcpu_cache __user *, unused)
{
    int err = 0;
    int cpu = raw_smp_processor_id();

    if (cpup)
        err |= put_user(cpu, cpup);
    if (nodep)
        err |= put_user(cpu_to_node(cpu), nodep);
    return err ? -EFAULT : 0;
}

so clearly we see that -EFAULT is returned if there is a problem with put_user.

It is worth mentioning that my glibc does have a getcpu wrapper as well in sched.h, but that implementation segfaults in case of bad addresses, which is a bit confusing: How do I include Linux header files like linux/getcpu.h? But it is not what the actual syscall does to the process, just whatever glibc is doing with that address.

Tested on Ubuntu 20.04, Linux 5.4.

花伊自在美 2025-01-11 16:11:27

EFAULT 是文件“include/uapi/asm-generic/errno-base.h”中定义的宏

#define EFAULT          14      /* Bad address */

EFAULT is a macro defined in a file "include/uapi/asm-generic/errno-base.h"

#define EFAULT          14      /* Bad address */
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文