This allows qemu to drop privileges to a dynamically allocated, anonymous UID and GID without needing a temporary /etc/passwd entry for that UID. The UID:GID format is very standard, being (for example) the syntax used by chown(1) for numeric IDs.
Signed-off-by: Chris Webb <ch...@arachsys.com> --- os-posix.c | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletions(-) diff --git a/os-posix.c b/os-posix.c index 1b2061a..44a841b 100644 --- a/os-posix.c +++ b/os-posix.c @@ -179,6 +179,15 @@ void os_parse_cmd_args(int index, const char *optarg) case QEMU_OPTION_runas: user_pwd = getpwnam(optarg); if (!user_pwd) { + long uid, gid, tail; + if (sscanf(optarg, "%ld:%ld%ln", &uid, &gid, &tail) >= 2 + && !optarg[tail]) { + user_pwd = g_new0(struct passwd, 1); + user_pwd->pw_uid = uid; + user_pwd->pw_gid = gid; + } + } + if (!user_pwd) { fprintf(stderr, "User \"%s\" doesn't exist\n", optarg); exit(1); } @@ -200,7 +209,12 @@ static void change_process_uid(void) fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid); exit(1); } - if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) { + if (!user_pwd->pw_name) { + if (setgroups(0, NULL) < 0) { + fprintf(stderr, "Failed to setgroups(0, NULL)\n"); + exit(1); + } + } else if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) { fprintf(stderr, "Failed to initgroups(\"%s\", %d)\n", user_pwd->pw_name, user_pwd->pw_gid); exit(1); -- 1.7.5.4