os-posix: Provide new -runas <uid>:<gid> facility
This allows the caller to specify a uid and gid to use, even if there is no corresponding password entry. This will be useful in certain Xen configurations. We don't support just -runas <uid> because: (i) deprivileging without calling setgroups would be ineffective (ii) given only a uid we don't know what gid we ought to use (since uids may eppear in multiple passwd file entries with different gids). Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com> Reviewed-by: Anthony PERARD <anthony.perard@citrix.com> CC: Paolo Bonzini <pbonzini@redhat.com> CC: Markus Armbruster <armbru@redhat.com> CC: Daniel P. Berrange <berrange@redhat.com> CC: Michael Tokarev <mjt@tls.msk.ru> Reviewed-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
parent
f0a2171bf9
commit
2c42f1e801
77
os-posix.c
77
os-posix.c
@ -41,7 +41,14 @@
|
|||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct passwd *user_pwd;
|
/*
|
||||||
|
* Must set all three of these at once.
|
||||||
|
* Legal combinations are unset by name by uid
|
||||||
|
*/
|
||||||
|
static struct passwd *user_pwd; /* NULL non-NULL NULL */
|
||||||
|
static uid_t user_uid = (uid_t)-1; /* -1 -1 >=0 */
|
||||||
|
static gid_t user_gid = (gid_t)-1; /* -1 -1 >=0 */
|
||||||
|
|
||||||
static const char *chroot_dir;
|
static const char *chroot_dir;
|
||||||
static int daemonize;
|
static int daemonize;
|
||||||
static int daemon_pipe;
|
static int daemon_pipe;
|
||||||
@ -127,6 +134,33 @@ void os_set_proc_name(const char *s)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool os_parse_runas_uid_gid(const char *optarg)
|
||||||
|
{
|
||||||
|
unsigned long lv;
|
||||||
|
const char *ep;
|
||||||
|
uid_t got_uid;
|
||||||
|
gid_t got_gid;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = qemu_strtoul(optarg, &ep, 0, &lv);
|
||||||
|
got_uid = lv; /* overflow here is ID in C99 */
|
||||||
|
if (rc || *ep != ':' || got_uid != lv || got_uid == (uid_t)-1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = qemu_strtoul(ep + 1, 0, 0, &lv);
|
||||||
|
got_gid = lv; /* overflow here is ID in C99 */
|
||||||
|
if (rc || got_gid != lv || got_gid == (gid_t)-1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
user_pwd = NULL;
|
||||||
|
user_uid = got_uid;
|
||||||
|
user_gid = got_gid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse OS specific command line options.
|
* Parse OS specific command line options.
|
||||||
* return 0 if option handled, -1 otherwise
|
* return 0 if option handled, -1 otherwise
|
||||||
@ -144,8 +178,13 @@ void os_parse_cmd_args(int index, const char *optarg)
|
|||||||
#endif
|
#endif
|
||||||
case QEMU_OPTION_runas:
|
case QEMU_OPTION_runas:
|
||||||
user_pwd = getpwnam(optarg);
|
user_pwd = getpwnam(optarg);
|
||||||
if (!user_pwd) {
|
if (user_pwd) {
|
||||||
fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
|
user_uid = -1;
|
||||||
|
user_gid = -1;
|
||||||
|
} else if (!os_parse_runas_uid_gid(optarg)) {
|
||||||
|
error_report("User \"%s\" doesn't exist"
|
||||||
|
" (and is not <uid>:<gid>)",
|
||||||
|
optarg);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -165,18 +204,32 @@ void os_parse_cmd_args(int index, const char *optarg)
|
|||||||
|
|
||||||
static void change_process_uid(void)
|
static void change_process_uid(void)
|
||||||
{
|
{
|
||||||
if (user_pwd) {
|
assert((user_uid == (uid_t)-1) || user_pwd == NULL);
|
||||||
if (setgid(user_pwd->pw_gid) < 0) {
|
assert((user_uid == (uid_t)-1) ==
|
||||||
error_report("Failed to setgid(%d)", user_pwd->pw_gid);
|
(user_gid == (gid_t)-1));
|
||||||
|
|
||||||
|
if (user_pwd || user_uid != (uid_t)-1) {
|
||||||
|
gid_t intended_gid = user_pwd ? user_pwd->pw_gid : user_gid;
|
||||||
|
uid_t intended_uid = user_pwd ? user_pwd->pw_uid : user_uid;
|
||||||
|
if (setgid(intended_gid) < 0) {
|
||||||
|
error_report("Failed to setgid(%d)", intended_gid);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
|
if (user_pwd) {
|
||||||
error_report("Failed to initgroups(\"%s\", %d)",
|
if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
|
||||||
user_pwd->pw_name, user_pwd->pw_gid);
|
error_report("Failed to initgroups(\"%s\", %d)",
|
||||||
exit(1);
|
user_pwd->pw_name, user_pwd->pw_gid);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (setgroups(1, &user_gid) < 0) {
|
||||||
|
error_report("Failed to setgroups(1, [%d])",
|
||||||
|
user_gid);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (setuid(user_pwd->pw_uid) < 0) {
|
if (setuid(intended_uid) < 0) {
|
||||||
error_report("Failed to setuid(%d)", user_pwd->pw_uid);
|
error_report("Failed to setuid(%d)", intended_uid);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (setuid(0) != -1) {
|
if (setuid(0) != -1) {
|
||||||
|
@ -3765,7 +3765,8 @@ ETEXI
|
|||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
DEF("runas", HAS_ARG, QEMU_OPTION_runas, \
|
DEF("runas", HAS_ARG, QEMU_OPTION_runas, \
|
||||||
"-runas user change to user id user just before starting the VM\n",
|
"-runas user change to user id user just before starting the VM\n" \
|
||||||
|
" user can be numeric uid:gid instead\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
#endif
|
#endif
|
||||||
STEXI
|
STEXI
|
||||||
|
Loading…
Reference in New Issue
Block a user