Commit 90564f1e authored by Florent Revest's avatar Florent Revest Committed by Daniel Borkmann

bpf, arm64: Support struct arguments in the BPF trampoline

This extends the BPF trampoline JIT to support attachment to functions
that take small structures (up to 128bit) as argument. This is trivially
achieved by saving/restoring a number of "argument registers" rather
than a number of arguments.

The AAPCS64 section 6.8.2 describes the parameter passing ABI.
"Composite types" (like C structs) below 16 bytes (as enforced by the
BPF verifier) are provided as part of the 8 argument registers as
explained in the section C.12.
Signed-off-by: default avatarFlorent Revest <revest@chromium.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarYonghong Song <yhs@fb.com>
Acked-by: default avatarXu Kuohai <xukuohai@huawei.com>
Link: https://lore.kernel.org/bpf/20230511140507.514888-1-revest@chromium.org
parent 04cb8453
...@@ -1731,21 +1731,21 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl, ...@@ -1731,21 +1731,21 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl,
} }
} }
static void save_args(struct jit_ctx *ctx, int args_off, int nargs) static void save_args(struct jit_ctx *ctx, int args_off, int nregs)
{ {
int i; int i;
for (i = 0; i < nargs; i++) { for (i = 0; i < nregs; i++) {
emit(A64_STR64I(i, A64_SP, args_off), ctx); emit(A64_STR64I(i, A64_SP, args_off), ctx);
args_off += 8; args_off += 8;
} }
} }
static void restore_args(struct jit_ctx *ctx, int args_off, int nargs) static void restore_args(struct jit_ctx *ctx, int args_off, int nregs)
{ {
int i; int i;
for (i = 0; i < nargs; i++) { for (i = 0; i < nregs; i++) {
emit(A64_LDR64I(i, A64_SP, args_off), ctx); emit(A64_LDR64I(i, A64_SP, args_off), ctx);
args_off += 8; args_off += 8;
} }
...@@ -1764,7 +1764,7 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nargs) ...@@ -1764,7 +1764,7 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nargs)
*/ */
static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
struct bpf_tramp_links *tlinks, void *orig_call, struct bpf_tramp_links *tlinks, void *orig_call,
int nargs, u32 flags) int nregs, u32 flags)
{ {
int i; int i;
int stack_size; int stack_size;
...@@ -1772,7 +1772,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, ...@@ -1772,7 +1772,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
int regs_off; int regs_off;
int retval_off; int retval_off;
int args_off; int args_off;
int nargs_off; int nregs_off;
int ip_off; int ip_off;
int run_ctx_off; int run_ctx_off;
struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
...@@ -1795,11 +1795,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, ...@@ -1795,11 +1795,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
* SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or
* BPF_TRAMP_F_RET_FENTRY_RET * BPF_TRAMP_F_RET_FENTRY_RET
* *
* [ argN ] * [ arg reg N ]
* [ ... ] * [ ... ]
* SP + args_off [ arg1 ] * SP + args_off [ arg reg 1 ]
* *
* SP + nargs_off [ args count ] * SP + nregs_off [ arg regs count ]
* *
* SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag
* *
...@@ -1816,13 +1816,13 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, ...@@ -1816,13 +1816,13 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
if (flags & BPF_TRAMP_F_IP_ARG) if (flags & BPF_TRAMP_F_IP_ARG)
stack_size += 8; stack_size += 8;
nargs_off = stack_size; nregs_off = stack_size;
/* room for args count */ /* room for args count */
stack_size += 8; stack_size += 8;
args_off = stack_size; args_off = stack_size;
/* room for args */ /* room for args */
stack_size += nargs * 8; stack_size += nregs * 8;
/* room for return value */ /* room for return value */
retval_off = stack_size; retval_off = stack_size;
...@@ -1865,12 +1865,12 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, ...@@ -1865,12 +1865,12 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
emit(A64_STR64I(A64_R(10), A64_SP, ip_off), ctx); emit(A64_STR64I(A64_R(10), A64_SP, ip_off), ctx);
} }
/* save args count*/ /* save arg regs count*/
emit(A64_MOVZ(1, A64_R(10), nargs, 0), ctx); emit(A64_MOVZ(1, A64_R(10), nregs, 0), ctx);
emit(A64_STR64I(A64_R(10), A64_SP, nargs_off), ctx); emit(A64_STR64I(A64_R(10), A64_SP, nregs_off), ctx);
/* save args */ /* save arg regs */
save_args(ctx, args_off, nargs); save_args(ctx, args_off, nregs);
/* save callee saved registers */ /* save callee saved registers */
emit(A64_STR64I(A64_R(19), A64_SP, regs_off), ctx); emit(A64_STR64I(A64_R(19), A64_SP, regs_off), ctx);
...@@ -1897,7 +1897,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, ...@@ -1897,7 +1897,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
} }
if (flags & BPF_TRAMP_F_CALL_ORIG) { if (flags & BPF_TRAMP_F_CALL_ORIG) {
restore_args(ctx, args_off, nargs); restore_args(ctx, args_off, nregs);
/* call original func */ /* call original func */
emit(A64_LDR64I(A64_R(10), A64_SP, retaddr_off), ctx); emit(A64_LDR64I(A64_R(10), A64_SP, retaddr_off), ctx);
emit(A64_ADR(A64_LR, AARCH64_INSN_SIZE * 2), ctx); emit(A64_ADR(A64_LR, AARCH64_INSN_SIZE * 2), ctx);
...@@ -1926,7 +1926,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, ...@@ -1926,7 +1926,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
} }
if (flags & BPF_TRAMP_F_RESTORE_REGS) if (flags & BPF_TRAMP_F_RESTORE_REGS)
restore_args(ctx, args_off, nargs); restore_args(ctx, args_off, nregs);
/* restore callee saved register x19 and x20 */ /* restore callee saved register x19 and x20 */
emit(A64_LDR64I(A64_R(19), A64_SP, regs_off), ctx); emit(A64_LDR64I(A64_R(19), A64_SP, regs_off), ctx);
...@@ -1967,24 +1967,25 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, ...@@ -1967,24 +1967,25 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image,
void *orig_call) void *orig_call)
{ {
int i, ret; int i, ret;
int nargs = m->nr_args; int nregs = m->nr_args;
int max_insns = ((long)image_end - (long)image) / AARCH64_INSN_SIZE; int max_insns = ((long)image_end - (long)image) / AARCH64_INSN_SIZE;
struct jit_ctx ctx = { struct jit_ctx ctx = {
.image = NULL, .image = NULL,
.idx = 0, .idx = 0,
}; };
/* the first 8 arguments are passed by registers */ /* extra registers needed for struct argument */
if (nargs > 8)
return -ENOTSUPP;
/* don't support struct argument */
for (i = 0; i < MAX_BPF_FUNC_ARGS; i++) { for (i = 0; i < MAX_BPF_FUNC_ARGS; i++) {
/* The arg_size is at most 16 bytes, enforced by the verifier. */
if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG)
return -ENOTSUPP; nregs += (m->arg_size[i] + 7) / 8 - 1;
} }
ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nargs, flags); /* the first 8 registers are used for arguments */
if (nregs > 8)
return -ENOTSUPP;
ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1995,7 +1996,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, ...@@ -1995,7 +1996,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image,
ctx.idx = 0; ctx.idx = 0;
jit_fill_hole(image, (unsigned int)(image_end - image)); jit_fill_hole(image, (unsigned int)(image_end - image));
ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nargs, flags); ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags);
if (ret > 0 && validate_code(&ctx) < 0) if (ret > 0 && validate_code(&ctx) < 0)
ret = -EINVAL; ret = -EINVAL;
......
...@@ -10,4 +10,3 @@ kprobe_multi_test/link_api_addrs # link_fd unexpected link_fd: a ...@@ -10,4 +10,3 @@ kprobe_multi_test/link_api_addrs # link_fd unexpected link_fd: a
kprobe_multi_test/link_api_syms # link_fd unexpected link_fd: actual -95 < expected 0 kprobe_multi_test/link_api_syms # link_fd unexpected link_fd: actual -95 < expected 0
kprobe_multi_test/skel_api # libbpf: failed to load BPF skeleton 'kprobe_multi': -3 kprobe_multi_test/skel_api # libbpf: failed to load BPF skeleton 'kprobe_multi': -3
module_attach # prog 'kprobe_multi': failed to auto-attach: -95 module_attach # prog 'kprobe_multi': failed to auto-attach: -95
tracing_struct # tracing_struct__attach unexpected error: -524 (errno 524)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment