@@ -26,6 +26,7 @@ struct bpf_verifier_log;
struct perf_event;
struct bpf_prog;
struct bpf_prog_aux;
+struct bpf_tracing_link;
struct bpf_map;
struct sock;
struct seq_file;
@@ -614,8 +615,8 @@ static __always_inline unsigned int bpf_dispatcher_nop_func(
}
#ifdef CONFIG_BPF_JIT
struct bpf_trampoline *bpf_trampoline_lookup(u64 key);
-int bpf_trampoline_link_prog(struct bpf_prog *prog);
-int bpf_trampoline_unlink_prog(struct bpf_prog *prog);
+int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr);
+int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr);
int bpf_trampoline_get(u64 key, void *addr,
struct btf_func_model *fmodel,
struct bpf_trampoline **trampoline);
@@ -667,11 +668,13 @@ static inline struct bpf_trampoline *bpf_trampoline_lookup(u64 key)
{
return NULL;
}
-static inline int bpf_trampoline_link_prog(struct bpf_prog *prog)
+static inline int bpf_trampoline_link_prog(struct bpf_prog *prog,
+ struct bpf_trampoline *tr)
{
return -ENOTSUPP;
}
-static inline int bpf_trampoline_unlink_prog(struct bpf_prog *prog)
+static inline int bpf_trampoline_unlink_prog(struct bpf_prog *prog,
+ struct bpf_trampoline *tr)
{
return -ENOTSUPP;
}
@@ -740,14 +743,13 @@ struct bpf_prog_aux {
u32 max_rdonly_access;
u32 max_rdwr_access;
const struct bpf_ctx_arg_aux *ctx_arg_info;
- struct bpf_prog *linked_prog;
+ struct bpf_tracing_link *tgt_link;
bool verifier_zext; /* Zero extensions has been inserted by verifier. */
bool offload_requested;
bool attach_btf_trace; /* true if attaching to BTF-enabled raw tp */
bool func_proto_unreliable;
bool sleepable;
enum bpf_tramp_prog_type trampoline_prog_type;
- struct bpf_trampoline *trampoline;
struct hlist_node tramp_hlist;
/* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
const struct btf_type *attach_func_proto;
@@ -827,6 +829,13 @@ struct bpf_link {
struct work_struct work;
};
+struct bpf_tracing_link {
+ struct bpf_link link;
+ enum bpf_attach_type attach_type;
+ struct bpf_trampoline *trampoline;
+ struct bpf_prog *tgt_prog;
+};
+
struct bpf_link_ops {
void (*release)(struct bpf_link *link);
void (*dealloc)(struct bpf_link *link);
@@ -3706,10 +3706,10 @@ struct btf *btf_parse_vmlinux(void)
struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog)
{
- struct bpf_prog *tgt_prog = prog->aux->linked_prog;
+ struct bpf_tracing_link *tgt_link = prog->aux->tgt_link;
- if (tgt_prog) {
- return tgt_prog->aux->btf;
+ if (tgt_link && tgt_link->tgt_prog) {
+ return tgt_link->tgt_prog->aux->btf;
} else {
return btf_vmlinux;
}
@@ -3733,14 +3733,17 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
struct bpf_insn_access_aux *info)
{
const struct btf_type *t = prog->aux->attach_func_proto;
- struct bpf_prog *tgt_prog = prog->aux->linked_prog;
struct btf *btf = bpf_prog_get_target_btf(prog);
const char *tname = prog->aux->attach_func_name;
struct bpf_verifier_log *log = info->log;
+ struct bpf_prog *tgt_prog = NULL;
const struct btf_param *args;
u32 nr_args, arg;
int i, ret;
+ if (prog->aux->tgt_link)
+ tgt_prog = prog->aux->tgt_link->tgt_prog;
+
if (off % 8) {
bpf_log(log, "func '%s' offset %d is not multiple of 8\n",
tname, off);
@@ -4572,7 +4575,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
return -EFAULT;
}
if (prog_type == BPF_PROG_TYPE_EXT)
- prog_type = prog->aux->linked_prog->type;
+ prog_type = prog->aux->tgt_link->tgt_prog->type;
t = btf_type_by_id(btf, t->type);
if (!t || !btf_type_is_func_proto(t)) {
@@ -2130,7 +2130,6 @@ static void bpf_prog_free_deferred(struct work_struct *work)
if (aux->prog->has_callchain_buf)
put_callchain_buffers();
#endif
- bpf_trampoline_put(aux->trampoline);
for (i = 0; i < aux->func_cnt; i++)
bpf_jit_free(aux->func[i]);
if (aux->func_cnt) {
@@ -2146,8 +2145,8 @@ void bpf_prog_free(struct bpf_prog *fp)
{
struct bpf_prog_aux *aux = fp->aux;
- if (aux->linked_prog)
- bpf_prog_put(aux->linked_prog);
+ if (aux->tgt_link)
+ bpf_link_put(&aux->tgt_link->link);
INIT_WORK(&aux->work, bpf_prog_free_deferred);
schedule_work(&aux->work);
}
@@ -2095,10 +2095,13 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
/* last field in 'union bpf_attr' used by this command */
#define BPF_PROG_LOAD_LAST_FIELD attach_prog_fd
+static struct bpf_tracing_link *bpf_tracing_link_create(struct bpf_prog *prog,
+ struct bpf_prog *tgt_prog);
+
static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
{
enum bpf_prog_type type = attr->prog_type;
- struct bpf_prog *prog;
+ struct bpf_prog *prog, *tgt_prog = NULL;
int err;
char license[128];
bool is_gpl;
@@ -2154,14 +2157,27 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
prog->expected_attach_type = attr->expected_attach_type;
prog->aux->attach_btf_id = attr->attach_btf_id;
if (attr->attach_prog_fd) {
- struct bpf_prog *tgt_prog;
-
tgt_prog = bpf_prog_get(attr->attach_prog_fd);
if (IS_ERR(tgt_prog)) {
err = PTR_ERR(tgt_prog);
goto free_prog_nouncharge;
}
- prog->aux->linked_prog = tgt_prog;
+ }
+
+ if (tgt_prog || prog->aux->attach_btf_id) {
+ struct bpf_tracing_link *link;
+
+ link = bpf_tracing_link_create(prog, tgt_prog);
+ if (IS_ERR(link)) {
+ err = PTR_ERR(link);
+ if (tgt_prog)
+ bpf_prog_put(tgt_prog);
+ goto free_prog_nouncharge;
+ }
+ prog->aux->tgt_link = link;
+
+ /* avoid circular ref - will be set on link activation */
+ link->link.prog = NULL;
}
prog->aux->offload_requested = !!attr->prog_ifindex;
@@ -2495,14 +2511,21 @@ struct bpf_link *bpf_link_get_from_fd(u32 ufd)
return link;
}
-struct bpf_tracing_link {
- struct bpf_link link;
- enum bpf_attach_type attach_type;
-};
-
static void bpf_tracing_link_release(struct bpf_link *link)
{
- WARN_ON_ONCE(bpf_trampoline_unlink_prog(link->prog));
+ struct bpf_tracing_link *tr_link =
+ container_of(link, struct bpf_tracing_link, link);
+
+ if (tr_link->trampoline) {
+ if (link->id)
+ WARN_ON_ONCE(bpf_trampoline_unlink_prog(link->prog,
+ tr_link->trampoline));
+
+ bpf_trampoline_put(tr_link->trampoline);
+ }
+
+ if (tr_link->tgt_prog)
+ bpf_prog_put(tr_link->tgt_prog);
}
static void bpf_tracing_link_dealloc(struct bpf_link *link)
@@ -2542,10 +2565,27 @@ static const struct bpf_link_ops bpf_tracing_link_lops = {
.fill_link_info = bpf_tracing_link_fill_link_info,
};
+static struct bpf_tracing_link *bpf_tracing_link_create(struct bpf_prog *prog,
+ struct bpf_prog *tgt_prog)
+{
+ struct bpf_tracing_link *link;
+
+ link = kzalloc(sizeof(*link), GFP_USER);
+ if (!link)
+ return ERR_PTR(-ENOMEM);
+
+ bpf_link_init(&link->link, BPF_LINK_TYPE_TRACING,
+ &bpf_tracing_link_lops, prog);
+ link->attach_type = prog->expected_attach_type;
+ link->tgt_prog = tgt_prog;
+
+ return link;
+}
+
static int bpf_tracing_prog_attach(struct bpf_prog *prog)
{
+ struct bpf_tracing_link *link, *olink;
struct bpf_link_primer link_primer;
- struct bpf_tracing_link *link;
int err;
switch (prog->type) {
@@ -2574,14 +2614,16 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog)
goto out_put_prog;
}
- link = kzalloc(sizeof(*link), GFP_USER);
+ link = READ_ONCE(prog->aux->tgt_link);
if (!link) {
- err = -ENOMEM;
+ err = -ENOENT;
+ goto out_put_prog;
+ }
+ olink = cmpxchg(&prog->aux->tgt_link, link, NULL);
+ if (olink != link) {
+ err = -ENOENT;
goto out_put_prog;
}
- bpf_link_init(&link->link, BPF_LINK_TYPE_TRACING,
- &bpf_tracing_link_lops, prog);
- link->attach_type = prog->expected_attach_type;
err = bpf_link_prime(&link->link, &link_primer);
if (err) {
@@ -2589,12 +2631,17 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog)
goto out_put_prog;
}
- err = bpf_trampoline_link_prog(prog);
+ err = bpf_trampoline_link_prog(prog, link->trampoline);
if (err) {
bpf_link_cleanup(&link_primer);
goto out_put_prog;
}
+ /* at this point the link is no longer referenced from struct bpf_prog,
+ * so we can populate this without introducing a circular reference.
+ */
+ link->link.prog = prog;
+
return bpf_link_settle(&link_primer);
out_put_prog:
bpf_prog_put(prog);
@@ -261,14 +261,12 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)
}
}
-int bpf_trampoline_link_prog(struct bpf_prog *prog)
+int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr)
{
enum bpf_tramp_prog_type kind;
- struct bpf_trampoline *tr;
int err = 0;
int cnt;
- tr = prog->aux->trampoline;
kind = bpf_attach_type_to_tramp(prog);
mutex_lock(&tr->mutex);
if (tr->extension_prog) {
@@ -301,7 +299,7 @@ int bpf_trampoline_link_prog(struct bpf_prog *prog)
}
hlist_add_head(&prog->aux->tramp_hlist, &tr->progs_hlist[kind]);
tr->progs_cnt[kind]++;
- err = bpf_trampoline_update(prog->aux->trampoline);
+ err = bpf_trampoline_update(tr);
if (err) {
hlist_del(&prog->aux->tramp_hlist);
tr->progs_cnt[kind]--;
@@ -312,13 +310,11 @@ int bpf_trampoline_link_prog(struct bpf_prog *prog)
}
/* bpf_trampoline_unlink_prog() should never fail. */
-int bpf_trampoline_unlink_prog(struct bpf_prog *prog)
+int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr)
{
enum bpf_tramp_prog_type kind;
- struct bpf_trampoline *tr;
int err;
- tr = prog->aux->trampoline;
kind = bpf_attach_type_to_tramp(prog);
mutex_lock(&tr->mutex);
if (kind == BPF_TRAMP_REPLACE) {
@@ -330,7 +326,7 @@ int bpf_trampoline_unlink_prog(struct bpf_prog *prog)
}
hlist_del(&prog->aux->tramp_hlist);
tr->progs_cnt[kind]--;
- err = bpf_trampoline_update(prog->aux->trampoline);
+ err = bpf_trampoline_update(tr);
out:
mutex_unlock(&tr->mutex);
return err;
@@ -2628,8 +2628,10 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno,
static enum bpf_prog_type resolve_prog_type(struct bpf_prog *prog)
{
- return prog->aux->linked_prog ? prog->aux->linked_prog->type
- : prog->type;
+ if (prog->aux->tgt_link && prog->aux->tgt_link->tgt_prog)
+ return prog->aux->tgt_link->tgt_prog->type;
+
+ return prog->type;
}
static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
@@ -11266,8 +11268,8 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
static int check_attach_btf_id(struct bpf_verifier_env *env)
{
struct bpf_prog *prog = env->prog;
- struct bpf_prog *tgt_prog = prog->aux->linked_prog;
u32 btf_id = prog->aux->attach_btf_id;
+ struct bpf_prog *tgt_prog = NULL;
struct btf_func_model fmodel;
const struct btf_type *t;
const char *tname;
@@ -11275,6 +11277,9 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
int ret;
u64 key;
+ if (prog->aux->tgt_link)
+ tgt_prog = prog->aux->tgt_link->tgt_prog;
+
if (prog->aux->sleepable && prog->type != BPF_PROG_TYPE_TRACING &&
prog->type != BPF_PROG_TYPE_LSM) {
verbose(env, "Only fentry/fexit/fmod_ret and lsm programs can be sleepable\n");
@@ -11334,7 +11339,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
return ret;
}
return bpf_trampoline_get(key, (void *)addr, &fmodel,
- &prog->aux->trampoline);
+ &prog->aux->tgt_link->trampoline);
}
}