diff --git a/bind-mount.c b/bind-mount.c
index 877b0955..6836796a 100644
--- a/bind-mount.c
+++ b/bind-mount.c
@@ -241,7 +241,6 @@ parse_mountinfo (int proc_fd,
int max_id;
unsigned int n_lines;
int root;
-
mountinfo = load_file_at (proc_fd, "self/mountinfo");
if (mountinfo == NULL)
die_with_error ("Can't open /proc/self/mountinfo");
@@ -376,6 +375,7 @@ parse_mountinfo (int proc_fd,
bind_mount_result
bind_mount (int proc_fd,
+ int p_priv,
const char *src,
const char *dest,
bind_option_t options)
@@ -391,10 +391,12 @@ bind_mount (int proc_fd,
cleanup_free char *kernel_case_combination = NULL;
cleanup_fd int dest_fd = -1;
int i;
-
+ int current_propagation = 0;
+ if (p_priv == 1)
+ current_propagation = MS_PRIVATE;
if (src)
{
- if (mount (src, dest, NULL, MS_SILENT | MS_BIND | (recursive ? MS_REC : 0), NULL) != 0)
+ if (mount (src, dest, NULL, MS_SILENT | MS_BIND | current_propagation | (recursive ? MS_REC : 0), NULL) != 0)
return BIND_MOUNT_ERROR_MOUNT;
}
@@ -436,7 +438,7 @@ bind_mount (int proc_fd,
new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | (readonly ? MS_RDONLY : 0);
if (new_flags != current_flags &&
mount ("none", resolved_dest,
- NULL, MS_SILENT | MS_BIND | MS_REMOUNT | new_flags, NULL) != 0)
+ NULL, MS_SILENT | MS_BIND | MS_REMOUNT | new_flags | current_propagation, NULL) != 0)
return BIND_MOUNT_ERROR_REMOUNT_DEST;
/* We need to work around the fact that a bind mount does not apply the flags, so we need to manually
@@ -451,7 +453,7 @@ bind_mount (int proc_fd,
new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | (readonly ? MS_RDONLY : 0);
if (new_flags != current_flags &&
mount ("none", mount_tab[i].mountpoint,
- NULL, MS_SILENT | MS_BIND | MS_REMOUNT | new_flags, NULL) != 0)
+ NULL, MS_SILENT | MS_BIND | MS_REMOUNT | new_flags | current_propagation, NULL) != 0)
{
/* If we can't read the mountpoint we can't remount it, but that should
be safe to ignore because its not something the user can access. */
diff --git a/bind-mount.h b/bind-mount.h
index 1fac3e58..2b072558 100644
--- a/bind-mount.h
+++ b/bind-mount.h
@@ -40,6 +40,7 @@ typedef enum
} bind_mount_result;
bind_mount_result bind_mount (int proc_fd,
+ int p_priv,
const char *src,
const char *dest,
bind_option_t options);
diff --git a/bubblewrap.c b/bubblewrap.c
index b17ff990..6107ab60 100644
--- a/bubblewrap.c
+++ b/bubblewrap.c
@@ -85,6 +85,7 @@ int opt_userns_block_fd = -1;
int opt_info_fd = -1;
int opt_json_status_fd = -1;
int opt_seccomp_fd = -1;
+int opt_propagation = 0;
const char *opt_sandbox_hostname = NULL;
char *opt_args_data = NULL; /* owned */
int opt_userns_fd = -1;
@@ -331,6 +332,7 @@ usage (int ecode, FILE *out)
" --symlink SRC DEST Create symlink at DEST with target SRC\n"
" --seccomp FD Load and use seccomp rules from FD (not repeatable)\n"
" --add-seccomp-fd FD Load and use seccomp rules from FD (repeatable)\n"
+ " --private Set mount propagation to private\n"
" --block-fd FD Block on FD until some data to read is available\n"
" --userns-block-fd FD Block on FD until the user namespace is ready\n"
" --info-fd FD Write information about the running container to FD\n"
@@ -1070,7 +1072,7 @@ privileged_op (int privileged_op_socket,
break;
case PRIV_SEP_OP_REMOUNT_RO_NO_RECURSIVE:
- bind_result = bind_mount (proc_fd, NULL, arg2, BIND_READONLY);
+ bind_result = bind_mount (proc_fd, opt_propagation, NULL, arg2, BIND_READONLY);
if (bind_result != BIND_MOUNT_SUCCESS)
die_with_bind_result (bind_result, errno,
@@ -1081,7 +1083,7 @@ privileged_op (int privileged_op_socket,
case PRIV_SEP_OP_BIND_MOUNT:
/* We always bind directories recursively, otherwise this would let us
access files that are otherwise covered on the host */
- bind_result = bind_mount (proc_fd, arg1, arg2, BIND_RECURSIVE | flags);
+ bind_result = bind_mount (proc_fd, opt_propagation, arg1, arg2, BIND_RECURSIVE | flags);
if (bind_result != BIND_MOUNT_SUCCESS)
die_with_bind_result (bind_result, errno,
@@ -2149,6 +2151,8 @@ parse_args_recurse (int *argcp,
argv += 1;
argc -= 1;
}
+ else if (strcmp (arg, "--private") == 0)
+ opt_propagation = 1;
else if (strcmp (arg, "--add-seccomp-fd") == 0)
{
int the_fd;
@@ -2956,7 +2960,12 @@ main (int argc,
/* Mark everything as slave, so that we still
* receive mounts from the real root, but don't
* propagate mounts to the real root. */
- if (mount (NULL, "/", NULL, MS_SILENT | MS_SLAVE | MS_REC, NULL) < 0)
+ int current_propagation;
+ if (opt_propagation == 0)
+ current_propagation = MS_SLAVE;
+ else
+ current_propagation = MS_PRIVATE;
+ if (mount (NULL, "/", NULL, MS_SILENT | current_propagation | MS_REC, NULL) < 0)
die_with_error ("Failed to make / slave");
/* Create a tmpfs which we will use as / in the namespace */
diff --git a/bwrap.xml b/bwrap.xml
index 2baec5d8..f0794ca7 100644
--- a/bwrap.xml
+++ b/bwrap.xml
@@ -161,6 +161,10 @@
Use a custom hostname in the sandbox (requires )
+
+
+ Use private propagation instead of slave one (prevents host mounts from propagating to the sandbox, but may cause some problems, for example, by keeping removable media mounted in the sandbox).
+ Options about environment setup:
diff --git a/completions/bash/bwrap b/completions/bash/bwrap
index c57d9abe..710c8b06 100644
--- a/completions/bash/bwrap
+++ b/completions/bash/bwrap
@@ -13,6 +13,7 @@ _bwrap() {
--clearenv
--help
--new-session
+ --private
--unshare-all
--unshare-cgroup
--unshare-cgroup-try
diff --git a/completions/zsh/_bwrap b/completions/zsh/_bwrap
index 1e365f09..17e41f7d 100644
--- a/completions/zsh/_bwrap
+++ b/completions/zsh/_bwrap
@@ -41,6 +41,7 @@ _bwrap_args=(
'--new-session[Create a new terminal session]'
'--perms[Set permissions for next action argument]: :_guard "[0-7]#" "permissions in octal": :->after_perms'
'--pidns[Use this user namespace (as parent namespace if using --unshare-pid)]: :'
+ '--private[Use private propagation instead of slave]'
'--proc[Mount new procfs on DEST]:mount point for procfs:_files -/'
'--remount-ro[Remount DEST as readonly; does not recursively remount]:mount point to remount read-only:_files'
'--ro-bind-try[Equal to --ro-bind but ignores non-existent SRC]:source:_files:destination:_files'