Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
.eh_frame: Read user stacks from kernel context
Context ======= If a userspace process was compiled with frame pointers, we can rely on `bpf_get_stackid` with the `BPF_F_USER_STACK` flag to fetch user stacks. It does all the hard work, including making sure we can walk user stacks from kernel context, such as when we are executing a system call. When this happens, the kernel saves the userspace registers in memory. The registers we get through the perf events are the current registers. As we are in kernel context, these are registers that point to kernel data and code. For this reason, we need a way to recover said stored registers. If we were building a kernel extension we would use the `task_pt_regs` macro. There's a new helper [1] to achieve exactly this, `bpf_task_pt_regs`, but unfortunately we can't always rely on it's included only in v5.15 or greater. Proposed solution ================= We walk the internal kernel datastructures until we can read the x86_64 registers we need. In case we are in kernel context, and current thread is not a kernel process (kworker), we read the saved task's registers and continue the normal unwinding process. Notes ===== For some reason, not really sure about why; needs more investigation, writing this code has not been a walk in the park. The verifier didn't allow me to do direct pointer dereferences, that's why the code is littered with manual ones. Mostly complained with > `avoid R0 invalid mem access 'scalar'` The other interesting bit is that I can't make the verifier pass when checking for the return value of `set_initial_state` and returning if there is an issue. > dereference of modified ctx ptr R6 off=32 disallowed Additonally, the full `vmlinux.h` has been dumped as we need the definition of a bunch of structs. Future changes / areas of improvement ===================================== - Once we have automatic feature calibration we can use the new helper, if available, which will be more reliable; - This code is pretty fragile. Any changes in the running box, such as running with KASAN=on, will make it fail, resulting in missing kernel stacks; Test Plan ========= Ran it for 1h without issues. The kernel stacks now appear and look reasonable. See PR for more. **kernel tests** ``` ============= Test results: ============= - ✅ 5.4 - ✅ 5.10 - ✅ 5.18 - ✅ 5.19 ``` - [0]: https://github.com/torvalds/linux/blob/3d7cb6b04c3f3115719235cc6866b10326de34cd/arch/x86/include/asm/processor.h#L758-L763 - [1]: torvalds/linux@dd6e10f Signed-off-by: Francisco Javier Honduvilla Coto <[email protected]>
- Loading branch information