unix socket error 14: EFAULT (bad address)

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.


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.