xref: /linux/tools/testing/selftests/bpf/prog_tests/token.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1fcb9597fSAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0
2fcb9597fSAndrii Nakryiko /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3fcb9597fSAndrii Nakryiko #define _GNU_SOURCE
4fcb9597fSAndrii Nakryiko #include <test_progs.h>
5fcb9597fSAndrii Nakryiko #include <bpf/btf.h>
6fcb9597fSAndrii Nakryiko #include "cap_helpers.h"
7fcb9597fSAndrii Nakryiko #include <fcntl.h>
8fcb9597fSAndrii Nakryiko #include <sched.h>
9fcb9597fSAndrii Nakryiko #include <signal.h>
10fcb9597fSAndrii Nakryiko #include <unistd.h>
11fcb9597fSAndrii Nakryiko #include <linux/filter.h>
12fcb9597fSAndrii Nakryiko #include <linux/unistd.h>
13fcb9597fSAndrii Nakryiko #include <linux/mount.h>
14fcb9597fSAndrii Nakryiko #include <sys/socket.h>
15b73d08d1SAndrii Nakryiko #include <sys/stat.h>
16fcb9597fSAndrii Nakryiko #include <sys/syscall.h>
17fcb9597fSAndrii Nakryiko #include <sys/un.h>
18d5baf0caSAndrii Nakryiko #include "priv_map.skel.h"
19d5baf0caSAndrii Nakryiko #include "priv_prog.skel.h"
20d5baf0caSAndrii Nakryiko #include "dummy_st_ops_success.skel.h"
21*906ee42cSAndrii Nakryiko #include "token_lsm.skel.h"
22fcb9597fSAndrii Nakryiko 
sys_mount(const char * dev_name,const char * dir_name,const char * type,unsigned long flags,const void * data)23fcb9597fSAndrii Nakryiko static inline int sys_mount(const char *dev_name, const char *dir_name,
24fcb9597fSAndrii Nakryiko 			    const char *type, unsigned long flags,
25fcb9597fSAndrii Nakryiko 			    const void *data)
26fcb9597fSAndrii Nakryiko {
27fcb9597fSAndrii Nakryiko 	return syscall(__NR_mount, dev_name, dir_name, type, flags, data);
28fcb9597fSAndrii Nakryiko }
29fcb9597fSAndrii Nakryiko 
sys_fsopen(const char * fsname,unsigned flags)30fcb9597fSAndrii Nakryiko static inline int sys_fsopen(const char *fsname, unsigned flags)
31fcb9597fSAndrii Nakryiko {
32fcb9597fSAndrii Nakryiko 	return syscall(__NR_fsopen, fsname, flags);
33fcb9597fSAndrii Nakryiko }
34fcb9597fSAndrii Nakryiko 
sys_fspick(int dfd,const char * path,unsigned flags)35fcb9597fSAndrii Nakryiko static inline int sys_fspick(int dfd, const char *path, unsigned flags)
36fcb9597fSAndrii Nakryiko {
37fcb9597fSAndrii Nakryiko 	return syscall(__NR_fspick, dfd, path, flags);
38fcb9597fSAndrii Nakryiko }
39fcb9597fSAndrii Nakryiko 
sys_fsconfig(int fs_fd,unsigned cmd,const char * key,const void * val,int aux)40fcb9597fSAndrii Nakryiko static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key, const void *val, int aux)
41fcb9597fSAndrii Nakryiko {
42fcb9597fSAndrii Nakryiko 	return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux);
43fcb9597fSAndrii Nakryiko }
44fcb9597fSAndrii Nakryiko 
sys_fsmount(int fs_fd,unsigned flags,unsigned ms_flags)45fcb9597fSAndrii Nakryiko static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags)
46fcb9597fSAndrii Nakryiko {
47fcb9597fSAndrii Nakryiko 	return syscall(__NR_fsmount, fs_fd, flags, ms_flags);
48fcb9597fSAndrii Nakryiko }
49fcb9597fSAndrii Nakryiko 
sys_move_mount(int from_dfd,const char * from_path,int to_dfd,const char * to_path,unsigned flags)50b73d08d1SAndrii Nakryiko static inline int sys_move_mount(int from_dfd, const char *from_path,
51b73d08d1SAndrii Nakryiko 				 int to_dfd, const char *to_path,
52b73d08d1SAndrii Nakryiko 				 unsigned flags)
53b73d08d1SAndrii Nakryiko {
54b73d08d1SAndrii Nakryiko 	return syscall(__NR_move_mount, from_dfd, from_path, to_dfd, to_path, flags);
55b73d08d1SAndrii Nakryiko }
56b73d08d1SAndrii Nakryiko 
drop_priv_caps(__u64 * old_caps)57fcb9597fSAndrii Nakryiko static int drop_priv_caps(__u64 *old_caps)
58fcb9597fSAndrii Nakryiko {
59fcb9597fSAndrii Nakryiko 	return cap_disable_effective((1ULL << CAP_BPF) |
60fcb9597fSAndrii Nakryiko 				     (1ULL << CAP_PERFMON) |
61fcb9597fSAndrii Nakryiko 				     (1ULL << CAP_NET_ADMIN) |
62fcb9597fSAndrii Nakryiko 				     (1ULL << CAP_SYS_ADMIN), old_caps);
63fcb9597fSAndrii Nakryiko }
64fcb9597fSAndrii Nakryiko 
restore_priv_caps(__u64 old_caps)65fcb9597fSAndrii Nakryiko static int restore_priv_caps(__u64 old_caps)
66fcb9597fSAndrii Nakryiko {
67fcb9597fSAndrii Nakryiko 	return cap_enable_effective(old_caps, NULL);
68fcb9597fSAndrii Nakryiko }
69fcb9597fSAndrii Nakryiko 
set_delegate_mask(int fs_fd,const char * key,__u64 mask,const char * mask_str)700350f9d9SAndrii Nakryiko static int set_delegate_mask(int fs_fd, const char *key, __u64 mask, const char *mask_str)
71fcb9597fSAndrii Nakryiko {
72fcb9597fSAndrii Nakryiko 	char buf[32];
73fcb9597fSAndrii Nakryiko 	int err;
74fcb9597fSAndrii Nakryiko 
750350f9d9SAndrii Nakryiko 	if (!mask_str) {
760350f9d9SAndrii Nakryiko 		if (mask == ~0ULL) {
770350f9d9SAndrii Nakryiko 			mask_str = "any";
780350f9d9SAndrii Nakryiko 		} else {
79fcb9597fSAndrii Nakryiko 			snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask);
800350f9d9SAndrii Nakryiko 			mask_str = buf;
810350f9d9SAndrii Nakryiko 		}
820350f9d9SAndrii Nakryiko 	}
830350f9d9SAndrii Nakryiko 
84fcb9597fSAndrii Nakryiko 	err = sys_fsconfig(fs_fd, FSCONFIG_SET_STRING, key,
850350f9d9SAndrii Nakryiko 			   mask_str, 0);
86fcb9597fSAndrii Nakryiko 	if (err < 0)
87fcb9597fSAndrii Nakryiko 		err = -errno;
88fcb9597fSAndrii Nakryiko 	return err;
89fcb9597fSAndrii Nakryiko }
90fcb9597fSAndrii Nakryiko 
91fcb9597fSAndrii Nakryiko #define zclose(fd) do { if (fd >= 0) close(fd); fd = -1; } while (0)
92fcb9597fSAndrii Nakryiko 
93fcb9597fSAndrii Nakryiko struct bpffs_opts {
94fcb9597fSAndrii Nakryiko 	__u64 cmds;
95fcb9597fSAndrii Nakryiko 	__u64 maps;
96fcb9597fSAndrii Nakryiko 	__u64 progs;
97fcb9597fSAndrii Nakryiko 	__u64 attachs;
980350f9d9SAndrii Nakryiko 	const char *cmds_str;
990350f9d9SAndrii Nakryiko 	const char *maps_str;
1000350f9d9SAndrii Nakryiko 	const char *progs_str;
1010350f9d9SAndrii Nakryiko 	const char *attachs_str;
102fcb9597fSAndrii Nakryiko };
103fcb9597fSAndrii Nakryiko 
create_bpffs_fd(void)104fcb9597fSAndrii Nakryiko static int create_bpffs_fd(void)
105fcb9597fSAndrii Nakryiko {
106fcb9597fSAndrii Nakryiko 	int fs_fd;
107fcb9597fSAndrii Nakryiko 
108fcb9597fSAndrii Nakryiko 	/* create VFS context */
109fcb9597fSAndrii Nakryiko 	fs_fd = sys_fsopen("bpf", 0);
110fcb9597fSAndrii Nakryiko 	ASSERT_GE(fs_fd, 0, "fs_fd");
111fcb9597fSAndrii Nakryiko 
112fcb9597fSAndrii Nakryiko 	return fs_fd;
113fcb9597fSAndrii Nakryiko }
114fcb9597fSAndrii Nakryiko 
materialize_bpffs_fd(int fs_fd,struct bpffs_opts * opts)115fcb9597fSAndrii Nakryiko static int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts)
116fcb9597fSAndrii Nakryiko {
117fcb9597fSAndrii Nakryiko 	int mnt_fd, err;
118fcb9597fSAndrii Nakryiko 
119fcb9597fSAndrii Nakryiko 	/* set up token delegation mount options */
1200350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds, opts->cmds_str);
121fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "fs_cfg_cmds"))
122fcb9597fSAndrii Nakryiko 		return err;
1230350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps, opts->maps_str);
124fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "fs_cfg_maps"))
125fcb9597fSAndrii Nakryiko 		return err;
1260350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs, opts->progs_str);
127fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "fs_cfg_progs"))
128fcb9597fSAndrii Nakryiko 		return err;
1290350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs, opts->attachs_str);
130fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "fs_cfg_attachs"))
131fcb9597fSAndrii Nakryiko 		return err;
132fcb9597fSAndrii Nakryiko 
133fcb9597fSAndrii Nakryiko 	/* instantiate FS object */
134fcb9597fSAndrii Nakryiko 	err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
135fcb9597fSAndrii Nakryiko 	if (err < 0)
136fcb9597fSAndrii Nakryiko 		return -errno;
137fcb9597fSAndrii Nakryiko 
138fcb9597fSAndrii Nakryiko 	/* create O_PATH fd for detached mount */
139fcb9597fSAndrii Nakryiko 	mnt_fd = sys_fsmount(fs_fd, 0, 0);
140fcb9597fSAndrii Nakryiko 	if (err < 0)
141fcb9597fSAndrii Nakryiko 		return -errno;
142fcb9597fSAndrii Nakryiko 
143fcb9597fSAndrii Nakryiko 	return mnt_fd;
144fcb9597fSAndrii Nakryiko }
145fcb9597fSAndrii Nakryiko 
146fcb9597fSAndrii Nakryiko /* send FD over Unix domain (AF_UNIX) socket */
sendfd(int sockfd,int fd)147fcb9597fSAndrii Nakryiko static int sendfd(int sockfd, int fd)
148fcb9597fSAndrii Nakryiko {
149fcb9597fSAndrii Nakryiko 	struct msghdr msg = {};
150fcb9597fSAndrii Nakryiko 	struct cmsghdr *cmsg;
151fcb9597fSAndrii Nakryiko 	int fds[1] = { fd }, err;
152fcb9597fSAndrii Nakryiko 	char iobuf[1];
153fcb9597fSAndrii Nakryiko 	struct iovec io = {
154fcb9597fSAndrii Nakryiko 		.iov_base = iobuf,
155fcb9597fSAndrii Nakryiko 		.iov_len = sizeof(iobuf),
156fcb9597fSAndrii Nakryiko 	};
157fcb9597fSAndrii Nakryiko 	union {
158fcb9597fSAndrii Nakryiko 		char buf[CMSG_SPACE(sizeof(fds))];
159fcb9597fSAndrii Nakryiko 		struct cmsghdr align;
160fcb9597fSAndrii Nakryiko 	} u;
161fcb9597fSAndrii Nakryiko 
162fcb9597fSAndrii Nakryiko 	msg.msg_iov = &io;
163fcb9597fSAndrii Nakryiko 	msg.msg_iovlen = 1;
164fcb9597fSAndrii Nakryiko 	msg.msg_control = u.buf;
165fcb9597fSAndrii Nakryiko 	msg.msg_controllen = sizeof(u.buf);
166fcb9597fSAndrii Nakryiko 	cmsg = CMSG_FIRSTHDR(&msg);
167fcb9597fSAndrii Nakryiko 	cmsg->cmsg_level = SOL_SOCKET;
168fcb9597fSAndrii Nakryiko 	cmsg->cmsg_type = SCM_RIGHTS;
169fcb9597fSAndrii Nakryiko 	cmsg->cmsg_len = CMSG_LEN(sizeof(fds));
170fcb9597fSAndrii Nakryiko 	memcpy(CMSG_DATA(cmsg), fds, sizeof(fds));
171fcb9597fSAndrii Nakryiko 
172fcb9597fSAndrii Nakryiko 	err = sendmsg(sockfd, &msg, 0);
173fcb9597fSAndrii Nakryiko 	if (err < 0)
174fcb9597fSAndrii Nakryiko 		err = -errno;
175fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(err, 1, "sendmsg"))
176fcb9597fSAndrii Nakryiko 		return -EINVAL;
177fcb9597fSAndrii Nakryiko 
178fcb9597fSAndrii Nakryiko 	return 0;
179fcb9597fSAndrii Nakryiko }
180fcb9597fSAndrii Nakryiko 
181fcb9597fSAndrii Nakryiko /* receive FD over Unix domain (AF_UNIX) socket */
recvfd(int sockfd,int * fd)182fcb9597fSAndrii Nakryiko static int recvfd(int sockfd, int *fd)
183fcb9597fSAndrii Nakryiko {
184fcb9597fSAndrii Nakryiko 	struct msghdr msg = {};
185fcb9597fSAndrii Nakryiko 	struct cmsghdr *cmsg;
186fcb9597fSAndrii Nakryiko 	int fds[1], err;
187fcb9597fSAndrii Nakryiko 	char iobuf[1];
188fcb9597fSAndrii Nakryiko 	struct iovec io = {
189fcb9597fSAndrii Nakryiko 		.iov_base = iobuf,
190fcb9597fSAndrii Nakryiko 		.iov_len = sizeof(iobuf),
191fcb9597fSAndrii Nakryiko 	};
192fcb9597fSAndrii Nakryiko 	union {
193fcb9597fSAndrii Nakryiko 		char buf[CMSG_SPACE(sizeof(fds))];
194fcb9597fSAndrii Nakryiko 		struct cmsghdr align;
195fcb9597fSAndrii Nakryiko 	} u;
196fcb9597fSAndrii Nakryiko 
197fcb9597fSAndrii Nakryiko 	msg.msg_iov = &io;
198fcb9597fSAndrii Nakryiko 	msg.msg_iovlen = 1;
199fcb9597fSAndrii Nakryiko 	msg.msg_control = u.buf;
200fcb9597fSAndrii Nakryiko 	msg.msg_controllen = sizeof(u.buf);
201fcb9597fSAndrii Nakryiko 
202fcb9597fSAndrii Nakryiko 	err = recvmsg(sockfd, &msg, 0);
203fcb9597fSAndrii Nakryiko 	if (err < 0)
204fcb9597fSAndrii Nakryiko 		err = -errno;
205fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(err, 1, "recvmsg"))
206fcb9597fSAndrii Nakryiko 		return -EINVAL;
207fcb9597fSAndrii Nakryiko 
208fcb9597fSAndrii Nakryiko 	cmsg = CMSG_FIRSTHDR(&msg);
209fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK_PTR(cmsg, "cmsg_null") ||
210fcb9597fSAndrii Nakryiko 	    !ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(fds)), "cmsg_len") ||
211fcb9597fSAndrii Nakryiko 	    !ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET, "cmsg_level") ||
212fcb9597fSAndrii Nakryiko 	    !ASSERT_EQ(cmsg->cmsg_type, SCM_RIGHTS, "cmsg_type"))
213fcb9597fSAndrii Nakryiko 		return -EINVAL;
214fcb9597fSAndrii Nakryiko 
215fcb9597fSAndrii Nakryiko 	memcpy(fds, CMSG_DATA(cmsg), sizeof(fds));
216fcb9597fSAndrii Nakryiko 	*fd = fds[0];
217fcb9597fSAndrii Nakryiko 
218fcb9597fSAndrii Nakryiko 	return 0;
219fcb9597fSAndrii Nakryiko }
220fcb9597fSAndrii Nakryiko 
write_nointr(int fd,const void * buf,size_t count)221fcb9597fSAndrii Nakryiko static ssize_t write_nointr(int fd, const void *buf, size_t count)
222fcb9597fSAndrii Nakryiko {
223fcb9597fSAndrii Nakryiko 	ssize_t ret;
224fcb9597fSAndrii Nakryiko 
225fcb9597fSAndrii Nakryiko 	do {
226fcb9597fSAndrii Nakryiko 		ret = write(fd, buf, count);
227fcb9597fSAndrii Nakryiko 	} while (ret < 0 && errno == EINTR);
228fcb9597fSAndrii Nakryiko 
229fcb9597fSAndrii Nakryiko 	return ret;
230fcb9597fSAndrii Nakryiko }
231fcb9597fSAndrii Nakryiko 
write_file(const char * path,const void * buf,size_t count)232fcb9597fSAndrii Nakryiko static int write_file(const char *path, const void *buf, size_t count)
233fcb9597fSAndrii Nakryiko {
234fcb9597fSAndrii Nakryiko 	int fd;
235fcb9597fSAndrii Nakryiko 	ssize_t ret;
236fcb9597fSAndrii Nakryiko 
237fcb9597fSAndrii Nakryiko 	fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
238fcb9597fSAndrii Nakryiko 	if (fd < 0)
239fcb9597fSAndrii Nakryiko 		return -1;
240fcb9597fSAndrii Nakryiko 
241fcb9597fSAndrii Nakryiko 	ret = write_nointr(fd, buf, count);
242fcb9597fSAndrii Nakryiko 	close(fd);
243fcb9597fSAndrii Nakryiko 	if (ret < 0 || (size_t)ret != count)
244fcb9597fSAndrii Nakryiko 		return -1;
245fcb9597fSAndrii Nakryiko 
246fcb9597fSAndrii Nakryiko 	return 0;
247fcb9597fSAndrii Nakryiko }
248fcb9597fSAndrii Nakryiko 
create_and_enter_userns(void)249fcb9597fSAndrii Nakryiko static int create_and_enter_userns(void)
250fcb9597fSAndrii Nakryiko {
251fcb9597fSAndrii Nakryiko 	uid_t uid;
252fcb9597fSAndrii Nakryiko 	gid_t gid;
253fcb9597fSAndrii Nakryiko 	char map[100];
254fcb9597fSAndrii Nakryiko 
255fcb9597fSAndrii Nakryiko 	uid = getuid();
256fcb9597fSAndrii Nakryiko 	gid = getgid();
257fcb9597fSAndrii Nakryiko 
258fcb9597fSAndrii Nakryiko 	if (unshare(CLONE_NEWUSER))
259fcb9597fSAndrii Nakryiko 		return -1;
260fcb9597fSAndrii Nakryiko 
261fcb9597fSAndrii Nakryiko 	if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) &&
262fcb9597fSAndrii Nakryiko 	    errno != ENOENT)
263fcb9597fSAndrii Nakryiko 		return -1;
264fcb9597fSAndrii Nakryiko 
265fcb9597fSAndrii Nakryiko 	snprintf(map, sizeof(map), "0 %d 1", uid);
266fcb9597fSAndrii Nakryiko 	if (write_file("/proc/self/uid_map", map, strlen(map)))
267fcb9597fSAndrii Nakryiko 		return -1;
268fcb9597fSAndrii Nakryiko 
269fcb9597fSAndrii Nakryiko 
270fcb9597fSAndrii Nakryiko 	snprintf(map, sizeof(map), "0 %d 1", gid);
271fcb9597fSAndrii Nakryiko 	if (write_file("/proc/self/gid_map", map, strlen(map)))
272fcb9597fSAndrii Nakryiko 		return -1;
273fcb9597fSAndrii Nakryiko 
274fcb9597fSAndrii Nakryiko 	if (setgid(0))
275fcb9597fSAndrii Nakryiko 		return -1;
276fcb9597fSAndrii Nakryiko 
277fcb9597fSAndrii Nakryiko 	if (setuid(0))
278fcb9597fSAndrii Nakryiko 		return -1;
279fcb9597fSAndrii Nakryiko 
280fcb9597fSAndrii Nakryiko 	return 0;
281fcb9597fSAndrii Nakryiko }
282fcb9597fSAndrii Nakryiko 
283*906ee42cSAndrii Nakryiko typedef int (*child_callback_fn)(int bpffs_fd, struct token_lsm *lsm_skel);
284fcb9597fSAndrii Nakryiko 
child(int sock_fd,struct bpffs_opts * opts,child_callback_fn callback)285fcb9597fSAndrii Nakryiko static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callback)
286fcb9597fSAndrii Nakryiko {
287*906ee42cSAndrii Nakryiko 	int mnt_fd = -1, fs_fd = -1, err = 0, bpffs_fd = -1, token_fd = -1;
288*906ee42cSAndrii Nakryiko 	struct token_lsm *lsm_skel = NULL;
289*906ee42cSAndrii Nakryiko 
290*906ee42cSAndrii Nakryiko 	/* load and attach LSM "policy" before we go into unpriv userns */
291*906ee42cSAndrii Nakryiko 	lsm_skel = token_lsm__open_and_load();
292*906ee42cSAndrii Nakryiko 	if (!ASSERT_OK_PTR(lsm_skel, "lsm_skel_load")) {
293*906ee42cSAndrii Nakryiko 		err = -EINVAL;
294*906ee42cSAndrii Nakryiko 		goto cleanup;
295*906ee42cSAndrii Nakryiko 	}
296*906ee42cSAndrii Nakryiko 	lsm_skel->bss->my_pid = getpid();
297*906ee42cSAndrii Nakryiko 	err = token_lsm__attach(lsm_skel);
298*906ee42cSAndrii Nakryiko 	if (!ASSERT_OK(err, "lsm_skel_attach"))
299*906ee42cSAndrii Nakryiko 		goto cleanup;
300fcb9597fSAndrii Nakryiko 
301fcb9597fSAndrii Nakryiko 	/* setup userns with root mappings */
302fcb9597fSAndrii Nakryiko 	err = create_and_enter_userns();
303fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "create_and_enter_userns"))
304fcb9597fSAndrii Nakryiko 		goto cleanup;
305fcb9597fSAndrii Nakryiko 
306fcb9597fSAndrii Nakryiko 	/* setup mountns to allow creating BPF FS (fsopen("bpf")) from unpriv process */
307fcb9597fSAndrii Nakryiko 	err = unshare(CLONE_NEWNS);
308fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "create_mountns"))
309fcb9597fSAndrii Nakryiko 		goto cleanup;
310fcb9597fSAndrii Nakryiko 
311fcb9597fSAndrii Nakryiko 	err = sys_mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
312fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "remount_root"))
313fcb9597fSAndrii Nakryiko 		goto cleanup;
314fcb9597fSAndrii Nakryiko 
315fcb9597fSAndrii Nakryiko 	fs_fd = create_bpffs_fd();
316fcb9597fSAndrii Nakryiko 	if (!ASSERT_GE(fs_fd, 0, "create_bpffs_fd")) {
317fcb9597fSAndrii Nakryiko 		err = -EINVAL;
318fcb9597fSAndrii Nakryiko 		goto cleanup;
319fcb9597fSAndrii Nakryiko 	}
320fcb9597fSAndrii Nakryiko 
321fcb9597fSAndrii Nakryiko 	/* ensure unprivileged child cannot set delegation options */
3220350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_cmds", 0x1, NULL);
323fcb9597fSAndrii Nakryiko 	ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm");
3240350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_maps", 0x1, NULL);
325fcb9597fSAndrii Nakryiko 	ASSERT_EQ(err, -EPERM, "delegate_maps_eperm");
3260350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_progs", 0x1, NULL);
327fcb9597fSAndrii Nakryiko 	ASSERT_EQ(err, -EPERM, "delegate_progs_eperm");
3280350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_attachs", 0x1, NULL);
329fcb9597fSAndrii Nakryiko 	ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm");
330fcb9597fSAndrii Nakryiko 
331fcb9597fSAndrii Nakryiko 	/* pass BPF FS context object to parent */
332fcb9597fSAndrii Nakryiko 	err = sendfd(sock_fd, fs_fd);
333fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "send_fs_fd"))
334fcb9597fSAndrii Nakryiko 		goto cleanup;
335fcb9597fSAndrii Nakryiko 	zclose(fs_fd);
336fcb9597fSAndrii Nakryiko 
337fcb9597fSAndrii Nakryiko 	/* avoid mucking around with mount namespaces and mounting at
338fcb9597fSAndrii Nakryiko 	 * well-known path, just get detach-mounted BPF FS fd back from parent
339fcb9597fSAndrii Nakryiko 	 */
340fcb9597fSAndrii Nakryiko 	err = recvfd(sock_fd, &mnt_fd);
341fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "recv_mnt_fd"))
342fcb9597fSAndrii Nakryiko 		goto cleanup;
343fcb9597fSAndrii Nakryiko 
344fcb9597fSAndrii Nakryiko 	/* try to fspick() BPF FS and try to add some delegation options */
345fcb9597fSAndrii Nakryiko 	fs_fd = sys_fspick(mnt_fd, "", FSPICK_EMPTY_PATH);
346fcb9597fSAndrii Nakryiko 	if (!ASSERT_GE(fs_fd, 0, "bpffs_fspick")) {
347fcb9597fSAndrii Nakryiko 		err = -EINVAL;
348fcb9597fSAndrii Nakryiko 		goto cleanup;
349fcb9597fSAndrii Nakryiko 	}
350fcb9597fSAndrii Nakryiko 
351fcb9597fSAndrii Nakryiko 	/* ensure unprivileged child cannot reconfigure to set delegation options */
3520350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_cmds", 0, "any");
353fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm_reconfig")) {
354fcb9597fSAndrii Nakryiko 		err = -EINVAL;
355fcb9597fSAndrii Nakryiko 		goto cleanup;
356fcb9597fSAndrii Nakryiko 	}
3570350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_maps", 0, "any");
358fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(err, -EPERM, "delegate_maps_eperm_reconfig")) {
359fcb9597fSAndrii Nakryiko 		err = -EINVAL;
360fcb9597fSAndrii Nakryiko 		goto cleanup;
361fcb9597fSAndrii Nakryiko 	}
3620350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_progs", 0, "any");
363fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(err, -EPERM, "delegate_progs_eperm_reconfig")) {
364fcb9597fSAndrii Nakryiko 		err = -EINVAL;
365fcb9597fSAndrii Nakryiko 		goto cleanup;
366fcb9597fSAndrii Nakryiko 	}
3670350f9d9SAndrii Nakryiko 	err = set_delegate_mask(fs_fd, "delegate_attachs", 0, "any");
368fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm_reconfig")) {
369fcb9597fSAndrii Nakryiko 		err = -EINVAL;
370fcb9597fSAndrii Nakryiko 		goto cleanup;
371fcb9597fSAndrii Nakryiko 	}
372fcb9597fSAndrii Nakryiko 	zclose(fs_fd);
373fcb9597fSAndrii Nakryiko 
374fcb9597fSAndrii Nakryiko 	bpffs_fd = openat(mnt_fd, ".", 0, O_RDWR);
375fcb9597fSAndrii Nakryiko 	if (!ASSERT_GE(bpffs_fd, 0, "bpffs_open")) {
376fcb9597fSAndrii Nakryiko 		err = -EINVAL;
377fcb9597fSAndrii Nakryiko 		goto cleanup;
378fcb9597fSAndrii Nakryiko 	}
379fcb9597fSAndrii Nakryiko 
380*906ee42cSAndrii Nakryiko 	/* create BPF token FD and pass it to parent for some extra checks */
381*906ee42cSAndrii Nakryiko 	token_fd = bpf_token_create(bpffs_fd, NULL);
382*906ee42cSAndrii Nakryiko 	if (!ASSERT_GT(token_fd, 0, "child_token_create")) {
383*906ee42cSAndrii Nakryiko 		err = -EINVAL;
384*906ee42cSAndrii Nakryiko 		goto cleanup;
385*906ee42cSAndrii Nakryiko 	}
386*906ee42cSAndrii Nakryiko 	err = sendfd(sock_fd, token_fd);
387*906ee42cSAndrii Nakryiko 	if (!ASSERT_OK(err, "send_token_fd"))
388*906ee42cSAndrii Nakryiko 		goto cleanup;
389*906ee42cSAndrii Nakryiko 	zclose(token_fd);
390*906ee42cSAndrii Nakryiko 
391fcb9597fSAndrii Nakryiko 	/* do custom test logic with customly set up BPF FS instance */
392*906ee42cSAndrii Nakryiko 	err = callback(bpffs_fd, lsm_skel);
393fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "test_callback"))
394fcb9597fSAndrii Nakryiko 		goto cleanup;
395fcb9597fSAndrii Nakryiko 
396fcb9597fSAndrii Nakryiko 	err = 0;
397fcb9597fSAndrii Nakryiko cleanup:
398fcb9597fSAndrii Nakryiko 	zclose(sock_fd);
399fcb9597fSAndrii Nakryiko 	zclose(mnt_fd);
400fcb9597fSAndrii Nakryiko 	zclose(fs_fd);
401fcb9597fSAndrii Nakryiko 	zclose(bpffs_fd);
402*906ee42cSAndrii Nakryiko 	zclose(token_fd);
403*906ee42cSAndrii Nakryiko 
404*906ee42cSAndrii Nakryiko 	lsm_skel->bss->my_pid = 0;
405*906ee42cSAndrii Nakryiko 	token_lsm__destroy(lsm_skel);
406fcb9597fSAndrii Nakryiko 
407fcb9597fSAndrii Nakryiko 	exit(-err);
408fcb9597fSAndrii Nakryiko }
409fcb9597fSAndrii Nakryiko 
wait_for_pid(pid_t pid)410fcb9597fSAndrii Nakryiko static int wait_for_pid(pid_t pid)
411fcb9597fSAndrii Nakryiko {
412fcb9597fSAndrii Nakryiko 	int status, ret;
413fcb9597fSAndrii Nakryiko 
414fcb9597fSAndrii Nakryiko again:
415fcb9597fSAndrii Nakryiko 	ret = waitpid(pid, &status, 0);
416fcb9597fSAndrii Nakryiko 	if (ret == -1) {
417fcb9597fSAndrii Nakryiko 		if (errno == EINTR)
418fcb9597fSAndrii Nakryiko 			goto again;
419fcb9597fSAndrii Nakryiko 
420fcb9597fSAndrii Nakryiko 		return -1;
421fcb9597fSAndrii Nakryiko 	}
422fcb9597fSAndrii Nakryiko 
423fcb9597fSAndrii Nakryiko 	if (!WIFEXITED(status))
424fcb9597fSAndrii Nakryiko 		return -1;
425fcb9597fSAndrii Nakryiko 
426fcb9597fSAndrii Nakryiko 	return WEXITSTATUS(status);
427fcb9597fSAndrii Nakryiko }
428fcb9597fSAndrii Nakryiko 
parent(int child_pid,struct bpffs_opts * bpffs_opts,int sock_fd)429fcb9597fSAndrii Nakryiko static void parent(int child_pid, struct bpffs_opts *bpffs_opts, int sock_fd)
430fcb9597fSAndrii Nakryiko {
431*906ee42cSAndrii Nakryiko 	int fs_fd = -1, mnt_fd = -1, token_fd = -1, err;
432fcb9597fSAndrii Nakryiko 
433fcb9597fSAndrii Nakryiko 	err = recvfd(sock_fd, &fs_fd);
434fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "recv_bpffs_fd"))
435fcb9597fSAndrii Nakryiko 		goto cleanup;
436fcb9597fSAndrii Nakryiko 
437fcb9597fSAndrii Nakryiko 	mnt_fd = materialize_bpffs_fd(fs_fd, bpffs_opts);
438fcb9597fSAndrii Nakryiko 	if (!ASSERT_GE(mnt_fd, 0, "materialize_bpffs_fd")) {
439fcb9597fSAndrii Nakryiko 		err = -EINVAL;
440fcb9597fSAndrii Nakryiko 		goto cleanup;
441fcb9597fSAndrii Nakryiko 	}
442fcb9597fSAndrii Nakryiko 	zclose(fs_fd);
443fcb9597fSAndrii Nakryiko 
444fcb9597fSAndrii Nakryiko 	/* pass BPF FS context object to parent */
445fcb9597fSAndrii Nakryiko 	err = sendfd(sock_fd, mnt_fd);
446fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "send_mnt_fd"))
447fcb9597fSAndrii Nakryiko 		goto cleanup;
448fcb9597fSAndrii Nakryiko 	zclose(mnt_fd);
449fcb9597fSAndrii Nakryiko 
450*906ee42cSAndrii Nakryiko 	/* receive BPF token FD back from child for some extra tests */
451*906ee42cSAndrii Nakryiko 	err = recvfd(sock_fd, &token_fd);
452*906ee42cSAndrii Nakryiko 	if (!ASSERT_OK(err, "recv_token_fd"))
453*906ee42cSAndrii Nakryiko 		goto cleanup;
454*906ee42cSAndrii Nakryiko 
455fcb9597fSAndrii Nakryiko 	err = wait_for_pid(child_pid);
456fcb9597fSAndrii Nakryiko 	ASSERT_OK(err, "waitpid_child");
457fcb9597fSAndrii Nakryiko 
458fcb9597fSAndrii Nakryiko cleanup:
459fcb9597fSAndrii Nakryiko 	zclose(sock_fd);
460fcb9597fSAndrii Nakryiko 	zclose(fs_fd);
461fcb9597fSAndrii Nakryiko 	zclose(mnt_fd);
462*906ee42cSAndrii Nakryiko 	zclose(token_fd);
463fcb9597fSAndrii Nakryiko 
464fcb9597fSAndrii Nakryiko 	if (child_pid > 0)
465fcb9597fSAndrii Nakryiko 		(void)kill(child_pid, SIGKILL);
466fcb9597fSAndrii Nakryiko }
467fcb9597fSAndrii Nakryiko 
subtest_userns(struct bpffs_opts * bpffs_opts,child_callback_fn child_cb)468*906ee42cSAndrii Nakryiko static void subtest_userns(struct bpffs_opts *bpffs_opts,
469*906ee42cSAndrii Nakryiko 			   child_callback_fn child_cb)
470fcb9597fSAndrii Nakryiko {
471fcb9597fSAndrii Nakryiko 	int sock_fds[2] = { -1, -1 };
472fcb9597fSAndrii Nakryiko 	int child_pid = 0, err;
473fcb9597fSAndrii Nakryiko 
474fcb9597fSAndrii Nakryiko 	err = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds);
475fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "socketpair"))
476fcb9597fSAndrii Nakryiko 		goto cleanup;
477fcb9597fSAndrii Nakryiko 
478fcb9597fSAndrii Nakryiko 	child_pid = fork();
479fcb9597fSAndrii Nakryiko 	if (!ASSERT_GE(child_pid, 0, "fork"))
480fcb9597fSAndrii Nakryiko 		goto cleanup;
481fcb9597fSAndrii Nakryiko 
482fcb9597fSAndrii Nakryiko 	if (child_pid == 0) {
483fcb9597fSAndrii Nakryiko 		zclose(sock_fds[0]);
484*906ee42cSAndrii Nakryiko 		return child(sock_fds[1], bpffs_opts, child_cb);
485fcb9597fSAndrii Nakryiko 
486fcb9597fSAndrii Nakryiko 	} else {
487fcb9597fSAndrii Nakryiko 		zclose(sock_fds[1]);
488fcb9597fSAndrii Nakryiko 		return parent(child_pid, bpffs_opts, sock_fds[0]);
489fcb9597fSAndrii Nakryiko 	}
490fcb9597fSAndrii Nakryiko 
491fcb9597fSAndrii Nakryiko cleanup:
492fcb9597fSAndrii Nakryiko 	zclose(sock_fds[0]);
493fcb9597fSAndrii Nakryiko 	zclose(sock_fds[1]);
494fcb9597fSAndrii Nakryiko 	if (child_pid > 0)
495fcb9597fSAndrii Nakryiko 		(void)kill(child_pid, SIGKILL);
496fcb9597fSAndrii Nakryiko }
497fcb9597fSAndrii Nakryiko 
userns_map_create(int mnt_fd,struct token_lsm * lsm_skel)498*906ee42cSAndrii Nakryiko static int userns_map_create(int mnt_fd, struct token_lsm *lsm_skel)
499fcb9597fSAndrii Nakryiko {
500fcb9597fSAndrii Nakryiko 	LIBBPF_OPTS(bpf_map_create_opts, map_opts);
501fcb9597fSAndrii Nakryiko 	int err, token_fd = -1, map_fd = -1;
502fcb9597fSAndrii Nakryiko 	__u64 old_caps = 0;
503fcb9597fSAndrii Nakryiko 
504fcb9597fSAndrii Nakryiko 	/* create BPF token from BPF FS mount */
505fcb9597fSAndrii Nakryiko 	token_fd = bpf_token_create(mnt_fd, NULL);
506fcb9597fSAndrii Nakryiko 	if (!ASSERT_GT(token_fd, 0, "token_create")) {
507fcb9597fSAndrii Nakryiko 		err = -EINVAL;
508fcb9597fSAndrii Nakryiko 		goto cleanup;
509fcb9597fSAndrii Nakryiko 	}
510fcb9597fSAndrii Nakryiko 
511fcb9597fSAndrii Nakryiko 	/* while inside non-init userns, we need both a BPF token *and*
512fcb9597fSAndrii Nakryiko 	 * CAP_BPF inside current userns to create privileged map; let's test
513fcb9597fSAndrii Nakryiko 	 * that neither BPF token alone nor namespaced CAP_BPF is sufficient
514fcb9597fSAndrii Nakryiko 	 */
515fcb9597fSAndrii Nakryiko 	err = drop_priv_caps(&old_caps);
516fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "drop_caps"))
517fcb9597fSAndrii Nakryiko 		goto cleanup;
518fcb9597fSAndrii Nakryiko 
519fcb9597fSAndrii Nakryiko 	/* no token, no CAP_BPF -> fail */
520fcb9597fSAndrii Nakryiko 	map_opts.map_flags = 0;
521fcb9597fSAndrii Nakryiko 	map_opts.token_fd = 0;
522fcb9597fSAndrii Nakryiko 	map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "wo_token_wo_bpf", 0, 8, 1, &map_opts);
523fcb9597fSAndrii Nakryiko 	if (!ASSERT_LT(map_fd, 0, "stack_map_wo_token_wo_cap_bpf_should_fail")) {
524fcb9597fSAndrii Nakryiko 		err = -EINVAL;
525fcb9597fSAndrii Nakryiko 		goto cleanup;
526fcb9597fSAndrii Nakryiko 	}
527fcb9597fSAndrii Nakryiko 
528fcb9597fSAndrii Nakryiko 	/* token without CAP_BPF -> fail */
529fcb9597fSAndrii Nakryiko 	map_opts.map_flags = BPF_F_TOKEN_FD;
530fcb9597fSAndrii Nakryiko 	map_opts.token_fd = token_fd;
531fcb9597fSAndrii Nakryiko 	map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "w_token_wo_bpf", 0, 8, 1, &map_opts);
532fcb9597fSAndrii Nakryiko 	if (!ASSERT_LT(map_fd, 0, "stack_map_w_token_wo_cap_bpf_should_fail")) {
533fcb9597fSAndrii Nakryiko 		err = -EINVAL;
534fcb9597fSAndrii Nakryiko 		goto cleanup;
535fcb9597fSAndrii Nakryiko 	}
536fcb9597fSAndrii Nakryiko 
537fcb9597fSAndrii Nakryiko 	/* get back effective local CAP_BPF (and CAP_SYS_ADMIN) */
538fcb9597fSAndrii Nakryiko 	err = restore_priv_caps(old_caps);
539fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "restore_caps"))
540fcb9597fSAndrii Nakryiko 		goto cleanup;
541fcb9597fSAndrii Nakryiko 
542fcb9597fSAndrii Nakryiko 	/* CAP_BPF without token -> fail */
543fcb9597fSAndrii Nakryiko 	map_opts.map_flags = 0;
544fcb9597fSAndrii Nakryiko 	map_opts.token_fd = 0;
545fcb9597fSAndrii Nakryiko 	map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "wo_token_w_bpf", 0, 8, 1, &map_opts);
546fcb9597fSAndrii Nakryiko 	if (!ASSERT_LT(map_fd, 0, "stack_map_wo_token_w_cap_bpf_should_fail")) {
547fcb9597fSAndrii Nakryiko 		err = -EINVAL;
548fcb9597fSAndrii Nakryiko 		goto cleanup;
549fcb9597fSAndrii Nakryiko 	}
550fcb9597fSAndrii Nakryiko 
551fcb9597fSAndrii Nakryiko 	/* finally, namespaced CAP_BPF + token -> success */
552fcb9597fSAndrii Nakryiko 	map_opts.map_flags = BPF_F_TOKEN_FD;
553fcb9597fSAndrii Nakryiko 	map_opts.token_fd = token_fd;
554fcb9597fSAndrii Nakryiko 	map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, "w_token_w_bpf", 0, 8, 1, &map_opts);
555fcb9597fSAndrii Nakryiko 	if (!ASSERT_GT(map_fd, 0, "stack_map_w_token_w_cap_bpf")) {
556fcb9597fSAndrii Nakryiko 		err = -EINVAL;
557fcb9597fSAndrii Nakryiko 		goto cleanup;
558fcb9597fSAndrii Nakryiko 	}
559fcb9597fSAndrii Nakryiko 
560fcb9597fSAndrii Nakryiko cleanup:
561fcb9597fSAndrii Nakryiko 	zclose(token_fd);
562fcb9597fSAndrii Nakryiko 	zclose(map_fd);
563fcb9597fSAndrii Nakryiko 	return err;
564fcb9597fSAndrii Nakryiko }
565fcb9597fSAndrii Nakryiko 
userns_btf_load(int mnt_fd,struct token_lsm * lsm_skel)566*906ee42cSAndrii Nakryiko static int userns_btf_load(int mnt_fd, struct token_lsm *lsm_skel)
567fcb9597fSAndrii Nakryiko {
568fcb9597fSAndrii Nakryiko 	LIBBPF_OPTS(bpf_btf_load_opts, btf_opts);
569fcb9597fSAndrii Nakryiko 	int err, token_fd = -1, btf_fd = -1;
570fcb9597fSAndrii Nakryiko 	const void *raw_btf_data;
571fcb9597fSAndrii Nakryiko 	struct btf *btf = NULL;
572fcb9597fSAndrii Nakryiko 	__u32 raw_btf_size;
573fcb9597fSAndrii Nakryiko 	__u64 old_caps = 0;
574fcb9597fSAndrii Nakryiko 
575fcb9597fSAndrii Nakryiko 	/* create BPF token from BPF FS mount */
576fcb9597fSAndrii Nakryiko 	token_fd = bpf_token_create(mnt_fd, NULL);
577fcb9597fSAndrii Nakryiko 	if (!ASSERT_GT(token_fd, 0, "token_create")) {
578fcb9597fSAndrii Nakryiko 		err = -EINVAL;
579fcb9597fSAndrii Nakryiko 		goto cleanup;
580fcb9597fSAndrii Nakryiko 	}
581fcb9597fSAndrii Nakryiko 
582fcb9597fSAndrii Nakryiko 	/* while inside non-init userns, we need both a BPF token *and*
583fcb9597fSAndrii Nakryiko 	 * CAP_BPF inside current userns to create privileged map; let's test
584fcb9597fSAndrii Nakryiko 	 * that neither BPF token alone nor namespaced CAP_BPF is sufficient
585fcb9597fSAndrii Nakryiko 	 */
586fcb9597fSAndrii Nakryiko 	err = drop_priv_caps(&old_caps);
587fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "drop_caps"))
588fcb9597fSAndrii Nakryiko 		goto cleanup;
589fcb9597fSAndrii Nakryiko 
590fcb9597fSAndrii Nakryiko 	/* setup a trivial BTF data to load to the kernel */
591fcb9597fSAndrii Nakryiko 	btf = btf__new_empty();
592fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK_PTR(btf, "empty_btf"))
593fcb9597fSAndrii Nakryiko 		goto cleanup;
594fcb9597fSAndrii Nakryiko 
595fcb9597fSAndrii Nakryiko 	ASSERT_GT(btf__add_int(btf, "int", 4, 0), 0, "int_type");
596fcb9597fSAndrii Nakryiko 
597fcb9597fSAndrii Nakryiko 	raw_btf_data = btf__raw_data(btf, &raw_btf_size);
598fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK_PTR(raw_btf_data, "raw_btf_data"))
599fcb9597fSAndrii Nakryiko 		goto cleanup;
600fcb9597fSAndrii Nakryiko 
601fcb9597fSAndrii Nakryiko 	/* no token + no CAP_BPF -> failure */
602fcb9597fSAndrii Nakryiko 	btf_opts.btf_flags = 0;
603fcb9597fSAndrii Nakryiko 	btf_opts.token_fd = 0;
604fcb9597fSAndrii Nakryiko 	btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts);
605fcb9597fSAndrii Nakryiko 	if (!ASSERT_LT(btf_fd, 0, "no_token_no_cap_should_fail"))
606fcb9597fSAndrii Nakryiko 		goto cleanup;
607fcb9597fSAndrii Nakryiko 
608fcb9597fSAndrii Nakryiko 	/* token + no CAP_BPF -> failure */
609fcb9597fSAndrii Nakryiko 	btf_opts.btf_flags = BPF_F_TOKEN_FD;
610fcb9597fSAndrii Nakryiko 	btf_opts.token_fd = token_fd;
611fcb9597fSAndrii Nakryiko 	btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts);
612fcb9597fSAndrii Nakryiko 	if (!ASSERT_LT(btf_fd, 0, "token_no_cap_should_fail"))
613fcb9597fSAndrii Nakryiko 		goto cleanup;
614fcb9597fSAndrii Nakryiko 
615fcb9597fSAndrii Nakryiko 	/* get back effective local CAP_BPF (and CAP_SYS_ADMIN) */
616fcb9597fSAndrii Nakryiko 	err = restore_priv_caps(old_caps);
617fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "restore_caps"))
618fcb9597fSAndrii Nakryiko 		goto cleanup;
619fcb9597fSAndrii Nakryiko 
620fcb9597fSAndrii Nakryiko 	/* token + CAP_BPF -> success */
621fcb9597fSAndrii Nakryiko 	btf_opts.btf_flags = BPF_F_TOKEN_FD;
622fcb9597fSAndrii Nakryiko 	btf_opts.token_fd = token_fd;
623fcb9597fSAndrii Nakryiko 	btf_fd = bpf_btf_load(raw_btf_data, raw_btf_size, &btf_opts);
624fcb9597fSAndrii Nakryiko 	if (!ASSERT_GT(btf_fd, 0, "token_and_cap_success"))
625fcb9597fSAndrii Nakryiko 		goto cleanup;
626fcb9597fSAndrii Nakryiko 
627fcb9597fSAndrii Nakryiko 	err = 0;
628fcb9597fSAndrii Nakryiko cleanup:
629fcb9597fSAndrii Nakryiko 	btf__free(btf);
630fcb9597fSAndrii Nakryiko 	zclose(btf_fd);
631fcb9597fSAndrii Nakryiko 	zclose(token_fd);
632fcb9597fSAndrii Nakryiko 	return err;
633fcb9597fSAndrii Nakryiko }
634fcb9597fSAndrii Nakryiko 
userns_prog_load(int mnt_fd,struct token_lsm * lsm_skel)635*906ee42cSAndrii Nakryiko static int userns_prog_load(int mnt_fd, struct token_lsm *lsm_skel)
636fcb9597fSAndrii Nakryiko {
637fcb9597fSAndrii Nakryiko 	LIBBPF_OPTS(bpf_prog_load_opts, prog_opts);
638fcb9597fSAndrii Nakryiko 	int err, token_fd = -1, prog_fd = -1;
639fcb9597fSAndrii Nakryiko 	struct bpf_insn insns[] = {
640fcb9597fSAndrii Nakryiko 		/* bpf_jiffies64() requires CAP_BPF */
641fcb9597fSAndrii Nakryiko 		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_jiffies64),
642fcb9597fSAndrii Nakryiko 		/* bpf_get_current_task() requires CAP_PERFMON */
643fcb9597fSAndrii Nakryiko 		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_current_task),
644fcb9597fSAndrii Nakryiko 		/* r0 = 0; exit; */
645fcb9597fSAndrii Nakryiko 		BPF_MOV64_IMM(BPF_REG_0, 0),
646fcb9597fSAndrii Nakryiko 		BPF_EXIT_INSN(),
647fcb9597fSAndrii Nakryiko 	};
648fcb9597fSAndrii Nakryiko 	size_t insn_cnt = ARRAY_SIZE(insns);
649fcb9597fSAndrii Nakryiko 	__u64 old_caps = 0;
650fcb9597fSAndrii Nakryiko 
651fcb9597fSAndrii Nakryiko 	/* create BPF token from BPF FS mount */
652fcb9597fSAndrii Nakryiko 	token_fd = bpf_token_create(mnt_fd, NULL);
653fcb9597fSAndrii Nakryiko 	if (!ASSERT_GT(token_fd, 0, "token_create")) {
654fcb9597fSAndrii Nakryiko 		err = -EINVAL;
655fcb9597fSAndrii Nakryiko 		goto cleanup;
656fcb9597fSAndrii Nakryiko 	}
657fcb9597fSAndrii Nakryiko 
658fcb9597fSAndrii Nakryiko 	/* validate we can successfully load BPF program with token; this
659fcb9597fSAndrii Nakryiko 	 * being XDP program (CAP_NET_ADMIN) using bpf_jiffies64() (CAP_BPF)
660fcb9597fSAndrii Nakryiko 	 * and bpf_get_current_task() (CAP_PERFMON) helpers validates we have
661fcb9597fSAndrii Nakryiko 	 * BPF token wired properly in a bunch of places in the kernel
662fcb9597fSAndrii Nakryiko 	 */
663fcb9597fSAndrii Nakryiko 	prog_opts.prog_flags = BPF_F_TOKEN_FD;
664fcb9597fSAndrii Nakryiko 	prog_opts.token_fd = token_fd;
665fcb9597fSAndrii Nakryiko 	prog_opts.expected_attach_type = BPF_XDP;
666fcb9597fSAndrii Nakryiko 	prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL",
667fcb9597fSAndrii Nakryiko 				insns, insn_cnt, &prog_opts);
668fcb9597fSAndrii Nakryiko 	if (!ASSERT_GT(prog_fd, 0, "prog_fd")) {
669fcb9597fSAndrii Nakryiko 		err = -EPERM;
670fcb9597fSAndrii Nakryiko 		goto cleanup;
671fcb9597fSAndrii Nakryiko 	}
672fcb9597fSAndrii Nakryiko 
673fcb9597fSAndrii Nakryiko 	/* no token + caps -> failure */
674fcb9597fSAndrii Nakryiko 	prog_opts.prog_flags = 0;
675fcb9597fSAndrii Nakryiko 	prog_opts.token_fd = 0;
676fcb9597fSAndrii Nakryiko 	prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL",
677fcb9597fSAndrii Nakryiko 				insns, insn_cnt, &prog_opts);
678fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) {
679fcb9597fSAndrii Nakryiko 		err = -EPERM;
680fcb9597fSAndrii Nakryiko 		goto cleanup;
681fcb9597fSAndrii Nakryiko 	}
682fcb9597fSAndrii Nakryiko 
683fcb9597fSAndrii Nakryiko 	err = drop_priv_caps(&old_caps);
684fcb9597fSAndrii Nakryiko 	if (!ASSERT_OK(err, "drop_caps"))
685fcb9597fSAndrii Nakryiko 		goto cleanup;
686fcb9597fSAndrii Nakryiko 
687fcb9597fSAndrii Nakryiko 	/* no caps + token -> failure */
688fcb9597fSAndrii Nakryiko 	prog_opts.prog_flags = BPF_F_TOKEN_FD;
689fcb9597fSAndrii Nakryiko 	prog_opts.token_fd = token_fd;
690fcb9597fSAndrii Nakryiko 	prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL",
691fcb9597fSAndrii Nakryiko 				insns, insn_cnt, &prog_opts);
692fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) {
693fcb9597fSAndrii Nakryiko 		err = -EPERM;
694fcb9597fSAndrii Nakryiko 		goto cleanup;
695fcb9597fSAndrii Nakryiko 	}
696fcb9597fSAndrii Nakryiko 
697fcb9597fSAndrii Nakryiko 	/* no caps + no token -> definitely a failure */
698fcb9597fSAndrii Nakryiko 	prog_opts.prog_flags = 0;
699fcb9597fSAndrii Nakryiko 	prog_opts.token_fd = 0;
700fcb9597fSAndrii Nakryiko 	prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, "token_prog", "GPL",
701fcb9597fSAndrii Nakryiko 				insns, insn_cnt, &prog_opts);
702fcb9597fSAndrii Nakryiko 	if (!ASSERT_EQ(prog_fd, -EPERM, "prog_fd_eperm")) {
703fcb9597fSAndrii Nakryiko 		err = -EPERM;
704fcb9597fSAndrii Nakryiko 		goto cleanup;
705fcb9597fSAndrii Nakryiko 	}
706fcb9597fSAndrii Nakryiko 
707fcb9597fSAndrii Nakryiko 	err = 0;
708fcb9597fSAndrii Nakryiko cleanup:
709fcb9597fSAndrii Nakryiko 	zclose(prog_fd);
710fcb9597fSAndrii Nakryiko 	zclose(token_fd);
711fcb9597fSAndrii Nakryiko 	return err;
712fcb9597fSAndrii Nakryiko }
713fcb9597fSAndrii Nakryiko 
userns_obj_priv_map(int mnt_fd,struct token_lsm * lsm_skel)714*906ee42cSAndrii Nakryiko static int userns_obj_priv_map(int mnt_fd, struct token_lsm *lsm_skel)
715d5baf0caSAndrii Nakryiko {
716d5baf0caSAndrii Nakryiko 	LIBBPF_OPTS(bpf_object_open_opts, opts);
717d5baf0caSAndrii Nakryiko 	char buf[256];
718d5baf0caSAndrii Nakryiko 	struct priv_map *skel;
719d5baf0caSAndrii Nakryiko 	int err;
720d5baf0caSAndrii Nakryiko 
721d5baf0caSAndrii Nakryiko 	skel = priv_map__open_and_load();
722d5baf0caSAndrii Nakryiko 	if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) {
723d5baf0caSAndrii Nakryiko 		priv_map__destroy(skel);
724d5baf0caSAndrii Nakryiko 		return -EINVAL;
725d5baf0caSAndrii Nakryiko 	}
726d5baf0caSAndrii Nakryiko 
727d5baf0caSAndrii Nakryiko 	/* use bpf_token_path to provide BPF FS path */
728d5baf0caSAndrii Nakryiko 	snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd);
729d5baf0caSAndrii Nakryiko 	opts.bpf_token_path = buf;
730d5baf0caSAndrii Nakryiko 	skel = priv_map__open_opts(&opts);
731d5baf0caSAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_token_path_open"))
732d5baf0caSAndrii Nakryiko 		return -EINVAL;
733d5baf0caSAndrii Nakryiko 
734d5baf0caSAndrii Nakryiko 	err = priv_map__load(skel);
735d5baf0caSAndrii Nakryiko 	priv_map__destroy(skel);
736d5baf0caSAndrii Nakryiko 	if (!ASSERT_OK(err, "obj_token_path_load"))
737d5baf0caSAndrii Nakryiko 		return -EINVAL;
738d5baf0caSAndrii Nakryiko 
739d5baf0caSAndrii Nakryiko 	return 0;
740d5baf0caSAndrii Nakryiko }
741d5baf0caSAndrii Nakryiko 
userns_obj_priv_prog(int mnt_fd,struct token_lsm * lsm_skel)742*906ee42cSAndrii Nakryiko static int userns_obj_priv_prog(int mnt_fd, struct token_lsm *lsm_skel)
743d5baf0caSAndrii Nakryiko {
744d5baf0caSAndrii Nakryiko 	LIBBPF_OPTS(bpf_object_open_opts, opts);
745d5baf0caSAndrii Nakryiko 	char buf[256];
746d5baf0caSAndrii Nakryiko 	struct priv_prog *skel;
747d5baf0caSAndrii Nakryiko 	int err;
748d5baf0caSAndrii Nakryiko 
749d5baf0caSAndrii Nakryiko 	skel = priv_prog__open_and_load();
750d5baf0caSAndrii Nakryiko 	if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) {
751d5baf0caSAndrii Nakryiko 		priv_prog__destroy(skel);
752d5baf0caSAndrii Nakryiko 		return -EINVAL;
753d5baf0caSAndrii Nakryiko 	}
754d5baf0caSAndrii Nakryiko 
755d5baf0caSAndrii Nakryiko 	/* use bpf_token_path to provide BPF FS path */
756d5baf0caSAndrii Nakryiko 	snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd);
757d5baf0caSAndrii Nakryiko 	opts.bpf_token_path = buf;
758d5baf0caSAndrii Nakryiko 	skel = priv_prog__open_opts(&opts);
759d5baf0caSAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_token_path_open"))
760d5baf0caSAndrii Nakryiko 		return -EINVAL;
761d5baf0caSAndrii Nakryiko 	err = priv_prog__load(skel);
762d5baf0caSAndrii Nakryiko 	priv_prog__destroy(skel);
763d5baf0caSAndrii Nakryiko 	if (!ASSERT_OK(err, "obj_token_path_load"))
764d5baf0caSAndrii Nakryiko 		return -EINVAL;
765d5baf0caSAndrii Nakryiko 
766*906ee42cSAndrii Nakryiko 	/* provide BPF token, but reject bpf_token_capable() with LSM */
767*906ee42cSAndrii Nakryiko 	lsm_skel->bss->reject_capable = true;
768*906ee42cSAndrii Nakryiko 	lsm_skel->bss->reject_cmd = false;
769*906ee42cSAndrii Nakryiko 	skel = priv_prog__open_opts(&opts);
770*906ee42cSAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_token_lsm_reject_cap_open"))
771*906ee42cSAndrii Nakryiko 		return -EINVAL;
772*906ee42cSAndrii Nakryiko 	err = priv_prog__load(skel);
773*906ee42cSAndrii Nakryiko 	priv_prog__destroy(skel);
774*906ee42cSAndrii Nakryiko 	if (!ASSERT_ERR(err, "obj_token_lsm_reject_cap_load"))
775*906ee42cSAndrii Nakryiko 		return -EINVAL;
776*906ee42cSAndrii Nakryiko 
777*906ee42cSAndrii Nakryiko 	/* provide BPF token, but reject bpf_token_cmd() with LSM */
778*906ee42cSAndrii Nakryiko 	lsm_skel->bss->reject_capable = false;
779*906ee42cSAndrii Nakryiko 	lsm_skel->bss->reject_cmd = true;
780*906ee42cSAndrii Nakryiko 	skel = priv_prog__open_opts(&opts);
781*906ee42cSAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_token_lsm_reject_cmd_open"))
782*906ee42cSAndrii Nakryiko 		return -EINVAL;
783*906ee42cSAndrii Nakryiko 	err = priv_prog__load(skel);
784*906ee42cSAndrii Nakryiko 	priv_prog__destroy(skel);
785*906ee42cSAndrii Nakryiko 	if (!ASSERT_ERR(err, "obj_token_lsm_reject_cmd_load"))
786*906ee42cSAndrii Nakryiko 		return -EINVAL;
787*906ee42cSAndrii Nakryiko 
788d5baf0caSAndrii Nakryiko 	return 0;
789d5baf0caSAndrii Nakryiko }
790d5baf0caSAndrii Nakryiko 
791d5baf0caSAndrii Nakryiko /* this test is called with BPF FS that doesn't delegate BPF_BTF_LOAD command,
792d5baf0caSAndrii Nakryiko  * which should cause struct_ops application to fail, as BTF won't be uploaded
793d5baf0caSAndrii Nakryiko  * into the kernel, even if STRUCT_OPS programs themselves are allowed
794d5baf0caSAndrii Nakryiko  */
validate_struct_ops_load(int mnt_fd,bool expect_success)795d5baf0caSAndrii Nakryiko static int validate_struct_ops_load(int mnt_fd, bool expect_success)
796d5baf0caSAndrii Nakryiko {
797d5baf0caSAndrii Nakryiko 	LIBBPF_OPTS(bpf_object_open_opts, opts);
798d5baf0caSAndrii Nakryiko 	char buf[256];
799d5baf0caSAndrii Nakryiko 	struct dummy_st_ops_success *skel;
800d5baf0caSAndrii Nakryiko 	int err;
801d5baf0caSAndrii Nakryiko 
802d5baf0caSAndrii Nakryiko 	snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd);
803d5baf0caSAndrii Nakryiko 	opts.bpf_token_path = buf;
804d5baf0caSAndrii Nakryiko 	skel = dummy_st_ops_success__open_opts(&opts);
805d5baf0caSAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_token_path_open"))
806d5baf0caSAndrii Nakryiko 		return -EINVAL;
807d5baf0caSAndrii Nakryiko 
808d5baf0caSAndrii Nakryiko 	err = dummy_st_ops_success__load(skel);
809d5baf0caSAndrii Nakryiko 	dummy_st_ops_success__destroy(skel);
810d5baf0caSAndrii Nakryiko 	if (expect_success) {
811d5baf0caSAndrii Nakryiko 		if (!ASSERT_OK(err, "obj_token_path_load"))
812d5baf0caSAndrii Nakryiko 			return -EINVAL;
813d5baf0caSAndrii Nakryiko 	} else /* expect failure */ {
814d5baf0caSAndrii Nakryiko 		if (!ASSERT_ERR(err, "obj_token_path_load"))
815d5baf0caSAndrii Nakryiko 			return -EINVAL;
816d5baf0caSAndrii Nakryiko 	}
817d5baf0caSAndrii Nakryiko 
818d5baf0caSAndrii Nakryiko 	return 0;
819d5baf0caSAndrii Nakryiko }
820d5baf0caSAndrii Nakryiko 
userns_obj_priv_btf_fail(int mnt_fd,struct token_lsm * lsm_skel)821*906ee42cSAndrii Nakryiko static int userns_obj_priv_btf_fail(int mnt_fd, struct token_lsm *lsm_skel)
822d5baf0caSAndrii Nakryiko {
823d5baf0caSAndrii Nakryiko 	return validate_struct_ops_load(mnt_fd, false /* should fail */);
824d5baf0caSAndrii Nakryiko }
825d5baf0caSAndrii Nakryiko 
userns_obj_priv_btf_success(int mnt_fd,struct token_lsm * lsm_skel)826*906ee42cSAndrii Nakryiko static int userns_obj_priv_btf_success(int mnt_fd, struct token_lsm *lsm_skel)
827d5baf0caSAndrii Nakryiko {
828d5baf0caSAndrii Nakryiko 	return validate_struct_ops_load(mnt_fd, true /* should succeed */);
829d5baf0caSAndrii Nakryiko }
830d5baf0caSAndrii Nakryiko 
831fadf5493SAndrii Nakryiko #define TOKEN_ENVVAR "LIBBPF_BPF_TOKEN_PATH"
832fadf5493SAndrii Nakryiko #define TOKEN_BPFFS_CUSTOM "/bpf-token-fs"
833fadf5493SAndrii Nakryiko 
userns_obj_priv_implicit_token(int mnt_fd,struct token_lsm * lsm_skel)834*906ee42cSAndrii Nakryiko static int userns_obj_priv_implicit_token(int mnt_fd, struct token_lsm *lsm_skel)
835b73d08d1SAndrii Nakryiko {
836b73d08d1SAndrii Nakryiko 	LIBBPF_OPTS(bpf_object_open_opts, opts);
837b73d08d1SAndrii Nakryiko 	struct dummy_st_ops_success *skel;
838b73d08d1SAndrii Nakryiko 	int err;
839b73d08d1SAndrii Nakryiko 
840b73d08d1SAndrii Nakryiko 	/* before we mount BPF FS with token delegation, struct_ops skeleton
841b73d08d1SAndrii Nakryiko 	 * should fail to load
842b73d08d1SAndrii Nakryiko 	 */
843b73d08d1SAndrii Nakryiko 	skel = dummy_st_ops_success__open_and_load();
844b73d08d1SAndrii Nakryiko 	if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) {
845b73d08d1SAndrii Nakryiko 		dummy_st_ops_success__destroy(skel);
846b73d08d1SAndrii Nakryiko 		return -EINVAL;
847b73d08d1SAndrii Nakryiko 	}
848b73d08d1SAndrii Nakryiko 
849b73d08d1SAndrii Nakryiko 	/* mount custom BPF FS over /sys/fs/bpf so that libbpf can create BPF
850b73d08d1SAndrii Nakryiko 	 * token automatically and implicitly
851b73d08d1SAndrii Nakryiko 	 */
852b73d08d1SAndrii Nakryiko 	err = sys_move_mount(mnt_fd, "", AT_FDCWD, "/sys/fs/bpf", MOVE_MOUNT_F_EMPTY_PATH);
853b73d08d1SAndrii Nakryiko 	if (!ASSERT_OK(err, "move_mount_bpffs"))
854b73d08d1SAndrii Nakryiko 		return -EINVAL;
855b73d08d1SAndrii Nakryiko 
856fadf5493SAndrii Nakryiko 	/* disable implicit BPF token creation by setting
857fadf5493SAndrii Nakryiko 	 * LIBBPF_BPF_TOKEN_PATH envvar to empty value, load should fail
858fadf5493SAndrii Nakryiko 	 */
859fadf5493SAndrii Nakryiko 	err = setenv(TOKEN_ENVVAR, "", 1 /*overwrite*/);
860fadf5493SAndrii Nakryiko 	if (!ASSERT_OK(err, "setenv_token_path"))
861fadf5493SAndrii Nakryiko 		return -EINVAL;
862fadf5493SAndrii Nakryiko 	skel = dummy_st_ops_success__open_and_load();
863fadf5493SAndrii Nakryiko 	if (!ASSERT_ERR_PTR(skel, "obj_token_envvar_disabled_load")) {
864fadf5493SAndrii Nakryiko 		unsetenv(TOKEN_ENVVAR);
865fadf5493SAndrii Nakryiko 		dummy_st_ops_success__destroy(skel);
866fadf5493SAndrii Nakryiko 		return -EINVAL;
867fadf5493SAndrii Nakryiko 	}
868fadf5493SAndrii Nakryiko 	unsetenv(TOKEN_ENVVAR);
869fadf5493SAndrii Nakryiko 
870b73d08d1SAndrii Nakryiko 	/* now the same struct_ops skeleton should succeed thanks to libppf
871b73d08d1SAndrii Nakryiko 	 * creating BPF token from /sys/fs/bpf mount point
872b73d08d1SAndrii Nakryiko 	 */
873b73d08d1SAndrii Nakryiko 	skel = dummy_st_ops_success__open_and_load();
874b73d08d1SAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_implicit_token_load"))
875b73d08d1SAndrii Nakryiko 		return -EINVAL;
876b73d08d1SAndrii Nakryiko 
877b73d08d1SAndrii Nakryiko 	dummy_st_ops_success__destroy(skel);
878b73d08d1SAndrii Nakryiko 
879b73d08d1SAndrii Nakryiko 	/* now disable implicit token through empty bpf_token_path, should fail */
880b73d08d1SAndrii Nakryiko 	opts.bpf_token_path = "";
881b73d08d1SAndrii Nakryiko 	skel = dummy_st_ops_success__open_opts(&opts);
882b73d08d1SAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_empty_token_path_open"))
883b73d08d1SAndrii Nakryiko 		return -EINVAL;
884b73d08d1SAndrii Nakryiko 
885b73d08d1SAndrii Nakryiko 	err = dummy_st_ops_success__load(skel);
886b73d08d1SAndrii Nakryiko 	dummy_st_ops_success__destroy(skel);
887b73d08d1SAndrii Nakryiko 	if (!ASSERT_ERR(err, "obj_empty_token_path_load"))
888b73d08d1SAndrii Nakryiko 		return -EINVAL;
889b73d08d1SAndrii Nakryiko 
890b73d08d1SAndrii Nakryiko 	return 0;
891b73d08d1SAndrii Nakryiko }
892b73d08d1SAndrii Nakryiko 
userns_obj_priv_implicit_token_envvar(int mnt_fd,struct token_lsm * lsm_skel)893*906ee42cSAndrii Nakryiko static int userns_obj_priv_implicit_token_envvar(int mnt_fd, struct token_lsm *lsm_skel)
894fadf5493SAndrii Nakryiko {
895fadf5493SAndrii Nakryiko 	LIBBPF_OPTS(bpf_object_open_opts, opts);
896fadf5493SAndrii Nakryiko 	struct dummy_st_ops_success *skel;
897fadf5493SAndrii Nakryiko 	int err;
898fadf5493SAndrii Nakryiko 
899fadf5493SAndrii Nakryiko 	/* before we mount BPF FS with token delegation, struct_ops skeleton
900fadf5493SAndrii Nakryiko 	 * should fail to load
901fadf5493SAndrii Nakryiko 	 */
902fadf5493SAndrii Nakryiko 	skel = dummy_st_ops_success__open_and_load();
903fadf5493SAndrii Nakryiko 	if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) {
904fadf5493SAndrii Nakryiko 		dummy_st_ops_success__destroy(skel);
905fadf5493SAndrii Nakryiko 		return -EINVAL;
906fadf5493SAndrii Nakryiko 	}
907fadf5493SAndrii Nakryiko 
908fadf5493SAndrii Nakryiko 	/* mount custom BPF FS over custom location, so libbpf can't create
909fadf5493SAndrii Nakryiko 	 * BPF token implicitly, unless pointed to it through
910fadf5493SAndrii Nakryiko 	 * LIBBPF_BPF_TOKEN_PATH envvar
911fadf5493SAndrii Nakryiko 	 */
912fadf5493SAndrii Nakryiko 	rmdir(TOKEN_BPFFS_CUSTOM);
913fadf5493SAndrii Nakryiko 	if (!ASSERT_OK(mkdir(TOKEN_BPFFS_CUSTOM, 0777), "mkdir_bpffs_custom"))
914fadf5493SAndrii Nakryiko 		goto err_out;
915fadf5493SAndrii Nakryiko 	err = sys_move_mount(mnt_fd, "", AT_FDCWD, TOKEN_BPFFS_CUSTOM, MOVE_MOUNT_F_EMPTY_PATH);
916fadf5493SAndrii Nakryiko 	if (!ASSERT_OK(err, "move_mount_bpffs"))
917fadf5493SAndrii Nakryiko 		goto err_out;
918fadf5493SAndrii Nakryiko 
919fadf5493SAndrii Nakryiko 	/* even though we have BPF FS with delegation, it's not at default
920fadf5493SAndrii Nakryiko 	 * /sys/fs/bpf location, so we still fail to load until envvar is set up
921fadf5493SAndrii Nakryiko 	 */
922fadf5493SAndrii Nakryiko 	skel = dummy_st_ops_success__open_and_load();
923fadf5493SAndrii Nakryiko 	if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load2")) {
924fadf5493SAndrii Nakryiko 		dummy_st_ops_success__destroy(skel);
925fadf5493SAndrii Nakryiko 		goto err_out;
926fadf5493SAndrii Nakryiko 	}
927fadf5493SAndrii Nakryiko 
928fadf5493SAndrii Nakryiko 	err = setenv(TOKEN_ENVVAR, TOKEN_BPFFS_CUSTOM, 1 /*overwrite*/);
929fadf5493SAndrii Nakryiko 	if (!ASSERT_OK(err, "setenv_token_path"))
930fadf5493SAndrii Nakryiko 		goto err_out;
931fadf5493SAndrii Nakryiko 
932fadf5493SAndrii Nakryiko 	/* now the same struct_ops skeleton should succeed thanks to libppf
933fadf5493SAndrii Nakryiko 	 * creating BPF token from custom mount point
934fadf5493SAndrii Nakryiko 	 */
935fadf5493SAndrii Nakryiko 	skel = dummy_st_ops_success__open_and_load();
936fadf5493SAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_implicit_token_load"))
937fadf5493SAndrii Nakryiko 		goto err_out;
938fadf5493SAndrii Nakryiko 
939fadf5493SAndrii Nakryiko 	dummy_st_ops_success__destroy(skel);
940fadf5493SAndrii Nakryiko 
941fadf5493SAndrii Nakryiko 	/* now disable implicit token through empty bpf_token_path, envvar
942fadf5493SAndrii Nakryiko 	 * will be ignored, should fail
943fadf5493SAndrii Nakryiko 	 */
944fadf5493SAndrii Nakryiko 	opts.bpf_token_path = "";
945fadf5493SAndrii Nakryiko 	skel = dummy_st_ops_success__open_opts(&opts);
946fadf5493SAndrii Nakryiko 	if (!ASSERT_OK_PTR(skel, "obj_empty_token_path_open"))
947fadf5493SAndrii Nakryiko 		goto err_out;
948fadf5493SAndrii Nakryiko 
949fadf5493SAndrii Nakryiko 	err = dummy_st_ops_success__load(skel);
950fadf5493SAndrii Nakryiko 	dummy_st_ops_success__destroy(skel);
951fadf5493SAndrii Nakryiko 	if (!ASSERT_ERR(err, "obj_empty_token_path_load"))
952fadf5493SAndrii Nakryiko 		goto err_out;
953fadf5493SAndrii Nakryiko 
954fadf5493SAndrii Nakryiko 	rmdir(TOKEN_BPFFS_CUSTOM);
955fadf5493SAndrii Nakryiko 	unsetenv(TOKEN_ENVVAR);
956fadf5493SAndrii Nakryiko 	return 0;
957fadf5493SAndrii Nakryiko err_out:
958fadf5493SAndrii Nakryiko 	rmdir(TOKEN_BPFFS_CUSTOM);
959fadf5493SAndrii Nakryiko 	unsetenv(TOKEN_ENVVAR);
960fadf5493SAndrii Nakryiko 	return -EINVAL;
961fadf5493SAndrii Nakryiko }
962fadf5493SAndrii Nakryiko 
963d5baf0caSAndrii Nakryiko #define bit(n) (1ULL << (n))
964d5baf0caSAndrii Nakryiko 
test_token(void)965fcb9597fSAndrii Nakryiko void test_token(void)
966fcb9597fSAndrii Nakryiko {
967fcb9597fSAndrii Nakryiko 	if (test__start_subtest("map_token")) {
968fcb9597fSAndrii Nakryiko 		struct bpffs_opts opts = {
9690350f9d9SAndrii Nakryiko 			.cmds_str = "map_create",
9700350f9d9SAndrii Nakryiko 			.maps_str = "stack",
971fcb9597fSAndrii Nakryiko 		};
972fcb9597fSAndrii Nakryiko 
973fcb9597fSAndrii Nakryiko 		subtest_userns(&opts, userns_map_create);
974fcb9597fSAndrii Nakryiko 	}
975fcb9597fSAndrii Nakryiko 	if (test__start_subtest("btf_token")) {
976fcb9597fSAndrii Nakryiko 		struct bpffs_opts opts = {
977fcb9597fSAndrii Nakryiko 			.cmds = 1ULL << BPF_BTF_LOAD,
978fcb9597fSAndrii Nakryiko 		};
979fcb9597fSAndrii Nakryiko 
980fcb9597fSAndrii Nakryiko 		subtest_userns(&opts, userns_btf_load);
981fcb9597fSAndrii Nakryiko 	}
982fcb9597fSAndrii Nakryiko 	if (test__start_subtest("prog_token")) {
983fcb9597fSAndrii Nakryiko 		struct bpffs_opts opts = {
9840350f9d9SAndrii Nakryiko 			.cmds_str = "PROG_LOAD",
9850350f9d9SAndrii Nakryiko 			.progs_str = "XDP",
9860350f9d9SAndrii Nakryiko 			.attachs_str = "xdp",
987fcb9597fSAndrii Nakryiko 		};
988fcb9597fSAndrii Nakryiko 
989fcb9597fSAndrii Nakryiko 		subtest_userns(&opts, userns_prog_load);
990fcb9597fSAndrii Nakryiko 	}
991d5baf0caSAndrii Nakryiko 	if (test__start_subtest("obj_priv_map")) {
992d5baf0caSAndrii Nakryiko 		struct bpffs_opts opts = {
993d5baf0caSAndrii Nakryiko 			.cmds = bit(BPF_MAP_CREATE),
994d5baf0caSAndrii Nakryiko 			.maps = bit(BPF_MAP_TYPE_QUEUE),
995d5baf0caSAndrii Nakryiko 		};
996d5baf0caSAndrii Nakryiko 
997d5baf0caSAndrii Nakryiko 		subtest_userns(&opts, userns_obj_priv_map);
998d5baf0caSAndrii Nakryiko 	}
999d5baf0caSAndrii Nakryiko 	if (test__start_subtest("obj_priv_prog")) {
1000d5baf0caSAndrii Nakryiko 		struct bpffs_opts opts = {
1001d5baf0caSAndrii Nakryiko 			.cmds = bit(BPF_PROG_LOAD),
1002d5baf0caSAndrii Nakryiko 			.progs = bit(BPF_PROG_TYPE_KPROBE),
1003d5baf0caSAndrii Nakryiko 			.attachs = ~0ULL,
1004d5baf0caSAndrii Nakryiko 		};
1005d5baf0caSAndrii Nakryiko 
1006d5baf0caSAndrii Nakryiko 		subtest_userns(&opts, userns_obj_priv_prog);
1007d5baf0caSAndrii Nakryiko 	}
1008d5baf0caSAndrii Nakryiko 	if (test__start_subtest("obj_priv_btf_fail")) {
1009d5baf0caSAndrii Nakryiko 		struct bpffs_opts opts = {
1010d5baf0caSAndrii Nakryiko 			/* disallow BTF loading */
1011d5baf0caSAndrii Nakryiko 			.cmds = bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD),
1012d5baf0caSAndrii Nakryiko 			.maps = bit(BPF_MAP_TYPE_STRUCT_OPS),
1013d5baf0caSAndrii Nakryiko 			.progs = bit(BPF_PROG_TYPE_STRUCT_OPS),
1014d5baf0caSAndrii Nakryiko 			.attachs = ~0ULL,
1015d5baf0caSAndrii Nakryiko 		};
1016d5baf0caSAndrii Nakryiko 
1017d5baf0caSAndrii Nakryiko 		subtest_userns(&opts, userns_obj_priv_btf_fail);
1018d5baf0caSAndrii Nakryiko 	}
1019d5baf0caSAndrii Nakryiko 	if (test__start_subtest("obj_priv_btf_success")) {
1020d5baf0caSAndrii Nakryiko 		struct bpffs_opts opts = {
1021d5baf0caSAndrii Nakryiko 			/* allow BTF loading */
1022d5baf0caSAndrii Nakryiko 			.cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD),
1023d5baf0caSAndrii Nakryiko 			.maps = bit(BPF_MAP_TYPE_STRUCT_OPS),
1024d5baf0caSAndrii Nakryiko 			.progs = bit(BPF_PROG_TYPE_STRUCT_OPS),
1025d5baf0caSAndrii Nakryiko 			.attachs = ~0ULL,
1026d5baf0caSAndrii Nakryiko 		};
1027d5baf0caSAndrii Nakryiko 
1028d5baf0caSAndrii Nakryiko 		subtest_userns(&opts, userns_obj_priv_btf_success);
1029d5baf0caSAndrii Nakryiko 	}
1030b73d08d1SAndrii Nakryiko 	if (test__start_subtest("obj_priv_implicit_token")) {
1031b73d08d1SAndrii Nakryiko 		struct bpffs_opts opts = {
1032b73d08d1SAndrii Nakryiko 			/* allow BTF loading */
1033b73d08d1SAndrii Nakryiko 			.cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD),
1034b73d08d1SAndrii Nakryiko 			.maps = bit(BPF_MAP_TYPE_STRUCT_OPS),
1035b73d08d1SAndrii Nakryiko 			.progs = bit(BPF_PROG_TYPE_STRUCT_OPS),
1036b73d08d1SAndrii Nakryiko 			.attachs = ~0ULL,
1037b73d08d1SAndrii Nakryiko 		};
1038b73d08d1SAndrii Nakryiko 
1039b73d08d1SAndrii Nakryiko 		subtest_userns(&opts, userns_obj_priv_implicit_token);
1040b73d08d1SAndrii Nakryiko 	}
1041fadf5493SAndrii Nakryiko 	if (test__start_subtest("obj_priv_implicit_token_envvar")) {
1042fadf5493SAndrii Nakryiko 		struct bpffs_opts opts = {
1043fadf5493SAndrii Nakryiko 			/* allow BTF loading */
1044fadf5493SAndrii Nakryiko 			.cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD),
1045fadf5493SAndrii Nakryiko 			.maps = bit(BPF_MAP_TYPE_STRUCT_OPS),
1046fadf5493SAndrii Nakryiko 			.progs = bit(BPF_PROG_TYPE_STRUCT_OPS),
1047fadf5493SAndrii Nakryiko 			.attachs = ~0ULL,
1048fadf5493SAndrii Nakryiko 		};
1049fadf5493SAndrii Nakryiko 
1050fadf5493SAndrii Nakryiko 		subtest_userns(&opts, userns_obj_priv_implicit_token_envvar);
1051fadf5493SAndrii Nakryiko 	}
1052fcb9597fSAndrii Nakryiko }
1053