util-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] unshare: add some chroot magic
@ 2018-09-28 12:45 Laurent Vivier
  2018-09-28 12:45 ` [PATCH 1/2] unshare: allow to set a new root Laurent Vivier
  2018-09-28 12:45 ` [PATCH 2/2] unshare: allows to set user ID and group ID Laurent Vivier
  0 siblings, 2 replies; 6+ messages in thread
From: Laurent Vivier @ 2018-09-28 12:45 UTC (permalink / raw)
  To: util-linux; +Cc: Laurent Vivier

This couple of patches merges "unshare chroot" in one command.
Parameter names are copied from nsenter.
Doing like this the /proc filesystem is correctly mounted in the
new root with "--mount-proc".

Laurent Vivier (2):
  unshare: allow to set a new root
  unshare: allows to set user ID and group ID

 bash-completion/unshare |  6 ++++-
 sys-utils/unshare.1     | 13 ++++++++++
 sys-utils/unshare.c     | 53 +++++++++++++++++++++++++++++++++++++----
 3 files changed, 67 insertions(+), 5 deletions(-)

-- 
2.17.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] unshare: allow to set a new root
  2018-09-28 12:45 [PATCH 0/2] unshare: add some chroot magic Laurent Vivier
@ 2018-09-28 12:45 ` Laurent Vivier
  2018-10-04 10:11   ` Karel Zak
  2018-09-28 12:45 ` [PATCH 2/2] unshare: allows to set user ID and group ID Laurent Vivier
  1 sibling, 1 reply; 6+ messages in thread
From: Laurent Vivier @ 2018-09-28 12:45 UTC (permalink / raw)
  To: util-linux; +Cc: Laurent Vivier

This patch instroduces two new parameters to set the new
root and the new working directory in this new root.

This allows to combine "unshare chroot" in one command,
and doing like this the /proc filesystem is correctly
mounted in the new root with "--mount-proc".

The new parameters are -R, --root and -w, --wd. The names
are the same as for nsenter, except for "-r" that is already
used by "--map-root-user" and replaced by "-R".

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 bash-completion/unshare |  4 +++-
 sys-utils/unshare.1     |  6 ++++++
 sys-utils/unshare.c     | 25 +++++++++++++++++++++++--
 3 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/bash-completion/unshare b/bash-completion/unshare
index 3fda4a194..64aea6784 100644
--- a/bash-completion/unshare
+++ b/bash-completion/unshare
@@ -33,7 +33,9 @@ _unshare_module()
 				--propagation
 				--setgroups
 				--help
-				--version"
+				--version
+				--root
+				--wd"
 			COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
 			return 0
 			;;
diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1
index 746c41152..40cbedbd1 100644
--- a/sys-utils/unshare.1
+++ b/sys-utils/unshare.1
@@ -186,6 +186,12 @@ the GID map becomes writable by unprivileged processes when
 .BR \%setgroups (2)
 is permanently disabled (with \fBdeny\fR).
 .TP
+.BR \-R, "\-\-root=\fIdir"
+run the command with root directory set to \fIdir\fP.
+.TP
+.BR \-w, "\-\-wd=\fIdir"
+change working directory to \fIdir\fP.
+.TP
 .BR \-V , " \-\-version"
 Display version information and exit.
 .TP
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 661665aeb..be2950a36 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -269,6 +269,9 @@ static void __attribute__((__noreturn__)) usage(void)
 	fputs(_(" --propagation slave|shared|private|unchanged\n"
 	        "                           modify mount propagation in mount namespace\n"), out);
 	fputs(_(" --setgroups allow|deny    control the setgroups syscall in user namespaces\n"), out);
+	fputs(USAGE_SEPARATOR, out);
+	fputs(_(" -R, --root=<dir>	    run the command with root directory set to <dir>\n"), out);
+	fputs(_(" -w, --wd=<dir>	    change working directory to <dir>\n"), out);
 
 	fputs(USAGE_SEPARATOR, out);
 	printf(USAGE_HELP_OPTIONS(27));
@@ -283,7 +286,7 @@ int main(int argc, char *argv[])
 		OPT_MOUNTPROC = CHAR_MAX + 1,
 		OPT_PROPAGATION,
 		OPT_SETGROUPS,
-		OPT_KILLCHILD
+		OPT_KILLCHILD,
 	};
 	static const struct option longopts[] = {
 		{ "help",          no_argument,       NULL, 'h'             },
@@ -303,6 +306,8 @@ int main(int argc, char *argv[])
 		{ "map-root-user", no_argument,       NULL, 'r'             },
 		{ "propagation",   required_argument, NULL, OPT_PROPAGATION },
 		{ "setgroups",     required_argument, NULL, OPT_SETGROUPS   },
+		{ "root",          required_argument, NULL, 'R'             },
+		{ "wd",            required_argument, NULL, 'w'             },
 		{ NULL, 0, NULL, 0 }
 	};
 
@@ -311,6 +316,8 @@ int main(int argc, char *argv[])
 	int c, forkit = 0, maproot = 0;
 	int kill_child_signo = 0; /* 0 means --kill-child was not used */
 	const char *procmnt = NULL;
+	const char *newroot = NULL;
+	const char *newdir = "/";
 	pid_t pid = 0;
 	int fds[2];
 	int status;
@@ -323,7 +330,7 @@ int main(int argc, char *argv[])
 	textdomain(PACKAGE);
 	atexit(close_stdout);
 
-	while ((c = getopt_long(argc, argv, "+fhVmuinpCUr", longopts, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "+fhVmuinpCUrR:w:", longopts, NULL)) != -1) {
 		switch (c) {
 		case 'f':
 			forkit = 1;
@@ -392,6 +399,12 @@ int main(int argc, char *argv[])
 				kill_child_signo = SIGKILL;
 			}
 			break;
+		case 'R':
+			newroot = optarg;
+			break;
+		case 'w':
+			newdir = optarg;
+			break;
 		default:
 			errtryhelp(EXIT_FAILURE);
 		}
@@ -471,6 +484,14 @@ int main(int argc, char *argv[])
 	if ((unshare_flags & CLONE_NEWNS) && propagation)
 		set_propagation(propagation);
 
+	if (newroot) {
+		if (chroot(newroot) != 0)
+			err(EXIT_FAILURE,
+			    _("cannot change root directory to '%s'"), newroot);
+		if (chdir(newdir))
+			err(EXIT_FAILURE, _("cannot chdir to '%s'"), newdir);
+	}
+
 	if (procmnt &&
 	    (mount("none", procmnt, NULL, MS_PRIVATE|MS_REC, NULL) != 0 ||
 	     mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0))
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] unshare: allows to set user ID and group ID
  2018-09-28 12:45 [PATCH 0/2] unshare: add some chroot magic Laurent Vivier
  2018-09-28 12:45 ` [PATCH 1/2] unshare: allow to set a new root Laurent Vivier
@ 2018-09-28 12:45 ` Laurent Vivier
  1 sibling, 0 replies; 6+ messages in thread
From: Laurent Vivier @ 2018-09-28 12:45 UTC (permalink / raw)
  To: util-linux; +Cc: Laurent Vivier

This patch introduces two new parameters to set the
user ID and the group ID of the program to be executed.
Setting group ID also drops supplementary groups.

The option names used are the same as for nsenter,
-S, --setuid and -G, --setgid.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 bash-completion/unshare |  4 +++-
 sys-utils/unshare.1     |  7 +++++++
 sys-utils/unshare.c     | 30 +++++++++++++++++++++++++++---
 3 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/bash-completion/unshare b/bash-completion/unshare
index 64aea6784..10afffe19 100644
--- a/bash-completion/unshare
+++ b/bash-completion/unshare
@@ -35,7 +35,9 @@ _unshare_module()
 				--help
 				--version
 				--root
-				--wd"
+				--wd
+				--setuid
+				--setgid"
 			COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
 			return 0
 			;;
diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1
index 40cbedbd1..d2ba6c3a5 100644
--- a/sys-utils/unshare.1
+++ b/sys-utils/unshare.1
@@ -192,6 +192,13 @@ run the command with root directory set to \fIdir\fP.
 .BR \-w, "\-\-wd=\fIdir"
 change working directory to \fIdir\fP.
 .TP
+.BR \-S, "\-\-setuid \fIuid"
+Set the user ID which will be used in the entered namespace.
+.TP
+.BR \-G, "\-\-setgid \fIgid"
+Set the group ID which will be used in the entered namespace and drop
+supplementary groups.
+.TP
 .BR \-V , " \-\-version"
 Display version information and exit.
 .TP
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index be2950a36..09a2b10de 100644
--- a/sys-utils/unshare.c
+++ b/sys-utils/unshare.c
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/prctl.h>
+#include <grp.h>
 
 /* we only need some defines missing in sys/mount.h, no libmount linkage */
 #include <libmount.h>
@@ -42,6 +43,7 @@
 #include "pathnames.h"
 #include "all-io.h"
 #include "signames.h"
+#include "strutils.h"
 
 /* synchronize parent and child by pipe */
 #define PIPE_SYNC_BYTE	0x06
@@ -272,6 +274,8 @@ static void __attribute__((__noreturn__)) usage(void)
 	fputs(USAGE_SEPARATOR, out);
 	fputs(_(" -R, --root=<dir>	    run the command with root directory set to <dir>\n"), out);
 	fputs(_(" -w, --wd=<dir>	    change working directory to <dir>\n"), out);
+        fputs(_(" -S, --setuid <uid>	    set uid in entered namespace\n"), out);
+        fputs(_(" -G, --setgid <gid>	    set gid in entered namespace\n"), out);
 
 	fputs(USAGE_SEPARATOR, out);
 	printf(USAGE_HELP_OPTIONS(27));
@@ -306,6 +310,8 @@ int main(int argc, char *argv[])
 		{ "map-root-user", no_argument,       NULL, 'r'             },
 		{ "propagation",   required_argument, NULL, OPT_PROPAGATION },
 		{ "setgroups",     required_argument, NULL, OPT_SETGROUPS   },
+		{ "setuid",        required_argument, NULL, 'S'             },
+		{ "setgid",        required_argument, NULL, 'G'             },
 		{ "root",          required_argument, NULL, 'R'             },
 		{ "wd",            required_argument, NULL, 'w'             },
 		{ NULL, 0, NULL, 0 }
@@ -322,15 +328,16 @@ int main(int argc, char *argv[])
 	int fds[2];
 	int status;
 	unsigned long propagation = UNSHARE_PROPAGATION_DEFAULT;
-	uid_t real_euid = geteuid();
-	gid_t real_egid = getegid();
+	int force_uid = 0, force_gid = 0;
+	uid_t uid = 0, real_euid = geteuid();
+	gid_t gid = 0, real_egid = getegid();
 
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 	atexit(close_stdout);
 
-	while ((c = getopt_long(argc, argv, "+fhVmuinpCUrR:w:", longopts, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "+fhVmuinpCUrR:w:S:G:", longopts, NULL)) != -1) {
 		switch (c) {
 		case 'f':
 			forkit = 1;
@@ -399,6 +406,14 @@ int main(int argc, char *argv[])
 				kill_child_signo = SIGKILL;
 			}
 			break;
+		case 'S':
+			uid = strtoul_or_err(optarg, _("failed to parse uid"));
+			force_uid = 1;
+			break;
+		case 'G':
+			gid = strtoul_or_err(optarg, _("failed to parse gid"));
+			force_gid = 1;
+			break;
 		case 'R':
 			newroot = optarg;
 			break;
@@ -497,6 +512,15 @@ int main(int argc, char *argv[])
 	     mount("proc", procmnt, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) != 0))
 			err(EXIT_FAILURE, _("mount %s failed"), procmnt);
 
+	if (force_gid) {
+		if (setgroups(0, NULL) != 0)	/* drop supplementary groups */
+			err(EXIT_FAILURE, _("setgroups failed"));
+		if (setgid(gid) < 0)		/* change GID */
+			err(EXIT_FAILURE, _("setgid failed"));
+	}
+	if (force_uid && setuid(uid) < 0)	/* change UID */
+			err(EXIT_FAILURE, _("setuid failed"));
+
 	if (optind < argc) {
 		execvp(argv[optind], argv + optind);
 		errexec(argv[optind]);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] unshare: allow to set a new root
  2018-09-28 12:45 ` [PATCH 1/2] unshare: allow to set a new root Laurent Vivier
@ 2018-10-04 10:11   ` Karel Zak
  2018-10-04 10:15     ` Laurent Vivier
  0 siblings, 1 reply; 6+ messages in thread
From: Karel Zak @ 2018-10-04 10:11 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: util-linux

On Fri, Sep 28, 2018 at 02:45:11PM +0200, Laurent Vivier wrote:
> +	if (newroot) {
> +		if (chroot(newroot) != 0)
> +			err(EXIT_FAILURE,
> +			    _("cannot change root directory to '%s'"), newroot);
> +		if (chdir(newdir))
> +			err(EXIT_FAILURE, _("cannot chdir to '%s'"), newdir);
> +	}

It means that --wd is usable only when --root is specified. Is it
expected? Would be better to use

 char *newdir = NULL;

 while ((c = getopt_long(....))) {
    ...
    case 'w':
        newdir = optarg;
        break;
 }
 ...

 if (newroot) {
    if (chroot(newroot))
        ... error ...
    if (chdir(newdir ? newdir : "/"))
        ... error ...

 } else if (newdir && chdir(newdir))
    ... error ...


    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] unshare: allow to set a new root
  2018-10-04 10:11   ` Karel Zak
@ 2018-10-04 10:15     ` Laurent Vivier
  2018-10-05  9:54       ` Karel Zak
  0 siblings, 1 reply; 6+ messages in thread
From: Laurent Vivier @ 2018-10-04 10:15 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux

Le 04/10/2018 à 12:11, Karel Zak a écrit :
> On Fri, Sep 28, 2018 at 02:45:11PM +0200, Laurent Vivier wrote:
>> +	if (newroot) {
>> +		if (chroot(newroot) != 0)
>> +			err(EXIT_FAILURE,
>> +			    _("cannot change root directory to '%s'"), newroot);
>> +		if (chdir(newdir))
>> +			err(EXIT_FAILURE, _("cannot chdir to '%s'"), newdir);
>> +	}
> 
> It means that --wd is usable only when --root is specified. Is it
> expected? Would be better to use

Yes, the idea was to switch to a working directory in the chroot case.

But if you think it can be useful to switch to another directory on the
non-chroot case, I can upgrade the patch as you say.

Thanks,
Laurent
>  char *newdir = NULL;
> 
>  while ((c = getopt_long(....))) {
>     ...
>     case 'w':
>         newdir = optarg;
>         break;
>  }
>  ...
> 
>  if (newroot) {
>     if (chroot(newroot))
>         ... error ...
>     if (chdir(newdir ? newdir : "/"))
>         ... error ...
> 
>  } else if (newdir && chdir(newdir))
>     ... error ...
> 
> 
>     Karel
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] unshare: allow to set a new root
  2018-10-04 10:15     ` Laurent Vivier
@ 2018-10-05  9:54       ` Karel Zak
  0 siblings, 0 replies; 6+ messages in thread
From: Karel Zak @ 2018-10-05  9:54 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: util-linux

On Thu, Oct 04, 2018 at 12:15:15PM +0200, Laurent Vivier wrote:
> Le 04/10/2018 à 12:11, Karel Zak a écrit :
> > On Fri, Sep 28, 2018 at 02:45:11PM +0200, Laurent Vivier wrote:
> >> +	if (newroot) {
> >> +		if (chroot(newroot) != 0)
> >> +			err(EXIT_FAILURE,
> >> +			    _("cannot change root directory to '%s'"), newroot);
> >> +		if (chdir(newdir))
> >> +			err(EXIT_FAILURE, _("cannot chdir to '%s'"), newdir);
> >> +	}
> > 
> > It means that --wd is usable only when --root is specified. Is it
> > expected? Would be better to use
> 
> Yes, the idea was to switch to a working directory in the chroot case.
> 
> But if you think it can be useful to switch to another directory on the
> non-chroot case, I can upgrade the patch as you say.

In the nsenter we use --wd as generic and independent on --root. It
would be probably better to keep the semantic the same (although in
this case it has probably minimal sense for end-users).

So yes, upgrade the patch to call chdir() always when --wd specified.
Thanks.

    Karel

> 
> Thanks,
> Laurent
> >  char *newdir = NULL;
> > 
> >  while ((c = getopt_long(....))) {
> >     ...
> >     case 'w':
> >         newdir = optarg;
> >         break;
> >  }
> >  ...
> > 
> >  if (newroot) {
> >     if (chroot(newroot))
> >         ... error ...
> >     if (chdir(newdir ? newdir : "/"))
> >         ... error ...
> > 
> >  } else if (newdir && chdir(newdir))
> >     ... error ...
> > 
> > 
> >     Karel
> > 
> 

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-10-05 16:52 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-28 12:45 [PATCH 0/2] unshare: add some chroot magic Laurent Vivier
2018-09-28 12:45 ` [PATCH 1/2] unshare: allow to set a new root Laurent Vivier
2018-10-04 10:11   ` Karel Zak
2018-10-04 10:15     ` Laurent Vivier
2018-10-05  9:54       ` Karel Zak
2018-09-28 12:45 ` [PATCH 2/2] unshare: allows to set user ID and group ID Laurent Vivier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).