[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Please test slurm-llnl 2.3.4-2+deb7u1



Hello,

I prepared an updated version of slurm-llnl to fix CVE-2016-10030 which
is a rather severe issue even if only applies to some rare cases (when there's
a prolog script and when the attacker can make it fail).

While I'm relatively confident that I have correctly backported the patch,
I have no way to test the updated package and as this package is not used
by Debian LTS sponsors, I don't want to spend too much time on it either.

The package is probably not very popular and this call for test is likely
to remain without answers so I'm putting the package maintainers in copy.

Gennaro, Mehdi, Remi, maybe you know wheezy users of the package to ping?
Or maybe you can test it quickly?

Anyway the updated package is available here:
https://people.debian.org/~hertzog/packages/slurm-llnl_2.3.4-2+deb7u1_amd64.changes

I would like to have some slurm-llnl users test it for me. Thank you!

Cheers,

PS: And the debdiff is attached.
-- 
Raphaël Hertzog ◈ Debian Developer

Support Debian LTS: https://www.freexian.com/services/debian-lts.html
Learn to master Debian: https://debian-handbook.info/get/
diff -Nru slurm-llnl-2.3.4/debian/changelog slurm-llnl-2.3.4/debian/changelog
--- slurm-llnl-2.3.4/debian/changelog	2012-04-05 12:43:00.000000000 +0200
+++ slurm-llnl-2.3.4/debian/changelog	2017-04-20 17:56:14.000000000 +0200
@@ -1,3 +1,12 @@
+slurm-llnl (2.3.4-2+deb7u1) wheezy-security; urgency=medium
+
+  * Non-maintainer upload by the Debian LTS team.
+  * Don't drop quilt's .pc directory on clean.
+  * Add patch to fix CVE-2016-10030 where a failing prolog script
+    can be used to overwrite arbitrary files (on the compute node).
+
+ -- Raphaël Hertzog <hertzog@debian.org>  Thu, 20 Apr 2017 17:56:14 +0200
+
 slurm-llnl (2.3.4-2) unstable; urgency=low
 
   * Avoiding deluser to fail on purge (Closes: #667537) 
diff -Nru slurm-llnl-2.3.4/debian/patches/CVE-2016-10030 slurm-llnl-2.3.4/debian/patches/CVE-2016-10030
--- slurm-llnl-2.3.4/debian/patches/CVE-2016-10030	1970-01-01 01:00:00.000000000 +0100
+++ slurm-llnl-2.3.4/debian/patches/CVE-2016-10030	2017-04-20 17:56:14.000000000 +0200
@@ -0,0 +1,195 @@
+From 465c98ccff9f1e0018e6a0e6e86ee485ae480ae6 Mon Sep 17 00:00:00 2001
+From: Tim Wickberg <tim@schedmd.com>
+Date: Wed, 4 Jan 2017 13:58:01 -0700
+Subject: [PATCH] Fix security issue in _prolog_error().
+
+Fix security issue caused by insecure file path handling triggered by
+the failure of a Prolog script. To exploit this a user needs to
+anticipate or cause the Prolog to fail for their job.
+
+CVE-2016-10030.
+
+[hertzog@debian.org: Patch grabbed in the slurm-15.08 branch which is closer
+to the very old version in wheezy
+- drop calls related to containerization (feature not available in wheezy)
+- adjust parameters to _get_grouplist()
+]
+
+Origin: backport, https://github.com/SchedMD/slurm/commit/465c98ccff9f1e0018e6a0e6e86ee485ae480ae6
+Bug-Debian: https://bugs.debian.org/850491
+---
+ NEWS                    |   3 +
+ src/slurmd/slurmd/req.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 160 insertions(+), 4 deletions(-)
+
+--- a/src/slurmd/slurmd/req.c
++++ b/src/slurmd/slurmd/req.c
+@@ -133,6 +133,7 @@ static bool _job_still_running(uint32_t
+ static int  _kill_all_active_steps(uint32_t jobid, int sig, bool batch);
+ static int  _step_limits_match(void *x, void *key);
+ static int  _terminate_all_steps(uint32_t jobid, bool batch);
++static int  _receive_fd(int socket);
+ static void _rpc_launch_tasks(slurm_msg_t *);
+ static void _rpc_abort_job(slurm_msg_t *);
+ static void _rpc_batch_job(slurm_msg_t *);
+@@ -186,6 +187,7 @@ static void _add_job_running_prolog(uint
+ static void _remove_job_running_prolog(uint32_t job_id);
+ static int  _compare_job_running_prolog(void *s0, void *s1);
+ static void _wait_for_job_running_prolog(uint32_t job_id);
++static int _open_as_other(char *path_name, batch_job_launch_msg_t *req);
+ 
+ /*
+  *  List of threads waiting for jobs to complete
+@@ -1084,10 +1086,8 @@ _prolog_error(batch_job_launch_msg_t *re
+ 			req->work_dir, err_name_ptr);
+ 	else
+ 		snprintf(path_name, MAXPATHLEN, "/%s", err_name_ptr);
+-
+-	if ((fd = open(path_name, (O_CREAT|O_APPEND|O_WRONLY), 0644)) == -1) {
+-		error("Unable to open %s: %s", path_name,
+-		      slurm_strerror(errno));
++	if ((fd = _open_as_other(path_name, req)) == -1) {
++		error("Unable to open %s: Permission denied", path_name);
+ 		return;
+ 	}
+ 	snprintf(err_name, sizeof(err_name),
+@@ -4355,3 +4355,139 @@ static void _wait_for_job_running_prolog
+ 	slurm_mutex_unlock(&conf->prolog_running_lock);
+ 	debug( "Finished wait for job %d's prolog to complete", job_id);
+ }
++
++/* pass an open file descriptor back to the parent process */
++static void _send_back_fd(int socket, int fd)
++{
++	struct msghdr msg = { 0 };
++	struct cmsghdr *cmsg;
++	char buf[CMSG_SPACE(sizeof(fd))];
++	memset(buf, '\0', sizeof(buf));
++
++	msg.msg_iov = NULL;
++	msg.msg_iovlen = 0;
++	msg.msg_control = buf;
++	msg.msg_controllen = sizeof(buf);
++
++	cmsg = CMSG_FIRSTHDR(&msg);
++	cmsg->cmsg_level = SOL_SOCKET;
++	cmsg->cmsg_type = SCM_RIGHTS;
++	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
++
++	memmove(CMSG_DATA(cmsg), &fd, sizeof(fd));
++	msg.msg_controllen = cmsg->cmsg_len;
++
++	if (sendmsg(socket, &msg, 0) < 0)
++		error("%s: failed to send fd: %m", __func__);
++}
++
++/* receive an open file descriptor from fork()'d child over unix socket */
++static int _receive_fd(int socket)
++{
++	struct msghdr msg = {0};
++	struct cmsghdr *cmsg;
++	int fd;
++	msg.msg_iov = NULL;
++	msg.msg_iovlen = 0;
++	char c_buffer[256];
++	msg.msg_control = c_buffer;
++	msg.msg_controllen = sizeof(c_buffer);
++
++	if (recvmsg(socket, &msg, 0) < 0) {
++		error("%s: failed to receive fd: %m", __func__);
++		return -1;
++	}
++
++	cmsg = CMSG_FIRSTHDR(&msg);
++	memmove(&fd, CMSG_DATA(cmsg), sizeof(fd));
++	return fd;
++}
++
++/*
++ * Open file based upon permissions of a different user
++ * IN path_name - name of file to open
++ * IN uid - User ID to use for file access check
++ * IN gid - Group ID to use for file access check
++ * RET -1 on error, file descriptor otherwise
++ */
++static int _open_as_other(char *path_name, batch_job_launch_msg_t *req)
++{
++	pid_t child;
++	int ngroups = 16;
++	gid_t *groups;
++	int pipe[2];
++	int fd = -1, rc = 0;
++
++	if ((rc = _get_grouplist(req->uid, req->gid, &ngroups, &groups)) < 0) {
++		error("%s: getgrouplist(%u): %m", __func__, req->uid);
++		return rc;
++	}
++
++	/* child process will setuid to the user, register the process
++	 * with the container, and open the file for us. */
++	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe) != 0) {
++		error("%s: Failed to open pipe: %m", __func__);
++		xfree(groups);
++		return -1;
++	}
++
++	child = fork();
++	if (child == -1) {
++		error("%s: fork failure", __func__);
++		xfree(groups);
++		close(pipe[0]);
++		close(pipe[1]);
++		return -1;
++	} else if (child > 0) {
++		close(pipe[0]);
++		(void) waitpid(child, &rc, 0);
++		xfree(groups);
++		if (WIFEXITED(rc) && (WEXITSTATUS(rc) == 0))
++			fd = _receive_fd(pipe[1]);
++		close(pipe[1]);
++		return fd;
++	}
++
++	/* child process below here */
++
++	close(pipe[1]);
++
++	/* The child actually performs the I/O and exits with
++	 * a return code, do not return! */
++
++	/*********************************************************************\
++	 * NOTE: It would be best to do an exec() immediately after the fork()
++	 * in order to help prevent a possible deadlock in the child process
++	 * due to locks being set at the time of the fork and being freed by
++	 * the parent process, but not freed by the child process. Performing
++	 * the work inline is done for simplicity. Note that the logging
++	 * performed by error() should be safe due to the use of
++	 * atfork_install_handlers() as defined in src/common/log.c.
++	 * Change the code below with caution.
++	\*********************************************************************/
++
++	if (setgroups(ngroups, groups) < 0) {
++		error("%s: uid: %u setgroups failed: %m", __func__, req->uid);
++		exit(errno);
++	}
++	xfree(groups);
++
++	if (setgid(req->gid) < 0) {
++		error("%s: uid:%u setgid(%u): %m", __func__, req->uid,req->gid);
++		exit(errno);
++	}
++	if (setuid(req->uid) < 0) {
++		error("%s: getuid(%u): %m", __func__, req->uid);
++		exit(errno);
++	}
++
++	fd = open(path_name, (O_CREAT|O_APPEND|O_WRONLY), 0644);
++	if (fd == -1) {
++		error("%s: uid:%u can't open `%s`: %m",
++		      __func__, req->uid, path_name);
++		exit(errno);
++	}
++	_send_back_fd(pipe[0], fd);
++	close(fd);
++	exit(SLURM_SUCCESS);
++}
diff -Nru slurm-llnl-2.3.4/debian/patches/series slurm-llnl-2.3.4/debian/patches/series
--- slurm-llnl-2.3.4/debian/patches/series	2012-04-05 12:47:23.000000000 +0200
+++ slurm-llnl-2.3.4/debian/patches/series	2017-04-20 17:56:14.000000000 +0200
@@ -1,2 +1,3 @@
 mail-path
 use-dpkg-buildflags
+CVE-2016-10030
diff -Nru slurm-llnl-2.3.4/debian/rules slurm-llnl-2.3.4/debian/rules
--- slurm-llnl-2.3.4/debian/rules	2012-01-21 20:56:56.000000000 +0100
+++ slurm-llnl-2.3.4/debian/rules	2017-04-20 17:56:14.000000000 +0200
@@ -67,7 +67,7 @@
 	[ ! -f contribs/pam/Makefile ] || $(MAKE) -C contribs/pam distclean
 	[ ! -f Makefile ] || $(MAKE) distclean
 
-	  rm -rf .pc contribs/pam/.deps \
+	  rm -rf contribs/pam/.deps \
 		src/plugins/accounting_storage/common/.deps \
 		src/plugins/accounting_storage/common/.libs
 	  rm -f config.sub

Reply to: