Skip to content

Commit 6f44929

Browse files
jrifeKernel Patches Daemon
authored andcommitted
bpf: Set up update_prog scaffolding for bpf_tracing_link_lops
The type and expected_attach_type of the new program must match the original program and the new program must be compatible with the attachment target. Use a global mutex, trace_link_mutex, to synchronize parallel update operations similar to other link types (sock_map, xdp, etc.) that use a global mutex. Contention should be low, so this should be OK. Subsequent patches fill in the program update logic for freplace/fentry/fmod_ret/fexit links. Signed-off-by: Jordan Rife <[email protected]>
1 parent 86f62c3 commit 6f44929

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

include/linux/bpf.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,9 @@ static inline int bpf_dynptr_check_off_len(const struct bpf_dynptr_kern *ptr, u6
14201420
int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
14211421
struct bpf_trampoline *tr,
14221422
struct bpf_prog *tgt_prog);
1423+
int bpf_trampoline_update_prog(struct bpf_tramp_link *link,
1424+
struct bpf_prog *new_prog,
1425+
struct bpf_trampoline *tr);
14231426
int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
14241427
struct bpf_trampoline *tr,
14251428
struct bpf_prog *tgt_prog);
@@ -1509,6 +1512,14 @@ static inline int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
15091512
{
15101513
return -ENOTSUPP;
15111514
}
1515+
1516+
static inline int bpf_trampoline_update_prog(struct bpf_tramp_link *link,
1517+
struct bpf_prog *new_prog,
1518+
struct bpf_trampoline *tr)
1519+
{
1520+
return -ENOTSUPP;
1521+
}
1522+
15121523
static inline int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
15131524
struct bpf_trampoline *tr,
15141525
struct bpf_prog *tgt_prog)

kernel/bpf/syscall.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ static DEFINE_IDR(map_idr);
6363
static DEFINE_SPINLOCK(map_idr_lock);
6464
static DEFINE_IDR(link_idr);
6565
static DEFINE_SPINLOCK(link_idr_lock);
66+
/* Synchronizes access to prog between link update operations. */
67+
static DEFINE_MUTEX(trace_link_mutex);
6668

6769
int sysctl_unprivileged_bpf_disabled __read_mostly =
6870
IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
@@ -3562,11 +3564,77 @@ static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
35623564
return 0;
35633565
}
35643566

3567+
static int bpf_tracing_link_update_prog(struct bpf_link *link,
3568+
struct bpf_prog *new_prog,
3569+
struct bpf_prog *old_prog)
3570+
{
3571+
struct bpf_tracing_link *tr_link =
3572+
container_of(link, struct bpf_tracing_link, link.link);
3573+
struct bpf_attach_target_info tgt_info = {0};
3574+
int err = 0;
3575+
u32 btf_id;
3576+
3577+
mutex_lock(&trace_link_mutex);
3578+
3579+
if (old_prog && link->prog != old_prog) {
3580+
err = -EPERM;
3581+
goto out;
3582+
}
3583+
old_prog = link->prog;
3584+
if (old_prog->type != new_prog->type ||
3585+
old_prog->expected_attach_type != new_prog->expected_attach_type) {
3586+
err = -EINVAL;
3587+
goto out;
3588+
}
3589+
3590+
mutex_lock(&new_prog->aux->dst_mutex);
3591+
3592+
if (!new_prog->aux->dst_trampoline ||
3593+
new_prog->aux->dst_trampoline->key != tr_link->trampoline->key) {
3594+
bpf_trampoline_unpack_key(tr_link->trampoline->key, NULL,
3595+
&btf_id);
3596+
/* If there is no saved target, or the target associated with
3597+
* this link is different from the destination specified at
3598+
* load time, we need to check for compatibility.
3599+
*/
3600+
err = bpf_check_attach_target(NULL, new_prog, tr_link->tgt_prog,
3601+
btf_id, &tgt_info);
3602+
if (err)
3603+
goto out_unlock;
3604+
}
3605+
3606+
err = bpf_trampoline_update_prog(&tr_link->link, new_prog,
3607+
tr_link->trampoline);
3608+
if (err)
3609+
goto out_unlock;
3610+
3611+
/* Clear the trampoline, mod, and target prog from new_prog->aux to make
3612+
* sure the original attach destination is not kept alive after a
3613+
* program is (re-)attached to another target.
3614+
*/
3615+
if (new_prog->aux->dst_prog)
3616+
bpf_prog_put(new_prog->aux->dst_prog);
3617+
bpf_trampoline_put(new_prog->aux->dst_trampoline);
3618+
module_put(new_prog->aux->mod);
3619+
3620+
new_prog->aux->dst_prog = NULL;
3621+
new_prog->aux->dst_trampoline = NULL;
3622+
new_prog->aux->mod = tgt_info.tgt_mod;
3623+
tgt_info.tgt_mod = NULL; /* Make module_put() below do nothing. */
3624+
out_unlock:
3625+
mutex_unlock(&new_prog->aux->dst_mutex);
3626+
out:
3627+
mutex_unlock(&trace_link_mutex);
3628+
module_put(tgt_info.tgt_mod);
3629+
return err;
3630+
}
3631+
35653632
static const struct bpf_link_ops bpf_tracing_link_lops = {
35663633
.release = bpf_tracing_link_release,
35673634
.dealloc = bpf_tracing_link_dealloc,
35683635
.show_fdinfo = bpf_tracing_link_show_fdinfo,
35693636
.fill_link_info = bpf_tracing_link_fill_link_info,
3637+
.update_prog = bpf_tracing_link_update_prog,
35703638
};
35713639

35723640
static int bpf_tracing_prog_attach(struct bpf_prog *prog,

kernel/bpf/trampoline.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,35 @@ int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
607607
return err;
608608
}
609609

610+
static int __bpf_trampoline_update_prog(struct bpf_tramp_link *link,
611+
struct bpf_prog *new_prog,
612+
struct bpf_trampoline *tr)
613+
{
614+
return -ENOTSUPP;
615+
}
616+
617+
int bpf_trampoline_update_prog(struct bpf_tramp_link *link,
618+
struct bpf_prog *new_prog,
619+
struct bpf_trampoline *tr)
620+
{
621+
struct bpf_prog *old_prog;
622+
int err;
623+
624+
mutex_lock(&tr->mutex);
625+
err = __bpf_trampoline_update_prog(link, new_prog, tr);
626+
if (!err) {
627+
/* If a program update was successful, switch the program
628+
* in the link before releasing tr->mutex; otherwise, another
629+
* operation could come along and update the trampoline with
630+
* the link still pointing at the old program.
631+
*/
632+
old_prog = xchg(&link->link.prog, new_prog);
633+
bpf_prog_put(old_prog);
634+
}
635+
mutex_unlock(&tr->mutex);
636+
return err;
637+
}
638+
610639
static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
611640
struct bpf_trampoline *tr,
612641
struct bpf_prog *tgt_prog)

0 commit comments

Comments
 (0)