diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 21f8dbcf3f48..2dbc00904a84 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -679,7 +679,14 @@ struct bpf_tramp_id {
struct bpf_tramp_node {
struct hlist_node hlist_tramp;
+ struct hlist_node hlist_attach;
struct bpf_prog *prog;
+ struct bpf_trampoline *tr;
+};
+
+struct bpf_tramp_attach {
+ struct bpf_tramp_id *id;
+ struct hlist_head nodes;
};
struct bpf_trampoline {@@ -751,9 +758,14 @@ void bpf_tramp_id_init(struct bpf_tramp_id *id,
struct btf *btf, u32 btf_id);
int bpf_trampoline_link_prog(struct bpf_tramp_node *node, struct bpf_trampoline *tr);
int bpf_trampoline_unlink_prog(struct bpf_tramp_node *node, struct bpf_trampoline *tr);
-struct bpf_trampoline *bpf_trampoline_get(struct bpf_tramp_id *id,
- struct bpf_attach_target_info *tgt_info);
void bpf_trampoline_put(struct bpf_trampoline *tr);
+
+struct bpf_tramp_attach *bpf_tramp_attach(struct bpf_tramp_id *id,
+ struct bpf_prog *tgt_prog,
+ struct bpf_prog *prog);
+void bpf_tramp_detach(struct bpf_tramp_attach *attach);
+int bpf_tramp_attach_link(struct bpf_tramp_attach *attach);
+int bpf_tramp_attach_unlink(struct bpf_tramp_attach *attach);
#define BPF_DISPATCHER_INIT(_name) { \
.mutex = __MUTEX_INITIALIZER(_name.mutex), \
.func = &_name##_func, \@@ -888,8 +900,8 @@ struct bpf_prog_aux {
const struct bpf_ctx_arg_aux *ctx_arg_info;
struct mutex dst_mutex; /* protects dst_* pointers below, *after* prog becomes visible */
struct bpf_prog *dst_prog;
- struct bpf_trampoline *dst_trampoline;
- struct bpf_trampoline *trampoline;
+ struct bpf_tramp_attach *dst_attach;
+ struct bpf_tramp_attach *attach;
enum bpf_prog_type saved_dst_prog_type;
enum bpf_attach_type saved_dst_attach_type;
bool verifier_zext; /* Zero extensions has been inserted by verifier. */@@ -899,7 +911,6 @@ struct bpf_prog_aux {
bool sleepable;
bool tail_call_reachable;
bool multi_func;
- struct bpf_tramp_node tramp_node;
/* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
const struct btf_type *attach_func_proto;
/* function name for valid attach_btf_id */diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 2eed91153a3f..993ae224e371 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -105,7 +105,6 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
fp->aux = aux;
fp->aux->prog = fp;
fp->jit_requested = ebpf_jit_enabled();
- fp->aux->tramp_node.prog = fp;
INIT_LIST_HEAD_RCU(&fp->aux->ksym.lnode);
mutex_init(&fp->aux->used_maps_mutex);
@@ -2284,8 +2283,8 @@ static void bpf_prog_free_deferred(struct work_struct *work)
if (aux->prog->has_callchain_buf)
put_callchain_buffers();
#endif
- if (aux->dst_trampoline)
- bpf_trampoline_put(aux->dst_trampoline);
+ if (aux->dst_attach)
+ bpf_tramp_detach(aux->dst_attach);
for (i = 0; i < aux->func_cnt; i++) {
/* We can just unlink the subprog poke descriptor table as
* it was originally linked to the main program and is alsodiff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0d916e3b7676..a65c1862ab68 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2644,32 +2644,32 @@ struct bpf_link *bpf_link_get_from_fd(u32 ufd)
struct bpf_tracing_link {
struct bpf_link link;
enum bpf_attach_type attach_type;
- struct bpf_trampoline *trampoline;
+ struct bpf_tramp_attach *attach;
struct bpf_prog *tgt_prog;
};
-static struct bpf_trampoline *link_trampoline(struct bpf_tracing_link *link)
+static struct bpf_tramp_attach *link_attach(struct bpf_tracing_link *link)
{
struct bpf_prog *prog = link->link.prog;
if (prog->type == BPF_PROG_TYPE_EXT)
- return link->trampoline;
+ return link->attach;
else
- return prog->aux->trampoline;
+ return prog->aux->attach;
}
static void bpf_tracing_link_release(struct bpf_link *link)
{
struct bpf_tracing_link *tr_link =
container_of(link, struct bpf_tracing_link, link);
- struct bpf_trampoline *tr = link_trampoline(tr_link);
+ struct bpf_tramp_attach *attach = link_attach(tr_link);
struct bpf_prog *prog = link->prog;
- WARN_ON_ONCE(bpf_trampoline_unlink_prog(&link->prog->aux->tramp_node, tr));
+ WARN_ON_ONCE(bpf_tramp_attach_unlink(attach));
if (prog->type != BPF_PROG_TYPE_EXT)
- prog->aux->trampoline = NULL;
- bpf_trampoline_put(tr);
+ prog->aux->attach = NULL;
+ bpf_tramp_detach(attach);
/* tgt_prog is NULL if target is a kernel function */
if (tr_link->tgt_prog)@@ -2700,11 +2700,11 @@ static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
{
struct bpf_tracing_link *tr_link =
container_of(link, struct bpf_tracing_link, link);
- struct bpf_trampoline *tr = link_trampoline(tr_link);
+ struct bpf_tramp_attach *attach = link_attach(tr_link);
info->tracing.attach_type = tr_link->attach_type;
- info->tracing.target_obj_id = tr->id->obj_id;
- info->tracing.target_btf_id = tr->id->btf_id;
+ info->tracing.target_obj_id = attach->id->obj_id;
+ info->tracing.target_btf_id = attach->id->btf_id;
return 0;
}@@ -2721,9 +2721,9 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
u32 btf_id)
{
bool prog_extension = prog->type == BPF_PROG_TYPE_EXT;
+ struct bpf_tramp_attach *attach = NULL;
struct bpf_link_primer link_primer;
struct bpf_prog *tgt_prog = NULL;
- struct bpf_trampoline *tr = NULL;
struct bpf_tracing_link *link;
struct bpf_tramp_id *id = NULL;
int err;@@ -2793,7 +2793,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
mutex_lock(&prog->aux->dst_mutex);
- if (!prog_extension && prog->aux->trampoline) {
+ if (!prog_extension && prog->aux->attach) {
err = -EBUSY;
goto out_unlock;
}@@ -2816,7 +2816,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
* - if prog->aux->dst_trampoline and tgt_prog is NULL, the program
* was detached and is going for re-attachment.
*/
- if (!prog->aux->dst_trampoline && !tgt_prog) {
+ if (!prog->aux->dst_attach && !tgt_prog) {
/*
* Allow re-attach for TRACING and LSM programs. If it's
* currently linked, bpf_trampoline_link_prog will fail.@@ -2839,9 +2839,9 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
bpf_tramp_id_init(id, NULL, prog->aux->attach_btf, btf_id);
}
- if (!prog->aux->dst_trampoline ||
+ if (!prog->aux->dst_attach ||
(!bpf_tramp_id_is_empty(id) &&
- bpf_tramp_id_is_equal(id, prog->aux->dst_trampoline->id))) {
+ bpf_tramp_id_is_equal(id, prog->aux->dst_attach->id))) {
/* If there is no saved target, or the specified target is
* different from the destination specified at load time, we
* need a new trampoline and a check for compatibility@@ -2853,9 +2853,11 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
if (err)
goto out_unlock;
- tr = bpf_trampoline_get(id, &tgt_info);
- if (!tr) {
- err = -ENOMEM;
+ id->addr = (void *) tgt_info.tgt_addr;
+
+ attach = bpf_tramp_attach(id, tgt_prog, prog);
+ if (IS_ERR(attach)) {
+ err = PTR_ERR(attach);
goto out_unlock;
}
} else {@@ -2866,7 +2868,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
* can only happen once for any program, as the saved values in
* prog->aux are cleared below.
*/
- tr = prog->aux->dst_trampoline;
+ attach = prog->aux->dst_attach;
tgt_prog = prog->aux->dst_prog;
}
@@ -2874,7 +2876,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
if (err)
goto out_unlock;
- err = bpf_trampoline_link_prog(&prog->aux->tramp_node, tr);
+ err = bpf_tramp_attach_link(attach);
if (err) {
bpf_link_cleanup(&link_primer);
link = NULL;@@ -2882,32 +2884,31 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
}
link->tgt_prog = tgt_prog;
-
if (prog_extension)
- link->trampoline = tr;
+ link->attach = attach;
else
- prog->aux->trampoline = tr;
+ prog->aux->attach = attach;
/* 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 (prog->aux->dst_prog &&
- (tgt_prog_fd || tr != prog->aux->dst_trampoline))
+ (tgt_prog_fd || attach != prog->aux->dst_attach))
/* got extra prog ref from syscall, or attaching to different prog */
bpf_prog_put(prog->aux->dst_prog);
- if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline)
+ if (prog->aux->dst_attach && attach != prog->aux->dst_attach)
/* we allocated a new trampoline, so free the old one */
- bpf_trampoline_put(prog->aux->dst_trampoline);
+ bpf_tramp_detach(prog->aux->dst_attach);
prog->aux->dst_prog = NULL;
- prog->aux->dst_trampoline = NULL;
+ prog->aux->dst_attach = NULL;
mutex_unlock(&prog->aux->dst_mutex);
return bpf_link_settle(&link_primer);
out_unlock:
- if (tr && tr != prog->aux->dst_trampoline)
- bpf_trampoline_put(tr);
+ if (attach && attach != prog->aux->dst_attach)
+ bpf_tramp_detach(attach);
mutex_unlock(&prog->aux->dst_mutex);
kfree(link);
out_put_prog:
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index b6af3e0982d7..16fc4c14319b 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -11,6 +11,7 @@
#include <linux/rcupdate_wait.h>
#include <linux/module.h>
#include <linux/static_call.h>
+#include <linux/bpf_verifier.h>
/* dummy _ops. The verifier will operate on target program's ops. */
const struct bpf_verifier_ops bpf_extension_verifier_ops = {@@ -98,7 +99,7 @@ void bpf_tramp_id_free(struct bpf_tramp_id *id)
kfree(id);
}
-static struct bpf_trampoline *bpf_trampoline_lookup(struct bpf_tramp_id *id)
+static struct bpf_trampoline *bpf_trampoline_get(struct bpf_tramp_id *id)
{
struct bpf_trampoline *tr;
struct hlist_head *head;@@ -528,26 +529,6 @@ int bpf_trampoline_unlink_prog(struct bpf_tramp_node *node, struct bpf_trampolin
return err;
}
-struct bpf_trampoline *bpf_trampoline_get(struct bpf_tramp_id *id,
- struct bpf_attach_target_info *tgt_info)
-{
- struct bpf_trampoline *tr;
-
- tr = bpf_trampoline_lookup(id);
- if (!tr)
- return NULL;
-
- mutex_lock(&tr->mutex);
- if (tr->id->addr)
- goto out;
-
- memcpy(&tr->func.model, &tgt_info->fmodel, sizeof(tgt_info->fmodel));
- tr->id->addr = (void *)tgt_info->tgt_addr;
-out:
- mutex_unlock(&tr->mutex);
- return tr;
-}
-
void bpf_trampoline_put(struct bpf_trampoline *tr)
{
if (!tr)@@ -567,12 +548,109 @@ void bpf_trampoline_put(struct bpf_trampoline *tr)
* multiple rcu callbacks.
*/
hlist_del(&tr->hlist);
- bpf_tramp_id_free(tr->id);
kfree(tr);
out:
mutex_unlock(&trampoline_mutex);
}
+static struct bpf_tramp_node *node_alloc(struct bpf_trampoline *tr, struct bpf_prog *prog)
+{
+ struct bpf_tramp_node *node;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return NULL;
+
+ INIT_HLIST_NODE(&node->hlist_tramp);
+ INIT_HLIST_NODE(&node->hlist_attach);
+ node->prog = prog;
+ node->tr = tr;
+ return node;
+}
+
+static void node_free(struct bpf_tramp_node *node)
+{
+ bpf_trampoline_put(node->tr);
+ kfree(node);
+}
+
+struct bpf_tramp_attach *bpf_tramp_attach(struct bpf_tramp_id *id,
+ struct bpf_prog *tgt_prog,
+ struct bpf_prog *prog)
+{
+ struct bpf_trampoline *tr = NULL;
+ struct bpf_tramp_attach *attach;
+ struct bpf_tramp_node *node;
+ int err;
+
+ attach = kzalloc(sizeof(*attach), GFP_KERNEL);
+ if (!attach)
+ return ERR_PTR(-ENOMEM);
+
+ tr = bpf_trampoline_get(id);
+ if (!tr) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ node = node_alloc(tr, prog);
+ if (!node)
+ goto out;
+
+ err = bpf_check_attach_model(prog, tgt_prog, id->btf_id, &tr->func.model);
+ if (err)
+ goto out;
+
+ attach->id = id;
+ hlist_add_head(&node->hlist_attach, &attach->nodes);
+ return attach;
+
+out:
+ bpf_trampoline_put(tr);
+ kfree(attach);
+ return ERR_PTR(err);
+}
+
+void bpf_tramp_detach(struct bpf_tramp_attach *attach)
+{
+ struct bpf_tramp_node *node;
+ struct hlist_node *n;
+
+ hlist_for_each_entry_safe(node, n, &attach->nodes, hlist_attach)
+ node_free(node);
+
+ bpf_tramp_id_free(attach->id);
+ kfree(attach);
+}
+
+int bpf_tramp_attach_link(struct bpf_tramp_attach *attach)
+{
+ struct bpf_tramp_node *node;
+ int err;
+
+ hlist_for_each_entry(node, &attach->nodes, hlist_attach) {
+ err = bpf_trampoline_link_prog(node, node->tr);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+int bpf_tramp_attach_unlink(struct bpf_tramp_attach *attach)
+{
+ struct bpf_tramp_node *node;
+ int err;
+
+ hlist_for_each_entry(node, &attach->nodes, hlist_attach) {
+ err = bpf_trampoline_unlink_prog(node, node->tr);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
#define NO_START_TIME 1
static __always_inline u64 notrace bpf_prog_start_time(void)
{diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a1e4389b0e9e..e05f39fd2708 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -13928,7 +13928,7 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
struct bpf_prog *tgt_prog = prog->aux->dst_prog;
struct bpf_attach_target_info tgt_info = {};
u32 btf_id = prog->aux->attach_btf_id;
- struct bpf_trampoline *tr;
+ struct bpf_tramp_attach *attach;
struct bpf_tramp_id *id;
int ret;
@@ -14000,13 +14000,15 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
return -ENOMEM;
bpf_tramp_id_init(id, tgt_prog, prog->aux->attach_btf, btf_id);
- tr = bpf_trampoline_get(id, &tgt_info);
- if (!tr) {
+ id->addr = (void *) tgt_info.tgt_addr;
+
+ attach = bpf_tramp_attach(id, tgt_prog, prog);
+ if (IS_ERR(attach)) {
bpf_tramp_id_free(id);
- return -ENOMEM;
+ return PTR_ERR(attach);
}
- prog->aux->dst_trampoline = tr;
+ prog->aux->dst_attach = attach;
return 0;
}
--
2.31.1