On Fri, Nov 13, 2015 at 06:12:26PM +0100, Salvatore Bonaccorso wrote:
> Hi Antonio,
> 
> On Fri, Nov 13, 2015 at 01:48:29PM +0100, Florian Weimer wrote:
> > * Antonio Terceiro:
> > 
> > > On Tue, Sep 29, 2015 at 10:33:27PM +0200, Salvatore Bonaccorso wrote:
> > >> Source: lxc
> > >> Version: 1:1.0.7-10
> > >> Severity: important
> > >> Tags: security upstream patch fixed-upstream
> > >
> > > I intend to upload the attached diff to jessie-security. I am uploading
> > > the same fix for unstable shortly.
> > 
> > Looks good, except for this part:
> > 
> > diff --git a/debian/gbp.conf b/debian/gbp.conf
> > new file mode 100644
> > index 0000000..28f6bb3
> > --- /dev/null
> > +++ b/debian/gbp.conf
> > @@ -0,0 +1,2 @@
> > +[DEAFULT]
> > +debian-branch = debian/jessie
> > 
> > I'm not sure if this belongs there, and there seems to be a typo.

OK, I dropped it.

> Additionally to that, are the patches actually complete?
> 
> This lxc update contained regressions initially which resulted in
> http://www.ubuntu.com/usn/usn-2753-2/ and
> http://www.ubuntu.com/usn/usn-2753-3/
> 
> AFAICS (but correct me if I'm wrong, I just only skimmed really
> quickly over the proposed debdiff) patches from 2753-2 and 2753-3 are
> not included.

I was assuming they had amended the original patch, but you are right:
the regression updates are separate patches, which I have now included
as well. Updated diff attached.

-- 
Antonio Terceiro <terce...@debian.org>
diff --git a/debian/changelog b/debian/changelog
index 4b4aecb..599a211 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+lxc (1:1.0.6-6+deb8u2) jessie-security; urgency=high
+
+  * CVE-2015-1335: prevent local containment administrator from escaping
+    container via symlink attack. (Closes: #800471). Also include 2 followup
+    patches that fixed regressions in the original fix. Patches obtained from
+    the Ubuntu package:
+    - 0020-CVE-2015-1335.patch
+    - 0021-CVE-2015-1335-2.patch
+    - 0022-CVE-2015-1335-3.patch
+
+ -- Antonio Terceiro <terce...@debian.org>  Fri, 13 Nov 2015 09:53:32 -0200
+
 lxc (1:1.0.6-6+deb8u1) jessie-security; urgency=high
 
   * Non-maintainer upload by the Security Team.
diff --git a/debian/patches/0020-CVE-2015-1335.patch b/debian/patches/0020-CVE-2015-1335.patch
new file mode 100644
index 0000000..0bce2a7
--- /dev/null
+++ b/debian/patches/0020-CVE-2015-1335.patch
@@ -0,0 +1,455 @@
+From 3c62cae308e8e66dcc616c5bd34671e1d2eea5a6 Mon Sep 17 00:00:00 2001
+From: Serge Hallyn <serge.hal...@ubuntu.com>
+Date: Mon, 31 Aug 2015 12:57:20 -0500
+Subject: [PATCH 1/1] Protect container mounts against symlinks
+
+When a container starts up, lxc sets up the container's inital fstree
+by doing a bunch of mounting, guided by the container configuration
+file.  The container config is owned by the admin or user on the host,
+so we do not try to guard against bad entries.  However, since the
+mount target is in the container, it's possible that the container admin
+could divert the mount with symbolic links.  This could bypass proper
+container startup (i.e. confinement of a root-owned container by the
+restrictive apparmor policy, by diverting the required write to
+/proc/self/attr/current), or bypass the (path-based) apparmor policy
+by diverting, say, /proc to /mnt in the container.
+
+To prevent this,
+
+1. do not allow mounts to paths containing symbolic links
+
+2. do not allow bind mounts from relative paths containing symbolic
+links.
+
+Details:
+
+This patch causes lxc to check /proc/self/mountinfo after each
+mount into a container rootfs (that is, where we are not chrooted
+into the container), making sure that the mount target wasn't a
+symlink.
+
+Use safe_mount() in mount_entry(), when mounting container proc,
+and when needed.  In particular, safe_mount() need not be used in
+any case where:
+
+1. the mount is done in the container's namespace
+2. the mount is for the container's rootfs
+3. the mount is relative to a tmpfs or proc/sysfs which we have
+   just safe_mount()ed ourselves
+
+Since we were using proc/net as a temporary placeholder for /proc/sys/net
+during container startup, and proc/net is a symbolic link, use proc/tty
+instead.
+
+Update the lxc.container.conf manpage with details about the new
+restrictions.
+
+Finally, add a testcase to test some symbolic link possibilities.
+
+lxc-test-symlink: background lxc-start
+
+CVE-2015-1335
+
+Signed-off-by: Serge Hallyn <serge.hal...@ubuntu.com>
+---
+ doc/lxc.container.conf.sgml.in | 12 ++++++
+ src/lxc/cgfs.c                 |  5 ++-
+ src/lxc/cgmanager.c            |  4 +-
+ src/lxc/conf.c                 | 30 +++++++-------
+ src/lxc/utils.c                | 90 ++++++++++++++++++++++++++++++++++++++++++
+ src/lxc/utils.h                |  2 +
+ src/tests/Makefile.am          |  3 +-
+ src/tests/lxc-test-symlink     | 88 +++++++++++++++++++++++++++++++++++++++++
+ 8 files changed, 216 insertions(+), 18 deletions(-)
+ create mode 100644 src/tests/lxc-test-symlink
+
+--- a/doc/lxc.container.conf.sgml.in
++++ b/doc/lxc.container.conf.sgml.in
+@@ -676,6 +676,18 @@ Foundation, Inc., 51 Franklin Street, Fi
+ 	container. This is useful to mount /etc, /var or /home for
+ 	examples.
+       </para>
++      <para>
++	NOTE - LXC will generally ensure that mount targets and relative
++	bind-mount sources are properly confined under the container
++	root, to avoid attacks involving over-mounting host directories
++	and files.  (Symbolic links in absolute mount sources are ignored)
++	However, if the container configuration first mounts a directory which
++	is under the control of the container user, such as /home/joe, into
++        the container at some <filename>path</filename>, and then mounts
++        under <filename>path</filename>, then a TOCTTOU attack would be
++        possible where the container user modifies a symbolic link under
++        his home directory at just the right time.
++      </para>
+       <variablelist>
+ 	<varlistentry>
+ 	  <term>
+--- a/src/lxc/cgfs.c
++++ b/src/lxc/cgfs.c
+@@ -1363,7 +1363,10 @@ static bool cgroupfs_mount_cgroup(void *
+ 	if (!path)
+ 		return false;
+ 	snprintf(path, bufsz, "%s/sys/fs/cgroup", root);
+-	r = mount("cgroup_root", path, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "size=10240k,mode=755");
++	r = safe_mount("cgroup_root", path, "tmpfs",
++			MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
++			"size=10240k,mode=755",
++			root);
+ 	if (r < 0) {
+ 		SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container");
+ 		return false;
+--- a/src/lxc/cgmanager.c
++++ b/src/lxc/cgmanager.c
+@@ -1262,7 +1262,7 @@ static bool cgm_bind_dir(const char *roo
+ 	}
+ 
+ 	/* mount a tmpfs there so we can create subdirs */
+-	if (mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755")) {
++	if (safe_mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755", root)) {
+ 		SYSERROR("Failed to mount tmpfs at %s", cgpath);
+ 		return false;
+ 	}
+@@ -1273,7 +1273,7 @@ static bool cgm_bind_dir(const char *roo
+ 		return false;
+ 	}
+ 
+-	if (mount(dirname, cgpath, "none", MS_BIND, 0)) {
++	if (safe_mount(dirname, cgpath, "none", MS_BIND, 0, root)) {
+ 		SYSERROR("Failed to bind mount %s to %s", dirname, cgpath);
+ 		return false;
+ 	}
+--- a/src/lxc/conf.c
++++ b/src/lxc/conf.c
+@@ -791,7 +791,7 @@ static int lxc_mount_auto_mounts(struct
+ 			}
+ 			mflags = add_required_remount_flags(source, destination,
+ 					default_mounts[i].flags);
+-			r = mount(source, destination, default_mounts[i].fstype, mflags, default_mounts[i].options);
++			r = safe_mount(source, destination, default_mounts[i].fstype, mflags, default_mounts[i].options, conf->rootfs.path ? conf->rootfs.mount : NULL);
+ 			saved_errno = errno;
+ 			if (r < 0)
+ 				SYSERROR("error mounting %s on %s flags %lu", source, destination, mflags);
+@@ -985,7 +985,8 @@ static int setup_tty(const struct lxc_ro
+ 				return -1;
+ 			}
+ 
+-			if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) {
++			if (safe_mount(pty_info->name, lxcpath, "none", MS_BIND, 0,
++					rootfs->mount)) {
+ 				WARN("failed to mount '%s'->'%s'",
+ 				     pty_info->name, path);
+ 				continue;
+@@ -1012,7 +1013,8 @@ static int setup_tty(const struct lxc_ro
+ 					close(ret);
+ 				}
+ 			}
+-			if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
++			if (safe_mount(pty_info->name, path, "none", MS_BIND, 0,
++					rootfs->mount)) {
+ 				WARN("failed to mount '%s'->'%s'",
+ 						pty_info->name, path);
+ 				continue;
+@@ -1438,16 +1440,16 @@ static int mount_autodev(const char *nam
+ 			SYSERROR("WARNING: Failed to create symlink '%s'->'%s'", host_path, devtmpfs_path);
+ 		}
+ 		DEBUG("Bind mounting %s to %s", devtmpfs_path , path );
+-		ret = mount(devtmpfs_path, path, NULL, MS_BIND, 0 );
++		ret = safe_mount(devtmpfs_path, path, NULL, MS_BIND, 0, root );
+ 	} else {
+ 		/* Only mount a tmpfs on here if we don't already a mount */
+ 		if ( ! mount_check_fs( host_path, NULL ) ) {
+ 			DEBUG("Mounting tmpfs to %s", host_path );
+-			ret = mount("none", path, "tmpfs", 0, "size=100000,mode=755");
++			ret = safe_mount("none", path, "tmpfs", 0, "size=100000,mode=755", root);
+ 		} else {
+ 			/* This allows someone to manually set up a mount */
+ 			DEBUG("Bind mounting %s to %s", host_path, path );
+-			ret = mount(host_path , path, NULL, MS_BIND, 0 );
++			ret = safe_mount(host_path , path, NULL, MS_BIND, 0, root );
+ 		}
+ 	}
+ 	if (ret) {
+@@ -1792,7 +1794,7 @@ static int setup_dev_console(const struc
+ 		return -1;
+ 	}
+ 
+-	if (mount(console->name, path, "none", MS_BIND, 0)) {
++	if (safe_mount(console->name, path, "none", MS_BIND, 0, rootfs->mount)) {
+ 		ERROR("failed to mount '%s' on '%s'", console->name, path);
+ 		return -1;
+ 	}
+@@ -1847,7 +1849,7 @@ static int setup_ttydir_console(const st
+ 		return 0;
+ 	}
+ 
+-	if (mount(console->name, lxcpath, "none", MS_BIND, 0)) {
++	if (safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs->mount)) {
+ 		ERROR("failed to mount '%s' on '%s'", console->name, lxcpath);
+ 		return -1;
+ 	}
+@@ -1997,13 +1999,13 @@ static char *get_field(char *src, int nf
+ 
+ static int mount_entry(const char *fsname, const char *target,
+ 		       const char *fstype, unsigned long mountflags,
+-		       const char *data, int optional)
++		       const char *data, int optional, const char *rootfs)
+ {
+ #ifdef HAVE_STATVFS
+ 	struct statvfs sb;
+ #endif
+ 
+-	if (mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data)) {
++	if (safe_mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data, rootfs)) {
+ 		if (optional) {
+ 			INFO("failed to mount '%s' on '%s' (optional): %s", fsname,
+ 			     target, strerror(errno));
+@@ -2134,7 +2136,7 @@ static inline int mount_entry_on_systemf
+ 	}
+ 
+ 	ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir,
+-			  mntent->mnt_type, mntflags, mntdata, optional);
++			  mntent->mnt_type, mntflags, mntdata, optional, NULL);
+ 
+ 	free(pathdirname);
+ 	free(mntdata);
+@@ -2221,7 +2223,7 @@ skipabs:
+ 	}
+ 
+ 	ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
+-			  mntflags, mntdata, optional);
++			  mntflags, mntdata, optional, rootfs->mount);
+ 
+ 	free(mntdata);
+ 
+@@ -2277,7 +2279,7 @@ static int mount_entry_on_relative_rootf
+ 	}
+ 
+ 	ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
+-			  mntflags, mntdata, optional);
++			  mntflags, mntdata, optional, rootfs);
+ 
+ 	free(pathdirname);
+ 	free(mntdata);
+@@ -3943,7 +3945,7 @@ static int do_tmp_proc_mount(const char
+ 	return 0;
+ 
+ domount:
+-	if (mount("proc", path, "proc", 0, NULL))
++	if (safe_mount("proc", path, "proc", 0, NULL, rootfs))
+ 		return -1;
+ 	INFO("Mounted /proc in container for security transition");
+ 	return 1;
+--- a/src/lxc/utils.c
++++ b/src/lxc/utils.c
+@@ -1306,3 +1306,93 @@ next_loop:
+ 	free(path);
+ 	return NULL;
+ }
++
++/*
++ * ws points into an array of \0-separate path elements.
++ * ws should be pointing to one of the path elements or
++ * the next \0.  It will return the first character of the
++ * next path element.
++ */
++static char *next_word(char *ws) {
++	while (*ws && *ws != ' ') ws++;
++	while (*ws && *ws == ' ') ws++;
++	return ws;
++}
++
++/*
++ * This is only used during container startup.  So we know we won't race
++ * with anyone else mounting.  Check the last line in /proc/self/mountinfo
++ * to make sure the target is under the container root.
++ */
++static bool ensure_not_symlink(const char *target, const char *croot)
++{
++	FILE *f = fopen("/proc/self/mountinfo", "r");
++	char *line = NULL, *ws = NULL, *we = NULL;
++	size_t len = 0, i;
++	bool ret = false;
++
++	if (!croot || croot[0] == '\0')
++		return true;
++
++	if (!f) {
++		ERROR("Cannot open /proc/self/mountinfo");
++		return false;
++	}
++
++	while (getline(&line, &len, f) != -1) {
++	}
++	fclose(f);
++
++	if (!line)
++		return false;
++	ws = line;
++	for (i = 0; i < 4; i++)
++		ws = next_word(ws);
++	if (!*ws)
++		goto out;
++	we = ws;
++	while (*we && *we != ' ')
++		we++;
++	if (!*we)
++		goto out;
++	*we = '\0';
++
++	/* now make sure that ws starts with croot and ends with rest of target */
++	if (croot && strncmp(ws, croot, strlen(croot)) != 0) {
++		ERROR("Mount onto %s resulted in %s\n", target, ws);
++		goto out;
++	}
++
++	size_t start = croot ? strlen(croot) : 0;
++	if (strcmp(ws + start, target + start) != 0) {
++		ERROR("Mount onto %s resulted in %s\n", target, ws);
++		goto out;
++	}
++
++	ret = true;
++
++out:
++	free(line);
++	return ret;
++}
++/*
++ * Safely mount a path into a container, ensuring that the mount target
++ * is under the container's @rootfs.  (If @rootfs is NULL, then the container
++ * uses the host's /)
++ */
++int safe_mount(const char *src, const char *dest, const char *fstype,
++		unsigned long flags, const void *data, const char *rootfs)
++{
++	int ret;
++	ret = mount(src, dest, fstype, flags, data);
++	if (ret < 0) {
++		SYSERROR("Mount of '%s' onto '%s' failed", src, dest);
++		return ret;
++	}
++	if (!ensure_not_symlink(dest, rootfs)) {
++		ERROR("Mount of '%s' onto '%s' was onto a symlink!", src, dest);
++		umount(dest);
++		return -1;
++	}
++	return 0;
++}
+--- a/src/lxc/utils.h
++++ b/src/lxc/utils.h
+@@ -280,3 +280,5 @@ uint64_t fnv_64a_buf(void *buf, size_t l
+ int detect_shared_rootfs(void);
+ int detect_ramfs_rootfs(void);
+ char *on_path(char *cmd);
++int safe_mount(const char *src, const char *dest, const char *fstype,
++		unsigned long flags, const void *data, const char *rootfs);
+--- a/src/tests/Makefile.am
++++ b/src/tests/Makefile.am
+@@ -48,7 +48,7 @@ bin_PROGRAMS = lxc-test-containertests l
+ 	lxc-test-reboot lxc-test-list lxc-test-attach lxc-test-device-add-remove \
+ 	lxc-test-apparmor
+ 
+-bin_SCRIPTS = lxc-test-autostart
++bin_SCRIPTS = lxc-test-autostart lxc-test-symlink
+ 
+ if DISTRO_UBUNTU
+ bin_SCRIPTS += lxc-test-usernic lxc-test-ubuntu lxc-test-unpriv
+@@ -71,6 +71,7 @@ EXTRA_DIST = \
+ 	locktests.c \
+ 	lxcpath.c \
+ 	lxc-test-autostart \
++	lxc-test-symlink \
+ 	lxc-test-ubuntu \
+ 	lxc-test-unpriv \
+ 	lxc-test-usernic \
+--- /dev/null
++++ b/src/tests/lxc-test-symlink
+@@ -0,0 +1,88 @@
++#!/bin/bash
++
++set -ex
++
++# lxc: linux Container library
++
++# Authors:
++# Serge Hallyn <serge.hal...@ubuntu.com>
++#
++# This is a regression test for symbolic links
++
++dirname=`mktemp -d`
++fname=`mktemp`
++fname2=`mktemp`
++
++lxcpath=/var/lib/lxcsym1
++
++cleanup() {
++	lxc-destroy -P $lxcpath -f -n symtest1 || true
++	rm -f $lxcpath
++	rmdir $dirname || true
++	rm -f $fname || true
++	rm -f $fname2 || true
++}
++
++trap cleanup EXIT SIGHUP SIGINT SIGTERM
++
++testrun() {
++	expected=$1
++	run=$2
++	pass="pass"
++	lxc-start -d -P $lxcpath -n symtest1 -l trace -o $lxcpath/log || pass="fail"
++	[ $pass = "pass" ] && lxc-wait -P $lxcpath -n symtest1 -t 10 -s RUNNING || pass="fail"
++	if [ "$pass" != "$expected" ]; then
++		echo "Test $run: expected $expected but container did not.  Start log:"
++		cat $lxcpath/log
++		echo "FAIL: Test $run: expected $expected but container did not."
++		false
++	fi
++	lxc-stop -P $lxcpath -n symtest1 -k || true
++}
++
++# make lxcpath a symlink - this should NOT cause failure
++ln -s /var/lib/lxc $lxcpath
++
++lxc-destroy -P $lxcpath -f -n symtest1 || true
++lxc-create -P $lxcpath -t busybox -n symtest1
++
++cat >> /var/lib/lxc/symtest1/config << EOF
++lxc.mount.entry = $dirname opt/xxx/dir none bind,create=dir
++lxc.mount.entry = $fname opt/xxx/file none bind,create=file
++lxc.mount.entry = $fname2 opt/xxx/file2 none bind
++EOF
++
++# Regular - should succeed
++mkdir -p /var/lib/lxc/symtest1/rootfs/opt/xxx
++touch /var/lib/lxc/symtest1/rootfs/opt/xxx/file2
++testrun pass 1
++
++# symlink - should fail
++rm -rf /var/lib/lxc/symtest1/rootfs/opt/xxx
++mkdir -p /var/lib/lxc/symtest1/rootfs/opt/xxx2
++ln -s /var/lib/lxc/symtest1/rootfs/opt/xxx2 /var/lib/lxc/symtest1/rootfs/opt/xxx
++touch /var/lib/lxc/symtest1/rootfs/opt/xxx/file2
++testrun fail 2
++
++# final final symlink - should fail
++rm -rf $lxcpath/symtest1/rootfs/opt/xxx
++mkdir -p $lxcpath/symtest1/rootfs/opt/xxx
++mkdir -p $lxcpath/symtest1/rootfs/opt/xxx/dir
++touch $lxcpath/symtest1/rootfs/opt/xxx/file
++touch $lxcpath/symtest1/rootfs/opt/xxx/file2src
++ln -s $lxcpath/symtest1/rootfs/opt/xxx/file2src $lxcpath/symtest1/rootfs/opt/xxx/file2
++testrun fail 3
++
++# Ideally we'd also try a loop device, but that won't work in nested containers
++# anyway - TODO
++
++# what about /proc itself
++
++rm -rf $lxcpath/symtest1/rootfs/opt/xxx
++mkdir -p $lxcpath/symtest1/rootfs/opt/xxx
++touch $lxcpath/symtest1/rootfs/opt/xxx/file2
++mv $lxcpath/symtest1/rootfs/proc $lxcpath/symtest1/rootfs/proc1
++ln -s $lxcpath/symtest1/rootfs/proc1 $lxcpath/symtest1/rootfs/proc
++testrun fail 4
++
++echo "all tests passed"
diff --git a/debian/patches/0021-CVE-2015-1335-2.patch b/debian/patches/0021-CVE-2015-1335-2.patch
new file mode 100644
index 0000000..98f849c
--- /dev/null
+++ b/debian/patches/0021-CVE-2015-1335-2.patch
@@ -0,0 +1,60 @@
+Description: fix mount target mismatches due to multiple slashes
+ The patch to fix symlink tocttou's in mount entries at container start
+ notices that target and actual mount point don't match.
+ We introduce a // when the user specifies an absolute mount target, but
+ rather than fix that, check for all '//' since user may have them in
+ their container configuration, and we don't want to break configs which
+ worked before.
+Author: Serge Hallyn <serge.hal...@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1476662
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1501310
+
+--- a/src/lxc/utils.c
++++ b/src/lxc/utils.c
+@@ -1319,6 +1319,17 @@ static char *next_word(char *ws) {
+ 	return ws;
+ }
+ 
++/* copy src to dest, collapsing multiple '/' into one */
++static void copy_cleanedup(char *dest, const char *src)
++{
++	while (*src) {
++		while (*src == '/' && *(src+1) == '/')
++			src++;
++		*(dest++) = *(src++);
++	}
++	*dest = '\0';
++}
++
+ /*
+  * This is only used during container startup.  So we know we won't race
+  * with anyone else mounting.  Check the last line in /proc/self/mountinfo
+@@ -1327,7 +1338,7 @@ static char *next_word(char *ws) {
+ static bool ensure_not_symlink(const char *target, const char *croot)
+ {
+ 	FILE *f = fopen("/proc/self/mountinfo", "r");
+-	char *line = NULL, *ws = NULL, *we = NULL;
++	char *line = NULL, *ws = NULL, *we = NULL, *tgtcopy;
+ 	size_t len = 0, i;
+ 	bool ret = false;
+ 
+@@ -1357,14 +1368,17 @@ static bool ensure_not_symlink(const cha
+ 		goto out;
+ 	*we = '\0';
+ 
++	tgtcopy = alloca(strlen(target) + 1);
++	copy_cleanedup(tgtcopy, target);
+ 	/* now make sure that ws starts with croot and ends with rest of target */
+ 	if (croot && strncmp(ws, croot, strlen(croot)) != 0) {
+-		ERROR("Mount onto %s resulted in %s\n", target, ws);
++		ERROR("Mount onto %s resulted in %s, does not match root %s\n",
++			target, ws, croot);
+ 		goto out;
+ 	}
+ 
+ 	size_t start = croot ? strlen(croot) : 0;
+-	if (strcmp(ws + start, target + start) != 0) {
++	if (strcmp(ws + start, tgtcopy + start) != 0) {
+ 		ERROR("Mount onto %s resulted in %s\n", target, ws);
+ 		goto out;
+ 	}
diff --git a/debian/patches/0022-CVE-2015-1335-3.patch b/debian/patches/0022-CVE-2015-1335-3.patch
new file mode 100644
index 0000000..c22142f
--- /dev/null
+++ b/debian/patches/0022-CVE-2015-1335-3.patch
@@ -0,0 +1,60 @@
+Description: also avoid /./
+Author: Serge Hallyn <serge.hal...@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1501491
+
+--- a/src/lxc/utils.c
++++ b/src/lxc/utils.c
+@@ -1319,15 +1319,30 @@ static char *next_word(char *ws) {
+ 	return ws;
+ }
+ 
+-/* copy src to dest, collapsing multiple '/' into one */
++/*
++ * copy src to dest, collapsing multiple '/' into one and
++ * collapsing '/./' to '/'
++ */
+ static void copy_cleanedup(char *dest, const char *src)
+ {
++	char *orig = dest;
+ 	while (*src) {
+-		while (*src == '/' && *(src+1) == '/')
++		if (*src == '/' && *(src+1) == '/') {
+ 			src++;
++			continue;
++		}
++		if (*src == '/' && *(src+1) == '.' &&
++			(*(src+2) == '/' || *(src+2) == '\0')) {
++			src += 2;
++			continue;
++		}
+ 		*(dest++) = *(src++);
+ 	}
+ 	*dest = '\0';
++	/* remove trailing / */
++	dest--;
++	while (dest > orig && *dest == '/')
++		*(dest--) = '\0';
+ }
+ 
+ /*
+@@ -1379,7 +1394,7 @@ static bool ensure_not_symlink(const cha
+ 
+ 	size_t start = croot ? strlen(croot) : 0;
+ 	if (strcmp(ws + start, tgtcopy + start) != 0) {
+-		ERROR("Mount onto %s resulted in %s\n", target, ws);
++		ERROR("Mount onto %s resulted in %s, not %s\n", target, ws, tgtcopy);
+ 		goto out;
+ 	}
+ 
+--- a/src/tests/lxc-test-symlink
++++ b/src/tests/lxc-test-symlink
+@@ -50,6 +50,9 @@ cat >> /var/lib/lxc/symtest1/config << E
+ lxc.mount.entry = $dirname opt/xxx/dir none bind,create=dir
+ lxc.mount.entry = $fname opt/xxx/file none bind,create=file
+ lxc.mount.entry = $fname2 opt/xxx/file2 none bind
++lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir2 none bind,create=dir
++lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir3// none bind,create=dir
++lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir4/. none bind,create=dir
+ EOF
+ 
+ # Regular - should succeed
diff --git a/debian/patches/series b/debian/patches/series
index d8f17d2..0f054c0 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -17,3 +17,6 @@
 0017-lxc-debian-mirror.patch
 0018-CVE-2015-1331-lxclock-use-run-lxc-lock-rather-than-r.patch
 0019-CVE-2015-1334-Don-t-use-the-container-s-proc-during-.patch
+0020-CVE-2015-1335.patch
+0021-CVE-2015-1335-2.patch
+0022-CVE-2015-1335-3.patch

Attachment: signature.asc
Description: PGP signature

Reply via email to