diff mbox series

[RFC,bpf-next,10/13] bpf: Alloc and free bpf_link id in bpf namespace

Message ID 20230326092208.13613-11-laoar.shao@gmail.com (mailing list archive)
State RFC
Delegated to: BPF
Headers show
Series bpf: Introduce BPF namespace | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-7 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 fail Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 fail Logs for test_maps on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-10 pending Logs for test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-11 fail Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-12 fail Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-13 fail Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 fail Logs for test_progs on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-16 fail Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 fail Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 fail Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 fail Logs for test_progs_no_alu32 on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 fail Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 fail Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_progs_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-31 fail Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-32 fail Logs for test_verifier on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-34 fail Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 fail Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-33 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-20 fail Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs on s390x with gcc
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1472 this patch: 1472
netdev/cc_maintainers warning 3 maintainers not CCed: quentin@isovalent.com martin.lau@linux.dev song@kernel.org
netdev/build_clang success Errors and warnings before: 168 this patch: 168
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1464 this patch: 1464
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Yafang Shao March 26, 2023, 9:22 a.m. UTC
Similar to bpf map, We only expose the bpf link id under current bpf
namespace to user. The link->id is still the id in the init bpf
namespace.

The result as follows,

Run bpftool in a new bpf namespace,
$ bpftool map show
4: array  name kprobe_b.rodata  flags 0x80
        key 4B  value 37B  max_entries 1  memlock 360B
        btf_id 79  frozen
        pids kprobe(8322)
5: array  name kprobe_b.data  flags 0x400
        key 4B  value 4B  max_entries 1  memlock 8192B
        btf_id 79
        pids kprobe(8322)

$ bpftool prog show
7: kprobe  name kretprobe_run  tag 0de47cc241a2b1b3  gpl
        loaded_at 2023-03-21T13:54:34+0800  uid 0
        xlated 56B  jited 39B  memlock 4096B  map_ids 4
        btf_id 79
        pids kprobe(8322)
9: kprobe  name kprobe_run  tag bf163b23cd3b174d  gpl
        loaded_at 2023-03-21T13:54:34+0800  uid 0
        xlated 48B  jited 35B  memlock 4096B  map_ids 4
        btf_id 79
        pids kprobe(8322)

$ bpftool link show
1: perf_event  prog 9
        bpf_cookie 0
        pids kprobe(8322)
2: perf_event  prog 7
        bpf_cookie 0
        pids kprobe(8322)

At the same time, run bpftool in the init bpf namespace,
$ bpftool map show
8: array  name kprobe_b.rodata  flags 0x80
        key 4B  value 37B  max_entries 1  memlock 360B
        btf_id 79  frozen
        pids kprobe(8322)
9: array  name kprobe_b.data  flags 0x400
        key 4B  value 4B  max_entries 1  memlock 8192B
        btf_id 79
        pids kprobe(8322)

$ bpftool prog show
15: kprobe  name kretprobe_run  tag 0de47cc241a2b1b3  gpl
        loaded_at 2023-03-21T13:54:34+0800  uid 0
        xlated 56B  jited 39B  memlock 4096B  map_ids 8
        btf_id 79
        pids kprobe(8322)
17: kprobe  name kprobe_run  tag bf163b23cd3b174d  gpl
        loaded_at 2023-03-21T13:54:34+0800  uid 0
        xlated 48B  jited 35B  memlock 4096B  map_ids 8
        btf_id 79
        pids kprobe(8322)

$ bpftool link show
2: perf_event  prog 17
        bpf_cookie 0
        pids kprobe(8322)
3: perf_event  prog 15
        bpf_cookie 0
        pids kprobe(8322)

The bpftool running in the init bpf namespace can also show other bpf
links, but the bpftool in the new bpf namespace can only show the links
in its current bpf namespace.

Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
 include/linux/bpf.h                       |  2 ++
 kernel/bpf/bpf_namespace.c                |  1 +
 kernel/bpf/syscall.c                      | 55 +++++++++++--------------------
 tools/bpf/bpftool/skeleton/pid_iter.bpf.c |  3 +-
 4 files changed, 24 insertions(+), 37 deletions(-)
diff mbox series

Patch

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 16f2a01..efa14ac 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1468,6 +1468,7 @@  struct bpf_link {
 	const struct bpf_link_ops *ops;
 	struct bpf_prog *prog;
 	struct work_struct work;
+	struct bpf_obj_id *obj_id;
 };
 
 struct bpf_link_ops {
@@ -1506,6 +1507,7 @@  struct bpf_link_primer {
 	struct file *file;
 	int fd;
 	u32 id;
+	struct bpf_obj_id *obj_id;
 };
 
 struct bpf_struct_ops_value;
diff --git a/kernel/bpf/bpf_namespace.c b/kernel/bpf/bpf_namespace.c
index 8c70945..c7d62ef 100644
--- a/kernel/bpf/bpf_namespace.c
+++ b/kernel/bpf/bpf_namespace.c
@@ -13,6 +13,7 @@ 
 #define MAX_BPF_NS_LEVEL 32
 DEFINE_SPINLOCK(map_idr_lock);
 DEFINE_SPINLOCK(prog_idr_lock);
+DEFINE_SPINLOCK(link_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 4725924..855d5f7 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(link_idr);
-DEFINE_SPINLOCK(link_idr_lock);
 
 int sysctl_unprivileged_bpf_disabled __read_mostly =
 	IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
@@ -2670,17 +2668,11 @@  void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
 	atomic64_set(&link->refcnt, 1);
 	link->type = type;
 	link->id = 0;
+	link->obj_id = NULL;
 	link->ops = ops;
 	link->prog = prog;
 }
 
-static void bpf_link_free_id(int id)
-{
-	spin_lock_bh(&link_idr_lock);
-	idr_remove(&link_idr, id);
-	spin_unlock_bh(&link_idr_lock);
-}
-
 /* Clean up bpf_link and corresponding anon_inode file and FD. After
  * anon_inode is created, bpf_link can't be just kfree()'d due to deferred
  * anon_inode's release() call. This helper marksbpf_link as
@@ -2692,7 +2684,7 @@  void bpf_link_cleanup(struct bpf_link_primer *primer)
 {
 	primer->link->prog = NULL;
 	if (primer->id) {
-		bpf_link_free_id(primer->id);
+		bpf_free_obj_id(primer->obj_id, LINK_OBJ_ID);
 		primer->id = 0;
 	}
 	fput(primer->file);
@@ -2708,7 +2700,7 @@  void bpf_link_inc(struct bpf_link *link)
 static void bpf_link_free(struct bpf_link *link)
 {
 	if (link->id) {
-		bpf_link_free_id(link->id);
+		bpf_free_obj_id(link->obj_id, LINK_OBJ_ID);
 		link->id = 0;
 	}
 	if (link->prog) {
@@ -2774,7 +2766,7 @@  static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
 		   "link_type:\t%s\n"
 		   "link_id:\t%u\n",
 		   bpf_link_type_strs[link->type],
-		   link->id);
+		   bpf_obj_id_vnr(link->obj_id));
 	if (prog) {
 		bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
 		seq_printf(m,
@@ -2797,19 +2789,6 @@  static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
 	.write		= bpf_dummy_write,
 };
 
-static int bpf_link_alloc_id(struct bpf_link *link)
-{
-	int id;
-
-	idr_preload(GFP_KERNEL);
-	spin_lock_bh(&link_idr_lock);
-	id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC);
-	spin_unlock_bh(&link_idr_lock);
-	idr_preload_end();
-
-	return id;
-}
-
 /* Prepare bpf_link to be exposed to user-space by allocating anon_inode file,
  * reserving unused FD and allocating ID from link_idr. This is to be paired
  * with bpf_link_settle() to install FD and ID and expose bpf_link to
@@ -2825,23 +2804,23 @@  static int bpf_link_alloc_id(struct bpf_link *link)
  */
 int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer)
 {
+	struct bpf_obj_id *obj_id;
 	struct file *file;
-	int fd, id;
+	int fd;
 
 	fd = get_unused_fd_flags(O_CLOEXEC);
 	if (fd < 0)
 		return fd;
 
-
-	id = bpf_link_alloc_id(link);
-	if (id < 0) {
+	obj_id = bpf_alloc_obj_id(current->nsproxy->bpf_ns, link, LINK_OBJ_ID);
+	if (IS_ERR(obj_id)) {
 		put_unused_fd(fd);
-		return id;
+		return PTR_ERR(obj_id);
 	}
 
 	file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC);
 	if (IS_ERR(file)) {
-		bpf_link_free_id(id);
+		bpf_free_obj_id(obj_id, LINK_OBJ_ID);
 		put_unused_fd(fd);
 		return PTR_ERR(file);
 	}
@@ -2849,7 +2828,8 @@  int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer)
 	primer->link = link;
 	primer->file = file;
 	primer->fd = fd;
-	primer->id = id;
+	primer->id = bpf_obj_id_nr(obj_id);
+	primer->obj_id = obj_id;
 	return 0;
 }
 
@@ -2858,6 +2838,7 @@  int bpf_link_settle(struct bpf_link_primer *primer)
 	/* make bpf_link fetchable by ID */
 	spin_lock_bh(&link_idr_lock);
 	primer->link->id = primer->id;
+	primer->link->obj_id = primer->obj_id;
 	spin_unlock_bh(&link_idr_lock);
 	/* make bpf_link fetchable by FD */
 	fd_install(primer->fd, primer->file);
@@ -4265,7 +4246,7 @@  static int bpf_link_get_info_by_fd(struct file *file,
 		return -EFAULT;
 
 	info.type = link->type;
-	info.id = link->id;
+	info.id = bpf_obj_id_vnr(link->obj_id);
 	if (link->prog)
 		info.prog_id = bpf_obj_id_vnr(link->prog->aux->obj_id);
 
@@ -4748,6 +4729,7 @@  static struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link)
 
 struct bpf_link *bpf_link_by_id(u32 id)
 {
+	struct bpf_namespace *ns = current->nsproxy->bpf_ns;
 	struct bpf_link *link;
 
 	if (!id)
@@ -4755,7 +4737,7 @@  struct bpf_link *bpf_link_by_id(u32 id)
 
 	spin_lock_bh(&link_idr_lock);
 	/* before link is "settled", ID is 0, pretend it doesn't exist yet */
-	link = idr_find(&link_idr, id);
+	link = idr_find(&ns->idr[LINK_OBJ_ID], id);
 	if (link) {
 		if (link->id)
 			link = bpf_link_inc_not_zero(link);
@@ -4770,11 +4752,12 @@  struct bpf_link *bpf_link_by_id(u32 id)
 
 struct bpf_link *bpf_link_get_curr_or_next(u32 *id)
 {
+	struct bpf_namespace *ns = current->nsproxy->bpf_ns;
 	struct bpf_link *link;
 
 	spin_lock_bh(&link_idr_lock);
 again:
-	link = idr_get_next(&link_idr, id);
+	link = idr_get_next(&ns->idr[LINK_OBJ_ID], id);
 	if (link) {
 		link = bpf_link_inc_not_zero(link);
 		if (IS_ERR(link)) {
@@ -5086,7 +5069,7 @@  static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
 		break;
 	case BPF_LINK_GET_NEXT_ID:
 		err = bpf_obj_get_next_id(&attr, uattr.user,
-					  &link_idr, &link_idr_lock);
+					  &ns->idr[LINK_OBJ_ID], &link_idr_lock);
 		break;
 	case BPF_ENABLE_STATS:
 		err = bpf_enable_stats(&attr);
diff --git a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c
index 1fd8ceb..e2237ad 100644
--- a/tools/bpf/bpftool/skeleton/pid_iter.bpf.c
+++ b/tools/bpf/bpftool/skeleton/pid_iter.bpf.c
@@ -36,7 +36,8 @@  static __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type)
 	case BPF_OBJ_BTF:
 		return BPF_CORE_READ((struct btf *)ent, id);
 	case BPF_OBJ_LINK:
-		return BPF_CORE_READ((struct bpf_link *)ent, id);
+		obj_id = BPF_CORE_READ((struct bpf_link *)ent, obj_id);
+		break;
 	default:
 		return 0;
 	}