Projects
Mega:24.03:SP1:Everything
bubblewrap
_service:tar_scm:backport-Add--bind-fd-and--ro-...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:backport-Add--bind-fd-and--ro-bind-fd-to-let-you-bind-a-O_PATH-fd.patch of Package bubblewrap
From a253257cd298892da43e15201d83f9a02c9b58b5 Mon Sep 17 00:00:00 2001 From: Alexander Larsson <alexl@redhat.com> Date: Tue, 18 Jun 2024 10:20:36 +0200 Subject: [PATCH] Add --bind-fd and --ro-bind-fd to let you bind a O_PATH fd. Origin: https://github.com/containers/bubblewrap/commit/a253257cd298892da43e15201d83f9a02c9b58b5 This is useful for example if you for some reason don't have the real path. It is also a way to make bind-mounts race-free (i.e. to have the mount actually be the thing you wanted to be mounted, avoiding issues where some other process replaces the target in parallel with the bwrap launch. Unfortunately due to some technical details we can't actually directly mount the dirfd, as they come from different user namespace which is not permitted, but at least we can delay resolving the fd to a path as much as possible, and then validate after mount that we actually mounted the right thing. Signed-off-by: Alexander Larsson <alexl@redhat.com> --- bubblewrap.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test-run.sh | 6 ++++++ 2 files changed, 56 insertions(+) diff --git a/bubblewrap.c b/bubblewrap.c index c414bb06..bc75da47 100644 --- a/bubblewrap.c +++ b/bubblewrap.c @@ -341,6 +341,8 @@ usage (int ecode, FILE *out) " --dev-bind-try SRC DEST Equal to --dev-bind but ignores non-existent SRC\n" " --ro-bind SRC DEST Bind mount the host path SRC readonly on DEST\n" " --ro-bind-try SRC DEST Equal to --ro-bind but ignores non-existent SRC\n" + " --bind-fd FD DEST Bind open directory or path fd on DEST\n" + " --ro-bind-fd FD DEST Bind open directory or path fd read-only on DEST\n" " --remount-ro DEST Remount DEST as readonly; does not recursively remount\n" " --exec-label LABEL Exec label for the sandbox\n" " --file-label LABEL File label for temporary sandbox content\n" @@ -1231,6 +1233,30 @@ setup_newroot (bool unshare_pid, (op->type == SETUP_RO_BIND_MOUNT ? BIND_READONLY : 0) | (op->type == SETUP_DEV_BIND_MOUNT ? BIND_DEVICES : 0), 0, 0, source, dest); + + if (op->fd >= 0) + { + struct stat fd_st, mount_st; + + /* When using bind-fd, there is a race condition between resolving the fd as a magic symlink + * and mounting it, where someone could replace what is at the symlink target. Ideally + * we would not even resolve the symlink and directly bind-mount from the fd, but unfortunately + * we can't do that, because its not permitted to bind mount a fd from another user namespace. + * So, we resolve, mount and then compare fstat+stat to detect the race. */ + + if (fstat(op->fd, &fd_st) != 0) + die_with_error("Can't stat fd %d", op->fd); + if (lstat(dest, &mount_st) != 0) + die_with_error("Can't stat mount at %s", dest); + + if (fd_st.st_ino != mount_st.st_ino || + fd_st.st_dev != mount_st.st_dev) + die_with_error("Race condition binding dirfd"); + + close(op->fd); + op->fd = -1; + } + break; case SETUP_REMOUNT_RO_NO_RECURSIVE: @@ -1874,6 +1900,30 @@ parse_args_recurse (int *argcp, if (strcmp(arg, "--dev-bind-try") == 0) op->flags = ALLOW_NOTEXIST; + argv += 2; + argc -= 2; + } + else if (strcmp (arg, "--bind-fd") == 0 || + strcmp (arg, "--ro-bind-fd") == 0) + { + int src_fd; + char *endptr; + + if (argc < 3) + die ("--bind-fd takes two arguments"); + + src_fd = strtol (argv[1], &endptr, 10); + if (argv[1][0] == 0 || endptr[0] != 0 || src_fd < 0) + die ("Invalid fd: %s", argv[1]); + + if (strcmp(arg, "--ro-bind-fd") == 0) + op = setup_op_new (SETUP_RO_BIND_MOUNT); + else + op = setup_op_new (SETUP_BIND_MOUNT); + op->source = xasprintf ("/proc/self/fd/%d", src_fd); + op->fd = src_fd; + op->dest = argv[2]; + argv += 2; argc -= 2; } diff --git a/tests/test-run.sh b/tests/test-run.sh index 6151f1a8..8d063b57 100755 --- a/tests/test-run.sh +++ b/tests/test-run.sh @@ -565,4 +565,10 @@ $RUN --argv0 right sh -c 'echo $0' > stdout assert_files_equal stdout reference echo "ok - environment manipulation" +echo "foobar" > file-data +$RUN --proc /proc --dev /dev --bind / / --bind-fd 100 /tmp cat /tmp/file-data 100< . > stdout +assert_file_has_content stdout foobar + +echo "ok - bind-fd" + echo "ok - End of test"
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2