From 3b340a1f26e5f85e95b30d9463ca13b5091e7191 Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Thu, 17 Jan 2008 04:17:27 +0200 Subject: [PATCH] s-s-d: Check uid and gid before calling setuid, setgid and initgroups Based on a patch by Samuel Thibault. Closes: #222524 --- ChangeLog | 9 +++++++++ debian/changelog | 3 +++ utils/start-stop-daemon.c | 37 ++++++++++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 44bd23f8..74c226a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-01-17 Samuel Thibault , + Guillem Jover + + * utils/start-stop-daemon.c (gid_in_current_groups): New function. + (main): Call setuid only if requested to run as a different user + than the current one. Call setgid only if requested to run as a group + different than the current one, and initgroups only if the groups is + not part of the supplementary groups. + 2008-01-16 Guillem Jover * utils/start-stop-daemon.c (do_stop): Do not print messages when diff --git a/debian/changelog b/debian/changelog index b88b4c72..271d0db6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,9 @@ dpkg (1.14.16) UNRELEASED; urgency=low --retry even if the daemon removed the pidfile. Closes: #460903 Thanks to Justin Pryzby for the analysis. * Make --quiet silence --test in start-stop-daemon. Closes: #367998 + * Check current uid and gid in start-stop-daemon before calling setuid, + setgid and initgroups. Closes: #222524 + Based on a patch by Samuel Thibault. [ Frank Lichtenheld ] * Make the -L option of dpkg-parsechangelog actually work (it's diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c index a74f7c74..c384031e 100644 --- a/utils/start-stop-daemon.c +++ b/utils/start-stop-daemon.c @@ -313,6 +313,27 @@ clear(struct pid_list **list) *list = NULL; } +static int +gid_in_current_groups(gid_t gid) +{ + gid_t *gids; + int i, ngroups; + + ngroups = getgroups(0, NULL); + gids = xmalloc(ngroups * sizeof(gid_t)); + getgroups(ngroups, gids); + + for (i = 0; i < ngroups; i++) { + if (gid == gids[i]) { + free(gids); + return 1; + } + } + + free(gids); + return 0; +} + static void do_help(void) { @@ -1376,14 +1397,20 @@ main(int argc, char **argv) } if (chdir(changedir) < 0) fatal("Unable to chdir() to %s", changedir); - if (changeuser != NULL) { - if (setgid(runas_gid)) - fatal("Unable to set gid to %d", runas_gid); - if (initgroups(changeuser, runas_gid)) - fatal("Unable to set initgroups() with gid %d", runas_gid); + + if (changeuser != NULL && getuid() != runas_uid) { if (setuid(runas_uid)) fatal("Unable to set uid to %s", changeuser); } + if (changegroup != NULL && *changegroup != '\0' && getgid() != runas_gid) { + if (!gid_in_current_groups(runas_gid)) + if (initgroups(changeuser, runas_gid)) + fatal("Unable to set initgroups() with gid %d", + runas_gid); + if (setgid(runas_gid)) + fatal("Unable to set gid to %d", runas_gid); + } + if (background) { /* Continue background setup */ int i; -- 2.39.5