Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: Print hint about ulimit when getting permission denied error

Probably the single most common error newcomers to XDP are stumped by is
the 'permission denied' error they get when trying to load their program
and 'ulimit -l' is set too low. For examples, see [0], [1].

Since the error code is UAPI, we can't change that. Instead, this patch
adds a few heuristics in libbpf and outputs an additional hint if they are
met: If an EPERM is returned on map create or program load, and geteuid()
shows we are root, and the current RLIMIT_MEMLOCK is not infinity, we
output a hint about raising 'ulimit -l' as an additional log line.

[0] https://marc.info/?l=xdp-newbies&m=157043612505624&w=2
[1] https://github.com/xdp-project/xdp-tutorial/issues/86

Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20191216181204.724953-1-toke@redhat.com

authored by

Toke Høiland-Jørgensen and committed by
Alexei Starovoitov
dc3a2d25 d50ecc46

+29
+29
tools/lib/bpf/libbpf.c
··· 41 41 #include <sys/types.h> 42 42 #include <sys/vfs.h> 43 43 #include <sys/utsname.h> 44 + #include <sys/resource.h> 44 45 #include <tools/libc_compat.h> 45 46 #include <libelf.h> 46 47 #include <gelf.h> ··· 99 98 va_start(args, format); 100 99 __libbpf_pr(level, format, args); 101 100 va_end(args); 101 + } 102 + 103 + static void pr_perm_msg(int err) 104 + { 105 + struct rlimit limit; 106 + char buf[100]; 107 + 108 + if (err != -EPERM || geteuid() != 0) 109 + return; 110 + 111 + err = getrlimit(RLIMIT_MEMLOCK, &limit); 112 + if (err) 113 + return; 114 + 115 + if (limit.rlim_cur == RLIM_INFINITY) 116 + return; 117 + 118 + if (limit.rlim_cur < 1024) 119 + snprintf(buf, sizeof(buf), "%lu bytes", limit.rlim_cur); 120 + else if (limit.rlim_cur < 1024*1024) 121 + snprintf(buf, sizeof(buf), "%.1f KiB", (double)limit.rlim_cur / 1024); 122 + else 123 + snprintf(buf, sizeof(buf), "%.1f MiB", (double)limit.rlim_cur / (1024*1024)); 124 + 125 + pr_warn("permission error while running as root; try raising 'ulimit -l'? current value: %s\n", 126 + buf); 102 127 } 103 128 104 129 #define STRERR_BUFSIZE 128 ··· 3010 2983 cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); 3011 2984 pr_warn("failed to create map (name: '%s'): %s(%d)\n", 3012 2985 map->name, cp, err); 2986 + pr_perm_msg(err); 3013 2987 for (j = 0; j < i; j++) 3014 2988 zclose(obj->maps[j].fd); 3015 2989 return err; ··· 4409 4381 ret = -errno; 4410 4382 cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); 4411 4383 pr_warn("load bpf program failed: %s\n", cp); 4384 + pr_perm_msg(ret); 4412 4385 4413 4386 if (log_buf && log_buf[0] != '\0') { 4414 4387 ret = -LIBBPF_ERRNO__VERIFY;