If you are familiar with BPF, you likely know about the existing helper function bpf_probe_write_user, which can overwrite user space data. This function takes a pointer to the data to be overwritten, a pointer to the data from user space, and the size of the data to be overwritten.
But… there is no BPF helper function that can override parameters of a system call that are passed as direct values into registers.
Essentially, I propose a new BPF helper function, similar to bpf_probe_write_user, but designed to override the direct values of system call parameters.
For example, let’s take the system call open:
int open(const char *pathname, int flags);
Using bpf_probe_write_user we could modify the pathname parameter to a file of our choice. However, if we wish to preserve the flags parameter (or not), while also adding O_APPEND in case of a write, with the current BPF API, we cannot. We cannot modify the value of the register that holds the flags parameter using bpf_probe_write_user.
In order to override register values we have to add a new BPF helper function into the kernel, preferably implement it for every architecture the kernel supports 😭, and also add the new function reference in the BPF compiler BCC.
Someday, I may make the effort of writing an implementation that would work for all architectures, but for now I am going to describe a patch to make it work for the x86_64 architecture.
|
|
- First, we have to add the functionality to change the pt_regs structure at an arbitrary offset; this is done between lines 1 and 27 in /arch/x86/include/asm/ptrace.h.
- Secondly, we have to add the declaration of the eBPF helper function; this is done at line 30 in the /include/uapi/linux/bpf.h file.
- Thirdly, we have to add the eBPF helper function definition; this is done between lines 32 and 49 in the /kernel/trace/bpf_trace.c file.
- Lastly, the eBPF verifier must be made aware of the new eBPF helper function; this is done between lines 50 to 52, in the same file as the one in the previous step
I may not have followed the customary changes such a patch would entail, but this is a working patch that can be used to toy with.
As mentioned, besides the kernel, we have to patch the BCC compiler as well, in order to make it aware of the new eBPF helper function. The eBPF helper function must be simply declared in: src/cc/compat/linux/virtual_bpf.h, src/cc/export/helpers.h, src/cc/libbpf/src/include/uapi/linux/bpf.h, and src/cc/libbpf/src/bpf_helper_defs.h.
As a closing note: this new BPF helper function could open up new possibilities for dynamic system call manipulation, which in my opinion could be a very interesting feature to grow in BPF.