Package: release.debian.org
Severity: normal
Tags: jessie
User: release.debian....@packages.debian.org
Usertags: pu


I'd like to update slurm-llnl in the next oldstable point release to
address a vulnerability in how the slurmd daemon informs users of
a Prolog failure on a compute node. That vulnerability could allow a
user to assume control of an arbitrary file on the system. Any
exploitation of this is dependent on the user being able to cause or
anticipate the failure (non-zero return code) of a Prolog script that
their job would run on (CVE-2016-10030).

debdiff is attached. The diffstat is:

 changelog              |    7 +
 patches/CVE-2016-10030 |  198 +++++++++++++++++++++++++++++++++++++++++++++++++
 patches/series         |    1 
 3 files changed, 206 insertions(+)

Thanks
-- 
Gennaro Oliva
diff -Nru slurm-llnl-14.03.9/debian/changelog 
slurm-llnl-14.03.9/debian/changelog
--- slurm-llnl-14.03.9/debian/changelog 2014-11-12 12:07:35.000000000 +0100
+++ slurm-llnl-14.03.9/debian/changelog 2017-07-28 10:52:47.000000000 +0200
@@ -1,3 +1,10 @@
+slurm-llnl (14.03.9-5+deb8u1) jessie-security; urgency=high
+
+  * Fix security issue caused by insecure file path handling triggered by
+    the failure of a Prolog script (CVE-2016-10030)
+
+ -- Gennaro Oliva <oliv...@na.icar.cnr.it>  Fri, 28 Jul 2017 10:06:41 +0200
+
 slurm-llnl (14.03.9-5) unstable; urgency=medium
 
   [ Roland Fehrenbacher ]
diff -Nru slurm-llnl-14.03.9/debian/patches/CVE-2016-10030 
slurm-llnl-14.03.9/debian/patches/CVE-2016-10030
--- slurm-llnl-14.03.9/debian/patches/CVE-2016-10030    1970-01-01 
01:00:00.000000000 +0100
+++ slurm-llnl-14.03.9/debian/patches/CVE-2016-10030    2017-07-28 
10:03:53.000000000 +0200
@@ -0,0 +1,198 @@
+Description: FIX CVE-2016-10030
+ 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.
+Author: Tim Wickberg <t...@schedmd.com>
+
+---
+Origin: 
https://github.com/SchedMD/slurm/commit/465c98ccff9f1e0018e6a0e6e86ee485ae480ae6
+Bug: <url in upstream bugtracker>
+Bug-Debian: https://bugs.debian.org/850491
+Last-Update: 28-07-2017
+
+--- slurm-llnl-14.03.9.orig/src/slurmd/slurmd/req.c
++++ slurm-llnl-14.03.9/src/slurmd/slurmd/req.c
+@@ -155,6 +155,7 @@ static int  _kill_all_active_steps(uint3
+ static void _note_batch_job_finished(uint32_t job_id);
+ 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 *msg, bool new_msg);
+@@ -214,6 +215,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
+@@ -1275,9 +1277,8 @@ _prolog_error(batch_job_launch_msg_t *re
+       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),
+@@ -5306,4 +5307,155 @@ done:
+       slurm_send_rc_msg(msg, rc);
+ }
+ 
++/* 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->user_name, req->uid,
++                               req->gid, &ngroups, &groups)) < 0) {
++              error("%s: getgrouplist(%u): %m", __func__, req->uid);
++              return rc;
++      }
++
++      if ((rc = container_g_create(req->job_id))) {
++              error("%s: container_g_create(%u): %m", __func__, req->job_id);
++              xfree(groups);
++              return -1;
++      }
++
++      /* 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]);
++
++      /* container_g_add_pid needs to be called in the
++       * forked process part of the fork to avoid a race
++       * condition where if this process makes a file or
++       * detacts itself from a child before we add the pid
++       * to the container in the parent of the fork. */
++      if (container_g_add_pid(req->job_id, getpid(), req->uid)) {
++              error("%s container_g_add_pid(%u): %m", __func__, req->job_id);
++              exit(SLURM_ERROR);
++      }
++
++      /* 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-14.03.9/debian/patches/series 
slurm-llnl-14.03.9/debian/patches/series
--- slurm-llnl-14.03.9/debian/patches/series    2014-11-06 10:22:27.000000000 
+0100
+++ slurm-llnl-14.03.9/debian/patches/series    2017-07-28 10:02:04.000000000 
+0200
@@ -3,3 +3,4 @@
 sacctmgr-increase-buffer
 manpages
 honor-without-rpath-hwloc
+CVE-2016-10030

Reply via email to