diff --git a/bind-mount.c b/bind-mount.c index a2e1ac6c..a7a729dd 100644 --- a/bind-mount.c +++ b/bind-mount.c @@ -476,6 +476,15 @@ bind_mount (int proc_fd, be safe to ignore because its not something the user can access. */ if (errno != EACCES) { + /* And if we don't need a security boundary, we can also + * ignore other remount errors for submounts. */ + if (options & BIND_FAIL_OPEN) + { + warn ("Can't remount %s submount (%s), ignoring error", + mount_tab[i].mountpoint, strerror (errno)); + continue; + } + if (failing_path != NULL) *failing_path = xstrdup (mount_tab[i].mountpoint); diff --git a/bind-mount.h b/bind-mount.h index 8a361fbd..8f2d5108 100644 --- a/bind-mount.h +++ b/bind-mount.h @@ -25,6 +25,7 @@ typedef enum { BIND_READONLY = (1 << 0), BIND_DEVICES = (1 << 2), BIND_RECURSIVE = (1 << 3), + BIND_FAIL_OPEN = (1 << 4), } bind_option_t; typedef enum diff --git a/bubblewrap.c b/bubblewrap.c index 2fb926c4..3b9719c4 100644 --- a/bubblewrap.c +++ b/bubblewrap.c @@ -94,6 +94,7 @@ static int opt_tmp_overlay_count = 0; static int next_perms = -1; static size_t next_size_arg = 0; static int next_overlay_src_count = 0; +static bool opt_not_a_security_boundary = false; #define CAP_TO_MASK_0(x) (1L << ((x) & 31)) #define CAP_TO_MASK_1(x) CAP_TO_MASK_0(x - 32) @@ -350,6 +351,8 @@ usage (int ecode, FILE *out) " --perms OCTAL Set permissions of next argument (--bind-data, --file, etc.)\n" " --size BYTES Set size of next argument (only for --tmpfs)\n" " --chmod OCTAL PATH Change permissions of PATH (must already exist)\n" + " --not-a-security-boundary Do not fail hard when some sandbox setup steps fail;\n" + " use only when the sandbox is not a security boundary\n" ); exit (ecode); } @@ -1003,9 +1006,18 @@ setup_newroot (bool unshare_pid) else if (ensure_file (dest, 0444) != 0) die_with_error ("Can't create file at %s", op->dest); - setup_op_bind_mount ((op->type == SETUP_RO_BIND_MOUNT ? BIND_READONLY : 0) | - (op->type == SETUP_DEV_BIND_MOUNT ? BIND_DEVICES : 0), - source, dest); + bind_option_t bind_flags = 0; + + if (opt_not_a_security_boundary) + bind_flags |= BIND_FAIL_OPEN; + + if (op->type == SETUP_RO_BIND_MOUNT) + bind_flags |= BIND_READONLY; + + if (op->type == SETUP_DEV_BIND_MOUNT) + bind_flags |= BIND_DEVICES; + + setup_op_bind_mount (bind_flags, source, dest); if (op->fd >= 0) { @@ -2427,6 +2439,10 @@ parse_args_recurse (int *argcp, argv += 2; argc -= 2; } + else if (strcmp (arg, "--not-a-security-boundary") == 0) + { + opt_not_a_security_boundary = true; + } else if (strcmp (arg, "--") == 0) { argv += 1; diff --git a/bwrap.xml b/bwrap.xml index 61fb0445..ea9d118d 100644 --- a/bwrap.xml +++ b/bwrap.xml @@ -614,6 +614,33 @@ command line. Please be careful to the order they are specified. + + + + + Declare that this invocation of bwrap is not + intended to create a security boundary between the sandbox and the + host system. When this option is given, certain non-fatal sandbox + setup failures (such as a bind mount failing because an automounter + did not respond in time) will produce a warning and will be skipped, + rather than causing bwrap to exit with an error. + The effect of this option might be extended to make other sandbox + setup operations non-fatal in future releases of bubblewrap. + + + This option is intended for callers such as + xdg-dbus-proxy or Steam that use + bwrap to adjust the filesystem layout for a + process, but do not rely on it to create a security boundary. + + + Other operations that are fundamental to establishing the sandbox + (creating namespaces, pivot_root, + dropping capabilities) will still cause a hard failure + regardless of this option. + + + diff --git a/tests/test-run.sh b/tests/test-run.sh index 1003e8c4..2d0d307d 100755 --- a/tests/test-run.sh +++ b/tests/test-run.sh @@ -689,4 +689,13 @@ else fi fi +# Smoke-test --not-a-security-boundary +# +# Setting up an unavailable automount and triggering the right conditions is +# complicated to do here, but we can at least check that the option is there, +# and that it stays there. + +$RUN --not-a-security-boundary true +ok "Accepts --not-a-security-boundary" + done_testing