A few weeks ago I wanted to confirm if errno
was a libc
abstraction or a kernel feature. The glibc docs are deliberately vague
on the topic, so experimentation seemed like the best course.
static int use_wrapper(int cmd, union bpf_attr *attr, unsigned int size)
{
long ret;
/* Clear errno */
= 0;
errno
= syscall(__NR_bpf, cmd, attr, size);
ret
if (ret < 0)
("wrapped syscall failed, ret=%d, errno=%d\n", ret, errno);
printfelse
("wrapped syscall succeeded\n");
printf}
Here we make a syscall to bpf(2)
. Mostly b/c I’m quite
familiar with it.
static int use_raw(int cmd, union bpf_attr *attr, unsigned int size)
{
long ret;
/* Clear errno */
= 0;
errno
(
__asm__"movq %1, %%rax\n" /* syscall number */
"movq %2, %%rdi\n" /* arg1 */
"movq %3, %%rsi\n" /* arg2 */
"movq %4, %%rdx\n" /* arg3 */
"syscall\n"
"movq %%rax, %0\n"
/* retval */
: "=r"(ret)
/* input operands */
: "r"((long)__NR_bpf), "r"((long)cmd), "r"((long)attr), "r"((long)size)
/* clobbers */
: "rax", "rdi", "rsi", "rdx"
);
/* Check return value */
if (ret < 0)
("raw syscall failed, ret=%d, errno=%d\n", ret, errno);
printfelse
("raw syscall succeeded\n");
printf}
use_raw()
does the exact same thing as
use_wrapper()
, except we use inline assembly. Even if you
don’t know assembly or inline assembler, it should be quite clear the
semantics from the comments.
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <linux/bpf.h>
[..]
int main()
{
int cmd = BPF_PROG_LOAD;
union bpf_attr *attr = NULL;
unsigned int size = 0;
(cmd, attr, size);
use_raw(cmd, attr, size);
use_wrapper}
Finally, we put it together in main()
. Consider this
output:
$ gcc main.c
$ ./a.out
raw syscall failed, ret=-1, errno=0
wrapped syscall failed, ret=-1, errno=1
$ sudo ./a.out
raw syscall failed, ret=-7, errno=0
wrapped syscall failed, ret=-1, errno=7
Notice how errno
is always 0 when skiping libc. Further
notice how the return value of the raw syscall flipped to a positive
value and stored into errno
by libc.
So that settles it – errno
is a libc abstraction.