From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Gibson To: passt-dev@passt.top Subject: [PATCH v2 03/10] Consolidate determination of UID/GID to run as Date: Thu, 08 Sep 2022 13:59:00 +1000 Message-ID: <20220908035907.1750314-4-david@gibson.dropbear.id.au> In-Reply-To: <20220908035907.1750314-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5647665009246759693==" --===============5647665009246759693== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Currently the logic to work out what UID and GID we will run as is spread across conf(). If --runas is specified it's handled in conf_runas(), otherwise it's handled by check_root(), which depends on initialization of the uid and gid variables by either conf() itself or conf_runas(). Make this clearer by putting all the UID and GID logic into a single conf_ugid() function. Signed-off-by: David Gibson --- conf.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ util.c | 50 ------------------------------------ util.h | 1 - 3 files changed, 73 insertions(+), 59 deletions(-) diff --git a/conf.c b/conf.c index 545f61d..5c293b5 100644 --- a/conf.c +++ b/conf.c @@ -1021,6 +1021,70 @@ static int conf_runas(const char *opt, unsigned int *u= id, unsigned int *gid) #endif /* !GLIBC_NO_STATIC_NSS */ } =20 +/** + * conf_ugid() - Determine UID and GID to run as + * @runas: --runas option, may be NULL + * @uid: User ID, set on success + * @gid: Group ID, set on success + * + * Return: 0 on success, negative error code on failure + */ +static int conf_ugid(const char *runas, uid_t *uid, gid_t *gid) +{ + const char root_uid_map[] =3D " 0 0 4294967295"; + struct passwd *pw; + char buf[BUFSIZ]; + int ret; + int fd; + + /* If user has specified --runas, that takes precedence */ + if (runas) { + ret =3D conf_runas(runas, uid, gid); + if (ret) + err("Invalid --runas option: %s", runas); + return ret; + } + + /* Otherwise default to current user and group.. */ + *uid =3D geteuid(); + *gid =3D getegid(); + + /* ..as long as it's not root.. */ + if (*uid) + return 0; + + /* ..or at least not root in the init namespace.. */ + if ((fd =3D open("/proc/self/uid_map", O_RDONLY | O_CLOEXEC)) < 0) + return 0; + + if (read(fd, buf, BUFSIZ) !=3D sizeof(root_uid_map) || + strncmp(buf, root_uid_map, sizeof(root_uid_map) - 1)) { + close(fd); + return 0; + } + + close(fd); + + /* ..otherwise use nobody:nobody */ + warn("Don't run as root. Changing to nobody..."); +#ifndef GLIBC_NO_STATIC_NSS + pw =3D getpwnam("nobody"); + if (!pw) { + perror("getpwnam"); + exit(EXIT_FAILURE); + } + + *uid =3D pw->pw_uid; + *gid =3D pw->pw_gid; +#else + (void)pw; + + /* Common value for 'nobody', not really specified */ + *uid =3D *gid =3D 65534; +#endif + return 0; +} + /** * conf() - Process command-line arguments and set configuration * @c: Execution context @@ -1085,9 +1149,10 @@ void conf(struct ctx *c, int argc, char **argv) struct fqdn *dnss =3D c->dns_search; uint32_t *dns4 =3D c->ip4.dns; int name, ret, mask, b, i; + const char *runas =3D NULL; unsigned int ifi =3D 0; - uid_t uid =3D 0; - gid_t gid =3D 0; + uid_t uid; + gid_t gid; =20 if (c->mode =3D=3D MODE_PASTA) c->no_dhcp_dns =3D c->no_dhcp_dns_search =3D 1; @@ -1210,15 +1275,12 @@ void conf(struct ctx *c, int argc, char **argv) c->trace =3D c->debug =3D c->foreground =3D 1; break; case 12: - if (uid || gid) { + if (runas) { err("Multiple --runas options given"); usage(argv[0]); } =20 - if (conf_runas(optarg, &uid, &gid)) { - err("Invalid --runas option: %s", optarg); - usage(argv[0]); - } + runas =3D optarg; break; case 'd': if (c->debug) { @@ -1499,7 +1561,10 @@ void conf(struct ctx *c, int argc, char **argv) } } while (name !=3D -1); =20 - check_root(&uid, &gid); + ret =3D conf_ugid(runas, &uid, &gid); + if (ret) + usage(argv[0]); + drop_root(uid, gid); =20 if (c->mode =3D=3D MODE_PASTA) { diff --git a/util.c b/util.c index 17595c1..654410f 100644 --- a/util.c +++ b/util.c @@ -482,56 +482,6 @@ void drop_caps(void) } } =20 -/** - * check_root() - Check if root in init ns, exit if we can't drop to user - */ -void check_root(uid_t *uid, gid_t *gid) -{ - const char root_uid_map[] =3D " 0 0 4294967295"; - struct passwd *pw; - char buf[BUFSIZ]; - int fd; - - if (!*uid) - *uid =3D geteuid(); - - if (!*gid) - *gid =3D getegid(); - - if (*uid) - return; - - if ((fd =3D open("/proc/self/uid_map", O_RDONLY | O_CLOEXEC)) < 0) - return; - - if (read(fd, buf, BUFSIZ) !=3D sizeof(root_uid_map) || - strncmp(buf, root_uid_map, sizeof(root_uid_map) - 1)) { - close(fd); - return; - } - - close(fd); - - if (!*uid) { - fprintf(stderr, "Don't run as root. Changing to nobody...\n"); -#ifndef GLIBC_NO_STATIC_NSS - pw =3D getpwnam("nobody"); - if (!pw) { - perror("getpwnam"); - exit(EXIT_FAILURE); - } - - *uid =3D pw->pw_uid; - *gid =3D pw->pw_gid; -#else - (void)pw; - - /* Common value for 'nobody', not really specified */ - *uid =3D *gid =3D 65534; -#endif - } -} - /** * drop_root() - Switch to given UID and GID */ diff --git a/util.h b/util.h index e2f686b..9626cb5 100644 --- a/util.h +++ b/util.h @@ -234,7 +234,6 @@ char *line_read(char *buf, size_t len, int fd); void procfs_scan_listen(struct ctx *c, uint8_t proto, int ip_version, int ns, uint8_t *map, uint8_t *exclude); void drop_caps(void); -void check_root(uid_t *uid, gid_t *gid); void drop_root(uid_t uid, gid_t gid); int ns_enter(const struct ctx *c); void write_pidfile(int fd, pid_t pid); --=20 2.37.3 --===============5647665009246759693==--