]> git.baikalelectronics.ru Git - kernel.git/commitdiff
bpf, x64: Allow to use caller address from stack
authorJiri Olsa <jolsa@kernel.org>
Wed, 20 Jul 2022 00:21:25 +0000 (17:21 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 22 Jul 2022 20:04:37 +0000 (22:04 +0200)
Currently we call the original function by using the absolute address
given at the JIT generation. That's not usable when having trampoline
attached to multiple functions, or the target address changes dynamically
(in case of live patch). In such cases we need to take the return address
from the stack.

Adding support to retrieve the original function address from the stack
by adding new BPF_TRAMP_F_ORIG_STACK flag for arch_prepare_bpf_trampoline
function.

Basically we take the return address of the 'fentry' call:

   function + 0: call fentry    # stores 'function + 5' address on stack
   function + 5: ...

The 'function + 5' address will be used as the address for the
original function to call.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Song Liu <song@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20220720002126.803253-4-song@kernel.org
arch/x86/net/bpf_jit_comp.c
include/linux/bpf.h

index 54c7f46c453fbd2ebcc66ea32de1f684e2b7738b..e1b0c5ed0b7c5900854c3d27e0a61c3418a616a8 100644 (file)
@@ -2119,10 +2119,15 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
        if (flags & BPF_TRAMP_F_CALL_ORIG) {
                restore_regs(m, &prog, nr_args, regs_off);
 
-               /* call original function */
-               if (emit_call(&prog, orig_call, prog)) {
-                       ret = -EINVAL;
-                       goto cleanup;
+               if (flags & BPF_TRAMP_F_ORIG_STACK) {
+                       emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, 8);
+                       EMIT2(0xff, 0xd0); /* call *rax */
+               } else {
+                       /* call original function */
+                       if (emit_call(&prog, orig_call, prog)) {
+                               ret = -EINVAL;
+                               goto cleanup;
+                       }
                }
                /* remember return value in a stack for bpf prog to access */
                emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8);
index a97751d845c9b2a0532d5693045979654c84b6ae..1d22df8bf306a9328345f9cc83819b1523fbb170 100644 (file)
@@ -751,6 +751,11 @@ struct btf_func_model {
 /* Return the return value of fentry prog. Only used by bpf_struct_ops. */
 #define BPF_TRAMP_F_RET_FENTRY_RET     BIT(4)
 
+/* Get original function from stack instead of from provided direct address.
+ * Makes sense for trampolines with fexit or fmod_ret programs.
+ */
+#define BPF_TRAMP_F_ORIG_STACK         BIT(5)
+
 /* Each call __bpf_prog_enter + call bpf_func + call __bpf_prog_exit is ~50
  * bytes on x86.
  */