3

I am trying to run a simple bpf program that I wrote. But I am not able to run it as non root user. Below is the program I am trying to load, It basically gets the pointer to my map whose fd is map_fd (I am not showing the code where I create the map). It works as root but for some reason fails with non root user.

Output of uname -a

Linux 5.8.0-38-generic #43~20.04.1-Ubuntu SMP Tue Jan 12 16:39:47 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

BPF program

BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4),
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
BPF_LD_MAP_FD(BPF_REG_1,map_fd),
BPF_RAW_INSN(BPF_CALL | BPF_JMP, 0, 0, 0, BPF_FUNC_map_lookup_elem),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
BPF_EXIT_INSN(),
BPF_EXIT_INSN(),
Qeole
  • 8,284
  • 1
  • 24
  • 52
user40061
  • 85
  • 2
  • 5
  • 1
    Most program types are limited to root (or, to be precise, they [require a set of capabilities](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2c78ee898d8f10ae6fb2fa23a3fbaec96b1b7366) that non-root users usually do not possess). One notable exception is eBPF programs attached to network sockets, is this what you are using? If not, the rejection is expected. Are you trying to load an XDP program as non-root, as the tags on your question suggest? – Qeole Jan 29 '21 at 09:18
  • @Qeole Yeah I am using prog type of BPF_PROG_TYPE_SOCKET_FILTER. I think we can run this prog as unprivileged user. – user40061 Jan 29 '21 at 17:06

1 Answers1

3

TL;DR. Qeole is correct, you first need to make sure you are using one of the BPF program types allowed for unprivileged users. You also need to check your sysctl settings. Finally, your current program has a pointer leak that should be fixed before it is loaded by an unprivileged users.


Using the correct program type

The kernel allows unprivileged users to load only two types of BPF programs, BPF_PROG_TYPE_SOCKET_FILTER and BPF_PROG_TYPE_CGROUP_SKB. You can see the check in the kernel for that condition in kernel/bpf/syscall.c.


Setting the proper sysctl

The kernel.unprivileged_bpf_disabled sysctl controls whether unprivileged users can load eBPF programs. It is unfortunately set to 0 (allow loading) on major distributions.

sysctl -w kernel.unprivileged_bpf_disabled=0

Note: If you are not using unprivileged program types, I would strongly recommend to set this sysctl to 1.


Fixing the pointer leaks

Regardless of the above settings, BPF programs loaded by unprivileged users are never allowed to leak pointers to userspace. For example, if the program is returning a pointer to a map value, it is considered a leak. That's your case.

After the call to BPF_FUNC_map_lookup_elem, if R0 is non-zero, you should overwrite its value (set to 1?) before returning it.

pchaigno
  • 11,313
  • 2
  • 29
  • 54
  • Thank you for the reply. I am using prog type of BPF_PROG_TYPE_SOCKET_FILTER. And I have kernel.unprivileged_bpf_disabled set to 0 (Default ubuntu config for me). So the settings don't seem the issue for me. I will try to set r0 to 0 or 1 and see if it works. – user40061 Jan 29 '21 at 17:04
  • Setting r0 to 1 did the job but I am not leaking the r0 pointer. Leaking would be if I try to store the pointer in map? – user40061 Jan 29 '21 at 17:10
  • r0 is the value returned by your eBPF program (and in your case, considered by the system to see if the packet should be allowed or dropped). So from the verifier's point of view, it's probably a pointer leak as pchaigno suggests. – Qeole Jan 29 '21 at 17:55
  • Ah, sorry. I forgot to link to the line in the verifier that will reject the program. I've updated the answer with a link. That's the check you're hitting: https://elixir.bootlin.com/linux/v5.10.11/source/kernel/bpf/verifier.c#L7810 and it's called from https://elixir.bootlin.com/linux/v5.10.11/source/kernel/bpf/verifier.c#L9533. – pchaigno Jan 29 '21 at 18:17
  • That's considered a pointer leaks because the returned value can sometimes have userspace-visible impacts. For example, with some BPF programs, it is used to truncate the packet. You could therefore derive the pointer value from that information leak. – pchaigno Jan 29 '21 at 18:19
  • That makes sense. I was about to go through the verifier line by line today to debug, that saved me a lot of trouble. Also is there a way I can see the verbose messages printed somewhere? – user40061 Jan 29 '21 at 18:41
  • I mean the verbose(env, "R0 leaks addr as return value\n"); in the kernel source code. I assume its for logging and debugging. – user40061 Jan 29 '21 at 18:56
  • https://superuser.com/questions/980632/run-perf-without-root-rights/980757#980757 – Talespin_Kit Jan 04 '22 at 05:52