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

Ohai,

I would like to upload lxc/1:1.0.6-6+deb8u6 for Jessie and seek your 
(pre-)approval.

The reason for the upload is to fix #857295 aka
 CVE-2017-5985: lxc-user-nic didn't verify network namespace ownership
The patch for that is straight from upstream's stable-1.0 branch.

The same fix went in towards Stretch in #857442.

Thanks
Evgeni

-- System Information:
Debian Release: 9.0
  APT prefers unstable-debug
  APT policy: (500, 'unstable-debug'), (500, 'unstable'), (500, 'testing'), (1, 
'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.9.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
diff --git a/debian/changelog b/debian/changelog
index 65b7aad..9867357 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+lxc (1:1.0.6-6+deb8u6) jessie; urgency=medium
+
+  * CVE-2017-5985: Ensure target netns is caller-owned (Closes: #857295)
+
+ -- Evgeni Golov <evg...@debian.org>  Sat, 11 Mar 2017 10:42:30 +0100
+
 lxc (1:1.0.6-6+deb8u5) jessie; urgency=medium
 
   * attach: do not send procfd to attached process
diff --git 
a/debian/patches/0027-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch 
b/debian/patches/0027-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
new file mode 100644
index 0000000..206ee15
--- /dev/null
+++ 
b/debian/patches/0027-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
@@ -0,0 +1,205 @@
+From c905f00ad78b78a5e9c0d67504b86e00dfe085ec Mon Sep 17 00:00:00 2001
+From: Christian Brauner <christian.brau...@ubuntu.com>
+Date: Sat, 11 Feb 2017 13:27:06 +0100
+Subject: [PATCH] CVE-2017-5985: Ensure target netns is caller-owned
+
+Before this commit, lxc-user-nic could potentially have been tricked into
+operating on a network namespace over which the caller did not hold privilege.
+
+This commit ensures that the caller is privileged over the network namespace by
+temporarily dropping privilege.
+
+Launchpad: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1654676
+Reported-by: Jann Horn <ja...@google.com>
+Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
+---
+ src/lxc/lxc_user_nic.c | 130 ++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 96 insertions(+), 34 deletions(-)
+
+diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c
+index 8981e11a..08123860 100644
+--- a/src/lxc/lxc_user_nic.c
++++ b/src/lxc/lxc_user_nic.c
+@@ -49,6 +49,14 @@
+ #include "utils.h"
+ #include "network.h"
+ 
++#define usernic_debug_stream(stream, format, ...)                             
 \
++      do {                                                                   \
++              fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__,     \
++                      __func__, __VA_ARGS__);                                \
++      } while (false)
++
++#define usernic_error(format, ...) usernic_debug_stream(stderr, format, 
__VA_ARGS__)
++
+ static void usage(char *me, bool fail)
+ {
+       fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
+@@ -153,7 +161,7 @@ static char *get_eow(char *s, char *e)
+ static char *find_line(char *p, char *e, char *u, char *t, char *l)
+ {
+       char *p1, *p2, *ret;
+-      
++
+       while (p<e  && (p1 = get_eol(p, e)) < e) {
+               ret = p;
+               if (*p == '#')
+@@ -473,68 +481,122 @@ again:
+ static int rename_in_ns(int pid, char *oldname, char **newnamep)
+ {
+       char nspath[MAXPATHLEN];
++      uid_t ruid, suid, euid;
++      int fret = -1;
+       int fd = -1, ofd = -1, ret, ifindex = -1;
+       bool grab_newname = false;
+ 
+       ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", getpid());
+       if (ret < 0 || ret >= MAXPATHLEN)
+-              return -1;
++              goto do_partial_cleanup;
++
+       if ((ofd = open(nspath, O_RDONLY)) < 0) {
+-              fprintf(stderr, "Opening %s\n", nspath);
+-              return -1;
++              usernic_error("Failed opening network namespace path for 
'%d'.", getpid());
++              goto do_partial_cleanup;
+       }
++
+       ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", pid);
+       if (ret < 0 || ret >= MAXPATHLEN)
+-              goto out_err;
++              goto do_partial_cleanup;
+ 
+       if ((fd = open(nspath, O_RDONLY)) < 0) {
+-              fprintf(stderr, "Opening %s\n", nspath);
+-              goto out_err;
++              usernic_error("Failed opening network namespace path for 
'%d'.", pid);
++              goto do_partial_cleanup;
+       }
+-      if (setns(fd, 0) < 0) {
+-              fprintf(stderr, "setns to container network namespace\n");
+-              goto out_err;
++
++      ret = getresuid(&ruid, &euid, &suid);
++      if (ret < 0) {
++              usernic_error("Failed to retrieve real, effective, and saved "
++                            "user IDs: %s\n",
++                            strerror(errno));
++              goto do_partial_cleanup;
++      }
++
++      ret = setns(fd, CLONE_NEWNET);
++      close(fd);
++      fd = -1;
++      if (ret < 0) {
++              usernic_error("Failed to setns() to the network namespace of "
++                            "the container with PID %d: %s.\n",
++                            pid, strerror(errno));
++              goto do_partial_cleanup;
++      }
++
++      ret = setresuid(ruid, ruid, 0);
++      if (ret < 0) {
++              usernic_error("Failed to drop privilege by setting effective "
++                            "user id and real user id to %d, and saved user "
++                            "ID to 0: %s.\n",
++                            ruid, strerror(errno));
++              // COMMENT(brauner): It's ok to jump to do_full_cleanup here
++              // since setresuid() will succeed when trying to set real,
++              // effective, and saved to values they currently have.
++              goto do_full_cleanup;
+       }
+-      close(fd); fd = -1;
++
+       if (!*newnamep) {
+               grab_newname = true;
+               *newnamep = VETH_DEF_NAME;
+-              if (!(ifindex = if_nametoindex(oldname))) {
+-                      fprintf(stderr, "failed to get netdev index\n");
+-                      goto out_err;
++
++              ifindex = if_nametoindex(oldname);
++              if (!ifindex) {
++                      usernic_error("Failed to get netdev index: %s.\n",
++                                    strerror(errno));
++                      goto do_full_cleanup;
+               }
+       }
+-      if ((ret = lxc_netdev_rename_by_name(oldname, *newnamep)) < 0) {
+-              fprintf(stderr, "Error %d renaming netdev %s to %s in 
container\n", ret, oldname, *newnamep);
+-              goto out_err;
++
++      ret = lxc_netdev_rename_by_name(oldname, *newnamep);
++      if (ret < 0) {
++              usernic_error(
++                  "Error %d renaming netdev %s to %s in container.\n", ret,
++                  oldname, *newnamep);
++              goto do_full_cleanup;
+       }
++
+       if (grab_newname) {
+-              char ifname[IFNAMSIZ], *namep = ifname;
++              char ifname[IFNAMSIZ];
++              char *namep = ifname;
+               if (!if_indextoname(ifindex, namep)) {
+-                      fprintf(stderr, "Failed to get new netdev name\n");
+-                      goto out_err;
++                      usernic_error("Failed to get new netdev name: %s.\n",
++                                    strerror(errno));
++                      goto do_full_cleanup;
+               }
+               *newnamep = strdup(namep);
+               if (!*newnamep)
+-                      goto out_err;
+-      }
+-      if (setns(ofd, 0) < 0) {
+-              fprintf(stderr, "Error returning to original netns\n");
+-              close(ofd);
+-              return -1;
++                      goto do_full_cleanup;
+       }
+-      close(ofd);
+ 
+-      return 0;
++      fret = 0;
+ 
+-out_err:
+-      if (ofd >= 0)
+-              close(ofd);
+-      if (setns(ofd, 0) < 0)
+-              fprintf(stderr, "Error returning to original network 
namespace\n");
++do_full_cleanup:
++      ret = setresuid(ruid, euid, suid);
++      if (ret < 0) {
++              usernic_error(
++                  "Failed to restore privilege by setting effective "
++                  "user id to %d, real user id to %d, and saved user "
++                  "ID to %d: %s.\n",
++                  ruid, euid, suid, strerror(errno));
++              fret = -1;
++              // COMMENT(brauner): setns() should fail if setresuid() doesn't
++              // succeed but there's no harm in falling through; keeps the
++              // code cleaner.
++      }
++
++      ret = setns(ofd, CLONE_NEWNET);
++      if (ret < 0) {
++              usernic_error("Failed to setns() to original network namespace "
++                            "of PID %d: %s.\n",
++                            ofd, strerror(errno));
++              fret = -1;
++      }
++
++do_partial_cleanup:
+       if (fd >= 0)
+               close(fd);
+-      return -1;
++      close(ofd);
++
++      return fret;
+ }
+ 
+ /*
+-- 
+2.11.0
+
diff --git a/debian/patches/series b/debian/patches/series
index c97b6c5..4c1313c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -24,3 +24,4 @@
 0024-lxc-alpine-fix-verification-of-apk.static-binary.patch
 0025-Remounts-bind-mounts-if-read-only-flag-is-provided.patch
 0026-CVE-2016-8649_do-not-send-procfd-to-attached-process.patch
+0027-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch

Reply via email to