Commit 8c11ea5c authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Alexei Starovoitov

bpf, arm64: fix getting subprog addr from aux for calls

The arm64 JIT has the same issue as ppc64 JIT in that the relative BPF
to BPF call offset can be too far away from core kernel in that relative
encoding into imm is not sufficient and could potentially be truncated,
see also fd045f6c ("arm64: add support for module PLTs") which adds
spill-over space for module_alloc() and therefore bpf_jit_binary_alloc().
Therefore, use the recently added bpf_jit_get_func_addr() helper for
properly fetching the address through prog->aux->func[off]->bpf_func
instead. This also has the benefit to optimize normal helper calls since
their address can use the optimized emission. Tested on Cavium ThunderX
CN8890.

Fixes: db496944 ("bpf: arm64: add JIT support for multi-function programs")
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent e2c95a61
...@@ -351,7 +351,8 @@ static void build_epilogue(struct jit_ctx *ctx) ...@@ -351,7 +351,8 @@ static void build_epilogue(struct jit_ctx *ctx)
* >0 - successfully JITed a 16-byte eBPF instruction. * >0 - successfully JITed a 16-byte eBPF instruction.
* <0 - failed to JIT. * <0 - failed to JIT.
*/ */
static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
bool extra_pass)
{ {
const u8 code = insn->code; const u8 code = insn->code;
const u8 dst = bpf2a64[insn->dst_reg]; const u8 dst = bpf2a64[insn->dst_reg];
...@@ -625,12 +626,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) ...@@ -625,12 +626,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
case BPF_JMP | BPF_CALL: case BPF_JMP | BPF_CALL:
{ {
const u8 r0 = bpf2a64[BPF_REG_0]; const u8 r0 = bpf2a64[BPF_REG_0];
const u64 func = (u64)__bpf_call_base + imm; bool func_addr_fixed;
u64 func_addr;
int ret;
if (ctx->prog->is_func) ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
emit_addr_mov_i64(tmp, func, ctx); &func_addr, &func_addr_fixed);
if (ret < 0)
return ret;
if (func_addr_fixed)
/* We can use optimized emission here. */
emit_a64_mov_i64(tmp, func_addr, ctx);
else else
emit_a64_mov_i64(tmp, func, ctx); emit_addr_mov_i64(tmp, func_addr, ctx);
emit(A64_BLR(tmp), ctx); emit(A64_BLR(tmp), ctx);
emit(A64_MOV(1, r0, A64_R(0)), ctx); emit(A64_MOV(1, r0, A64_R(0)), ctx);
break; break;
...@@ -753,7 +761,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) ...@@ -753,7 +761,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
return 0; return 0;
} }
static int build_body(struct jit_ctx *ctx) static int build_body(struct jit_ctx *ctx, bool extra_pass)
{ {
const struct bpf_prog *prog = ctx->prog; const struct bpf_prog *prog = ctx->prog;
int i; int i;
...@@ -762,7 +770,7 @@ static int build_body(struct jit_ctx *ctx) ...@@ -762,7 +770,7 @@ static int build_body(struct jit_ctx *ctx)
const struct bpf_insn *insn = &prog->insnsi[i]; const struct bpf_insn *insn = &prog->insnsi[i];
int ret; int ret;
ret = build_insn(insn, ctx); ret = build_insn(insn, ctx, extra_pass);
if (ret > 0) { if (ret > 0) {
i++; i++;
if (ctx->image == NULL) if (ctx->image == NULL)
...@@ -858,7 +866,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) ...@@ -858,7 +866,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
/* 1. Initial fake pass to compute ctx->idx. */ /* 1. Initial fake pass to compute ctx->idx. */
/* Fake pass to fill in ctx->offset. */ /* Fake pass to fill in ctx->offset. */
if (build_body(&ctx)) { if (build_body(&ctx, extra_pass)) {
prog = orig_prog; prog = orig_prog;
goto out_off; goto out_off;
} }
...@@ -888,7 +896,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) ...@@ -888,7 +896,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
build_prologue(&ctx, was_classic); build_prologue(&ctx, was_classic);
if (build_body(&ctx)) { if (build_body(&ctx, extra_pass)) {
bpf_jit_binary_free(header); bpf_jit_binary_free(header);
prog = orig_prog; prog = orig_prog;
goto out_off; goto out_off;
......
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