Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions arch/arm64/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2284,24 +2284,23 @@ bool bpf_jit_supports_subprog_tailcalls(void)
return true;
}

static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_link *l,
static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_prog *p, u64 cookie,
int bargs_off, int retval_off, int run_ctx_off,
bool save_ret)
{
__le32 *branch;
u64 enter_prog;
u64 exit_prog;
struct bpf_prog *p = l->link.prog;
int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie);

enter_prog = (u64)bpf_trampoline_enter(p);
exit_prog = (u64)bpf_trampoline_exit(p);

if (l->cookie == 0) {
if (cookie == 0) {
/* if cookie is zero, one instruction is enough to store it */
emit(A64_STR64I(A64_ZR, A64_SP, run_ctx_off + cookie_off), ctx);
} else {
emit_a64_mov_i64(A64_R(10), l->cookie, ctx);
emit_a64_mov_i64(A64_R(10), cookie, ctx);
emit(A64_STR64I(A64_R(10), A64_SP, run_ctx_off + cookie_off),
ctx);
}
Expand Down Expand Up @@ -2362,7 +2361,8 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl,
*/
emit(A64_STR64I(A64_ZR, A64_SP, retval_off), ctx);
for (i = 0; i < tl->nr_links; i++) {
invoke_bpf_prog(ctx, tl->links[i], bargs_off, retval_off,
invoke_bpf_prog(ctx, bpf_tramp_links_prog(tl, i),
tl->links[i]->cookie, bargs_off, retval_off,
run_ctx_off, true);
/* if (*(u64 *)(sp + retval_off) != 0)
* goto do_fexit;
Expand Down Expand Up @@ -2656,8 +2656,9 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
}

for (i = 0; i < fentry->nr_links; i++)
invoke_bpf_prog(ctx, fentry->links[i], bargs_off,
retval_off, run_ctx_off,
invoke_bpf_prog(ctx, bpf_tramp_links_prog(fentry, i),
fentry->links[i]->cookie, bargs_off, retval_off,
run_ctx_off,
flags & BPF_TRAMP_F_RET_FENTRY_RET);

if (fmod_ret->nr_links) {
Expand Down Expand Up @@ -2691,7 +2692,8 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
}

for (i = 0; i < fexit->nr_links; i++)
invoke_bpf_prog(ctx, fexit->links[i], bargs_off, retval_off,
invoke_bpf_prog(ctx, bpf_tramp_links_prog(fexit, i),
fexit->links[i]->cookie, bargs_off, retval_off,
run_ctx_off, false);

if (flags & BPF_TRAMP_F_CALL_ORIG) {
Expand Down Expand Up @@ -2829,6 +2831,11 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *ro_image,
return ret;
}

bool arch_bpf_trampoline_supports_replace(void)
{
return true;
}

static bool is_long_jump(void *ip, void *target)
{
long offset;
Expand Down
24 changes: 16 additions & 8 deletions arch/s390/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2508,20 +2508,19 @@ static void load_imm64(struct bpf_jit *jit, int dst_reg, u64 val)

static int invoke_bpf_prog(struct bpf_tramp_jit *tjit,
const struct btf_func_model *m,
struct bpf_tramp_link *tlink, bool save_ret)
struct bpf_prog *p, u64 cookie, bool save_ret)
{
struct bpf_jit *jit = &tjit->common;
int cookie_off = tjit->run_ctx_off +
offsetof(struct bpf_tramp_run_ctx, bpf_cookie);
struct bpf_prog *p = tlink->link.prog;
int patch;

/*
* run_ctx.cookie = tlink->cookie;
* run_ctx.cookie = cookie;
*/

/* %r0 = tlink->cookie */
load_imm64(jit, REG_W0, tlink->cookie);
/* %r0 = cookie */
load_imm64(jit, REG_W0, cookie);
/* stg %r0,cookie_off(%r15) */
EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W0, REG_0, REG_15, cookie_off);

Expand Down Expand Up @@ -2768,7 +2767,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
}

for (i = 0; i < fentry->nr_links; i++)
if (invoke_bpf_prog(tjit, m, fentry->links[i],
if (invoke_bpf_prog(tjit, m, bpf_tramp_links_prog(fentry, i),
fentry->links[i]->cookie,
flags & BPF_TRAMP_F_RET_FENTRY_RET))
return -EINVAL;

Expand All @@ -2782,7 +2782,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
0xf000 | tjit->retval_off);

for (i = 0; i < fmod_ret->nr_links; i++) {
if (invoke_bpf_prog(tjit, m, fmod_ret->links[i], true))
if (invoke_bpf_prog(tjit, m,
bpf_tramp_links_prog(fmod_ret, i),
fmod_ret->links[i]->cookie, true))
return -EINVAL;

/*
Expand Down Expand Up @@ -2850,7 +2852,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
/* do_fexit: */
tjit->do_fexit = jit->prg;
for (i = 0; i < fexit->nr_links; i++)
if (invoke_bpf_prog(tjit, m, fexit->links[i], false))
if (invoke_bpf_prog(tjit, m, bpf_tramp_links_prog(fexit, i),
fexit->links[i]->cookie, false))
return -EINVAL;

if (flags & BPF_TRAMP_F_CALL_ORIG) {
Expand Down Expand Up @@ -2946,6 +2949,11 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image,
return ret < 0 ? ret : tjit.common.prg;
}

bool arch_bpf_trampoline_supports_replace(void)
{
return true;
}

bool bpf_jit_supports_subprog_tailcalls(void)
{
return true;
Expand Down
17 changes: 11 additions & 6 deletions arch/x86/net/bpf_jit_comp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2956,15 +2956,13 @@ static void restore_regs(const struct btf_func_model *m, u8 **prog,
}

static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
struct bpf_tramp_link *l, int stack_size,
struct bpf_prog *p, u64 cookie, int stack_size,
int run_ctx_off, bool save_ret,
void *image, void *rw_image)
{
u8 *prog = *pprog;
u8 *jmp_insn;
int ctx_cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie);
struct bpf_prog *p = l->link.prog;
u64 cookie = l->cookie;

/* mov rdi, cookie */
emit_mov_imm64(&prog, BPF_REG_1, (long) cookie >> 32, (u32) (long) cookie);
Expand Down Expand Up @@ -3079,7 +3077,8 @@ static int invoke_bpf(const struct btf_func_model *m, u8 **pprog,
u8 *prog = *pprog;

for (i = 0; i < tl->nr_links; i++) {
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size,
if (invoke_bpf_prog(m, &prog, bpf_tramp_links_prog(tl, i),
tl->links[i]->cookie, stack_size,
run_ctx_off, save_ret, image, rw_image))
return -EINVAL;
}
Expand All @@ -3101,8 +3100,9 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog,
emit_mov_imm32(&prog, false, BPF_REG_0, 0);
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8);
for (i = 0; i < tl->nr_links; i++) {
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, true,
image, rw_image))
if (invoke_bpf_prog(m, &prog, bpf_tramp_links_prog(tl, i),
tl->links[i]->cookie, stack_size,
run_ctx_off, true, image, rw_image))
return -EINVAL;

/* mod_ret prog stored return value into [rbp - 8]. Emit:
Expand Down Expand Up @@ -3486,6 +3486,11 @@ int arch_protect_bpf_trampoline(void *image, unsigned int size)
return 0;
}

bool arch_bpf_trampoline_supports_replace(void)
{
return true;
}

int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end,
const struct btf_func_model *m, u32 flags,
struct bpf_tramp_links *tlinks,
Expand Down
11 changes: 11 additions & 0 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,8 @@ enum {

struct bpf_tramp_links {
struct bpf_tramp_link *links[BPF_MAX_TRAMP_LINKS];
struct bpf_tramp_link *replace_link;
struct bpf_prog *replace_prog;
int nr_links;
};

Expand Down Expand Up @@ -1245,6 +1247,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
const struct btf_func_model *m, u32 flags,
struct bpf_tramp_links *tlinks,
void *func_addr);
bool arch_bpf_trampoline_supports_replace(void);
void *arch_alloc_bpf_trampoline(unsigned int size);
void arch_free_bpf_trampoline(void *image, unsigned int size);
int __must_check arch_protect_bpf_trampoline(void *image, unsigned int size);
Expand Down Expand Up @@ -1418,6 +1421,7 @@ static inline int bpf_dynptr_check_off_len(const struct bpf_dynptr_kern *ptr, u6

#ifdef CONFIG_BPF_JIT
int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
struct bpf_prog *new_prog,
struct bpf_trampoline *tr,
struct bpf_prog *tgt_prog);
int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
Expand Down Expand Up @@ -1829,6 +1833,13 @@ struct bpf_tramp_link {
u64 cookie;
};

static inline struct bpf_prog *
bpf_tramp_links_prog(struct bpf_tramp_links *tl, int i)
{
return tl->links[i] == tl->replace_link ? tl->replace_prog :
tl->links[i]->link.prog;
}

struct bpf_shim_tramp_link {
struct bpf_tramp_link link;
struct bpf_trampoline *trampoline;
Expand Down
74 changes: 73 additions & 1 deletion kernel/bpf/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ static DEFINE_IDR(map_idr);
static DEFINE_SPINLOCK(map_idr_lock);
static DEFINE_IDR(link_idr);
static DEFINE_SPINLOCK(link_idr_lock);
/* Synchronizes access to and prog between link update operations. */
static DEFINE_MUTEX(trace_link_mutex);

int sysctl_unprivileged_bpf_disabled __read_mostly =
IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
Expand Down Expand Up @@ -3562,11 +3564,81 @@ static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
return 0;
}

static int bpf_tracing_link_update_prog(struct bpf_link *link,
struct bpf_prog *new_prog,
struct bpf_prog *old_prog)
{
struct bpf_tracing_link *tr_link =
container_of(link, struct bpf_tracing_link, link.link);
struct bpf_attach_target_info tgt_info = {};
int err = 0;
u32 btf_id;

mutex_lock(&trace_link_mutex);

if (old_prog && link->prog != old_prog) {
err = -EPERM;
goto out;
}
old_prog = link->prog;
if (old_prog->type != new_prog->type ||
old_prog->expected_attach_type != new_prog->expected_attach_type) {
err = -EINVAL;
goto out;
}

mutex_lock(&new_prog->aux->dst_mutex);

if (!new_prog->aux->dst_trampoline ||
new_prog->aux->dst_trampoline->key != tr_link->trampoline->key) {
bpf_trampoline_unpack_key(tr_link->trampoline->key, NULL,
&btf_id);
/* If there is no saved target, or the target associated with
* this link is different from the destination specified at
* load time, we need to check for compatibility.
*/
err = bpf_check_attach_target(NULL, new_prog, tr_link->tgt_prog,
btf_id, &tgt_info);
if (err)
goto out_unlock;

if (tgt_info.tgt_mod) {
module_put(new_prog->aux->mod);
new_prog->aux->mod = tgt_info.tgt_mod;
}
}

err = bpf_trampoline_link_prog(&tr_link->link, new_prog,
tr_link->trampoline, tr_link->tgt_prog);
if (err)
goto out_unlock;

/* Always clear the trampoline and target prog from prog->aux to make
* sure the original attach destination is not kept alive after a
* program is (re-)attached to another target.
*/
if (new_prog->aux->dst_prog &&
(tr_link->trampoline != new_prog->aux->dst_trampoline))
bpf_prog_put(new_prog->aux->dst_prog);
if (new_prog->aux->dst_trampoline &&
tr_link->trampoline != new_prog->aux->dst_trampoline)
bpf_trampoline_put(new_prog->aux->dst_trampoline);

new_prog->aux->dst_prog = NULL;
new_prog->aux->dst_trampoline = NULL;
out_unlock:
mutex_unlock(&new_prog->aux->dst_mutex);
out:
mutex_unlock(&trace_link_mutex);
return err;
}

static const struct bpf_link_ops bpf_tracing_link_lops = {
.release = bpf_tracing_link_release,
.dealloc = bpf_tracing_link_dealloc,
.show_fdinfo = bpf_tracing_link_show_fdinfo,
.fill_link_info = bpf_tracing_link_fill_link_info,
.update_prog = bpf_tracing_link_update_prog,
};

static int bpf_tracing_prog_attach(struct bpf_prog *prog,
Expand Down Expand Up @@ -3729,7 +3801,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
if (err)
goto out_unlock;

err = bpf_trampoline_link_prog(&link->link, tr, tgt_prog);
err = bpf_trampoline_link_prog(&link->link, NULL, tr, tgt_prog);
if (err) {
bpf_link_cleanup(&link_primer);
link = NULL;
Expand Down
Loading
Loading