Similar to bpf map, We only expose the bpf map id under current bpf namespace to user. The prog->aux->id is still the id in the init bpf namespace. The id of used_maps is also the id in current bpf namespace. The result as follows, Run bpftool in current namespace, $ bpftool map show 4: array name kprobe_b.rodata flags 0x80 key 4B value 37B max_entries 1 memlock 360B btf_id 96 frozen pids kprobe(8790) 5: array name kprobe_b.data flags 0x400 key 4B value 4B max_entries 1 memlock 8192B btf_id 96 pids kprobe(8790) $ bpftool prog show 7: kprobe name kretprobe_run tag 0de47cc241a2b1b3 gpl loaded_at 2023-03-21T10:20:58+0800 uid 0 xlated 56B jited 39B memlock 4096B map_ids 4 btf_id 96 9: kprobe name kprobe_run tag bf163b23cd3b174d gpl loaded_at 2023-03-21T10:20:58+0800 uid 0 xlated 48B jited 35B memlock 4096B map_ids 4 btf_id 96 At the same time, run bpftool in init bpf namespace. $ bpftool map show 18: array name kprobe_b.rodata flags 0x80 key 4B value 37B max_entries 1 memlock 360B btf_id 96 frozen pids kprobe(8790) 19: array name kprobe_b.data flags 0x400 key 4B value 4B max_entries 1 memlock 8192B btf_id 96 pids kprobe(8790) $ bpftool prog show 29: kprobe name kretprobe_run tag 0de47cc241a2b1b3 gpl loaded_at 2023-03-21T10:20:58+0800 uid 0 xlated 56B jited 39B memlock 4096B map_ids 18 btf_id 96 pids kprobe(8790) 31: kprobe name kprobe_run tag bf163b23cd3b174d gpl loaded_at 2023-03-21T10:20:58+0800 uid 0 xlated 48B jited 35B memlock 4096B map_ids 18 btf_id 96 pids kprobe(8790) In init bpf namespace, bpftool can also show other bpf progs, but the bpftool running in the new bpf namespace can't. Signed-off-by: Yafang Shao <laoar.shao@xxxxxxxxx> --- include/linux/bpf.h | 3 +- kernel/bpf/bpf_namespace.c | 1 + kernel/bpf/syscall.c | 56 ++++++++++--------------------- tools/bpf/bpftool/skeleton/pid_iter.bpf.c | 3 +- 4 files changed, 22 insertions(+), 41 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 2a1f19c..16f2a01 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1416,6 +1416,7 @@ struct bpf_prog_aux { struct work_struct work; struct rcu_head rcu; }; + struct bpf_obj_id *obj_id; }; struct bpf_prog { @@ -1940,8 +1941,6 @@ struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, struct bpf_prog * __must_check bpf_prog_inc_not_zero(struct bpf_prog *prog); void bpf_prog_put(struct bpf_prog *prog); -void bpf_prog_free_id(struct bpf_prog *prog); - struct btf_field *btf_record_find(const struct btf_record *rec, u32 offset, u32 field_mask); void btf_record_free(struct btf_record *rec); diff --git a/kernel/bpf/bpf_namespace.c b/kernel/bpf/bpf_namespace.c index 6a6ef70..8c70945 100644 --- a/kernel/bpf/bpf_namespace.c +++ b/kernel/bpf/bpf_namespace.c @@ -12,6 +12,7 @@ #define MAX_BPF_NS_LEVEL 32 DEFINE_SPINLOCK(map_idr_lock); +DEFINE_SPINLOCK(prog_idr_lock); static struct kmem_cache *bpfns_cachep; static struct kmem_cache *obj_id_cache[MAX_PID_NS_LEVEL]; static struct ns_common *bpfns_get(struct task_struct *task); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 1335200..4725924 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -48,8 +48,6 @@ #define BPF_OBJ_FLAG_MASK (BPF_F_RDONLY | BPF_F_WRONLY) DEFINE_PER_CPU(int, bpf_prog_active); -static DEFINE_IDR(prog_idr); -DEFINE_SPINLOCK(prog_idr_lock); static DEFINE_IDR(link_idr); DEFINE_SPINLOCK(link_idr_lock); @@ -1983,32 +1981,10 @@ static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op) if (unlikely(!ab)) return; audit_log_format(ab, "prog-id=%u op=%s", - prog->aux->id, bpf_audit_str[op]); + bpf_obj_id_vnr(prog->aux->obj_id), bpf_audit_str[op]); audit_log_end(ab); } -static int bpf_prog_alloc_id(struct bpf_prog *prog) -{ - int id; - - idr_preload(GFP_KERNEL); - spin_lock_bh(&prog_idr_lock); - id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC); - spin_unlock_bh(&prog_idr_lock); - idr_preload_end(); - - return id; -} - -void bpf_prog_free_id(struct bpf_prog *prog) -{ - unsigned long flags; - - spin_lock_irqsave(&prog_idr_lock, flags); - idr_remove(&prog_idr, prog->aux->id); - spin_unlock_irqrestore(&prog_idr_lock, flags); -} - static void __bpf_prog_put_rcu(struct rcu_head *rcu) { struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); @@ -2056,7 +2032,7 @@ static void bpf_prog_put_deferred(struct work_struct *work) * simply waiting for refcnt to drop to be freed. */ if (prog->aux->id) { - bpf_prog_free_id(prog); + bpf_free_obj_id(prog->aux->obj_id, PROG_OBJ_ID); prog->aux->id = 0; } __bpf_prog_put_noref(prog, true); @@ -2157,7 +2133,7 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) prog->jited, prog_tag, prog->pages * 1ULL << PAGE_SHIFT, - prog->aux->id, + bpf_obj_id_vnr(prog->aux->obj_id), stats.nsecs, stats.cnt, stats.misses, @@ -2468,6 +2444,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) enum bpf_prog_type type = attr->prog_type; struct bpf_prog *prog, *dst_prog = NULL; struct btf *attach_btf = NULL; + struct bpf_obj_id *obj_id; int err; char license[128]; bool is_gpl; @@ -2621,12 +2598,13 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) if (err < 0) goto free_used_maps; - err = bpf_prog_alloc_id(prog); - if (err < 0) + obj_id = bpf_alloc_obj_id(current->nsproxy->bpf_ns, prog, PROG_OBJ_ID); + if (IS_ERR(obj_id)) goto free_used_maps; - prog->aux->id = err; + prog->aux->obj_id = obj_id; + prog->aux->id = bpf_obj_id_nr(obj_id); - /* Upon success of bpf_prog_alloc_id(), the BPF prog is + /* Upon success of bpf_alloc_obj_id(), the BPF prog is * effectively publicly exposed. However, retrieving via * bpf_prog_get_fd_by_id() will take another reference, * therefore it cannot be gone underneath us. @@ -2803,7 +2781,7 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) "prog_tag:\t%s\n" "prog_id:\t%u\n", prog_tag, - prog->aux->id); + bpf_obj_id_vnr(prog->aux->obj_id)); } if (link->ops->show_fdinfo) link->ops->show_fdinfo(link, m); @@ -3706,11 +3684,12 @@ struct bpf_map *bpf_map_get_curr_or_next(u32 *id) struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id) { + struct bpf_namespace *ns = current->nsproxy->bpf_ns; struct bpf_prog *prog; spin_lock_bh(&prog_idr_lock); again: - prog = idr_get_next(&prog_idr, id); + prog = idr_get_next(&ns->idr[PROG_OBJ_ID], id); if (prog) { prog = bpf_prog_inc_not_zero(prog); if (IS_ERR(prog)) { @@ -3727,13 +3706,14 @@ struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id) struct bpf_prog *bpf_prog_by_id(u32 id) { + struct bpf_namespace *ns = current->nsproxy->bpf_ns; struct bpf_prog *prog; if (!id) return ERR_PTR(-ENOENT); spin_lock_bh(&prog_idr_lock); - prog = idr_find(&prog_idr, id); + prog = idr_find(&ns->idr[PROG_OBJ_ID], id); if (prog) prog = bpf_prog_inc_not_zero(prog); else @@ -3939,7 +3919,7 @@ static int bpf_prog_get_info_by_fd(struct file *file, return -EFAULT; info.type = prog->type; - info.id = prog->aux->id; + info.id = bpf_obj_id_vnr(prog->aux->obj_id); info.load_time = prog->aux->load_time; info.created_by_uid = from_kuid_munged(current_user_ns(), prog->aux->user->uid); @@ -4287,7 +4267,7 @@ static int bpf_link_get_info_by_fd(struct file *file, info.type = link->type; info.id = link->id; if (link->prog) - info.prog_id = link->prog->aux->id; + info.prog_id = bpf_obj_id_vnr(link->prog->aux->obj_id); if (link->ops->fill_link_info) { err = link->ops->fill_link_info(link, &info); @@ -4452,7 +4432,7 @@ static int bpf_task_fd_query(const union bpf_attr *attr, struct bpf_raw_event_map *btp = raw_tp->btp; err = bpf_task_fd_query_copy(attr, uattr, - raw_tp->link.prog->aux->id, + bpf_obj_id_vnr(raw_tp->link.prog->aux->obj_id), BPF_FD_TYPE_RAW_TRACEPOINT, btp->tp->name, 0, 0); goto put_file; @@ -5048,7 +5028,7 @@ static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) break; case BPF_PROG_GET_NEXT_ID: err = bpf_obj_get_next_id(&attr, uattr.user, - &prog_idr, &prog_idr_lock); + &ns->idr[PROG_OBJ_ID], &prog_idr_lock); break; case BPF_MAP_GET_NEXT_ID: err = bpf_obj_get_next_id(&attr, uattr.user, diff --git a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c index a71aef7..1fd8ceb 100644 --- a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c +++ b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c @@ -28,7 +28,8 @@ static __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type) switch (type) { case BPF_OBJ_PROG: - return BPF_CORE_READ((struct bpf_prog *)ent, aux, id); + obj_id = BPF_CORE_READ((struct bpf_prog *)ent, aux, obj_id); + break; case BPF_OBJ_MAP: obj_id = BPF_CORE_READ((struct bpf_map *)ent, obj_id); break; -- 1.8.3.1