unix socket error 14: EFAULT (bad address)

36,415

Solution 1

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.

Solution 2

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.

Share:
36,415
aktungmak
Author by

aktungmak

Updated on July 09, 2022

Comments

  • aktungmak
    aktungmak almost 2 years

    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?

  • aktungmak
    aktungmak about 12 years
    Aha okay thankyou, i'll check my buffer pointer when I get home and see if thats fixes it!
  • aktungmak
    aktungmak about 12 years
    yep, that did it! I had got some of my pointers confused, thankyou!