Stéphane Graber has proposed merging lp:~stgraber/upstart/upstart-initgroups 
into lp:upstart.

Requested reviews:
  Upstart Reviewers (upstart-reviewers)

For more details, see:
https://code.launchpad.net/~stgraber/upstart/upstart-initgroups/+merge/136794

Call initgroups() before spawning a job to ensure that the user's group list
is properly initialized.

This avoids the following issue:

=== Example of the security problem ===
root@upstart-test:~# cat /etc/init/test.conf
setuid nobody
setgid nogroup

task
script
    cat /tmp/secret-file > /tmp/public-file
    chmod 666 /tmp/public-file
    id > /tmp/debug
end script
root@upstart-test:~# id nobody
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
root@upstart-test:~# echo secret > /tmp/secret-file
root@upstart-test:~# chmod 660 /tmp/secret-file
root@upstart-test:~# start test
test stop/waiting
root@upstart-test:~# cat /tmp/public-file
secret
root@upstart-test:~# ls -l /tmp/public-file
-rw-rw-rw- 1 nobody nogroup 7 Nov 28 20:59 /tmp/public-file
root@upstart-test:~# cat /tmp/debug
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup),0(root)
root@upstart-test:~# 


=== Same commands but with the fixed version ===
root@upstart-test:~# cat /etc/init/test.conf
setuid nobody
setgid nogroup

task
script
    cat /tmp/secret-file > /tmp/public-file
    chmod 666 /tmp/public-file
    id > /tmp/debug
end script
root@upstart-test:~# id nobody
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
root@upstart-test:~# echo secret > /tmp/secret-file 
root@upstart-test:~# chmod 660 /tmp/secret-file 
root@upstart-test:~# start test
start: Job failed to start
root@upstart-test:~# 



The code was tested (as shown above) and the unit tests still all pass.
However, as the tests are meant to be run as non-root, it's not possible
to add new tests testing for initgroups() behaviour.
-- 
https://code.launchpad.net/~stgraber/upstart/upstart-initgroups/+merge/136794
Your team Upstart Reviewers is requested to review the proposed merge of 
lp:~stgraber/upstart/upstart-initgroups into lp:upstart.
=== modified file 'init/job_process.c'
--- init/job_process.c	2012-11-21 06:48:08 +0000
+++ init/job_process.c	2012-11-28 21:11:21 +0000
@@ -413,6 +413,8 @@
 	JobClass       *class;
 	uid_t           job_setuid = -1;
 	gid_t           job_setgid = -1;
+	struct passwd   *pwd;
+	struct group    *grp;
 
 
 	nih_assert (job != NULL);
@@ -705,6 +707,11 @@
 			job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHOWN, 0);
 		}
 
+		if (geteuid () == 0 && initgroups (pw->pw_name, pw->pw_gid) < 0) {
+			nih_error_raise_system ();
+			job_process_error_abort (fds[1], JOB_PROCESS_ERROR_INITGROUPS, 0);
+		}
+
 		if (pw->pw_gid && setgid (pw->pw_gid) < 0) {
 			nih_error_raise_system ();
 			job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0);
@@ -844,7 +851,6 @@
 	 * session jobs and jobs with a chroot stanza.
 	 */
 	if (class->setuid) {
-		struct passwd *pwd;
 		/* Without resetting errno, it's impossible to
 		 * distinguish between a non-existent user and and
 		 * error during lookup */
@@ -867,7 +873,6 @@
 	}
 
 	if (class->setgid) {
-		struct group *grp;
 		errno = 0;
 		grp = getgrnam (class->setgid);
 		if (! grp) {
@@ -891,6 +896,37 @@
 		job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHOWN, 0);
 	}
 
+	/* Make sure we always have the needed pwd and grp structs.
+	 * Then pass those to initgroups() to setup the user's group list.
+	 * Only do that if we're root as initgroups() won't work when non-root. */
+	if (geteuid () == 0) {
+		if (! pwd) {
+			errno = 0;
+			pwd = getpwuid (geteuid ());
+			if (! pwd) {
+				nih_error_raise_system ();
+				job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWUID, 0);
+			}
+		}
+
+		if (! grp) {
+			errno = 0;
+			grp = getgrgid (getegid ());
+			if (! grp) {
+				nih_error_raise_system ();
+				job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETGRGID, 0);
+			}
+		}
+
+		if (pwd && grp) {
+			if (initgroups (pwd->pw_name, grp->gr_gid) < 0) {
+				nih_error_raise_system ();
+				job_process_error_abort (fds[1], JOB_PROCESS_ERROR_INITGROUPS, 0);
+			}
+		}
+	}
+
+	/* Start dropping privileges */
 	if (job_setgid != (gid_t) -1 && setgid (job_setgid) < 0) {
 		nih_error_raise_system ();
 		job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0);

=== modified file 'init/job_process.h'
--- init/job_process.h	2012-11-07 15:17:58 +0000
+++ init/job_process.h	2012-11-28 21:11:21 +0000
@@ -94,7 +94,9 @@
 	JOB_PROCESS_ERROR_PTSNAME,
 	JOB_PROCESS_ERROR_OPENPT_SLAVE,
 	JOB_PROCESS_ERROR_SIGNAL,
-	JOB_PROCESS_ERROR_ALLOC
+	JOB_PROCESS_ERROR_ALLOC,
+	JOB_PROCESS_ERROR_INITGROUPS,
+	JOB_PROCESS_ERROR_GETGRGID
 } JobProcessErrorType;
 
 /**

-- 
upstart-devel mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/upstart-devel

Reply via email to