Explorar o código

s-s-d: Check uid and gid before calling setuid, setgid and initgroups

Based on a patch by Samuel Thibault. Closes: #222524
Guillem Jover %!s(int64=18) %!d(string=hai) anos
pai
achega
3b340a1f26
Modificáronse 3 ficheiros con 44 adicións e 5 borrados
  1. 9 0
      ChangeLog
  2. 3 0
      debian/changelog
  3. 32 5
      utils/start-stop-daemon.c

+ 9 - 0
ChangeLog

@@ -1,3 +1,12 @@
+2008-01-17  Samuel Thibault  <samuel.thibault@ens-lyon.org>,
+            Guillem Jover  <guillem@debian.org>
+
+	* 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  <guillem@debian.org>
 
 	* utils/start-stop-daemon.c (do_stop): Do not print messages when

+ 3 - 0
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

+ 32 - 5
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;