Split checking for root from dropping root privilege
check_root() both checks to see if we are root (in the init namespace), and if we are drops to an unprivileged user. To make future cleanups simpler, split the checking for root (now in check_root()) from the actual dropping of privilege (now in drop_root()). Note that this does slightly alter semantics. Previously we would only setuid() if we were originally root (in the init namespace). Now we will always setuid() and setgid(), though it won't actually change anything if we weren't privileged to begin with. This also means that we will now always attempt to switch to the user specified with --runas, even if we aren't (init namespace) root to begin with. Obviously this will fail with an error if we weren't privileged to start with. --help and the man page are updated accordingly. Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
7330ae3abf
commit
10c6347747
4 changed files with 33 additions and 7 deletions
5
conf.c
5
conf.c
|
@ -747,8 +747,8 @@ static void usage(const char *name)
|
||||||
info( " default: run in background if started from a TTY");
|
info( " default: run in background if started from a TTY");
|
||||||
info( " -e, --stderr Log to stderr too");
|
info( " -e, --stderr Log to stderr too");
|
||||||
info( " default: log to system logger only if started from a TTY");
|
info( " default: log to system logger only if started from a TTY");
|
||||||
info( " --runas UID|UID:GID Use given UID, GID if started as root");
|
info( " --runas UID|UID:GID Run as given UID, GID, which can be");
|
||||||
info( " UID and GID can be numeric, or login and group names");
|
info( " numeric, or login and group names");
|
||||||
info( " default: drop to user \"nobody\"");
|
info( " default: drop to user \"nobody\"");
|
||||||
info( " -h, --help Display this help message and exit");
|
info( " -h, --help Display this help message and exit");
|
||||||
|
|
||||||
|
@ -1500,6 +1500,7 @@ void conf(struct ctx *c, int argc, char **argv)
|
||||||
} while (name != -1);
|
} while (name != -1);
|
||||||
|
|
||||||
check_root(&uid, &gid);
|
check_root(&uid, &gid);
|
||||||
|
drop_root(uid, gid);
|
||||||
|
|
||||||
if (c->mode == MODE_PASTA) {
|
if (c->mode == MODE_PASTA) {
|
||||||
if (*netns && optind != argc) {
|
if (*netns && optind != argc) {
|
||||||
|
|
5
passt.1
5
passt.1
|
@ -104,9 +104,10 @@ terminal, and to both system logger and standard error otherwise.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-\-runas " " \fIUID\fR|\fIUID:GID\fR|\fILOGIN\fR|\fILOGIN:GROUP\fR
|
.BR \-\-runas " " \fIUID\fR|\fIUID:GID\fR|\fILOGIN\fR|\fILOGIN:GROUP\fR
|
||||||
If started as root, change to given UID and corresponding group if UID is given,
|
Attempt to change to given UID and corresponding group if UID is given,
|
||||||
or to given UID and given GID if both are given. Alternatively, login name, or
|
or to given UID and given GID if both are given. Alternatively, login name, or
|
||||||
login name and group name can be passed.
|
login name and group name can be passed. This requires privileges (either
|
||||||
|
initial effective UID 0 or CAP_SETUID capability) to work.
|
||||||
Default is to change to user \fInobody\fR if started as root.
|
Default is to change to user \fInobody\fR if started as root.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
|
|
29
util.c
29
util.c
|
@ -492,7 +492,13 @@ void check_root(uid_t *uid, gid_t *gid)
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (getuid() && geteuid())
|
if (!*uid)
|
||||||
|
*uid = geteuid();
|
||||||
|
|
||||||
|
if (!*gid)
|
||||||
|
*gid = getegid();
|
||||||
|
|
||||||
|
if (*uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((fd = open("/proc/self/uid_map", O_RDONLY | O_CLOEXEC)) < 0)
|
if ((fd = open("/proc/self/uid_map", O_RDONLY | O_CLOEXEC)) < 0)
|
||||||
|
@ -524,11 +530,28 @@ void check_root(uid_t *uid, gid_t *gid)
|
||||||
*uid = *gid = 65534;
|
*uid = *gid = 65534;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!setgroups(0, NULL) && !setgid(*gid) && !setuid(*uid))
|
/**
|
||||||
|
* drop_root() - Switch to given UID and GID
|
||||||
|
* @uid: User ID to switch to
|
||||||
|
* @gid: Group ID to switch to
|
||||||
|
*/
|
||||||
|
void drop_root(uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
if (setgroups(0, NULL)) {
|
||||||
|
/* If we don't start with CAP_SETGID, this will EPERM */
|
||||||
|
if (errno != EPERM) {
|
||||||
|
err("Can't drop supplementary groups: %s",
|
||||||
|
strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setgid(gid) && !setuid(uid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fprintf(stderr, "Can't change user/group, exiting");
|
err("Can't change user/group, exiting");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
util.h
1
util.h
|
@ -235,6 +235,7 @@ void procfs_scan_listen(struct ctx *c, uint8_t proto, int ip_version, int ns,
|
||||||
uint8_t *map, uint8_t *exclude);
|
uint8_t *map, uint8_t *exclude);
|
||||||
void drop_caps(void);
|
void drop_caps(void);
|
||||||
void check_root(uid_t *uid, gid_t *gid);
|
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);
|
int ns_enter(const struct ctx *c);
|
||||||
void write_pidfile(int fd, pid_t pid);
|
void write_pidfile(int fd, pid_t pid);
|
||||||
int __daemon(int pidfile_fd, int devnull_fd);
|
int __daemon(int pidfile_fd, int devnull_fd);
|
||||||
|
|
Loading…
Reference in a new issue