Commit 07ee18a0 authored by Matteo Croce's avatar Matteo Croce Committed by Andrii Nakryiko
Browse files

selftests/bpf: Don't call fsopen() as privileged user

In the BPF token example, the fsopen() syscall is called as privileged
user. This is unneeded because fsopen() can be called also as
unprivileged user from the user namespace.
As the `fs_fd` file descriptor which was sent back and forth is still the
same, keep it open instead of cloning and closing it twice via SCM_RIGHTS.

cfr. https://github.com/systemd/systemd/pull/36134



Signed-off-by: default avatarMatteo Croce <teknoraver@meta.com>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarChristian Brauner <brauner@kernel.org>
Link: https://lore.kernel.org/bpf/20250701183123.31781-1-technoboy85@gmail.com
parent 1230be82
Loading
Loading
Loading
Loading
+21 −20
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ static int create_bpffs_fd(void)

static int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts)
{
	int mnt_fd, err;
	int err;

	/* set up token delegation mount options */
	err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds, opts->cmds_str);
@@ -136,12 +136,7 @@ static int materialize_bpffs_fd(int fs_fd, struct bpffs_opts *opts)
	if (err < 0)
		return -errno;

	/* create O_PATH fd for detached mount */
	mnt_fd = sys_fsmount(fs_fd, 0, 0);
	if (err < 0)
		return -errno;

	return mnt_fd;
	return 0;
}

/* send FD over Unix domain (AF_UNIX) socket */
@@ -287,6 +282,7 @@ static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callba
{
	int mnt_fd = -1, fs_fd = -1, err = 0, bpffs_fd = -1, token_fd = -1;
	struct token_lsm *lsm_skel = NULL;
	char one;

	/* load and attach LSM "policy" before we go into unpriv userns */
	lsm_skel = token_lsm__open_and_load();
@@ -333,13 +329,19 @@ static void child(int sock_fd, struct bpffs_opts *opts, child_callback_fn callba
	err = sendfd(sock_fd, fs_fd);
	if (!ASSERT_OK(err, "send_fs_fd"))
		goto cleanup;
	zclose(fs_fd);

	/* wait that the parent reads the fd, does the fsconfig() calls
	 * and send us a signal that it is done
	 */
	err = read(sock_fd, &one, sizeof(one));
	if (!ASSERT_GE(err, 0, "read_one"))
		goto cleanup;

	/* avoid mucking around with mount namespaces and mounting at
	 * well-known path, just get detach-mounted BPF FS fd back from parent
	 * well-known path, just create O_PATH fd for detached mount
	 */
	err = recvfd(sock_fd, &mnt_fd);
	if (!ASSERT_OK(err, "recv_mnt_fd"))
	mnt_fd = sys_fsmount(fs_fd, 0, 0);
	if (!ASSERT_OK_FD(mnt_fd, "mnt_fd"))
		goto cleanup;

	/* try to fspick() BPF FS and try to add some delegation options */
@@ -429,24 +431,24 @@ static int wait_for_pid(pid_t pid)

static void parent(int child_pid, struct bpffs_opts *bpffs_opts, int sock_fd)
{
	int fs_fd = -1, mnt_fd = -1, token_fd = -1, err;
	int fs_fd = -1, token_fd = -1, err;
	char one = 1;

	err = recvfd(sock_fd, &fs_fd);
	if (!ASSERT_OK(err, "recv_bpffs_fd"))
		goto cleanup;

	mnt_fd = materialize_bpffs_fd(fs_fd, bpffs_opts);
	if (!ASSERT_GE(mnt_fd, 0, "materialize_bpffs_fd")) {
	err = materialize_bpffs_fd(fs_fd, bpffs_opts);
	if (!ASSERT_GE(err, 0, "materialize_bpffs_fd")) {
		err = -EINVAL;
		goto cleanup;
	}
	zclose(fs_fd);

	/* pass BPF FS context object to parent */
	err = sendfd(sock_fd, mnt_fd);
	if (!ASSERT_OK(err, "send_mnt_fd"))
	/* notify the child that we did the fsconfig() calls and it can proceed. */
	err = write(sock_fd, &one, sizeof(one));
	if (!ASSERT_EQ(err, sizeof(one), "send_one"))
		goto cleanup;
	zclose(mnt_fd);
	zclose(fs_fd);

	/* receive BPF token FD back from child for some extra tests */
	err = recvfd(sock_fd, &token_fd);
@@ -459,7 +461,6 @@ static void parent(int child_pid, struct bpffs_opts *bpffs_opts, int sock_fd)
cleanup:
	zclose(sock_fd);
	zclose(fs_fd);
	zclose(mnt_fd);
	zclose(token_fd);

	if (child_pid > 0)