mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Pull bpf fixes from Alexei Starovoitov:
"Most of the diff stat comes from Xu Kuohai's fix to emit ENDBR/BTI,
since all JITs had to be touched to move constant blinding out and
pass bpf_verifier_env in.
- Fix use-after-free in arena_vm_close on fork (Alexei Starovoitov)
- Dissociate struct_ops program with map if map_update fails (Amery
Hung)
- Fix out-of-range and off-by-one bugs in arm64 JIT (Daniel Borkmann)
- Fix precedence bug in convert_bpf_ld_abs alignment check (Daniel
Borkmann)
- Fix arg tracking for imprecise/multi-offset in BPF_ST/STX insns
(Eduard Zingerman)
- Copy token from main to subprogs to fix missing kallsyms (Eduard
Zingerman)
- Prevent double close and leak of btf objects in libbpf (Jiri Olsa)
- Fix af_unix null-ptr-deref in sockmap (Michal Luczaj)
- Fix NULL deref in map_kptr_match_type for scalar regs (Mykyta
Yatsenko)
- Avoid unnecessary IPIs. Remove redundant bpf_flush_icache() in
arm64 and riscv JITs (Puranjay Mohan)
- Fix out of bounds access. Validate node_id in arena_alloc_pages()
(Puranjay Mohan)
- Reject BPF-to-BPF calls and callbacks in arm32 JIT (Puranjay Mohan)
- Refactor all JITs to pass bpf_verifier_env to emit ENDBR/BTI for
indirect jump targets on x86-64, arm64 JITs (Xu Kuohai)
- Allow UTF-8 literals in bpf_bprintf_prepare() (Yihan Ding)"
* tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: (32 commits)
bpf, arm32: Reject BPF-to-BPF calls and callbacks in the JIT
bpf: Dissociate struct_ops program with map if map_update fails
bpf: Validate node_id in arena_alloc_pages()
libbpf: Prevent double close and leak of btf objects
selftests/bpf: cover UTF-8 trace_printk output
bpf: allow UTF-8 literals in bpf_bprintf_prepare()
selftests/bpf: Reject scalar store into kptr slot
bpf: Fix NULL deref in map_kptr_match_type for scalar regs
bpf: Fix precedence bug in convert_bpf_ld_abs alignment check
bpf, arm64: Emit BTI for indirect jump target
bpf, x86: Emit ENDBR for indirect jump targets
bpf: Add helper to detect indirect jump targets
bpf: Pass bpf_verifier_env to JIT
bpf: Move constants blinding out of arch-specific JITs
bpf, sockmap: Take state lock for af_unix iter
bpf, sockmap: Fix af_unix null-ptr-deref in proto update
selftests/bpf: Extend bpf_iter_unix to attempt deadlocking
bpf, sockmap: Fix af_unix iter deadlock
bpf, sockmap: Annotate af_unix sock:: Sk_state data-races
selftests/bpf: verify kallsyms entries for token-loaded subprograms
...
This commit is contained in:
+15
-26
@@ -79,7 +79,6 @@ struct arc_jit_data {
|
||||
* The JIT pertinent context that is used by different functions.
|
||||
*
|
||||
* prog: The current eBPF program being handled.
|
||||
* orig_prog: The original eBPF program before any possible change.
|
||||
* jit: The JIT buffer and its length.
|
||||
* bpf_header: The JITed program header. "jit.buf" points inside it.
|
||||
* emit: If set, opcodes are written to memory; else, a dry-run.
|
||||
@@ -94,12 +93,10 @@ struct arc_jit_data {
|
||||
* need_extra_pass: A forecast if an "extra_pass" will occur.
|
||||
* is_extra_pass: Indicates if the current pass is an extra pass.
|
||||
* user_bpf_prog: True, if VM opcodes come from a real program.
|
||||
* blinded: True if "constant blinding" step returned a new "prog".
|
||||
* success: Indicates if the whole JIT went OK.
|
||||
*/
|
||||
struct jit_context {
|
||||
struct bpf_prog *prog;
|
||||
struct bpf_prog *orig_prog;
|
||||
struct jit_buffer jit;
|
||||
struct bpf_binary_header *bpf_header;
|
||||
bool emit;
|
||||
@@ -114,7 +111,6 @@ struct jit_context {
|
||||
bool need_extra_pass;
|
||||
bool is_extra_pass;
|
||||
bool user_bpf_prog;
|
||||
bool blinded;
|
||||
bool success;
|
||||
};
|
||||
|
||||
@@ -161,13 +157,7 @@ static int jit_ctx_init(struct jit_context *ctx, struct bpf_prog *prog)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
ctx->orig_prog = prog;
|
||||
|
||||
/* If constant blinding was requested but failed, scram. */
|
||||
ctx->prog = bpf_jit_blind_constants(prog);
|
||||
if (IS_ERR(ctx->prog))
|
||||
return PTR_ERR(ctx->prog);
|
||||
ctx->blinded = (ctx->prog != ctx->orig_prog);
|
||||
ctx->prog = prog;
|
||||
|
||||
/* If the verifier doesn't zero-extend, then we have to do it. */
|
||||
ctx->do_zext = !ctx->prog->aux->verifier_zext;
|
||||
@@ -214,14 +204,6 @@ static inline void maybe_free(struct jit_context *ctx, void **mem)
|
||||
*/
|
||||
static void jit_ctx_cleanup(struct jit_context *ctx)
|
||||
{
|
||||
if (ctx->blinded) {
|
||||
/* if all went well, release the orig_prog. */
|
||||
if (ctx->success)
|
||||
bpf_jit_prog_release_other(ctx->prog, ctx->orig_prog);
|
||||
else
|
||||
bpf_jit_prog_release_other(ctx->orig_prog, ctx->prog);
|
||||
}
|
||||
|
||||
maybe_free(ctx, (void **)&ctx->bpf2insn);
|
||||
maybe_free(ctx, (void **)&ctx->jit_data);
|
||||
|
||||
@@ -229,12 +211,19 @@ static void jit_ctx_cleanup(struct jit_context *ctx)
|
||||
ctx->bpf2insn_valid = false;
|
||||
|
||||
/* Freeing "bpf_header" is enough. "jit.buf" is a sub-array of it. */
|
||||
if (!ctx->success && ctx->bpf_header) {
|
||||
bpf_jit_binary_free(ctx->bpf_header);
|
||||
ctx->bpf_header = NULL;
|
||||
ctx->jit.buf = NULL;
|
||||
ctx->jit.index = 0;
|
||||
ctx->jit.len = 0;
|
||||
if (!ctx->success) {
|
||||
if (ctx->bpf_header) {
|
||||
bpf_jit_binary_free(ctx->bpf_header);
|
||||
ctx->bpf_header = NULL;
|
||||
ctx->jit.buf = NULL;
|
||||
ctx->jit.index = 0;
|
||||
ctx->jit.len = 0;
|
||||
}
|
||||
if (ctx->is_extra_pass) {
|
||||
ctx->prog->bpf_func = NULL;
|
||||
ctx->prog->jited = 0;
|
||||
ctx->prog->jited_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->emit = false;
|
||||
@@ -1411,7 +1400,7 @@ static struct bpf_prog *do_extra_pass(struct bpf_prog *prog)
|
||||
* (re)locations involved that their addresses are not known
|
||||
* during the first run.
|
||||
*/
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
vm_dump(prog);
|
||||
|
||||
|
||||
+14
-35
@@ -1852,6 +1852,9 @@ exit:
|
||||
{
|
||||
u64 val = (u32)imm | (u64)insn[1].imm << 32;
|
||||
|
||||
if (insn->src_reg == BPF_PSEUDO_FUNC)
|
||||
goto notyet;
|
||||
|
||||
emit_a32_mov_i64(dst, val, ctx);
|
||||
|
||||
return 1;
|
||||
@@ -2055,6 +2058,9 @@ go_jmp:
|
||||
const s8 *r5 = bpf2a32[BPF_REG_5];
|
||||
const u32 func = (u32)__bpf_call_base + (u32)imm;
|
||||
|
||||
if (insn->src_reg == BPF_PSEUDO_CALL)
|
||||
goto notyet;
|
||||
|
||||
emit_a32_mov_r64(true, r0, r1, ctx);
|
||||
emit_a32_mov_r64(true, r1, r2, ctx);
|
||||
emit_push_r64(r5, ctx);
|
||||
@@ -2142,11 +2148,9 @@ bool bpf_jit_needs_zext(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
struct bpf_binary_header *header;
|
||||
bool tmp_blinded = false;
|
||||
struct jit_ctx ctx;
|
||||
unsigned int tmp_idx;
|
||||
unsigned int image_size;
|
||||
@@ -2156,20 +2160,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
* the interpreter.
|
||||
*/
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
/* If constant blinding was enabled and we failed during blinding
|
||||
* then we must fall back to the interpreter. Otherwise, we save
|
||||
* the new JITed code.
|
||||
*/
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.prog = prog;
|
||||
@@ -2179,10 +2170,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
* we must fall back to the interpreter
|
||||
*/
|
||||
ctx.offsets = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
|
||||
if (ctx.offsets == NULL) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
if (ctx.offsets == NULL)
|
||||
return prog;
|
||||
|
||||
/* 1) fake pass to find in the length of the JITed code,
|
||||
* to compute ctx->offsets and other context variables
|
||||
@@ -2194,10 +2183,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
* being successful in the second pass, so just fall back
|
||||
* to the interpreter.
|
||||
*/
|
||||
if (build_body(&ctx)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(&ctx))
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
tmp_idx = ctx.idx;
|
||||
build_prologue(&ctx);
|
||||
@@ -2213,10 +2200,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
ctx.idx += ctx.imm_count;
|
||||
if (ctx.imm_count) {
|
||||
ctx.imms = kcalloc(ctx.imm_count, sizeof(u32), GFP_KERNEL);
|
||||
if (ctx.imms == NULL) {
|
||||
prog = orig_prog;
|
||||
if (ctx.imms == NULL)
|
||||
goto out_off;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* there's nothing about the epilogue on ARMv7 */
|
||||
@@ -2238,10 +2223,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
/* Not able to allocate memory for the structure then
|
||||
* we must fall back to the interpretation
|
||||
*/
|
||||
if (header == NULL) {
|
||||
prog = orig_prog;
|
||||
if (header == NULL)
|
||||
goto out_imms;
|
||||
}
|
||||
|
||||
/* 2.) Actual pass to generate final JIT code */
|
||||
ctx.target = (u32 *) image_ptr;
|
||||
@@ -2278,16 +2261,12 @@ out_imms:
|
||||
#endif
|
||||
out_off:
|
||||
kfree(ctx.offsets);
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
|
||||
return prog;
|
||||
|
||||
out_free:
|
||||
image_ptr = NULL;
|
||||
bpf_jit_binary_free(header);
|
||||
prog = orig_prog;
|
||||
goto out_imms;
|
||||
}
|
||||
|
||||
|
||||
@@ -338,6 +338,8 @@ u32 aarch64_insn_gen_cond_branch_imm(unsigned long pc, unsigned long addr,
|
||||
long offset;
|
||||
|
||||
offset = label_imm_common(pc, addr, SZ_1M);
|
||||
if (offset >= SZ_1M)
|
||||
return AARCH64_BREAK_FAULT;
|
||||
|
||||
insn = aarch64_insn_get_bcond_value();
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <asm/asm-extable.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
#include <asm/insn.h>
|
||||
@@ -35,8 +34,8 @@
|
||||
#define ARENA_VM_START (MAX_BPF_JIT_REG + 5)
|
||||
|
||||
#define check_imm(bits, imm) do { \
|
||||
if ((((imm) > 0) && ((imm) >> (bits))) || \
|
||||
(((imm) < 0) && (~(imm) >> (bits)))) { \
|
||||
if ((((imm) > 0) && ((imm) >> ((bits) - 1))) || \
|
||||
(((imm) < 0) && (~(imm) >> ((bits) - 1)))) { \
|
||||
pr_info("[%2d] imm=%d(0x%x) out of range\n", \
|
||||
i, imm, imm); \
|
||||
return -EINVAL; \
|
||||
@@ -1198,8 +1197,8 @@ static int add_exception_handler(const struct bpf_insn *insn,
|
||||
* >0 - successfully JITed a 16-byte eBPF instruction.
|
||||
* <0 - failed to JIT.
|
||||
*/
|
||||
static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
||||
bool extra_pass)
|
||||
static int build_insn(const struct bpf_verifier_env *env, const struct bpf_insn *insn,
|
||||
struct jit_ctx *ctx, bool extra_pass)
|
||||
{
|
||||
const u8 code = insn->code;
|
||||
u8 dst = bpf2a64[insn->dst_reg];
|
||||
@@ -1224,6 +1223,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
|
||||
int ret;
|
||||
bool sign_extend;
|
||||
|
||||
if (bpf_insn_is_indirect_target(env, ctx->prog, i))
|
||||
emit_bti(A64_BTI_J, ctx);
|
||||
|
||||
switch (code) {
|
||||
/* dst = src */
|
||||
case BPF_ALU | BPF_MOV | BPF_X:
|
||||
@@ -1899,7 +1901,7 @@ emit_cond_jmp:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_body(struct jit_ctx *ctx, bool extra_pass)
|
||||
static int build_body(struct bpf_verifier_env *env, struct jit_ctx *ctx, bool extra_pass)
|
||||
{
|
||||
const struct bpf_prog *prog = ctx->prog;
|
||||
int i;
|
||||
@@ -1918,7 +1920,7 @@ static int build_body(struct jit_ctx *ctx, bool extra_pass)
|
||||
int ret;
|
||||
|
||||
ctx->offset[i] = ctx->idx;
|
||||
ret = build_insn(insn, ctx, extra_pass);
|
||||
ret = build_insn(env, insn, ctx, extra_pass);
|
||||
if (ret > 0) {
|
||||
i++;
|
||||
ctx->offset[i] = ctx->idx;
|
||||
@@ -1961,11 +1963,6 @@ static int validate_ctx(struct jit_ctx *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void bpf_flush_icache(void *start, void *end)
|
||||
{
|
||||
flush_icache_range((unsigned long)start, (unsigned long)end);
|
||||
}
|
||||
|
||||
static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size)
|
||||
{
|
||||
int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
|
||||
@@ -2006,17 +2003,15 @@ struct arm64_jit_data {
|
||||
struct jit_ctx ctx;
|
||||
};
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
int image_size, prog_size, extable_size, extable_align, extable_offset;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
struct bpf_binary_header *header;
|
||||
struct bpf_binary_header *ro_header = NULL;
|
||||
struct arm64_jit_data *jit_data;
|
||||
void __percpu *priv_stack_ptr = NULL;
|
||||
bool was_classic = bpf_prog_was_classic(prog);
|
||||
int priv_stack_alloc_sz;
|
||||
bool tmp_blinded = false;
|
||||
bool extra_pass = false;
|
||||
struct jit_ctx ctx;
|
||||
u8 *image_ptr;
|
||||
@@ -2025,26 +2020,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
int exentry_idx;
|
||||
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
/* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
jit_data = prog->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
if (!jit_data)
|
||||
return prog;
|
||||
prog->aux->jit_data = jit_data;
|
||||
}
|
||||
priv_stack_ptr = prog->aux->priv_stack_ptr;
|
||||
@@ -2056,10 +2038,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 16) +
|
||||
2 * PRIV_STACK_GUARD_SZ;
|
||||
priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 16, GFP_KERNEL);
|
||||
if (!priv_stack_ptr) {
|
||||
prog = orig_prog;
|
||||
if (!priv_stack_ptr)
|
||||
goto out_priv_stack;
|
||||
}
|
||||
|
||||
priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
|
||||
prog->aux->priv_stack_ptr = priv_stack_ptr;
|
||||
@@ -2079,10 +2059,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
ctx.prog = prog;
|
||||
|
||||
ctx.offset = kvzalloc_objs(int, prog->len + 1);
|
||||
if (ctx.offset == NULL) {
|
||||
prog = orig_prog;
|
||||
if (ctx.offset == NULL)
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
|
||||
ctx.arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
|
||||
@@ -2095,15 +2073,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
* BPF line info needs ctx->offset[i] to be the offset of
|
||||
* instruction[i] in jited image, so build prologue first.
|
||||
*/
|
||||
if (build_prologue(&ctx, was_classic)) {
|
||||
prog = orig_prog;
|
||||
if (build_prologue(&ctx, was_classic))
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
if (build_body(&ctx, extra_pass)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(env, &ctx, extra_pass))
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
ctx.epilogue_offset = ctx.idx;
|
||||
build_epilogue(&ctx, was_classic);
|
||||
@@ -2121,10 +2095,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
|
||||
sizeof(u64), &header, &image_ptr,
|
||||
jit_fill_hole);
|
||||
if (!ro_header) {
|
||||
prog = orig_prog;
|
||||
if (!ro_header)
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
/* Pass 2: Determine jited position and result for each instruction */
|
||||
|
||||
@@ -2152,10 +2124,8 @@ skip_init_ctx:
|
||||
/* Dont write body instructions to memory for now */
|
||||
ctx.write = false;
|
||||
|
||||
if (build_body(&ctx, extra_pass)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(env, &ctx, extra_pass))
|
||||
goto out_free_hdr;
|
||||
}
|
||||
|
||||
ctx.epilogue_offset = ctx.idx;
|
||||
ctx.exentry_idx = exentry_idx;
|
||||
@@ -2163,20 +2133,16 @@ skip_init_ctx:
|
||||
ctx.write = true;
|
||||
|
||||
/* Pass 3: Adjust jump offset and write final image */
|
||||
if (build_body(&ctx, extra_pass) ||
|
||||
WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(env, &ctx, extra_pass) ||
|
||||
WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset))
|
||||
goto out_free_hdr;
|
||||
}
|
||||
|
||||
build_epilogue(&ctx, was_classic);
|
||||
build_plt(&ctx);
|
||||
|
||||
/* Extra pass to validate JITed code. */
|
||||
if (validate_ctx(&ctx)) {
|
||||
prog = orig_prog;
|
||||
if (validate_ctx(&ctx))
|
||||
goto out_free_hdr;
|
||||
}
|
||||
|
||||
/* update the real prog size */
|
||||
prog_size = sizeof(u32) * ctx.idx;
|
||||
@@ -2193,23 +2159,14 @@ skip_init_ctx:
|
||||
if (extra_pass && ctx.idx > jit_data->ctx.idx) {
|
||||
pr_err_once("multi-func JIT bug %d > %d\n",
|
||||
ctx.idx, jit_data->ctx.idx);
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
goto out_free_hdr;
|
||||
}
|
||||
if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
|
||||
/* ro_header has been freed */
|
||||
/* ro_header and header has been freed */
|
||||
ro_header = NULL;
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
header = NULL;
|
||||
goto out_free_hdr;
|
||||
}
|
||||
/*
|
||||
* The instructions have now been copied to the ROX region from
|
||||
* where they will execute. Now the data cache has to be cleaned to
|
||||
* the PoU and the I-cache has to be invalidated for the VAs.
|
||||
*/
|
||||
bpf_flush_icache(ro_header, ctx.ro_image + ctx.idx);
|
||||
} else {
|
||||
jit_data->ctx = ctx;
|
||||
jit_data->ro_image = ro_image_ptr;
|
||||
@@ -2245,13 +2202,15 @@ out_priv_stack:
|
||||
kfree(jit_data);
|
||||
prog->aux->jit_data = NULL;
|
||||
}
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
|
||||
return prog;
|
||||
|
||||
out_free_hdr:
|
||||
if (extra_pass) {
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
}
|
||||
if (header) {
|
||||
bpf_arch_text_copy(&ro_header->size, &header->size,
|
||||
sizeof(header->size));
|
||||
|
||||
@@ -1920,45 +1920,28 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
||||
return ret < 0 ? ret : ret * LOONGARCH_INSN_SIZE;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
bool tmp_blinded = false, extra_pass = false;
|
||||
bool extra_pass = false;
|
||||
u8 *image_ptr, *ro_image_ptr;
|
||||
int image_size, prog_size, extable_size;
|
||||
struct jit_ctx ctx;
|
||||
struct jit_data *jit_data;
|
||||
struct bpf_binary_header *header;
|
||||
struct bpf_binary_header *ro_header;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
|
||||
/*
|
||||
* If BPF JIT was not enabled then we must fall back to
|
||||
* the interpreter.
|
||||
*/
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
/*
|
||||
* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter. Otherwise, we save
|
||||
* the new JITed code.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
jit_data = prog->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
if (!jit_data)
|
||||
return prog;
|
||||
prog->aux->jit_data = jit_data;
|
||||
}
|
||||
if (jit_data->ctx.offset) {
|
||||
@@ -1978,17 +1961,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
|
||||
|
||||
ctx.offset = kvcalloc(prog->len + 1, sizeof(u32), GFP_KERNEL);
|
||||
if (ctx.offset == NULL) {
|
||||
prog = orig_prog;
|
||||
if (ctx.offset == NULL)
|
||||
goto out_offset;
|
||||
}
|
||||
|
||||
/* 1. Initial fake pass to compute ctx->idx and set ctx->flags */
|
||||
build_prologue(&ctx);
|
||||
if (build_body(&ctx, extra_pass)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(&ctx, extra_pass))
|
||||
goto out_offset;
|
||||
}
|
||||
ctx.epilogue_offset = ctx.idx;
|
||||
build_epilogue(&ctx);
|
||||
|
||||
@@ -2004,10 +1983,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
/* Now we know the size of the structure to make */
|
||||
ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32),
|
||||
&header, &image_ptr, jit_fill_hole);
|
||||
if (!ro_header) {
|
||||
prog = orig_prog;
|
||||
if (!ro_header)
|
||||
goto out_offset;
|
||||
}
|
||||
|
||||
/* 2. Now, the actual pass to generate final JIT code */
|
||||
/*
|
||||
@@ -2027,17 +2004,13 @@ skip_init_ctx:
|
||||
ctx.num_exentries = 0;
|
||||
|
||||
build_prologue(&ctx);
|
||||
if (build_body(&ctx, extra_pass)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(&ctx, extra_pass))
|
||||
goto out_free;
|
||||
}
|
||||
build_epilogue(&ctx);
|
||||
|
||||
/* 3. Extra pass to validate JITed code */
|
||||
if (validate_ctx(&ctx)) {
|
||||
prog = orig_prog;
|
||||
if (validate_ctx(&ctx))
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* And we're done */
|
||||
if (bpf_jit_enable > 1)
|
||||
@@ -2050,9 +2023,9 @@ skip_init_ctx:
|
||||
goto out_free;
|
||||
}
|
||||
if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
|
||||
/* ro_header has been freed */
|
||||
/* ro_header and header have been freed */
|
||||
ro_header = NULL;
|
||||
prog = orig_prog;
|
||||
header = NULL;
|
||||
goto out_free;
|
||||
}
|
||||
/*
|
||||
@@ -2084,13 +2057,15 @@ out_offset:
|
||||
prog->aux->jit_data = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ? tmp : orig_prog);
|
||||
|
||||
return prog;
|
||||
|
||||
out_free:
|
||||
if (extra_pass) {
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
}
|
||||
|
||||
if (header) {
|
||||
bpf_arch_text_copy(&ro_header->size, &header->size, sizeof(header->size));
|
||||
bpf_jit_binary_pack_free(ro_header, header);
|
||||
|
||||
@@ -909,12 +909,10 @@ bool bpf_jit_needs_zext(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
struct bpf_binary_header *header = NULL;
|
||||
struct jit_context ctx;
|
||||
bool tmp_blinded = false;
|
||||
unsigned int tmp_idx;
|
||||
unsigned int image_size;
|
||||
u8 *image_ptr;
|
||||
@@ -925,19 +923,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
* the interpreter.
|
||||
*/
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
/*
|
||||
* If constant blinding was enabled and we failed during blinding
|
||||
* then we must fall back to the interpreter. Otherwise, we save
|
||||
* the new JITed code.
|
||||
*/
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.program = prog;
|
||||
@@ -1025,14 +1011,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
prog->jited_len = image_size;
|
||||
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
kfree(ctx.descriptors);
|
||||
return prog;
|
||||
|
||||
out_err:
|
||||
prog = orig_prog;
|
||||
if (header)
|
||||
bpf_jit_binary_free(header);
|
||||
goto out;
|
||||
|
||||
@@ -41,33 +41,22 @@ bool bpf_jit_needs_zext(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
unsigned int prog_size = 0, extable_size = 0;
|
||||
bool tmp_blinded = false, extra_pass = false;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
bool extra_pass = false;
|
||||
int pass = 0, prev_ninsns = 0, prologue_len, i;
|
||||
struct hppa_jit_data *jit_data;
|
||||
struct hppa_jit_context *ctx;
|
||||
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
jit_data = prog->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
if (!jit_data)
|
||||
return prog;
|
||||
prog->aux->jit_data = jit_data;
|
||||
}
|
||||
|
||||
@@ -81,10 +70,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
|
||||
ctx->prog = prog;
|
||||
ctx->offset = kzalloc_objs(int, prog->len);
|
||||
if (!ctx->offset) {
|
||||
prog = orig_prog;
|
||||
goto out_offset;
|
||||
}
|
||||
if (!ctx->offset)
|
||||
goto out_err;
|
||||
for (i = 0; i < prog->len; i++) {
|
||||
prev_ninsns += 20;
|
||||
ctx->offset[i] = prev_ninsns;
|
||||
@@ -93,10 +80,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
for (i = 0; i < NR_JIT_ITERATIONS; i++) {
|
||||
pass++;
|
||||
ctx->ninsns = 0;
|
||||
if (build_body(ctx, extra_pass, ctx->offset)) {
|
||||
prog = orig_prog;
|
||||
goto out_offset;
|
||||
}
|
||||
if (build_body(ctx, extra_pass, ctx->offset))
|
||||
goto out_err;
|
||||
ctx->body_len = ctx->ninsns;
|
||||
bpf_jit_build_prologue(ctx);
|
||||
ctx->prologue_len = ctx->ninsns - ctx->body_len;
|
||||
@@ -116,10 +101,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
&jit_data->image,
|
||||
sizeof(long),
|
||||
bpf_fill_ill_insns);
|
||||
if (!jit_data->header) {
|
||||
prog = orig_prog;
|
||||
goto out_offset;
|
||||
}
|
||||
if (!jit_data->header)
|
||||
goto out_err;
|
||||
|
||||
ctx->insns = (u32 *)jit_data->image;
|
||||
/*
|
||||
@@ -134,8 +117,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
|
||||
if (jit_data->header)
|
||||
bpf_jit_binary_free(jit_data->header);
|
||||
prog = orig_prog;
|
||||
goto out_offset;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (extable_size)
|
||||
@@ -148,8 +130,7 @@ skip_init_ctx:
|
||||
bpf_jit_build_prologue(ctx);
|
||||
if (build_body(ctx, extra_pass, NULL)) {
|
||||
bpf_jit_binary_free(jit_data->header);
|
||||
prog = orig_prog;
|
||||
goto out_offset;
|
||||
goto out_err;
|
||||
}
|
||||
bpf_jit_build_epilogue(ctx);
|
||||
|
||||
@@ -160,20 +141,19 @@ skip_init_ctx:
|
||||
{ extern int machine_restart(char *); machine_restart(""); }
|
||||
}
|
||||
|
||||
if (!prog->is_func || extra_pass) {
|
||||
if (bpf_jit_binary_lock_ro(jit_data->header)) {
|
||||
bpf_jit_binary_free(jit_data->header);
|
||||
goto out_err;
|
||||
}
|
||||
bpf_flush_icache(jit_data->header, ctx->insns + ctx->ninsns);
|
||||
}
|
||||
|
||||
prog->bpf_func = (void *)ctx->insns;
|
||||
prog->jited = 1;
|
||||
prog->jited_len = prog_size;
|
||||
|
||||
bpf_flush_icache(jit_data->header, ctx->insns + ctx->ninsns);
|
||||
|
||||
if (!prog->is_func || extra_pass) {
|
||||
if (bpf_jit_binary_lock_ro(jit_data->header)) {
|
||||
bpf_jit_binary_free(jit_data->header);
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
goto out_offset;
|
||||
}
|
||||
prologue_len = ctx->epilogue_offset - ctx->body_len;
|
||||
for (i = 0; i < prog->len; i++)
|
||||
ctx->offset[i] += prologue_len;
|
||||
@@ -183,14 +163,19 @@ out_offset:
|
||||
kfree(jit_data);
|
||||
prog->aux->jit_data = NULL;
|
||||
}
|
||||
out:
|
||||
|
||||
if (HPPA_JIT_REBOOT)
|
||||
{ extern int machine_restart(char *); machine_restart(""); }
|
||||
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
return prog;
|
||||
|
||||
out_err:
|
||||
if (extra_pass) {
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
}
|
||||
goto out_offset;
|
||||
}
|
||||
|
||||
u64 hppa_div64(u64 div, u64 divisor)
|
||||
|
||||
@@ -162,7 +162,7 @@ static void priv_stack_check_guard(void __percpu *priv_stack_ptr, int alloc_size
|
||||
}
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *fp)
|
||||
{
|
||||
u32 proglen;
|
||||
u32 alloclen;
|
||||
@@ -177,9 +177,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
void __percpu *priv_stack_ptr = NULL;
|
||||
struct bpf_binary_header *fhdr = NULL;
|
||||
struct bpf_binary_header *hdr = NULL;
|
||||
struct bpf_prog *org_fp = fp;
|
||||
struct bpf_prog *tmp_fp = NULL;
|
||||
bool bpf_blinded = false;
|
||||
bool extra_pass = false;
|
||||
u8 *fimage = NULL;
|
||||
u32 *fcode_base = NULL;
|
||||
@@ -187,24 +184,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
u32 fixup_len;
|
||||
|
||||
if (!fp->jit_requested)
|
||||
return org_fp;
|
||||
|
||||
tmp_fp = bpf_jit_blind_constants(org_fp);
|
||||
if (IS_ERR(tmp_fp))
|
||||
return org_fp;
|
||||
|
||||
if (tmp_fp != org_fp) {
|
||||
bpf_blinded = true;
|
||||
fp = tmp_fp;
|
||||
}
|
||||
return fp;
|
||||
|
||||
jit_data = fp->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
fp = org_fp;
|
||||
goto out;
|
||||
}
|
||||
if (!jit_data)
|
||||
return fp;
|
||||
fp->aux->jit_data = jit_data;
|
||||
}
|
||||
|
||||
@@ -219,10 +205,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
priv_stack_alloc_size = round_up(fp->aux->stack_depth, 16) +
|
||||
2 * PRIV_STACK_GUARD_SZ;
|
||||
priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_size, 16, GFP_KERNEL);
|
||||
if (!priv_stack_ptr) {
|
||||
fp = org_fp;
|
||||
if (!priv_stack_ptr)
|
||||
goto out_priv_stack;
|
||||
}
|
||||
|
||||
priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_size);
|
||||
fp->aux->priv_stack_ptr = priv_stack_ptr;
|
||||
@@ -249,10 +233,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
}
|
||||
|
||||
addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL);
|
||||
if (addrs == NULL) {
|
||||
fp = org_fp;
|
||||
goto out_addrs;
|
||||
}
|
||||
if (addrs == NULL)
|
||||
goto out_err;
|
||||
|
||||
memset(&cgctx, 0, sizeof(struct codegen_context));
|
||||
bpf_jit_init_reg_mapping(&cgctx);
|
||||
@@ -279,11 +261,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
}
|
||||
|
||||
/* Scouting faux-generate pass 0 */
|
||||
if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
|
||||
if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
|
||||
/* We hit something illegal or unsupported. */
|
||||
fp = org_fp;
|
||||
goto out_addrs;
|
||||
}
|
||||
goto out_err;
|
||||
|
||||
/*
|
||||
* If we have seen a tail call, we need a second pass.
|
||||
@@ -294,10 +274,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
*/
|
||||
if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {
|
||||
cgctx.idx = 0;
|
||||
if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
|
||||
fp = org_fp;
|
||||
goto out_addrs;
|
||||
}
|
||||
if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
bpf_jit_realloc_regs(&cgctx);
|
||||
@@ -318,10 +296,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
|
||||
fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image,
|
||||
bpf_jit_fill_ill_insns);
|
||||
if (!fhdr) {
|
||||
fp = org_fp;
|
||||
goto out_addrs;
|
||||
}
|
||||
if (!fhdr)
|
||||
goto out_err;
|
||||
|
||||
if (extable_len)
|
||||
fp->aux->extable = (void *)fimage + FUNCTION_DESCR_SIZE + proglen + fixup_len;
|
||||
@@ -340,8 +316,7 @@ skip_init_ctx:
|
||||
extra_pass)) {
|
||||
bpf_arch_text_copy(&fhdr->size, &hdr->size, sizeof(hdr->size));
|
||||
bpf_jit_binary_pack_free(fhdr, hdr);
|
||||
fp = org_fp;
|
||||
goto out_addrs;
|
||||
goto out_err;
|
||||
}
|
||||
bpf_jit_build_epilogue(code_base, &cgctx);
|
||||
|
||||
@@ -363,15 +338,16 @@ skip_init_ctx:
|
||||
((u64 *)image)[1] = local_paca->kernel_toc;
|
||||
#endif
|
||||
|
||||
if (!fp->is_func || extra_pass) {
|
||||
if (bpf_jit_binary_pack_finalize(fhdr, hdr))
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
fp->bpf_func = (void *)fimage;
|
||||
fp->jited = 1;
|
||||
fp->jited_len = cgctx.idx * 4 + FUNCTION_DESCR_SIZE;
|
||||
|
||||
if (!fp->is_func || extra_pass) {
|
||||
if (bpf_jit_binary_pack_finalize(fhdr, hdr)) {
|
||||
fp = org_fp;
|
||||
goto out_addrs;
|
||||
}
|
||||
bpf_prog_fill_jited_linfo(fp, addrs);
|
||||
/*
|
||||
* On ABI V1, executable code starts after the function
|
||||
@@ -398,11 +374,15 @@ out_priv_stack:
|
||||
jit_data->hdr = hdr;
|
||||
}
|
||||
|
||||
out:
|
||||
if (bpf_blinded)
|
||||
bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp);
|
||||
|
||||
return fp;
|
||||
|
||||
out_err:
|
||||
if (extra_pass) {
|
||||
fp->bpf_func = NULL;
|
||||
fp->jited = 0;
|
||||
fp->jited_len = 0;
|
||||
}
|
||||
goto out_addrs;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/filter.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/* verify runtime detection extension status */
|
||||
#define rv_ext_enabled(ext) \
|
||||
@@ -105,11 +104,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size)
|
||||
memset(area, 0, size);
|
||||
}
|
||||
|
||||
static inline void bpf_flush_icache(void *start, void *end)
|
||||
{
|
||||
flush_icache_range((unsigned long)start, (unsigned long)end);
|
||||
}
|
||||
|
||||
/* Emit a 4-byte riscv instruction. */
|
||||
static inline void emit(const u32 insn, struct rv_jit_context *ctx)
|
||||
{
|
||||
|
||||
@@ -41,32 +41,22 @@ bool bpf_jit_needs_zext(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
unsigned int prog_size = 0, extable_size = 0;
|
||||
bool tmp_blinded = false, extra_pass = false;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
bool extra_pass = false;
|
||||
int pass = 0, prev_ninsns = 0, i;
|
||||
struct rv_jit_data *jit_data;
|
||||
struct rv_jit_context *ctx;
|
||||
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
jit_data = prog->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
return prog;
|
||||
}
|
||||
prog->aux->jit_data = jit_data;
|
||||
}
|
||||
@@ -83,15 +73,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
|
||||
ctx->prog = prog;
|
||||
ctx->offset = kzalloc_objs(int, prog->len);
|
||||
if (!ctx->offset) {
|
||||
prog = orig_prog;
|
||||
if (!ctx->offset)
|
||||
goto out_offset;
|
||||
}
|
||||
|
||||
if (build_body(ctx, extra_pass, NULL)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(ctx, extra_pass, NULL))
|
||||
goto out_offset;
|
||||
}
|
||||
|
||||
for (i = 0; i < prog->len; i++) {
|
||||
prev_ninsns += 32;
|
||||
@@ -105,10 +91,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
|
||||
ctx->prologue_len = ctx->ninsns;
|
||||
|
||||
if (build_body(ctx, extra_pass, ctx->offset)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(ctx, extra_pass, ctx->offset))
|
||||
goto out_offset;
|
||||
}
|
||||
|
||||
ctx->epilogue_offset = ctx->ninsns;
|
||||
bpf_jit_build_epilogue(ctx);
|
||||
@@ -126,10 +110,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
&jit_data->ro_image, sizeof(u32),
|
||||
&jit_data->header, &jit_data->image,
|
||||
bpf_fill_ill_insns);
|
||||
if (!jit_data->ro_header) {
|
||||
prog = orig_prog;
|
||||
if (!jit_data->ro_header)
|
||||
goto out_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the image(RW) for writing the JITed instructions. But also save
|
||||
@@ -150,7 +132,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
|
||||
if (i == NR_JIT_ITERATIONS) {
|
||||
pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
|
||||
prog = orig_prog;
|
||||
goto out_free_hdr;
|
||||
}
|
||||
|
||||
@@ -163,33 +144,27 @@ skip_init_ctx:
|
||||
ctx->nexentries = 0;
|
||||
|
||||
bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
|
||||
if (build_body(ctx, extra_pass, NULL)) {
|
||||
prog = orig_prog;
|
||||
if (build_body(ctx, extra_pass, NULL))
|
||||
goto out_free_hdr;
|
||||
}
|
||||
bpf_jit_build_epilogue(ctx);
|
||||
|
||||
if (bpf_jit_enable > 1)
|
||||
bpf_jit_dump(prog->len, prog_size, pass, ctx->insns);
|
||||
|
||||
if (!prog->is_func || extra_pass) {
|
||||
if (WARN_ON(bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header))) {
|
||||
/* ro_header has been freed */
|
||||
jit_data->ro_header = NULL;
|
||||
jit_data->header = NULL;
|
||||
goto out_free_hdr;
|
||||
}
|
||||
}
|
||||
|
||||
prog->bpf_func = (void *)ctx->ro_insns + cfi_get_offset();
|
||||
prog->jited = 1;
|
||||
prog->jited_len = prog_size - cfi_get_offset();
|
||||
|
||||
if (!prog->is_func || extra_pass) {
|
||||
if (WARN_ON(bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header))) {
|
||||
/* ro_header has been freed */
|
||||
jit_data->ro_header = NULL;
|
||||
prog = orig_prog;
|
||||
goto out_offset;
|
||||
}
|
||||
/*
|
||||
* The instructions have now been copied to the ROX region from
|
||||
* where they will execute.
|
||||
* Write any modified data cache blocks out to memory and
|
||||
* invalidate the corresponding blocks in the instruction cache.
|
||||
*/
|
||||
bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns);
|
||||
for (i = 0; i < prog->len; i++)
|
||||
ctx->offset[i] = ninsns_rvoff(ctx->offset[i]);
|
||||
bpf_prog_fill_jited_linfo(prog, ctx->offset);
|
||||
@@ -198,14 +173,15 @@ out_offset:
|
||||
kfree(jit_data);
|
||||
prog->aux->jit_data = NULL;
|
||||
}
|
||||
out:
|
||||
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
return prog;
|
||||
|
||||
out_free_hdr:
|
||||
if (extra_pass) {
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
}
|
||||
if (jit_data->header) {
|
||||
bpf_arch_text_copy(&jit_data->ro_header->size, &jit_data->header->size,
|
||||
sizeof(jit_data->header->size));
|
||||
|
||||
@@ -2312,38 +2312,22 @@ static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
|
||||
/*
|
||||
* Compile eBPF program "fp"
|
||||
*/
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *fp)
|
||||
{
|
||||
struct bpf_prog *tmp, *orig_fp = fp;
|
||||
struct bpf_binary_header *header;
|
||||
struct s390_jit_data *jit_data;
|
||||
bool tmp_blinded = false;
|
||||
bool extra_pass = false;
|
||||
struct bpf_jit jit;
|
||||
int pass;
|
||||
|
||||
if (!fp->jit_requested)
|
||||
return orig_fp;
|
||||
|
||||
tmp = bpf_jit_blind_constants(fp);
|
||||
/*
|
||||
* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_fp;
|
||||
if (tmp != fp) {
|
||||
tmp_blinded = true;
|
||||
fp = tmp;
|
||||
}
|
||||
return fp;
|
||||
|
||||
jit_data = fp->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
fp = orig_fp;
|
||||
goto out;
|
||||
}
|
||||
if (!jit_data)
|
||||
return fp;
|
||||
fp->aux->jit_data = jit_data;
|
||||
}
|
||||
if (jit_data->ctx.addrs) {
|
||||
@@ -2356,34 +2340,27 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
|
||||
|
||||
memset(&jit, 0, sizeof(jit));
|
||||
jit.addrs = kvcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
|
||||
if (jit.addrs == NULL) {
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
}
|
||||
if (jit.addrs == NULL)
|
||||
goto out_err;
|
||||
/*
|
||||
* Three initial passes:
|
||||
* - 1/2: Determine clobbered registers
|
||||
* - 3: Calculate program size and addrs array
|
||||
*/
|
||||
for (pass = 1; pass <= 3; pass++) {
|
||||
if (bpf_jit_prog(&jit, fp, extra_pass)) {
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
}
|
||||
if (bpf_jit_prog(&jit, fp, extra_pass))
|
||||
goto out_err;
|
||||
}
|
||||
/*
|
||||
* Final pass: Allocate and generate program
|
||||
*/
|
||||
header = bpf_jit_alloc(&jit, fp);
|
||||
if (!header) {
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
}
|
||||
if (!header)
|
||||
goto out_err;
|
||||
skip_init_ctx:
|
||||
if (bpf_jit_prog(&jit, fp, extra_pass)) {
|
||||
bpf_jit_binary_free(header);
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
goto out_err;
|
||||
}
|
||||
if (bpf_jit_enable > 1) {
|
||||
bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf);
|
||||
@@ -2392,8 +2369,7 @@ skip_init_ctx:
|
||||
if (!fp->is_func || extra_pass) {
|
||||
if (bpf_jit_binary_lock_ro(header)) {
|
||||
bpf_jit_binary_free(header);
|
||||
fp = orig_fp;
|
||||
goto free_addrs;
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
jit_data->header = header;
|
||||
@@ -2411,11 +2387,16 @@ free_addrs:
|
||||
kfree(jit_data);
|
||||
fp->aux->jit_data = NULL;
|
||||
}
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(fp, fp == orig_fp ?
|
||||
tmp : orig_fp);
|
||||
|
||||
return fp;
|
||||
|
||||
out_err:
|
||||
if (extra_pass) {
|
||||
fp->bpf_func = NULL;
|
||||
fp->jited = 0;
|
||||
fp->jited_len = 0;
|
||||
}
|
||||
goto free_addrs;
|
||||
}
|
||||
|
||||
bool bpf_jit_supports_kfunc_call(void)
|
||||
|
||||
@@ -1477,39 +1477,24 @@ struct sparc64_jit_data {
|
||||
struct jit_ctx ctx;
|
||||
};
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
struct sparc64_jit_data *jit_data;
|
||||
struct bpf_binary_header *header;
|
||||
u32 prev_image_size, image_size;
|
||||
bool tmp_blinded = false;
|
||||
bool extra_pass = false;
|
||||
struct jit_ctx ctx;
|
||||
u8 *image_ptr;
|
||||
int pass, i;
|
||||
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
/* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
jit_data = prog->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
if (!jit_data)
|
||||
return prog;
|
||||
prog->aux->jit_data = jit_data;
|
||||
}
|
||||
if (jit_data->ctx.offset) {
|
||||
@@ -1527,10 +1512,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
ctx.prog = prog;
|
||||
|
||||
ctx.offset = kmalloc_array(prog->len, sizeof(unsigned int), GFP_KERNEL);
|
||||
if (ctx.offset == NULL) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
if (ctx.offset == NULL)
|
||||
goto out_err;
|
||||
|
||||
/* Longest sequence emitted is for bswap32, 12 instructions. Pre-cook
|
||||
* the offset array so that we converge faster.
|
||||
@@ -1543,10 +1526,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
ctx.idx = 0;
|
||||
|
||||
build_prologue(&ctx);
|
||||
if (build_body(&ctx)) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
if (build_body(&ctx))
|
||||
goto out_err;
|
||||
build_epilogue(&ctx);
|
||||
|
||||
if (bpf_jit_enable > 1)
|
||||
@@ -1569,10 +1550,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
image_size = sizeof(u32) * ctx.idx;
|
||||
header = bpf_jit_binary_alloc(image_size, &image_ptr,
|
||||
sizeof(u32), jit_fill_hole);
|
||||
if (header == NULL) {
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
}
|
||||
if (header == NULL)
|
||||
goto out_err;
|
||||
|
||||
ctx.image = (u32 *)image_ptr;
|
||||
skip_init_ctx:
|
||||
@@ -1582,8 +1561,7 @@ skip_init_ctx:
|
||||
|
||||
if (build_body(&ctx)) {
|
||||
bpf_jit_binary_free(header);
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
build_epilogue(&ctx);
|
||||
@@ -1592,8 +1570,7 @@ skip_init_ctx:
|
||||
pr_err("bpf_jit: Failed to converge, prev_size=%u size=%d\n",
|
||||
prev_image_size, ctx.idx * 4);
|
||||
bpf_jit_binary_free(header);
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (bpf_jit_enable > 1)
|
||||
@@ -1604,8 +1581,7 @@ skip_init_ctx:
|
||||
if (!prog->is_func || extra_pass) {
|
||||
if (bpf_jit_binary_lock_ro(header)) {
|
||||
bpf_jit_binary_free(header);
|
||||
prog = orig_prog;
|
||||
goto out_off;
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
jit_data->ctx = ctx;
|
||||
@@ -1624,9 +1600,14 @@ out_off:
|
||||
kfree(jit_data);
|
||||
prog->aux->jit_data = NULL;
|
||||
}
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
|
||||
return prog;
|
||||
|
||||
out_err:
|
||||
if (extra_pass) {
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
prog->jited_len = 0;
|
||||
}
|
||||
goto out_off;
|
||||
}
|
||||
|
||||
+23
-50
@@ -58,8 +58,8 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
|
||||
#define EMIT_ENDBR() EMIT(gen_endbr(), 4)
|
||||
#define EMIT_ENDBR_POISON() EMIT(gen_endbr_poison(), 4)
|
||||
#else
|
||||
#define EMIT_ENDBR()
|
||||
#define EMIT_ENDBR_POISON()
|
||||
#define EMIT_ENDBR() do { } while (0)
|
||||
#define EMIT_ENDBR_POISON() do { } while (0)
|
||||
#endif
|
||||
|
||||
static bool is_imm8(int value)
|
||||
@@ -1649,8 +1649,8 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
|
||||
int oldproglen, struct jit_context *ctx, bool jmp_padding)
|
||||
static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
||||
u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding)
|
||||
{
|
||||
bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
|
||||
struct bpf_insn *insn = bpf_prog->insnsi;
|
||||
@@ -1663,7 +1663,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
||||
void __percpu *priv_stack_ptr;
|
||||
int i, excnt = 0;
|
||||
int ilen, proglen = 0;
|
||||
u8 *prog = temp;
|
||||
u8 *ip, *prog = temp;
|
||||
u32 stack_depth;
|
||||
int err;
|
||||
|
||||
@@ -1734,6 +1734,11 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
||||
dst_reg = X86_REG_R9;
|
||||
}
|
||||
|
||||
if (bpf_insn_is_indirect_target(env, bpf_prog, i - 1))
|
||||
EMIT_ENDBR();
|
||||
|
||||
ip = image + addrs[i - 1] + (prog - temp);
|
||||
|
||||
switch (insn->code) {
|
||||
/* ALU */
|
||||
case BPF_ALU | BPF_ADD | BPF_X:
|
||||
@@ -2440,8 +2445,6 @@ populate_extable:
|
||||
|
||||
/* call */
|
||||
case BPF_JMP | BPF_CALL: {
|
||||
u8 *ip = image + addrs[i - 1];
|
||||
|
||||
func = (u8 *) __bpf_call_base + imm32;
|
||||
if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) {
|
||||
LOAD_TAIL_CALL_CNT_PTR(stack_depth);
|
||||
@@ -2465,7 +2468,8 @@ populate_extable:
|
||||
if (imm32)
|
||||
emit_bpf_tail_call_direct(bpf_prog,
|
||||
&bpf_prog->aux->poke_tab[imm32 - 1],
|
||||
&prog, image + addrs[i - 1],
|
||||
&prog,
|
||||
ip,
|
||||
callee_regs_used,
|
||||
stack_depth,
|
||||
ctx);
|
||||
@@ -2474,7 +2478,7 @@ populate_extable:
|
||||
&prog,
|
||||
callee_regs_used,
|
||||
stack_depth,
|
||||
image + addrs[i - 1],
|
||||
ip,
|
||||
ctx);
|
||||
break;
|
||||
|
||||
@@ -2639,7 +2643,7 @@ emit_cond_jmp: /* Convert BPF opcode to x86 */
|
||||
break;
|
||||
|
||||
case BPF_JMP | BPF_JA | BPF_X:
|
||||
emit_indirect_jump(&prog, insn->dst_reg, image + addrs[i - 1]);
|
||||
emit_indirect_jump(&prog, insn->dst_reg, ip);
|
||||
break;
|
||||
case BPF_JMP | BPF_JA:
|
||||
case BPF_JMP32 | BPF_JA:
|
||||
@@ -2729,8 +2733,6 @@ emit_jmp:
|
||||
ctx->cleanup_addr = proglen;
|
||||
if (bpf_prog_was_classic(bpf_prog) &&
|
||||
!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) {
|
||||
u8 *ip = image + addrs[i - 1];
|
||||
|
||||
if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -3713,17 +3715,15 @@ struct x64_jit_data {
|
||||
#define MAX_PASSES 20
|
||||
#define PADDING_PASSES (MAX_PASSES - 5)
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_binary_header *rw_header = NULL;
|
||||
struct bpf_binary_header *header = NULL;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
void __percpu *priv_stack_ptr = NULL;
|
||||
struct x64_jit_data *jit_data;
|
||||
int priv_stack_alloc_sz;
|
||||
int proglen, oldproglen = 0;
|
||||
struct jit_context ctx = {};
|
||||
bool tmp_blinded = false;
|
||||
bool extra_pass = false;
|
||||
bool padding = false;
|
||||
u8 *rw_image = NULL;
|
||||
@@ -3733,27 +3733,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
int i;
|
||||
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
/*
|
||||
* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
jit_data = prog->aux->jit_data;
|
||||
if (!jit_data) {
|
||||
jit_data = kzalloc_obj(*jit_data);
|
||||
if (!jit_data) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
if (!jit_data)
|
||||
return prog;
|
||||
prog->aux->jit_data = jit_data;
|
||||
}
|
||||
priv_stack_ptr = prog->aux->priv_stack_ptr;
|
||||
@@ -3765,10 +3751,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 8) +
|
||||
2 * PRIV_STACK_GUARD_SZ;
|
||||
priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 8, GFP_KERNEL);
|
||||
if (!priv_stack_ptr) {
|
||||
prog = orig_prog;
|
||||
if (!priv_stack_ptr)
|
||||
goto out_priv_stack;
|
||||
}
|
||||
|
||||
priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
|
||||
prog->aux->priv_stack_ptr = priv_stack_ptr;
|
||||
@@ -3786,10 +3770,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
goto skip_init_addrs;
|
||||
}
|
||||
addrs = kvmalloc_objs(*addrs, prog->len + 1);
|
||||
if (!addrs) {
|
||||
prog = orig_prog;
|
||||
if (!addrs)
|
||||
goto out_addrs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Before first pass, make a rough estimation of addrs[]
|
||||
@@ -3811,7 +3793,7 @@ skip_init_addrs:
|
||||
for (pass = 0; pass < MAX_PASSES || image; pass++) {
|
||||
if (!padding && pass >= PADDING_PASSES)
|
||||
padding = true;
|
||||
proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
|
||||
proglen = do_jit(env, prog, addrs, image, rw_image, oldproglen, &ctx, padding);
|
||||
if (proglen <= 0) {
|
||||
out_image:
|
||||
image = NULL;
|
||||
@@ -3820,8 +3802,6 @@ out_image:
|
||||
sizeof(rw_header->size));
|
||||
bpf_jit_binary_pack_free(header, rw_header);
|
||||
}
|
||||
/* Fall back to interpreter mode */
|
||||
prog = orig_prog;
|
||||
if (extra_pass) {
|
||||
prog->bpf_func = NULL;
|
||||
prog->jited = 0;
|
||||
@@ -3852,10 +3832,8 @@ out_image:
|
||||
header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
|
||||
&image, align, &rw_header, &rw_image,
|
||||
jit_fill_hole);
|
||||
if (!header) {
|
||||
prog = orig_prog;
|
||||
if (!header)
|
||||
goto out_addrs;
|
||||
}
|
||||
prog->aux->extable = (void *) image + roundup(proglen, align);
|
||||
}
|
||||
oldproglen = proglen;
|
||||
@@ -3908,8 +3886,6 @@ out_image:
|
||||
prog->bpf_func = (void *)image + cfi_get_offset();
|
||||
prog->jited = 1;
|
||||
prog->jited_len = proglen - cfi_get_offset();
|
||||
} else {
|
||||
prog = orig_prog;
|
||||
}
|
||||
|
||||
if (!image || !prog->is_func || extra_pass) {
|
||||
@@ -3925,10 +3901,7 @@ out_priv_stack:
|
||||
kfree(jit_data);
|
||||
prog->aux->jit_data = NULL;
|
||||
}
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
|
||||
return prog;
|
||||
}
|
||||
|
||||
|
||||
@@ -2518,38 +2518,22 @@ bool bpf_jit_needs_zext(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_binary_header *header = NULL;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
int proglen, oldproglen = 0;
|
||||
struct jit_context ctx = {};
|
||||
bool tmp_blinded = false;
|
||||
u8 *image = NULL;
|
||||
int *addrs;
|
||||
int pass;
|
||||
int i;
|
||||
|
||||
if (!prog->jit_requested)
|
||||
return orig_prog;
|
||||
|
||||
tmp = bpf_jit_blind_constants(prog);
|
||||
/*
|
||||
* If blinding was requested and we failed during blinding,
|
||||
* we must fall back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(tmp))
|
||||
return orig_prog;
|
||||
if (tmp != prog) {
|
||||
tmp_blinded = true;
|
||||
prog = tmp;
|
||||
}
|
||||
return prog;
|
||||
|
||||
addrs = kmalloc_objs(*addrs, prog->len);
|
||||
if (!addrs) {
|
||||
prog = orig_prog;
|
||||
goto out;
|
||||
}
|
||||
if (!addrs)
|
||||
return prog;
|
||||
|
||||
/*
|
||||
* Before first pass, make a rough estimation of addrs[]
|
||||
@@ -2574,7 +2558,6 @@ out_image:
|
||||
image = NULL;
|
||||
if (header)
|
||||
bpf_jit_binary_free(header);
|
||||
prog = orig_prog;
|
||||
goto out_addrs;
|
||||
}
|
||||
if (image) {
|
||||
@@ -2588,10 +2571,8 @@ out_image:
|
||||
if (proglen == oldproglen) {
|
||||
header = bpf_jit_binary_alloc(proglen, &image,
|
||||
1, jit_fill_hole);
|
||||
if (!header) {
|
||||
prog = orig_prog;
|
||||
if (!header)
|
||||
goto out_addrs;
|
||||
}
|
||||
}
|
||||
oldproglen = proglen;
|
||||
cond_resched();
|
||||
@@ -2604,16 +2585,10 @@ out_image:
|
||||
prog->bpf_func = (void *)image;
|
||||
prog->jited = 1;
|
||||
prog->jited_len = proglen;
|
||||
} else {
|
||||
prog = orig_prog;
|
||||
}
|
||||
|
||||
out_addrs:
|
||||
kfree(addrs);
|
||||
out:
|
||||
if (tmp_blinded)
|
||||
bpf_jit_prog_release_other(prog, prog == orig_prog ?
|
||||
tmp : orig_prog);
|
||||
return prog;
|
||||
}
|
||||
|
||||
|
||||
@@ -1541,6 +1541,8 @@ bool bpf_has_frame_pointer(unsigned long ip);
|
||||
int bpf_jit_charge_modmem(u32 size);
|
||||
void bpf_jit_uncharge_modmem(u32 size);
|
||||
bool bpf_prog_has_trampoline(const struct bpf_prog *prog);
|
||||
bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struct bpf_prog *prog,
|
||||
int insn_idx);
|
||||
#else
|
||||
static inline int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
|
||||
struct bpf_trampoline *tr,
|
||||
|
||||
@@ -630,16 +630,17 @@ struct bpf_insn_aux_data {
|
||||
|
||||
/* below fields are initialized once */
|
||||
unsigned int orig_idx; /* original instruction index */
|
||||
bool jmp_point;
|
||||
bool prune_point;
|
||||
u32 jmp_point:1;
|
||||
u32 prune_point:1;
|
||||
/* ensure we check state equivalence and save state checkpoint and
|
||||
* this instruction, regardless of any heuristics
|
||||
*/
|
||||
bool force_checkpoint;
|
||||
u32 force_checkpoint:1;
|
||||
/* true if instruction is a call to a helper function that
|
||||
* accepts callback function as a parameter.
|
||||
*/
|
||||
bool calls_callback;
|
||||
u32 calls_callback:1;
|
||||
u32 indirect_target:1; /* if it is an indirect jump target */
|
||||
/*
|
||||
* CFG strongly connected component this instruction belongs to,
|
||||
* zero if it is a singleton SCC.
|
||||
|
||||
+48
-2
@@ -1108,6 +1108,8 @@ sk_filter_reason(struct sock *sk, struct sk_buff *skb)
|
||||
return sk_filter_trim_cap(sk, skb, 1);
|
||||
}
|
||||
|
||||
struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,
|
||||
int *err);
|
||||
struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err);
|
||||
void bpf_prog_free(struct bpf_prog *fp);
|
||||
|
||||
@@ -1153,7 +1155,7 @@ u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
|
||||
((u64 (*)(u64, u64, u64, u64, u64, const struct bpf_insn *)) \
|
||||
(void *)__bpf_call_base)
|
||||
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog);
|
||||
struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog);
|
||||
void bpf_jit_compile(struct bpf_prog *prog);
|
||||
bool bpf_jit_needs_zext(void);
|
||||
bool bpf_jit_inlines_helper_call(s32 imm);
|
||||
@@ -1184,6 +1186,31 @@ static inline bool bpf_dump_raw_ok(const struct cred *cred)
|
||||
|
||||
struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
|
||||
const struct bpf_insn *patch, u32 len);
|
||||
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
|
||||
const struct bpf_insn *patch, u32 len);
|
||||
struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env);
|
||||
void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
|
||||
struct bpf_insn_aux_data *orig_insn_aux);
|
||||
#else
|
||||
static inline struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
|
||||
const struct bpf_insn *patch, u32 len)
|
||||
{
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
}
|
||||
|
||||
static inline struct bpf_insn_aux_data *bpf_dup_insn_aux_data(struct bpf_verifier_env *env)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void bpf_restore_insn_aux_data(struct bpf_verifier_env *env,
|
||||
struct bpf_insn_aux_data *orig_insn_aux)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_BPF_SYSCALL */
|
||||
|
||||
int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt);
|
||||
|
||||
static inline bool xdp_return_frame_no_direct(void)
|
||||
@@ -1310,9 +1337,14 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
|
||||
|
||||
const char *bpf_jit_get_prog_name(struct bpf_prog *prog);
|
||||
|
||||
struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *fp);
|
||||
struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog);
|
||||
void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other);
|
||||
|
||||
static inline bool bpf_prog_need_blind(const struct bpf_prog *prog)
|
||||
{
|
||||
return prog->blinding_requested && !prog->blinded;
|
||||
}
|
||||
|
||||
static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
|
||||
u32 pass, void *image)
|
||||
{
|
||||
@@ -1451,6 +1483,20 @@ static inline void bpf_prog_kallsyms_del(struct bpf_prog *fp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool bpf_prog_need_blind(const struct bpf_prog *prog)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
return prog;
|
||||
}
|
||||
|
||||
static inline void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_BPF_JIT */
|
||||
|
||||
void bpf_prog_kallsyms_del_all(struct bpf_prog *fp);
|
||||
|
||||
+20
-3
@@ -341,6 +341,16 @@ static void arena_vm_open(struct vm_area_struct *vma)
|
||||
refcount_inc(&vml->mmap_count);
|
||||
}
|
||||
|
||||
static int arena_vm_may_split(struct vm_area_struct *vma, unsigned long addr)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int arena_vm_mremap(struct vm_area_struct *vma)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void arena_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct bpf_map *map = vma->vm_file->private_data;
|
||||
@@ -417,6 +427,8 @@ out_unlock_sigsegv:
|
||||
|
||||
static const struct vm_operations_struct arena_vm_ops = {
|
||||
.open = arena_vm_open,
|
||||
.may_split = arena_vm_may_split,
|
||||
.mremap = arena_vm_mremap,
|
||||
.close = arena_vm_close,
|
||||
.fault = arena_vm_fault,
|
||||
};
|
||||
@@ -486,10 +498,11 @@ static int arena_map_mmap(struct bpf_map *map, struct vm_area_struct *vma)
|
||||
arena->user_vm_end = vma->vm_end;
|
||||
/*
|
||||
* bpf_map_mmap() checks that it's being mmaped as VM_SHARED and
|
||||
* clears VM_MAYEXEC. Set VM_DONTEXPAND as well to avoid
|
||||
* potential change of user_vm_start.
|
||||
* clears VM_MAYEXEC. Set VM_DONTEXPAND to avoid potential change
|
||||
* of user_vm_start. Set VM_DONTCOPY to prevent arena VMA from
|
||||
* being copied into the child process on fork.
|
||||
*/
|
||||
vm_flags_set(vma, VM_DONTEXPAND);
|
||||
vm_flags_set(vma, VM_DONTEXPAND | VM_DONTCOPY);
|
||||
vma->vm_ops = &arena_vm_ops;
|
||||
return 0;
|
||||
}
|
||||
@@ -549,6 +562,10 @@ static long arena_alloc_pages(struct bpf_arena *arena, long uaddr, long page_cnt
|
||||
u32 uaddr32;
|
||||
int ret, i;
|
||||
|
||||
if (node_id != NUMA_NO_NODE &&
|
||||
((unsigned int)node_id >= nr_node_ids || !node_online(node_id)))
|
||||
return 0;
|
||||
|
||||
if (page_cnt > page_cnt_max)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -811,9 +811,6 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
|
||||
goto reset_unlock;
|
||||
}
|
||||
|
||||
/* Poison pointer on error instead of return for backward compatibility */
|
||||
bpf_prog_assoc_struct_ops(prog, &st_map->map);
|
||||
|
||||
link = kzalloc_obj(*link, GFP_USER);
|
||||
if (!link) {
|
||||
bpf_prog_put(prog);
|
||||
@@ -824,6 +821,9 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
|
||||
&bpf_struct_ops_link_lops, prog, prog->expected_attach_type);
|
||||
*plink++ = &link->link;
|
||||
|
||||
/* Poison pointer on error instead of return for backward compatibility */
|
||||
bpf_prog_assoc_struct_ops(prog, &st_map->map);
|
||||
|
||||
ksym = kzalloc_obj(*ksym, GFP_USER);
|
||||
if (!ksym) {
|
||||
err = -ENOMEM;
|
||||
@@ -906,6 +906,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
|
||||
reset_unlock:
|
||||
bpf_struct_ops_map_free_ksyms(st_map);
|
||||
bpf_struct_ops_map_free_image(st_map);
|
||||
bpf_struct_ops_map_dissoc_progs(st_map);
|
||||
bpf_struct_ops_map_put_progs(st_map);
|
||||
memset(uvalue, 0, map->value_size);
|
||||
memset(kvalue, 0, map->value_size);
|
||||
|
||||
+99
-39
@@ -1491,24 +1491,11 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
|
||||
bpf_prog_clone_free(fp_other);
|
||||
}
|
||||
|
||||
static void adjust_insn_arrays(struct bpf_prog *prog, u32 off, u32 len)
|
||||
{
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
struct bpf_map *map;
|
||||
int i;
|
||||
|
||||
if (len <= 1)
|
||||
return;
|
||||
|
||||
for (i = 0; i < prog->aux->used_map_cnt; i++) {
|
||||
map = prog->aux->used_maps[i];
|
||||
if (map->map_type == BPF_MAP_TYPE_INSN_ARRAY)
|
||||
bpf_insn_array_adjust(map, off, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
|
||||
/*
|
||||
* Now this function is used only to blind the main prog and must be invoked only when
|
||||
* bpf_prog_need_blind() returns true.
|
||||
*/
|
||||
struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
struct bpf_insn insn_buff[16], aux[2];
|
||||
struct bpf_prog *clone, *tmp;
|
||||
@@ -1516,13 +1503,17 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
|
||||
struct bpf_insn *insn;
|
||||
int i, rewritten;
|
||||
|
||||
if (!prog->blinding_requested || prog->blinded)
|
||||
return prog;
|
||||
if (WARN_ON_ONCE(env && env->prog != prog))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
clone = bpf_prog_clone_create(prog, GFP_USER);
|
||||
if (!clone)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* make sure bpf_patch_insn_data() patches the correct prog */
|
||||
if (env)
|
||||
env->prog = clone;
|
||||
|
||||
insn_cnt = clone->len;
|
||||
insn = clone->insnsi;
|
||||
|
||||
@@ -1550,21 +1541,28 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
|
||||
if (!rewritten)
|
||||
continue;
|
||||
|
||||
tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
|
||||
if (IS_ERR(tmp)) {
|
||||
if (env)
|
||||
tmp = bpf_patch_insn_data(env, i, insn_buff, rewritten);
|
||||
else
|
||||
tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
|
||||
|
||||
if (IS_ERR_OR_NULL(tmp)) {
|
||||
if (env)
|
||||
/* restore the original prog */
|
||||
env->prog = prog;
|
||||
/* Patching may have repointed aux->prog during
|
||||
* realloc from the original one, so we need to
|
||||
* fix it up here on error.
|
||||
*/
|
||||
bpf_jit_prog_release_other(prog, clone);
|
||||
return tmp;
|
||||
return IS_ERR(tmp) ? tmp : ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
clone = tmp;
|
||||
insn_delta = rewritten - 1;
|
||||
|
||||
/* Instructions arrays must be updated using absolute xlated offsets */
|
||||
adjust_insn_arrays(clone, prog->aux->subprog_start + i, rewritten);
|
||||
if (env)
|
||||
env->prog = clone;
|
||||
|
||||
/* Walk new program and skip insns we just inserted. */
|
||||
insn = clone->insnsi + i + insn_delta;
|
||||
@@ -1575,6 +1573,15 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
|
||||
clone->blinded = 1;
|
||||
return clone;
|
||||
}
|
||||
|
||||
bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struct bpf_prog *prog,
|
||||
int insn_idx)
|
||||
{
|
||||
if (!env)
|
||||
return false;
|
||||
insn_idx += prog->aux->subprog_start;
|
||||
return env->insn_aux_data[insn_idx].indirect_target;
|
||||
}
|
||||
#endif /* CONFIG_BPF_JIT */
|
||||
|
||||
/* Base function for offset calculation. Needs to go into .text section,
|
||||
@@ -2533,18 +2540,55 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
|
||||
return select_interpreter;
|
||||
}
|
||||
|
||||
/**
|
||||
* bpf_prog_select_runtime - select exec runtime for BPF program
|
||||
* @fp: bpf_prog populated with BPF program
|
||||
* @err: pointer to error variable
|
||||
*
|
||||
* Try to JIT eBPF program, if JIT is not available, use interpreter.
|
||||
* The BPF program will be executed via bpf_prog_run() function.
|
||||
*
|
||||
* Return: the &fp argument along with &err set to 0 for success or
|
||||
* a negative errno code on failure
|
||||
*/
|
||||
struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
|
||||
static struct bpf_prog *bpf_prog_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
#ifdef CONFIG_BPF_JIT
|
||||
struct bpf_prog *orig_prog;
|
||||
struct bpf_insn_aux_data *orig_insn_aux;
|
||||
|
||||
if (!bpf_prog_need_blind(prog))
|
||||
return bpf_int_jit_compile(env, prog);
|
||||
|
||||
if (env) {
|
||||
/*
|
||||
* If env is not NULL, we are called from the end of bpf_check(), at this
|
||||
* point, only insn_aux_data is used after failure, so it should be restored
|
||||
* on failure.
|
||||
*/
|
||||
orig_insn_aux = bpf_dup_insn_aux_data(env);
|
||||
if (!orig_insn_aux)
|
||||
return prog;
|
||||
}
|
||||
|
||||
orig_prog = prog;
|
||||
prog = bpf_jit_blind_constants(env, prog);
|
||||
/*
|
||||
* If blinding was requested and we failed during blinding, we must fall
|
||||
* back to the interpreter.
|
||||
*/
|
||||
if (IS_ERR(prog))
|
||||
goto out_restore;
|
||||
|
||||
prog = bpf_int_jit_compile(env, prog);
|
||||
if (prog->jited) {
|
||||
bpf_jit_prog_release_other(prog, orig_prog);
|
||||
if (env)
|
||||
vfree(orig_insn_aux);
|
||||
return prog;
|
||||
}
|
||||
|
||||
bpf_jit_prog_release_other(orig_prog, prog);
|
||||
|
||||
out_restore:
|
||||
prog = orig_prog;
|
||||
if (env)
|
||||
bpf_restore_insn_aux_data(env, orig_insn_aux);
|
||||
#endif
|
||||
return prog;
|
||||
}
|
||||
|
||||
struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct bpf_prog *fp,
|
||||
int *err)
|
||||
{
|
||||
/* In case of BPF to BPF calls, verifier did all the prep
|
||||
* work with regards to JITing, etc.
|
||||
@@ -2572,7 +2616,7 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
|
||||
if (*err)
|
||||
return fp;
|
||||
|
||||
fp = bpf_int_jit_compile(fp);
|
||||
fp = bpf_prog_jit_compile(env, fp);
|
||||
bpf_prog_jit_attempt_done(fp);
|
||||
if (!fp->jited && jit_needed) {
|
||||
*err = -ENOTSUPP;
|
||||
@@ -2598,6 +2642,22 @@ finalize:
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
/**
|
||||
* bpf_prog_select_runtime - select exec runtime for BPF program
|
||||
* @fp: bpf_prog populated with BPF program
|
||||
* @err: pointer to error variable
|
||||
*
|
||||
* Try to JIT eBPF program, if JIT is not available, use interpreter.
|
||||
* The BPF program will be executed via bpf_prog_run() function.
|
||||
*
|
||||
* Return: the &fp argument along with &err set to 0 for success or
|
||||
* a negative errno code on failure
|
||||
*/
|
||||
struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
|
||||
{
|
||||
return __bpf_prog_select_runtime(NULL, fp, err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bpf_prog_select_runtime);
|
||||
|
||||
static unsigned int __bpf_prog_ret1(const void *ctx,
|
||||
@@ -3085,7 +3145,7 @@ const struct bpf_func_proto bpf_tail_call_proto = {
|
||||
* It is encouraged to implement bpf_int_jit_compile() instead, so that
|
||||
* eBPF and implicitly also cBPF can get JITed!
|
||||
*/
|
||||
struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
|
||||
{
|
||||
return prog;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user