summaryrefslogtreecommitdiffstats
path: root/sys-utils/unshare.c
diff options
context:
space:
mode:
authorLaurent Vivier2018-10-05 13:09:30 +0200
committerKarel Zak2018-11-12 11:52:15 +0100
commitf0af42b51761428bdd821b31381fbfa1346f6782 (patch)
treed470ecd3f56b55267523151531f95fffecf04659 /sys-utils/unshare.c
parentunshare: allow to set a new root (diff)
downloadkernel-qcow2-util-linux-f0af42b51761428bdd821b31381fbfa1346f6782.tar.gz
kernel-qcow2-util-linux-f0af42b51761428bdd821b31381fbfa1346f6782.tar.xz
kernel-qcow2-util-linux-f0af42b51761428bdd821b31381fbfa1346f6782.zip
unshare: allow to set user ID and group ID
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>
Diffstat (limited to 'sys-utils/unshare.c')
-rw-r--r--sys-utils/unshare.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c
index 12ef044f8..e9ddb09de 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;
@@ -500,6 +515,15 @@ int main(int argc, char *argv[])
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]);