summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys-utils/unshare.120
-rw-r--r--sys-utils/unshare.c44
2 files changed, 58 insertions, 6 deletions
diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1
index 99a0d0ae4..6fc71f4f7 100644
--- a/sys-utils/unshare.1
+++ b/sys-utils/unshare.1
@@ -14,12 +14,14 @@ options. Unshareable namespaces are:
.BR "mount namespace"
Mounting and unmounting filesystems will not affect the rest of the system
(\fBCLONE_NEWNS\fP flag), except for filesystems which are explicitly marked as
-shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP for the
-\fBshared\fP flags).
+shared (with \fBmount --make-shared\fP; see \fI/proc/self/mountinfo\fP or
+\fBfindmnt -o+PROPAGATION\fP for the \fBshared\fP flags).
.sp
-It's recommended to use \fBmount --make-rprivate\fP or \fBmount --make-rslave\fP
-after \fBunshare --mount\fP to make sure that mountpoints in the new namespace
-are really unshared from the parental namespace.
+.B unshare
+since util-linux version 2.27 automatically sets propagation to \fBprivate\fP
+in the new mount namespace to make sure that the new namespace is really
+unshared. This feature is possible to disable by option \fB\-\-propagation unchanged\fP.
+Note that \fBprivate\fP is the kernel default.
.TP
.BR "UTS namespace"
Setting hostname or domainname will not affect the rest of the system.
@@ -84,7 +86,13 @@ the mount namespace) even when run unprivileged. As a mere convenience feature,
more sophisticated use cases, such as mapping multiple ranges of UIDs and GIDs.
This option implies --setgroups=deny.
.TP
-.BR \-s , " \-\-setgroups \fIallow|deny\fP"
+.BR "\-\-propagation \fIprivate|shared|slave|unchanged\fP"
+Recursively sets mount propagation flag in the new mount namespace. The default
+is to set the propagation to \fIprivate\fP, this feature is possible to disable
+by \fIunchanged\fP argument. The options is silently ignored when mount namespace (\fB\-\-mount\fP)
+is not requested.
+.TP
+.BR "\-\-setgroups \fIallow|deny\fP"
Allow or deny
.BR setgroups (2)
syscall in user namespaces.
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 58e91648a..18a7c7bda 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -39,6 +39,9 @@
#include "pathnames.h"
#include "all-io.h"
+/* 'private' is kernel default */
+#define UNSHARE_PROPAGATION_DEFAULT (MS_REC | MS_PRIVATE)
+
enum {
SETGROUPS_NONE = -1,
SETGROUPS_DENY = 0,
@@ -100,6 +103,36 @@ static void map_id(const char *file, uint32_t from, uint32_t to)
close(fd);
}
+static unsigned long parse_propagation(const char *str)
+{
+ size_t i;
+ static const struct prop_opts {
+ const char *name;
+ unsigned long flag;
+ } opts[] = {
+ { "slave", MS_REC | MS_SLAVE },
+ { "private", MS_REC | MS_PRIVATE },
+ { "shared", MS_REC | MS_SHARED },
+ { "unchanged", 0 }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(opts); i++) {
+ if (strcmp(opts[i].name, str) == 0)
+ return opts[i].flag;
+ }
+
+ errx(EXIT_FAILURE, _("unsupported propagation mode: %s"), str);
+}
+
+static void set_propagation(unsigned long flags)
+{
+ if (flags == 0)
+ return;
+
+ if (mount("none", "/", NULL, flags, NULL) != 0)
+ err(EXIT_FAILURE, _("cannot change root filesystem propagation"));
+}
+
static void usage(int status)
{
FILE *out = status == EXIT_SUCCESS ? stdout : stderr;
@@ -121,6 +154,8 @@ static void usage(int status)
fputs(_(" -f, --fork fork before launching <program>\n"), out);
fputs(_(" --mount-proc[=<dir>] mount proc filesystem first (implies --mount)\n"), out);
fputs(_(" -r, --map-root-user map current user to root (implies --user)\n"), out);
+ fputs(_(" --propagation <slave|shared|private|unchanged>\n"
+ " modify mount propagation in mount namespace\n"), out);
fputs(_(" -s, --setgroups allow|deny control the setgroups syscall in user namespaces\n"), out);
fputs(USAGE_SEPARATOR, out);
@@ -135,6 +170,7 @@ int main(int argc, char *argv[])
{
enum {
OPT_MOUNTPROC = CHAR_MAX + 1,
+ OPT_PROPAGATION,
OPT_SETGROUPS
};
static const struct option longopts[] = {
@@ -149,6 +185,7 @@ int main(int argc, char *argv[])
{ "fork", no_argument, 0, 'f' },
{ "mount-proc", optional_argument, 0, OPT_MOUNTPROC },
{ "map-root-user", no_argument, 0, 'r' },
+ { "propagation", required_argument, 0, OPT_PROPAGATION },
{ "setgroups", required_argument, 0, OPT_SETGROUPS },
{ NULL, 0, 0, 0 }
};
@@ -157,6 +194,7 @@ int main(int argc, char *argv[])
int unshare_flags = 0;
int c, forkit = 0, maproot = 0;
const char *procmnt = NULL;
+ unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT;
uid_t real_euid = geteuid();
gid_t real_egid = getegid();;
@@ -204,6 +242,9 @@ int main(int argc, char *argv[])
case OPT_SETGROUPS:
setgrpcmd = setgroups_str2id(optarg);
break;
+ case OPT_PROPAGATION:
+ propagation = parse_propagation(optarg);
+ break;
default:
usage(EXIT_FAILURE);
}
@@ -248,6 +289,9 @@ int main(int argc, char *argv[])
} else if (setgrpcmd != SETGROUPS_NONE)
setgroups_control(setgrpcmd);
+ if ((unshare_flags & CLONE_NEWNS) && propagation)
+ set_propagation(propagation);
+
if (procmnt &&
(mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 ||
mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0))