Skip to content

How eBPF Program is Executed

An eBPF program can be interpreted as bytecode or compiled into native code and loaded into the kernel. An eBPF program, whether interpreted or compiled, should be verified by the eBPF verifier.

The CONFIG_JIT_ALWAYS_ON config option decides whether an eBPF program is compiled into native code. Distributions enable this configuration by default, yet defconfig disables it by default.

JIT brings performance benefits, yet requires much engineering work.

Required Privilege

In Linux v5.8 and earlier versions, certain eBPF programs require CAP_BPF, such as socket filters.

In Linux v6 and later versions, eBPF programs can be loaded by normal users, but they require a special config option.

eBPF Engineering Issue

  1. The eBPF verifier kills normal programs.
  2. eBPF verifier cannot detect out-of-bound write.
  3. eBPF debugging is not user friendly.
  4. Optimization may affect the eBPF verifier.
  5. Helper functions have different behavior
    • BPF_read_user() helper function issue on ARM (v7.1 and above)
    • caused by PAN feature
    • Issue Track
    • Patch Mail

eBPF Security Issue

If a data pointer pointing to an eBPF program is manipulated and redirected to a vulnerable eBPF program, the interpreter can interpret eBPF shellcode. Such shellcode can bypass the eBPF verifier.

When an eBPF tail call loads the malicious pointer, shellcode can be interpreted.

References

PREVAIL: a new eBPF verifier

Harnessing the eBPF Verifier

Unit Testing eBPF Programs