* [PATCH testsuite] tests/bpf: add tests for bpf token
@ 2025-08-01 15:50 danieldurning.work
2025-08-01 18:45 ` Stephen Smalley
0 siblings, 1 reply; 2+ messages in thread
From: danieldurning.work @ 2025-08-01 15:50 UTC (permalink / raw)
To: selinux; +Cc: paul, stephen.smalley.work, omosnace
From: Daniel Durning <danieldurning.work@gmail.com>
Added two tests using BPF tokens which will test the bpf_token_capable and bpf_token_cmd LSM hooks.
Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
---
policy/test_bpf.te | 40 ++++
tests/bpf/Makefile | 1 +
tests/bpf/bpf_common.c | 35 ++++
tests/bpf/bpf_common.h | 6 +
tests/bpf/bpf_test.c | 42 +++-
tests/bpf/bpf_token.c | 459 +++++++++++++++++++++++++++++++++++++++++
tests/bpf/test | 20 +-
7 files changed, 594 insertions(+), 9 deletions(-)
create mode 100644 tests/bpf/bpf_token.c
diff --git a/policy/test_bpf.te b/policy/test_bpf.te
index 5eab0bd..c62d6b0 100644
--- a/policy/test_bpf.te
+++ b/policy/test_bpf.te
@@ -5,6 +5,9 @@
attribute bpfdomain;
################################### Main ###################################
+require {
+ type bpf_t;
+}
type test_bpf_t;
testsuite_domain_type(test_bpf_t)
typeattribute test_bpf_t bpfdomain;
@@ -12,6 +15,13 @@ typeattribute test_bpf_t bpfdomain;
allow test_bpf_t self:process { setrlimit };
allow test_bpf_t self:capability { sys_resource sys_admin };
allow test_bpf_t self:bpf { map_create map_read map_write prog_load prog_run };
+allow test_bpf_t self:cap2_userns bpf;
+files_mounton_rootfs(test_bpf_t)
+fs_list_bpf_dirs(test_bpf_t)
+allow test_bpf_t self:cap_userns { setgid setuid sys_admin };
+allow test_bpf_t self:user_namespace create;
+allow test_bpf_t bpf_t:filesystem mount;
+allow test_bpf_t self:cap_userns net_admin;
############################## Deny map_create #############################
type test_bpf_deny_map_create_t;
@@ -57,3 +67,33 @@ typeattribute test_bpf_deny_prog_run_t bpfdomain;
allow test_bpf_deny_prog_run_t self:process { setrlimit };
allow test_bpf_deny_prog_run_t self:capability { sys_resource sys_admin };
allow test_bpf_deny_prog_run_t self:bpf { map_create map_read map_write prog_load };
+
+############################# Deny token_cap ###############################
+type test_bpf_deny_token_cap_t;
+testsuite_domain_type(test_bpf_deny_token_cap_t)
+typeattribute test_bpf_deny_token_cap_t bpfdomain;
+
+allow test_bpf_deny_token_cap_t self:process { setrlimit };
+allow test_bpf_deny_token_cap_t self:capability { sys_resource sys_admin };
+allow test_bpf_deny_token_cap_t self:cap2_userns bpf;
+allow test_bpf_deny_token_cap_t self:bpf { map_create map_read map_write prog_load prog_run };
+files_mounton_rootfs(test_bpf_deny_token_cap_t)
+fs_list_bpf_dirs(test_bpf_deny_token_cap_t)
+allow test_bpf_deny_token_cap_t self:cap_userns { setgid setuid sys_admin };
+allow test_bpf_deny_token_cap_t self:user_namespace create;
+allow test_bpf_deny_token_cap_t bpf_t:filesystem mount;
+
+############################# Deny token_cmd ###############################
+type test_bpf_deny_token_cmd_t;
+testsuite_domain_type(test_bpf_deny_token_cmd_t)
+typeattribute test_bpf_deny_token_cmd_t bpfdomain;
+
+allow test_bpf_deny_token_cmd_t self:process { setrlimit };
+allow test_bpf_deny_token_cmd_t self:capability { sys_resource sys_admin };
+allow test_bpf_deny_token_cmd_t self:cap2_userns bpf;
+allow test_bpf_deny_token_cmd_t self:bpf { map_read map_write prog_load prog_run };
+files_mounton_rootfs(test_bpf_deny_token_cmd_t)
+fs_list_bpf_dirs(test_bpf_deny_token_cmd_t)
+allow test_bpf_deny_token_cmd_t self:cap_userns { setgid setuid sys_admin };
+allow test_bpf_deny_token_cmd_t self:user_namespace create;
+allow test_bpf_deny_token_cmd_t bpf_t:filesystem mount;
diff --git a/tests/bpf/Makefile b/tests/bpf/Makefile
index 1ae8ce9..610a420 100644
--- a/tests/bpf/Makefile
+++ b/tests/bpf/Makefile
@@ -4,6 +4,7 @@ LDLIBS += -lselinux -lbpf
# export so that BPF_ENABLED entries get built correctly on local build
export CFLAGS += -DHAVE_BPF
+export CFLAGS += -D_GNU_SOURCE
BPF_ENABLED = ../fdreceive ../binder
diff --git a/tests/bpf/bpf_common.c b/tests/bpf/bpf_common.c
index 2d97299..97c4d2d 100644
--- a/tests/bpf/bpf_common.c
+++ b/tests/bpf/bpf_common.c
@@ -1,4 +1,6 @@
+#include <sched.h>
#include "bpf_common.h"
+#include "bpf_token.c"
/*
* v0.7 deprecates some functions in favor of a new API (introduced in v0.6).
@@ -58,6 +60,39 @@ int create_bpf_prog(void)
return prog_fd;
}
+/*
+ * BPF tokens did not exist in the old API - just return 0 if on an older version.
+ */
+int test_bpf_token_capable(void)
+{
+#ifdef USE_NEW_API
+ struct bpffs_opts opts = {
+ .cmds_str = "map_create",
+ .maps_str = "xskmap",
+ };
+
+ return create_bpf_token(&opts, map_test_bpf_token_capable);
+
+#else
+ return 0;
+#endif
+}
+
+int test_bpf_token_cmd(void)
+{
+#ifdef USE_NEW_API
+ struct bpffs_opts opts = {
+ .cmds_str = "map_create",
+ .maps_str = "stack",
+ };
+
+ return create_bpf_token(&opts, map_test_bpf_token_cmd);
+
+#else
+ return 0;
+#endif
+}
+
/*
* The default RLIMIT_MEMLOCK is normally 64K, however BPF map/prog requires
* more than this (the actual threshold varying across arches) so set it to
diff --git a/tests/bpf/bpf_common.h b/tests/bpf/bpf_common.h
index 44ac28f..ed34ab6 100644
--- a/tests/bpf/bpf_common.h
+++ b/tests/bpf/bpf_common.h
@@ -8,9 +8,15 @@
#include <bpf/bpf.h>
#include <linux/bpf.h>
#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <linux/unistd.h>
+#include <sys/mount.h>
+#include <fcntl.h>
extern int create_bpf_map(void);
extern int create_bpf_prog(void);
+extern int test_bpf_token_capable(void);
+extern int test_bpf_token_cmd(void);
extern void bpf_setrlimit(void);
/* edited eBPF instruction library */
diff --git a/tests/bpf/bpf_test.c b/tests/bpf/bpf_test.c
index 3c6a29c..ea7c02b 100644
--- a/tests/bpf/bpf_test.c
+++ b/tests/bpf/bpf_test.c
@@ -7,22 +7,27 @@ static void usage(char *progname)
"Where:\n\t"
"-m Create BPF map fd\n\t"
"-p Create BPF prog fd\n\t"
+ "-c Test BPF token capable\n\t"
+ "-d Test BPF token cmd\n\t"
"-v Print information.\n", progname);
exit(-1);
}
int main(int argc, char *argv[])
{
- int opt, result, fd;
+ int opt, result, ret;
+ bool isFd = true;
bool verbose = false;
char *context;
enum {
MAP_FD = 1,
- PROG_FD
+ PROG_FD,
+ TOKEN_CAP,
+ TOKEN_CMD
} bpf_fd_type;
- while ((opt = getopt(argc, argv, "mpv")) != -1) {
+ while ((opt = getopt(argc, argv, "mpvcd")) != -1) {
switch (opt) {
case 'm':
bpf_fd_type = MAP_FD;
@@ -30,6 +35,12 @@ int main(int argc, char *argv[])
case 'p':
bpf_fd_type = PROG_FD;
break;
+ case 'c':
+ bpf_fd_type = TOKEN_CAP;
+ break;
+ case 'd':
+ bpf_fd_type = TOKEN_CMD;
+ break;
case 'v':
verbose = true;
break;
@@ -57,21 +68,36 @@ int main(int argc, char *argv[])
if (verbose)
printf("Creating BPF map\n");
- fd = create_bpf_map();
+ ret = create_bpf_map();
break;
case PROG_FD:
if (verbose)
printf("Creating BPF prog\n");
- fd = create_bpf_prog();
+ ret = create_bpf_prog();
+ break;
+ case TOKEN_CAP:
+ isFd = false;
+ if (verbose)
+ printf("Creating token and testing bpf_token_capable\n");
+
+ ret = test_bpf_token_capable();
+ break;
+ case TOKEN_CMD:
+ isFd = false;
+ if (verbose)
+ printf("Creating token and testing bpf_token_cmd\n");
+
+ ret = test_bpf_token_cmd();
break;
default:
usage(argv[0]);
}
- if (fd < 0)
- return fd;
+ if (ret < 0)
+ return ret;
+ else if (isFd)
+ close(ret);
- close(fd);
return 0;
}
diff --git a/tests/bpf/bpf_token.c b/tests/bpf/bpf_token.c
new file mode 100644
index 0000000..8e33383
--- /dev/null
+++ b/tests/bpf/bpf_token.c
@@ -0,0 +1,459 @@
+// Code derived from: linux/source/tools/testing/selftests/bpf/prog_tests/token.c
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+
+#include "bpf_common.h"
+#include <sys/socket.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+struct bpffs_opts {
+ __u64 cmds;
+ __u64 maps;
+ __u64 progs;
+ __u64 attachs;
+ const char *cmds_str;
+ const char *maps_str;
+ const char *progs_str;
+ const char *attachs_str;
+};
+
+static inline int sys_fsopen(const char *fsname, unsigned flags)
+{
+ return syscall(__NR_fsopen, fsname, flags);
+}
+
+static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key,
+ const void *val, int aux)
+{
+ return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux);
+}
+
+static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags)
+{
+ return syscall(__NR_fsmount, fs_fd, flags, ms_flags);
+}
+
+static ssize_t write_nointr(int fd, const void *buf, size_t count)
+{
+ ssize_t ret;
+
+ do {
+ ret = write(fd, buf, count);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+static int write_file(const char *path, const void *buf, size_t count)
+{
+ int fd;
+ ssize_t ret;
+
+ fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
+ if (fd < 0)
+ return -1;
+
+ ret = write_nointr(fd, buf, count);
+ close(fd);
+ if (ret < 0 || (size_t)ret != count)
+ return -1;
+
+ return 0;
+}
+
+static int wait_for_pid(pid_t pid)
+{
+ int status, ret;
+
+again:
+ ret = waitpid(pid, &status, 0);
+ if (ret == -1) {
+ if (errno == EINTR)
+ goto again;
+
+ return -1;
+ }
+
+ if (!WIFEXITED(status))
+ return -1;
+
+ return WEXITSTATUS(status);
+}
+
+static int sendfd(int sockfd, int fd)
+{
+ struct msghdr msg = {};
+ struct cmsghdr *cmsg;
+ int fds[1] = { fd }, err;
+ char iobuf[1];
+ struct iovec io = {
+ .iov_base = iobuf,
+ .iov_len = sizeof(iobuf),
+ };
+ union {
+ char buf[CMSG_SPACE(sizeof(fds))];
+ struct cmsghdr align;
+ } u;
+
+ msg.msg_iov = &io;
+ msg.msg_iovlen = 1;
+ msg.msg_control = u.buf;
+ msg.msg_controllen = sizeof(u.buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fds));
+ memcpy(CMSG_DATA(cmsg), fds, sizeof(fds));
+
+ err = sendmsg(sockfd, &msg, 0);
+ if (err < 0) {
+ err = -errno;
+ return err;
+ }
+
+ return 0;
+}
+
+static int recvfd(int sockfd, int *fd)
+{
+ struct msghdr msg = {};
+ struct cmsghdr *cmsg;
+ int fds[1], err;
+ char iobuf[1];
+ struct iovec io = {
+ .iov_base = iobuf,
+ .iov_len = sizeof(iobuf),
+ };
+ union {
+ char buf[CMSG_SPACE(sizeof(fds))];
+ struct cmsghdr align;
+ } u;
+
+ msg.msg_iov = &io;
+ msg.msg_iovlen = 1;
+ msg.msg_control = u.buf;
+ msg.msg_controllen = sizeof(u.buf);
+
+ err = recvmsg(sockfd, &msg, 0);
+ if (err < 0) {
+ err = -errno;
+ return err;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+
+ memcpy(fds, CMSG_DATA(cmsg), sizeof(fds));
+ *fd = fds[0];
+
+ return 0;
+}
+
+static int create_and_enter_userns(void)
+{
+ uid_t uid;
+ gid_t gid;
+ char map[100];
+
+ uid = getuid();
+ gid = getgid();
+
+ if (unshare(CLONE_NEWUSER))
+ return -1;
+
+ if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) &&
+ errno != ENOENT)
+ return -1;
+
+ snprintf(map, sizeof(map), "0 %d 1", uid);
+ if (write_file("/proc/self/uid_map", map, strlen(map)))
+ return -1;
+
+
+ snprintf(map, sizeof(map), "0 %d 1", gid);
+ if (write_file("/proc/self/gid_map", map, strlen(map)))
+ return -1;
+
+ if (setgid(0))
+ return -1;
+
+ if (setuid(0))
+ return -1;
+
+ return 0;
+}
+
+int set_delegate_mask(int fs_fd, const char *key, __u64 mask,
+ const char *mask_str)
+{
+ char buf[32];
+ int err;
+
+ if (!mask_str) {
+ if (mask == ~0ULL) {
+ mask_str = "any";
+ } else {
+ snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask);
+ mask_str = buf;
+ }
+ }
+
+ err = sys_fsconfig(fs_fd, FSCONFIG_SET_STRING, key,
+ mask_str, 0);
+ if (err < 0)
+ err = -errno;
+ return err;
+}
+
+int create_bpffs_fd(void)
+{
+ int fs_fd;
+
+ fs_fd = sys_fsopen("bpf", 0);
+
+ return fs_fd;
+}
+
+int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts)
+{
+ int mnt_fd, err;
+
+ /* set up token delegation mount options */
+ err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds, opts->cmds_str);
+ if (err < 0) {
+ fprintf(stderr, "Failed to set delegate dms: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+ err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps, opts->maps_str);
+ if (err < 0) {
+ fprintf(stderr, "Failed to set delegate maps: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+ err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs, opts->progs_str);
+ if (err < 0) {
+ fprintf(stderr, "Failed to set delegate progs: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+ err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs,
+ opts->attachs_str);
+ if (err < 0) {
+ fprintf(stderr, "Failed to set delegate attachs: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+
+ err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
+ if (err < 0) {
+ fprintf(stderr, "Failed fsconfig: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+
+ mnt_fd = sys_fsmount(fs_fd, 0, 0);
+ if (mnt_fd < 0) {
+ fprintf(stderr, "Failed fsmount: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+
+ return mnt_fd;
+}
+
+typedef int (*child_callback_fn)(int token_fd);
+
+static int token_child(int sock_fd, struct bpffs_opts *opts,
+ child_callback_fn callback)
+{
+ int fs_fd, mnt_fd, bpffs_fd, token_fd, err;
+
+ err = create_and_enter_userns();
+ if (err < 0) {
+ fprintf(stderr, "Failed enter_userns: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ err = unshare(CLONE_NEWNS);
+ if (err < 0) {
+ fprintf(stderr, "Failed unshare: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ err = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
+ if (err < 0) {
+ fprintf(stderr, "Failed mount: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ fs_fd = create_bpffs_fd();
+ if (fs_fd < 0) {
+ fprintf(stderr, "Failed create bpffs_fd: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ err = sendfd(sock_fd, fs_fd);
+ if (err < 0) {
+ fprintf(stderr, "Failed to send to parent over socket: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ err = recvfd(sock_fd, &mnt_fd);
+ if (err < 0) {
+ fprintf(stderr, "Failed to receive from parent over socket: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ bpffs_fd = openat(mnt_fd, ".", 0, O_RDWR);
+ if (bpffs_fd < 0) {
+ fprintf(stderr, "Failed openat: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ token_fd = bpf_token_create(bpffs_fd, NULL);
+ if (token_fd < 0) {
+ fprintf(stderr, "Failed bpf_token_create: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ err = callback(token_fd);
+
+cleanup:
+ close(sock_fd);
+ close(mnt_fd);
+ close(fs_fd);
+ close(bpffs_fd);
+ close(token_fd);
+ if (err < 0)
+ exit(err);
+ exit(0);
+}
+
+static int token_parent(int child_pid, struct bpffs_opts *bpffs_opts,
+ int sock_fd)
+{
+ int fs_fd = -1, mnt_fd = -1, err;
+
+ err = recvfd(sock_fd, &fs_fd);
+ if (err < 0) {
+ fprintf(stderr, "Failed to receive from child: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ mnt_fd = materialize_bpffs_fd(fs_fd, bpffs_opts);
+ if (mnt_fd < 0) {
+ fprintf(stderr, "Failed materialize bpffs_fd: %s\n",
+ strerror(errno));
+ err = mnt_fd;
+ goto cleanup;
+ }
+ close(fs_fd);
+
+ /* pass BPF FS context object to parent */
+ err = sendfd(sock_fd, mnt_fd);
+ if (err < 0) {
+ fprintf(stderr, "Failed to send to child: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+cleanup:
+ close(sock_fd);
+ close(fs_fd);
+ close(mnt_fd);
+ return err;
+}
+
+int map_test_bpf_token_capable(int token_fd)
+{
+ int map_fd;
+
+ LIBBPF_OPTS(bpf_map_create_opts, optslib);
+ optslib.map_flags = BPF_F_TOKEN_FD;
+ optslib.token_fd = token_fd;
+ map_fd = bpf_map_create(BPF_MAP_TYPE_XSKMAP, NULL,
+ 4, 4, 16, &optslib);
+
+ if (map_fd < 0) {
+ fprintf(stderr, "Failed to create BPF map: %s\n",
+ strerror(errno));
+ }
+
+ return map_fd;
+}
+
+int map_test_bpf_token_cmd(int token_fd)
+{
+ int map_fd;
+
+ LIBBPF_OPTS(bpf_map_create_opts, optslib);
+ optslib.map_flags = BPF_F_TOKEN_FD;
+ optslib.token_fd = token_fd;
+ map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL,
+ 0, 8, 1, &optslib);
+
+ if (map_fd < 0) {
+ fprintf(stderr, "Failed to create BPF map: %s\n",
+ strerror(errno));
+ }
+
+ return map_fd;
+}
+
+int create_bpf_token(struct bpffs_opts *opts, child_callback_fn child_callback)
+{
+ int err, child_pid = 0;
+ int sock_fds[2] = { -1, -1 };
+
+ err = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds);
+ if (err < 0) {
+ fprintf(stderr, "Failed to create sockets: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+
+ child_pid = fork();
+ if (child_pid < 0) {
+ fprintf(stderr, "Failed fork: %s\n",
+ strerror(errno));
+ err = child_pid;
+ goto cleanup;
+ }
+
+ if (child_pid == 0) {
+ close(sock_fds[0]);
+ err = token_child(sock_fds[1], opts, child_callback);
+ if (err < 0) {
+ fprintf(stderr, "Child failed: %s\n",
+ strerror(errno));
+ }
+ } else {
+ close(sock_fds[1]);
+ err = token_parent(child_pid, opts, sock_fds[0]);
+ if (err < 0) {
+ fprintf(stderr, "Parent failed: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+ err = -(wait_for_pid(child_pid));
+ }
+
+cleanup:
+ close(sock_fds[0]);
+ close(sock_fds[1]);
+
+ if (child_pid > 0)
+ (void)kill(child_pid, SIGKILL);
+
+ return err;
+}
diff --git a/tests/bpf/test b/tests/bpf/test
index a3fd856..5220700 100755
--- a/tests/bpf/test
+++ b/tests/bpf/test
@@ -7,7 +7,7 @@ BEGIN {
$fdr_basedir = "$basedir/../fdreceive";
$binder_basedir = "$basedir/../binder";
- $test_bpf_count = 7;
+ $test_bpf_count = 11;
$test_fdreceive_count = 4;
$test_count = $test_bpf_count + $test_fdreceive_count;
@@ -67,6 +67,14 @@ ok( $result eq 0 );
$result = system "runcon -t test_bpf_t $basedir/bpf_test -p $v";
ok( $result eq 0 );
+# BPF map with token - checks bpf_token_capable
+$result = system "runcon -t test_bpf_t $basedir/bpf_test -c $v";
+ok( $result eq 0 );
+
+# BPF map with token - checks bpf_token_cmd
+$result = system "runcon -t test_bpf_t $basedir/bpf_test -d $v";
+ok( $result eq 0 );
+
# Deny map_create permission
$result =
system "runcon -t test_bpf_deny_map_create_t $basedir/bpf_test -m $v 2>&1";
@@ -92,6 +100,16 @@ $result =
system "runcon -t test_bpf_deny_prog_run_t $basedir/bpf_test -p $v 2>&1";
ok($result);
+# Deny token_cap permission
+$result =
+ system "runcon -t test_bpf_deny_token_cap_t $basedir/bpf_test -c $v 2>&1";
+ok($result);
+
+# Deny token_cmd permission
+$result =
+ system "runcon -t test_bpf_deny_token_cmd_t $basedir/bpf_test -d $v 2>&1";
+ok($result);
+
#
################ BPF Tests for fdreceive #######################
#
--
2.50.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH testsuite] tests/bpf: add tests for bpf token
2025-08-01 15:50 [PATCH testsuite] tests/bpf: add tests for bpf token danieldurning.work
@ 2025-08-01 18:45 ` Stephen Smalley
0 siblings, 0 replies; 2+ messages in thread
From: Stephen Smalley @ 2025-08-01 18:45 UTC (permalink / raw)
To: danieldurning.work; +Cc: selinux, paul, omosnace
On Fri, Aug 1, 2025 at 11:50 AM <danieldurning.work@gmail.com> wrote:
>
> From: Daniel Durning <danieldurning.work@gmail.com>
>
> Added two tests using BPF tokens which will test the bpf_token_capable and bpf_token_cmd LSM hooks.
>
> Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
We will likely need to wrap these new tests with a conditional based
on whether the kernel has the requisite checks merged but we won't
know the proper kernel version against which to check until the kernel
patch is merged. You can look at binder/test for an example of such
kernel version comparisons and conditionals.
I am also unsure of the proper way to handle the BPF API changes for
this case, will defer to others who know more in this area.
Otherwise,
Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Tested-by: Stephen Smalley <stephen.smalley.work@gmail.com>
> ---
> policy/test_bpf.te | 40 ++++
> tests/bpf/Makefile | 1 +
> tests/bpf/bpf_common.c | 35 ++++
> tests/bpf/bpf_common.h | 6 +
> tests/bpf/bpf_test.c | 42 +++-
> tests/bpf/bpf_token.c | 459 +++++++++++++++++++++++++++++++++++++++++
> tests/bpf/test | 20 +-
> 7 files changed, 594 insertions(+), 9 deletions(-)
> create mode 100644 tests/bpf/bpf_token.c
>
> diff --git a/policy/test_bpf.te b/policy/test_bpf.te
> index 5eab0bd..c62d6b0 100644
> --- a/policy/test_bpf.te
> +++ b/policy/test_bpf.te
> @@ -5,6 +5,9 @@
> attribute bpfdomain;
>
> ################################### Main ###################################
> +require {
> + type bpf_t;
> +}
> type test_bpf_t;
> testsuite_domain_type(test_bpf_t)
> typeattribute test_bpf_t bpfdomain;
> @@ -12,6 +15,13 @@ typeattribute test_bpf_t bpfdomain;
> allow test_bpf_t self:process { setrlimit };
> allow test_bpf_t self:capability { sys_resource sys_admin };
> allow test_bpf_t self:bpf { map_create map_read map_write prog_load prog_run };
> +allow test_bpf_t self:cap2_userns bpf;
> +files_mounton_rootfs(test_bpf_t)
> +fs_list_bpf_dirs(test_bpf_t)
> +allow test_bpf_t self:cap_userns { setgid setuid sys_admin };
> +allow test_bpf_t self:user_namespace create;
> +allow test_bpf_t bpf_t:filesystem mount;
> +allow test_bpf_t self:cap_userns net_admin;
>
> ############################## Deny map_create #############################
> type test_bpf_deny_map_create_t;
> @@ -57,3 +67,33 @@ typeattribute test_bpf_deny_prog_run_t bpfdomain;
> allow test_bpf_deny_prog_run_t self:process { setrlimit };
> allow test_bpf_deny_prog_run_t self:capability { sys_resource sys_admin };
> allow test_bpf_deny_prog_run_t self:bpf { map_create map_read map_write prog_load };
> +
> +############################# Deny token_cap ###############################
> +type test_bpf_deny_token_cap_t;
> +testsuite_domain_type(test_bpf_deny_token_cap_t)
> +typeattribute test_bpf_deny_token_cap_t bpfdomain;
> +
> +allow test_bpf_deny_token_cap_t self:process { setrlimit };
> +allow test_bpf_deny_token_cap_t self:capability { sys_resource sys_admin };
> +allow test_bpf_deny_token_cap_t self:cap2_userns bpf;
> +allow test_bpf_deny_token_cap_t self:bpf { map_create map_read map_write prog_load prog_run };
> +files_mounton_rootfs(test_bpf_deny_token_cap_t)
> +fs_list_bpf_dirs(test_bpf_deny_token_cap_t)
> +allow test_bpf_deny_token_cap_t self:cap_userns { setgid setuid sys_admin };
> +allow test_bpf_deny_token_cap_t self:user_namespace create;
> +allow test_bpf_deny_token_cap_t bpf_t:filesystem mount;
> +
> +############################# Deny token_cmd ###############################
> +type test_bpf_deny_token_cmd_t;
> +testsuite_domain_type(test_bpf_deny_token_cmd_t)
> +typeattribute test_bpf_deny_token_cmd_t bpfdomain;
> +
> +allow test_bpf_deny_token_cmd_t self:process { setrlimit };
> +allow test_bpf_deny_token_cmd_t self:capability { sys_resource sys_admin };
> +allow test_bpf_deny_token_cmd_t self:cap2_userns bpf;
> +allow test_bpf_deny_token_cmd_t self:bpf { map_read map_write prog_load prog_run };
> +files_mounton_rootfs(test_bpf_deny_token_cmd_t)
> +fs_list_bpf_dirs(test_bpf_deny_token_cmd_t)
> +allow test_bpf_deny_token_cmd_t self:cap_userns { setgid setuid sys_admin };
> +allow test_bpf_deny_token_cmd_t self:user_namespace create;
> +allow test_bpf_deny_token_cmd_t bpf_t:filesystem mount;
> diff --git a/tests/bpf/Makefile b/tests/bpf/Makefile
> index 1ae8ce9..610a420 100644
> --- a/tests/bpf/Makefile
> +++ b/tests/bpf/Makefile
> @@ -4,6 +4,7 @@ LDLIBS += -lselinux -lbpf
>
> # export so that BPF_ENABLED entries get built correctly on local build
> export CFLAGS += -DHAVE_BPF
> +export CFLAGS += -D_GNU_SOURCE
>
> BPF_ENABLED = ../fdreceive ../binder
>
> diff --git a/tests/bpf/bpf_common.c b/tests/bpf/bpf_common.c
> index 2d97299..97c4d2d 100644
> --- a/tests/bpf/bpf_common.c
> +++ b/tests/bpf/bpf_common.c
> @@ -1,4 +1,6 @@
> +#include <sched.h>
> #include "bpf_common.h"
> +#include "bpf_token.c"
>
> /*
> * v0.7 deprecates some functions in favor of a new API (introduced in v0.6).
> @@ -58,6 +60,39 @@ int create_bpf_prog(void)
> return prog_fd;
> }
>
> +/*
> + * BPF tokens did not exist in the old API - just return 0 if on an older version.
> + */
> +int test_bpf_token_capable(void)
> +{
> +#ifdef USE_NEW_API
> + struct bpffs_opts opts = {
> + .cmds_str = "map_create",
> + .maps_str = "xskmap",
> + };
> +
> + return create_bpf_token(&opts, map_test_bpf_token_capable);
> +
> +#else
> + return 0;
> +#endif
> +}
> +
> +int test_bpf_token_cmd(void)
> +{
> +#ifdef USE_NEW_API
> + struct bpffs_opts opts = {
> + .cmds_str = "map_create",
> + .maps_str = "stack",
> + };
> +
> + return create_bpf_token(&opts, map_test_bpf_token_cmd);
> +
> +#else
> + return 0;
> +#endif
> +}
> +
> /*
> * The default RLIMIT_MEMLOCK is normally 64K, however BPF map/prog requires
> * more than this (the actual threshold varying across arches) so set it to
> diff --git a/tests/bpf/bpf_common.h b/tests/bpf/bpf_common.h
> index 44ac28f..ed34ab6 100644
> --- a/tests/bpf/bpf_common.h
> +++ b/tests/bpf/bpf_common.h
> @@ -8,9 +8,15 @@
> #include <bpf/bpf.h>
> #include <linux/bpf.h>
> #include <sys/resource.h>
> +#include <sys/syscall.h>
> +#include <linux/unistd.h>
> +#include <sys/mount.h>
> +#include <fcntl.h>
>
> extern int create_bpf_map(void);
> extern int create_bpf_prog(void);
> +extern int test_bpf_token_capable(void);
> +extern int test_bpf_token_cmd(void);
> extern void bpf_setrlimit(void);
>
> /* edited eBPF instruction library */
> diff --git a/tests/bpf/bpf_test.c b/tests/bpf/bpf_test.c
> index 3c6a29c..ea7c02b 100644
> --- a/tests/bpf/bpf_test.c
> +++ b/tests/bpf/bpf_test.c
> @@ -7,22 +7,27 @@ static void usage(char *progname)
> "Where:\n\t"
> "-m Create BPF map fd\n\t"
> "-p Create BPF prog fd\n\t"
> + "-c Test BPF token capable\n\t"
> + "-d Test BPF token cmd\n\t"
> "-v Print information.\n", progname);
> exit(-1);
> }
>
> int main(int argc, char *argv[])
> {
> - int opt, result, fd;
> + int opt, result, ret;
> + bool isFd = true;
> bool verbose = false;
> char *context;
>
> enum {
> MAP_FD = 1,
> - PROG_FD
> + PROG_FD,
> + TOKEN_CAP,
> + TOKEN_CMD
> } bpf_fd_type;
>
> - while ((opt = getopt(argc, argv, "mpv")) != -1) {
> + while ((opt = getopt(argc, argv, "mpvcd")) != -1) {
> switch (opt) {
> case 'm':
> bpf_fd_type = MAP_FD;
> @@ -30,6 +35,12 @@ int main(int argc, char *argv[])
> case 'p':
> bpf_fd_type = PROG_FD;
> break;
> + case 'c':
> + bpf_fd_type = TOKEN_CAP;
> + break;
> + case 'd':
> + bpf_fd_type = TOKEN_CMD;
> + break;
> case 'v':
> verbose = true;
> break;
> @@ -57,21 +68,36 @@ int main(int argc, char *argv[])
> if (verbose)
> printf("Creating BPF map\n");
>
> - fd = create_bpf_map();
> + ret = create_bpf_map();
> break;
> case PROG_FD:
> if (verbose)
> printf("Creating BPF prog\n");
>
> - fd = create_bpf_prog();
> + ret = create_bpf_prog();
> + break;
> + case TOKEN_CAP:
> + isFd = false;
> + if (verbose)
> + printf("Creating token and testing bpf_token_capable\n");
> +
> + ret = test_bpf_token_capable();
> + break;
> + case TOKEN_CMD:
> + isFd = false;
> + if (verbose)
> + printf("Creating token and testing bpf_token_cmd\n");
> +
> + ret = test_bpf_token_cmd();
> break;
> default:
> usage(argv[0]);
> }
>
> - if (fd < 0)
> - return fd;
> + if (ret < 0)
> + return ret;
> + else if (isFd)
> + close(ret);
>
> - close(fd);
> return 0;
> }
> diff --git a/tests/bpf/bpf_token.c b/tests/bpf/bpf_token.c
> new file mode 100644
> index 0000000..8e33383
> --- /dev/null
> +++ b/tests/bpf/bpf_token.c
> @@ -0,0 +1,459 @@
> +// Code derived from: linux/source/tools/testing/selftests/bpf/prog_tests/token.c
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
> +
> +#include "bpf_common.h"
> +#include <sys/socket.h>
> +#include <signal.h>
> +#include <sys/wait.h>
> +
> +struct bpffs_opts {
> + __u64 cmds;
> + __u64 maps;
> + __u64 progs;
> + __u64 attachs;
> + const char *cmds_str;
> + const char *maps_str;
> + const char *progs_str;
> + const char *attachs_str;
> +};
> +
> +static inline int sys_fsopen(const char *fsname, unsigned flags)
> +{
> + return syscall(__NR_fsopen, fsname, flags);
> +}
> +
> +static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key,
> + const void *val, int aux)
> +{
> + return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux);
> +}
> +
> +static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags)
> +{
> + return syscall(__NR_fsmount, fs_fd, flags, ms_flags);
> +}
> +
> +static ssize_t write_nointr(int fd, const void *buf, size_t count)
> +{
> + ssize_t ret;
> +
> + do {
> + ret = write(fd, buf, count);
> + } while (ret < 0 && errno == EINTR);
> +
> + return ret;
> +}
> +
> +static int write_file(const char *path, const void *buf, size_t count)
> +{
> + int fd;
> + ssize_t ret;
> +
> + fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW);
> + if (fd < 0)
> + return -1;
> +
> + ret = write_nointr(fd, buf, count);
> + close(fd);
> + if (ret < 0 || (size_t)ret != count)
> + return -1;
> +
> + return 0;
> +}
> +
> +static int wait_for_pid(pid_t pid)
> +{
> + int status, ret;
> +
> +again:
> + ret = waitpid(pid, &status, 0);
> + if (ret == -1) {
> + if (errno == EINTR)
> + goto again;
> +
> + return -1;
> + }
> +
> + if (!WIFEXITED(status))
> + return -1;
> +
> + return WEXITSTATUS(status);
> +}
> +
> +static int sendfd(int sockfd, int fd)
> +{
> + struct msghdr msg = {};
> + struct cmsghdr *cmsg;
> + int fds[1] = { fd }, err;
> + char iobuf[1];
> + struct iovec io = {
> + .iov_base = iobuf,
> + .iov_len = sizeof(iobuf),
> + };
> + union {
> + char buf[CMSG_SPACE(sizeof(fds))];
> + struct cmsghdr align;
> + } u;
> +
> + msg.msg_iov = &io;
> + msg.msg_iovlen = 1;
> + msg.msg_control = u.buf;
> + msg.msg_controllen = sizeof(u.buf);
> + cmsg = CMSG_FIRSTHDR(&msg);
> + cmsg->cmsg_level = SOL_SOCKET;
> + cmsg->cmsg_type = SCM_RIGHTS;
> + cmsg->cmsg_len = CMSG_LEN(sizeof(fds));
> + memcpy(CMSG_DATA(cmsg), fds, sizeof(fds));
> +
> + err = sendmsg(sockfd, &msg, 0);
> + if (err < 0) {
> + err = -errno;
> + return err;
> + }
> +
> + return 0;
> +}
> +
> +static int recvfd(int sockfd, int *fd)
> +{
> + struct msghdr msg = {};
> + struct cmsghdr *cmsg;
> + int fds[1], err;
> + char iobuf[1];
> + struct iovec io = {
> + .iov_base = iobuf,
> + .iov_len = sizeof(iobuf),
> + };
> + union {
> + char buf[CMSG_SPACE(sizeof(fds))];
> + struct cmsghdr align;
> + } u;
> +
> + msg.msg_iov = &io;
> + msg.msg_iovlen = 1;
> + msg.msg_control = u.buf;
> + msg.msg_controllen = sizeof(u.buf);
> +
> + err = recvmsg(sockfd, &msg, 0);
> + if (err < 0) {
> + err = -errno;
> + return err;
> + }
> +
> + cmsg = CMSG_FIRSTHDR(&msg);
> +
> + memcpy(fds, CMSG_DATA(cmsg), sizeof(fds));
> + *fd = fds[0];
> +
> + return 0;
> +}
> +
> +static int create_and_enter_userns(void)
> +{
> + uid_t uid;
> + gid_t gid;
> + char map[100];
> +
> + uid = getuid();
> + gid = getgid();
> +
> + if (unshare(CLONE_NEWUSER))
> + return -1;
> +
> + if (write_file("/proc/self/setgroups", "deny", sizeof("deny") - 1) &&
> + errno != ENOENT)
> + return -1;
> +
> + snprintf(map, sizeof(map), "0 %d 1", uid);
> + if (write_file("/proc/self/uid_map", map, strlen(map)))
> + return -1;
> +
> +
> + snprintf(map, sizeof(map), "0 %d 1", gid);
> + if (write_file("/proc/self/gid_map", map, strlen(map)))
> + return -1;
> +
> + if (setgid(0))
> + return -1;
> +
> + if (setuid(0))
> + return -1;
> +
> + return 0;
> +}
> +
> +int set_delegate_mask(int fs_fd, const char *key, __u64 mask,
> + const char *mask_str)
> +{
> + char buf[32];
> + int err;
> +
> + if (!mask_str) {
> + if (mask == ~0ULL) {
> + mask_str = "any";
> + } else {
> + snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask);
> + mask_str = buf;
> + }
> + }
> +
> + err = sys_fsconfig(fs_fd, FSCONFIG_SET_STRING, key,
> + mask_str, 0);
> + if (err < 0)
> + err = -errno;
> + return err;
> +}
> +
> +int create_bpffs_fd(void)
> +{
> + int fs_fd;
> +
> + fs_fd = sys_fsopen("bpf", 0);
> +
> + return fs_fd;
> +}
> +
> +int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts)
> +{
> + int mnt_fd, err;
> +
> + /* set up token delegation mount options */
> + err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds, opts->cmds_str);
> + if (err < 0) {
> + fprintf(stderr, "Failed to set delegate dms: %s\n",
> + strerror(errno));
> + return -errno;
> + }
> + err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps, opts->maps_str);
> + if (err < 0) {
> + fprintf(stderr, "Failed to set delegate maps: %s\n",
> + strerror(errno));
> + return -errno;
> + }
> + err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs, opts->progs_str);
> + if (err < 0) {
> + fprintf(stderr, "Failed to set delegate progs: %s\n",
> + strerror(errno));
> + return -errno;
> + }
> + err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs,
> + opts->attachs_str);
> + if (err < 0) {
> + fprintf(stderr, "Failed to set delegate attachs: %s\n",
> + strerror(errno));
> + return -errno;
> + }
> +
> + err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
> + if (err < 0) {
> + fprintf(stderr, "Failed fsconfig: %s\n",
> + strerror(errno));
> + return -errno;
> + }
> +
> + mnt_fd = sys_fsmount(fs_fd, 0, 0);
> + if (mnt_fd < 0) {
> + fprintf(stderr, "Failed fsmount: %s\n",
> + strerror(errno));
> + return -errno;
> + }
> +
> + return mnt_fd;
> +}
> +
> +typedef int (*child_callback_fn)(int token_fd);
> +
> +static int token_child(int sock_fd, struct bpffs_opts *opts,
> + child_callback_fn callback)
> +{
> + int fs_fd, mnt_fd, bpffs_fd, token_fd, err;
> +
> + err = create_and_enter_userns();
> + if (err < 0) {
> + fprintf(stderr, "Failed enter_userns: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + err = unshare(CLONE_NEWNS);
> + if (err < 0) {
> + fprintf(stderr, "Failed unshare: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + err = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
> + if (err < 0) {
> + fprintf(stderr, "Failed mount: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + fs_fd = create_bpffs_fd();
> + if (fs_fd < 0) {
> + fprintf(stderr, "Failed create bpffs_fd: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + err = sendfd(sock_fd, fs_fd);
> + if (err < 0) {
> + fprintf(stderr, "Failed to send to parent over socket: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + err = recvfd(sock_fd, &mnt_fd);
> + if (err < 0) {
> + fprintf(stderr, "Failed to receive from parent over socket: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + bpffs_fd = openat(mnt_fd, ".", 0, O_RDWR);
> + if (bpffs_fd < 0) {
> + fprintf(stderr, "Failed openat: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + token_fd = bpf_token_create(bpffs_fd, NULL);
> + if (token_fd < 0) {
> + fprintf(stderr, "Failed bpf_token_create: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + err = callback(token_fd);
> +
> +cleanup:
> + close(sock_fd);
> + close(mnt_fd);
> + close(fs_fd);
> + close(bpffs_fd);
> + close(token_fd);
> + if (err < 0)
> + exit(err);
> + exit(0);
> +}
> +
> +static int token_parent(int child_pid, struct bpffs_opts *bpffs_opts,
> + int sock_fd)
> +{
> + int fs_fd = -1, mnt_fd = -1, err;
> +
> + err = recvfd(sock_fd, &fs_fd);
> + if (err < 0) {
> + fprintf(stderr, "Failed to receive from child: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + mnt_fd = materialize_bpffs_fd(fs_fd, bpffs_opts);
> + if (mnt_fd < 0) {
> + fprintf(stderr, "Failed materialize bpffs_fd: %s\n",
> + strerror(errno));
> + err = mnt_fd;
> + goto cleanup;
> + }
> + close(fs_fd);
> +
> + /* pass BPF FS context object to parent */
> + err = sendfd(sock_fd, mnt_fd);
> + if (err < 0) {
> + fprintf(stderr, "Failed to send to child: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> +cleanup:
> + close(sock_fd);
> + close(fs_fd);
> + close(mnt_fd);
> + return err;
> +}
> +
> +int map_test_bpf_token_capable(int token_fd)
> +{
> + int map_fd;
> +
> + LIBBPF_OPTS(bpf_map_create_opts, optslib);
> + optslib.map_flags = BPF_F_TOKEN_FD;
> + optslib.token_fd = token_fd;
> + map_fd = bpf_map_create(BPF_MAP_TYPE_XSKMAP, NULL,
> + 4, 4, 16, &optslib);
> +
> + if (map_fd < 0) {
> + fprintf(stderr, "Failed to create BPF map: %s\n",
> + strerror(errno));
> + }
> +
> + return map_fd;
> +}
> +
> +int map_test_bpf_token_cmd(int token_fd)
> +{
> + int map_fd;
> +
> + LIBBPF_OPTS(bpf_map_create_opts, optslib);
> + optslib.map_flags = BPF_F_TOKEN_FD;
> + optslib.token_fd = token_fd;
> + map_fd = bpf_map_create(BPF_MAP_TYPE_STACK, NULL,
> + 0, 8, 1, &optslib);
> +
> + if (map_fd < 0) {
> + fprintf(stderr, "Failed to create BPF map: %s\n",
> + strerror(errno));
> + }
> +
> + return map_fd;
> +}
> +
> +int create_bpf_token(struct bpffs_opts *opts, child_callback_fn child_callback)
> +{
> + int err, child_pid = 0;
> + int sock_fds[2] = { -1, -1 };
> +
> + err = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds);
> + if (err < 0) {
> + fprintf(stderr, "Failed to create sockets: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> +
> + child_pid = fork();
> + if (child_pid < 0) {
> + fprintf(stderr, "Failed fork: %s\n",
> + strerror(errno));
> + err = child_pid;
> + goto cleanup;
> + }
> +
> + if (child_pid == 0) {
> + close(sock_fds[0]);
> + err = token_child(sock_fds[1], opts, child_callback);
> + if (err < 0) {
> + fprintf(stderr, "Child failed: %s\n",
> + strerror(errno));
> + }
> + } else {
> + close(sock_fds[1]);
> + err = token_parent(child_pid, opts, sock_fds[0]);
> + if (err < 0) {
> + fprintf(stderr, "Parent failed: %s\n",
> + strerror(errno));
> + goto cleanup;
> + }
> + err = -(wait_for_pid(child_pid));
> + }
> +
> +cleanup:
> + close(sock_fds[0]);
> + close(sock_fds[1]);
> +
> + if (child_pid > 0)
> + (void)kill(child_pid, SIGKILL);
> +
> + return err;
> +}
> diff --git a/tests/bpf/test b/tests/bpf/test
> index a3fd856..5220700 100755
> --- a/tests/bpf/test
> +++ b/tests/bpf/test
> @@ -7,7 +7,7 @@ BEGIN {
> $fdr_basedir = "$basedir/../fdreceive";
> $binder_basedir = "$basedir/../binder";
>
> - $test_bpf_count = 7;
> + $test_bpf_count = 11;
> $test_fdreceive_count = 4;
>
> $test_count = $test_bpf_count + $test_fdreceive_count;
> @@ -67,6 +67,14 @@ ok( $result eq 0 );
> $result = system "runcon -t test_bpf_t $basedir/bpf_test -p $v";
> ok( $result eq 0 );
>
> +# BPF map with token - checks bpf_token_capable
> +$result = system "runcon -t test_bpf_t $basedir/bpf_test -c $v";
> +ok( $result eq 0 );
> +
> +# BPF map with token - checks bpf_token_cmd
> +$result = system "runcon -t test_bpf_t $basedir/bpf_test -d $v";
> +ok( $result eq 0 );
> +
> # Deny map_create permission
> $result =
> system "runcon -t test_bpf_deny_map_create_t $basedir/bpf_test -m $v 2>&1";
> @@ -92,6 +100,16 @@ $result =
> system "runcon -t test_bpf_deny_prog_run_t $basedir/bpf_test -p $v 2>&1";
> ok($result);
>
> +# Deny token_cap permission
> +$result =
> + system "runcon -t test_bpf_deny_token_cap_t $basedir/bpf_test -c $v 2>&1";
> +ok($result);
> +
> +# Deny token_cmd permission
> +$result =
> + system "runcon -t test_bpf_deny_token_cmd_t $basedir/bpf_test -d $v 2>&1";
> +ok($result);
> +
> #
> ################ BPF Tests for fdreceive #######################
> #
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-08-01 18:46 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-01 15:50 [PATCH testsuite] tests/bpf: add tests for bpf token danieldurning.work
2025-08-01 18:45 ` Stephen Smalley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).