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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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