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

Bug#862468: marked as done ((pre-approval) unblock: lxc/1:2.0.8-1)



Your message dated Sat, 27 May 2017 22:34:35 +0200
with message-id <20170527203433.GA4847@ugent.be>
and subject line Re: Bug#862468: (pre-approval) unblock: lxc/1:2.0.8-1
has caused the Debian Bug report #862468,
regarding (pre-approval) unblock: lxc/1:2.0.8-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
862468: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=862468
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Dear Release Team,

I wonder if you would be OK with accepting the latest LXC stable release
into Stretch at this point in time.
Admittedly, the diff between the version in testing and 2.0.8 is quite
big (64 files changed, 1652 insertions(+), 996 deletions(-)), but it
allows us to drop both cherry-picked patches we carry today and gives an
IMHO better base for later updates during the Stretch life cycle.

Ubuntu will be updating to the same version in their LTS soon, so I
expect high exposure and low risk.

Additionally I've been thinking about including the fix for
 #860974 lxc: systemd and other inotify-based programs fail with "Too many open files" with a large number of LXC containers
Which boils down to adding a one-liner (plus comments) to /etc/sysctl.d

Please tell me how crazy I am ;-)

Full debdiff attached.

Thanks for all your work!
Evgeni
diff --git a/README b/README
index 3e2a963..bca00c9 100644
--- a/README
+++ b/README
@@ -59,9 +59,6 @@ Getting help:
 
 Portability:
 
-  lxc  is  still  in  development, so the command syntax and the API can
-  change. The version 1.0.0 will be the frozen version.
-
   lxc is developed and tested on Linux since kernel mainline version 2.6.27
   (without network) and 2.6.29 with network isolation.
   It's compiled with gcc, and should work on most architectures as long as the
diff --git a/config/apparmor/Makefile.in b/config/apparmor/Makefile.in
index 6264641..9951f24 100644
--- a/config/apparmor/Makefile.in
+++ b/config/apparmor/Makefile.in
@@ -440,8 +440,8 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
-@ENABLE_APPARMOR_FALSE@install-data-local:
 @ENABLE_APPARMOR_FALSE@uninstall-local:
+@ENABLE_APPARMOR_FALSE@install-data-local:
 clean: clean-am
 
 clean-am: clean-generic clean-libtool mostlyclean-am
diff --git a/config/init/common/lxc-containers.in b/config/init/common/lxc-containers.in
index ebce36e..35b9084 100644
--- a/config/init/common/lxc-containers.in
+++ b/config/init/common/lxc-containers.in
@@ -51,7 +51,9 @@ fi
 # to start
 wait_for_bridge()
 {
-    local BRNAME try flags
+    [ "x$USE_LXC_BRIDGE" = "xtrue" ] || { return 0; }
+
+    local BRNAME try flags br
     [ -f "$sysconfdir"/lxc/default.conf ] || { return 0; }
 
     BRNAME=`grep '^[ 	]*lxc.network.link' "$sysconfdir"/lxc/default.conf | sed 's/^.*=[ 	]*//'`
@@ -60,11 +62,12 @@ wait_for_bridge()
     fi
 
     for try in `seq 1 30`; do
-        if [ -r /sys/class/net/$BRNAME/flags ]; then
-            read flags < /sys/class/net/$BRNAME/flags
-            [ $((flags & 0x1)) -eq 1 ] && { return 0; }
-        fi
-        sleep 1
+        for br in ${BRNAME}; do
+             [ -r /sys/class/net/${br}/flags ] || { sleep 1; continue 2; }
+             read flags < /sys/class/net/${br}/flags
+             [ $((flags & 0x1)) -eq 1 ] || { sleep 1; continue 2; }
+        done
+        return 0
     done
 }
 
diff --git a/config/init/common/lxc-net.in b/config/init/common/lxc-net.in
index 4797f20..f770950 100644
--- a/config/init/common/lxc-net.in
+++ b/config/init/common/lxc-net.in
@@ -66,6 +66,7 @@ start() {
         if [ "$FAILED" = "1" ]; then
             echo "Failed to setup lxc-net." >&2
             stop force
+            exit 1
         fi
     }
 
diff --git a/config/init/upstart/Makefile.in b/config/init/upstart/Makefile.in
index 5a7b1f8..259b9e3 100644
--- a/config/init/upstart/Makefile.in
+++ b/config/init/upstart/Makefile.in
@@ -432,8 +432,8 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
-@INIT_SCRIPT_UPSTART_FALSE@uninstall-local:
 @INIT_SCRIPT_UPSTART_FALSE@install-data-local:
+@INIT_SCRIPT_UPSTART_FALSE@uninstall-local:
 clean: clean-am
 
 clean-am: clean-generic clean-libtool mostlyclean-am
diff --git a/config/templates/userns.conf.in b/config/templates/userns.conf.in
index 5dc19c7..78383eb 100644
--- a/config/templates/userns.conf.in
+++ b/config/templates/userns.conf.in
@@ -6,7 +6,6 @@ lxc.cgroup.devices.allow =
 lxc.devttydir =
 
 # Extra bind-mounts for userns
-lxc.mount.entry = /dev/console dev/console none bind,create=file 0 0
 lxc.mount.entry = /dev/full dev/full none bind,create=file 0 0
 lxc.mount.entry = /dev/null dev/null none bind,create=file 0 0
 lxc.mount.entry = /dev/random dev/random none bind,create=file 0 0
diff --git a/configure b/configure
index edc109f..f7db3a4 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for lxc 2.0.7.
+# Generated by GNU Autoconf 2.69 for lxc 2.0.8.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='lxc'
 PACKAGE_TARNAME='lxc'
-PACKAGE_VERSION='2.0.7'
-PACKAGE_STRING='lxc 2.0.7'
+PACKAGE_VERSION='2.0.8'
+PACKAGE_STRING='lxc 2.0.8'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1503,7 +1503,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures lxc 2.0.7 to adapt to many kinds of systems.
+\`configure' configures lxc 2.0.8 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1574,7 +1574,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of lxc 2.0.7:";;
+     short | recursive ) echo "Configuration of lxc 2.0.8:";;
    esac
   cat <<\_ACEOF
 
@@ -1754,7 +1754,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-lxc configure 2.0.7
+lxc configure 2.0.8
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2219,7 +2219,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by lxc $as_me 2.0.7, which was
+It was created by lxc $as_me 2.0.8, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2690,7 +2690,7 @@ $as_echo "no" >&6; }
 	fi
 fi
 
-LXC_VERSION_BASE=2.0.7
+LXC_VERSION_BASE=2.0.8
 
 
 
@@ -2698,9 +2698,9 @@ LXC_VERSION_MAJOR=2
 
 LXC_VERSION_MINOR=0
 
-LXC_VERSION_MICRO=7
+LXC_VERSION_MICRO=8
 
-LXC_VERSION=2.0.7
+LXC_VERSION=2.0.8
 
 LXC_DEVEL=0
 
@@ -3232,7 +3232,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='lxc'
- VERSION='2.0.7'
+ VERSION='2.0.8'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -12897,13 +12897,13 @@ case "$with_init_script" in
 			fedora|altlinux|opensuse*)
 				init_script=systemd
 				;;
-			redhat|centos|oracle|oracleserver|sparclinux|plamo)
+			redhat|oracle|oracleserver|sparclinux|plamo)
 				init_script=sysvinit
 				;;
-			debian|raspbian)
-				init_script=upstart,systemd
+			centos)
+				init_script=sysvinit,systemd
 				;;
-			ubuntu)
+			debian|raspbian|ubuntu)
 				init_script=upstart,systemd
 				;;
 			*)
@@ -14463,7 +14463,15 @@ fi
 
 
 if test -z "$ENABLE_CAP_TRUE"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_set_proc in -lcap" >&5
+  ac_fn_c_check_header_mongrel "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_capability_h" = xyes; then :
+
+else
+  as_fn_error $? "You must install the libcap development package in order to compile lxc" "$LINENO" 5
+fi
+
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_set_proc in -lcap" >&5
 $as_echo_n "checking for cap_set_proc in -lcap... " >&6; }
 if ${ac_cv_lib_cap_cap_set_proc+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -14500,12 +14508,60 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_set_proc" >&5
 $as_echo "$ac_cv_lib_cap_cap_set_proc" >&6; }
 if test "x$ac_cv_lib_cap_cap_set_proc" = xyes; then :
-  true
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCAP 1
+_ACEOF
+
+  LIBS="-lcap $LIBS"
+
+else
+  as_fn_error $? "You must install the libcap development package in order to compile lxc" "$LINENO" 5
+fi
+
+        # Test whether we support getting file capabilities via cap_get_file().
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_get_file in -lcap" >&5
+$as_echo_n "checking for cap_get_file in -lcap... " >&6; }
+if ${ac_cv_lib_cap_cap_get_file+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  as_fn_error $? "You are missing libcap support." "$LINENO" 5
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcap  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cap_get_file ();
+int
+main ()
+{
+return cap_get_file ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_cap_cap_get_file=yes
+else
+  ac_cv_lib_cap_cap_get_file=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_get_file" >&5
+$as_echo "$ac_cv_lib_cap_cap_get_file" >&6; }
+if test "x$ac_cv_lib_cap_cap_get_file" = xyes; then :
+
+$as_echo "#define LIBCAP_SUPPORTS_FILE_CAPABILITIES 1" >>confdefs.h
+
 fi
 
-	CAP_LIBS=-lcap
+        CAP_LIBS=-lcap
 
 fi
 
@@ -16781,7 +16837,7 @@ _ACEOF
 
 
 # Check for some headers
-for ac_header in sys/signalfd.h pty.h ifaddrs.h sys/capability.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h
+for ac_header in sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -17996,7 +18052,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by lxc $as_me 2.0.7, which was
+This file was extended by lxc $as_me 2.0.8, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -18066,7 +18122,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-lxc config.status 2.0.7
+lxc config.status 2.0.8
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 42ece7a..bd2d82f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 m4_define([lxc_devel], 0)
 m4_define([lxc_version_major], 2)
 m4_define([lxc_version_minor], 0)
-m4_define([lxc_version_micro], 7)
+m4_define([lxc_version_micro], 8)
 m4_define([lxc_version_beta], [])
 
 m4_define([lxc_abi_major], 1)
@@ -113,13 +113,13 @@ case "$with_init_script" in
 			fedora|altlinux|opensuse*)
 				init_script=systemd
 				;;
-			redhat|centos|oracle|oracleserver|sparclinux|plamo)
+			redhat|oracle|oracleserver|sparclinux|plamo)
 				init_script=sysvinit
 				;;
-			debian|raspbian)
-				init_script=upstart,systemd
+			centos)
+				init_script=sysvinit,systemd
 				;;
-			ubuntu)
+			debian|raspbian|ubuntu)
 				init_script=upstart,systemd
 				;;
 			*)
@@ -366,8 +366,11 @@ fi
 AM_CONDITIONAL([ENABLE_CAP], [test "x$enable_capabilities" = "xyes"])
 
 AM_COND_IF([ENABLE_CAP],
-	[AC_CHECK_LIB(cap,cap_set_proc,[true],[AC_MSG_ERROR([You are missing libcap support.])])
-	AC_SUBST([CAP_LIBS], [-lcap])])
+	[AC_CHECK_HEADER([sys/capability.h],[],[AC_MSG_ERROR([You must install the libcap development package in order to compile lxc])])
+	AC_CHECK_LIB(cap,cap_set_proc,[],[AC_MSG_ERROR([You must install the libcap development package in order to compile lxc])])
+        # Test whether we support getting file capabilities via cap_get_file().
+        AC_CHECK_LIB(cap,cap_get_file, AC_DEFINE(LIBCAP_SUPPORTS_FILE_CAPABILITIES,1,[Have cap_get_file]),[],[])
+        AC_SUBST([CAP_LIBS], [-lcap])])
 
 # HAVE_SCMP_FILTER_CTX=1 will tell us we have libseccomp api >= 1.0.0
 OLD_CFLAGS="$CFLAGS"
@@ -630,7 +633,7 @@ AM_CONDITIONAL([IS_BIONIC], [test "x$is_bionic" = "xyes"])
 AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
 
 # Check for some headers
-AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/capability.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h])
+AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h])
 
 # lookup major()/minor()/makedev()
 AC_HEADER_MAJOR
diff --git a/debian/patches/0010-lxc-debian-root-password.patch b/debian/patches/0010-lxc-debian-root-password.patch
deleted file mode 100644
index ef071e2..0000000
--- a/debian/patches/0010-lxc-debian-root-password.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 515fb8d20cde7a4b8179ca45647edc4607a5c35b Mon Sep 17 00:00:00 2001
-From: Evgeni Golov <evgeni@debian.org>
-Date: Wed, 13 Apr 2016 18:04:19 +0200
-Subject: [PATCH] do not set the root password in the debian template
-
-closes #302
-
-Signed-off-by: Evgeni Golov <evgeni@debian.org>
----
- templates/lxc-debian.in | 3 ---
- 1 file changed, 3 deletions(-)
-
-diff --git a/templates/lxc-debian.in b/templates/lxc-debian.in
-index 1ed6f20..b5af844 100644
---- a/templates/lxc-debian.in
-+++ b/templates/lxc-debian.in
-@@ -140,9 +140,6 @@ EOF
-         echo "Timezone in container is not configured. Adjust it manually."
-     fi
- 
--    echo "root:root" | chroot "$rootfs" chpasswd
--    echo "Root password is 'root', please change !"
--
-     return 0
- }
- 
diff --git a/debian/patches/lxc-2.0-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch b/debian/patches/lxc-2.0-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
deleted file mode 100644
index 9570f12..0000000
--- a/debian/patches/lxc-2.0-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
+++ /dev/null
@@ -1,188 +0,0 @@
-From d512bd5efb0e407eba350c4e649c464a65b712a3 Mon Sep 17 00:00:00 2001
-From: Christian Brauner <christian.brauner@ubuntu.com>
-Date: Sat, 28 Jan 2017 13:02:34 +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 <jannh@google.com>
-Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
----
- src/lxc/lxc_user_nic.c | 119 ++++++++++++++++++++++++++++++++++++-------------
- 1 file changed, 87 insertions(+), 32 deletions(-)
-
-diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c
-index 409a53a1..96dc3986 100644
---- a/src/lxc/lxc_user_nic.c
-+++ b/src/lxc/lxc_user_nic.c
-@@ -50,6 +50,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 lxcpath name pid type bridge nicname\n", me);
-@@ -670,68 +678,115 @@ again:
- }
- 
- #define VETH_DEF_NAME "eth%d"
--
- static int rename_in_ns(int pid, char *oldname, char **newnamep)
- {
--	int fd = -1, ofd = -1, ret, ifindex = -1;
-+	uid_t ruid, suid, euid;
-+	int fret = -1;
-+	int fd = -1, ifindex = -1, ofd = -1, ret;
- 	bool grab_newname = false;
- 
- 	ofd = lxc_preserve_ns(getpid(), "net");
- 	if (ofd < 0) {
--		fprintf(stderr, "Failed opening network namespace path for '%d'.", getpid());
--		return -1;
-+		usernic_error("Failed opening network namespace path for '%d'.", getpid());
-+		return fret;
- 	}
- 
- 	fd = lxc_preserve_ns(pid, "net");
- 	if (fd < 0) {
--		fprintf(stderr, "Failed opening network namespace path for '%d'.", pid);
--		return -1;
-+		usernic_error("Failed opening network namespace path for '%d'.", pid);
-+		goto do_partial_cleanup;
-+	}
-+
-+	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;
- 	}
- 
--	if (setns(fd, 0) < 0) {
--		fprintf(stderr, "setns to container network namespace\n");
--		goto out_err;
-+	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;
-+			goto do_full_cleanup;
- 	}
--	if (setns(ofd, 0) < 0) {
--		fprintf(stderr, "Error returning to original netns\n");
--		close(ofd);
--		return -1;
-+
-+	fret = 0;
-+
-+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.
- 	}
--	close(ofd);
- 
--	return 0;
-+	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;
-+	}
- 
--out_err:
--	if (ofd >= 0)
--		close(ofd);
--	if (setns(ofd, 0) < 0)
--		fprintf(stderr, "Error returning to original network namespace\n");
-+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
deleted file mode 100644
index b99ca55..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1,2 +0,0 @@
-0010-lxc-debian-root-password.patch
-lxc-2.0-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 05baddd..a4ef46d 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -668,10 +668,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
           <listitem>
             <para>
               Specify a path to a device to which the console will be
-              attached.  The keyword 'none' will simply disable the
-              console.  This is dangerous once if have a rootfs with a
-              console device file where the application can write, the
-              messages will fall in the host.
+              attached. The keyword 'none' will simply disable the
+              console. Note, when specifying 'none' and creating a device node
+              for the console in the container at /dev/console or bind-mounting
+              the hosts's /dev/console into the container at /dev/console the
+              container will have direct access to the hosts's /dev/console.
+              This is dangerous when the container has write access to the
+              device and should thus be used with caution.
             </para>
           </listitem>
         </varlistentry>
@@ -727,7 +730,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
           <listitem>
             <para>
               Specify a directory under <filename>/dev</filename>
-              under which to create the container console devices.
+              under which to create the container console devices. Note that LXC
+              will move any bind-mounts or device nodes for /dev/console into
+              this directory.
             </para>
           </listitem>
         </varlistentry>
diff --git a/hooks/clonehostname b/hooks/clonehostname
index ed2765c..8eec7a6 100755
--- a/hooks/clonehostname
+++ b/hooks/clonehostname
@@ -19,9 +19,9 @@
 
 # Note that /etc/hostname is updated by lxc itself
 for file in \
-    $LXC_ROOTFS_PATH/etc/sysconfig/network \
-    $LXC_ROOTFS_PATH/etc/sysconfig/network-scripts/ifcfg-* \
-    $LXC_ROOTFS_PATH/etc/hosts ;
+    $LXC_ROOTFS_MOUNT/etc/sysconfig/network \
+    $LXC_ROOTFS_MOUNT/etc/sysconfig/network-scripts/ifcfg-* \
+    $LXC_ROOTFS_MOUNT/etc/hosts ;
 do
     if [ -f $file ]; then
         sed -i "s|$LXC_SRC_NAME|$LXC_NAME|" $file
diff --git a/lxc.spec b/lxc.spec
index 4d4ef07..993c46c 100644
--- a/lxc.spec
+++ b/lxc.spec
@@ -60,7 +60,7 @@ BuildRequires: systemd
 %endif
 
 Name: lxc
-Version: 2.0.7
+Version: 2.0.8
 Release: %{?beta_rel:0.1.%{beta_rel}}%{?!beta_rel:%{norm_rel}}%{?dist}
 URL: http://linuxcontainers.org
 Source: http://linuxcontainers.org/downloads/%{name}-%{version}%{?beta_dot}.tar.gz
diff --git a/src/config.h.in b/src/config.h.in
index a83788a..1228131 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -56,6 +56,9 @@
 /* Define to 1 if you have the `apparmor' library (-lapparmor). */
 #undef HAVE_LIBAPPARMOR
 
+/* Define to 1 if you have the `cap' library (-lcap). */
+#undef HAVE_LIBCAP
+
 /* Define to 1 if you have the `gnutls' library (-lgnutls). */
 #undef HAVE_LIBGNUTLS
 
@@ -128,9 +131,6 @@
 /* Define to 1 if you have the <string.h> header file. */
 #undef HAVE_STRING_H
 
-/* Define to 1 if you have the <sys/capability.h> header file. */
-#undef HAVE_SYS_CAPABILITY_H
-
 /* Define to 1 if you have the <sys/memfd.h> header file. */
 #undef HAVE_SYS_MEMFD_H
 
@@ -167,6 +167,9 @@
 /* bionic libc */
 #undef IS_BIONIC
 
+/* Have cap_get_file */
+#undef LIBCAP_SUPPORTS_FILE_CAPABILITIES
+
 /* Define to the sub-directory where libtool stores uninstalled libraries. */
 #undef LT_OBJDIR
 
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 6bcb6da..d7c05d6 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -290,7 +290,7 @@ init_lxc_static_SOURCES += ../include/getline.c
 endif
 endif
 
-init_lxc_static_LDFLAGS = -static
+init_lxc_static_LDFLAGS = -all-static
 init_lxc_static_LDADD = @CAP_LIBS@
 init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
 endif
diff --git a/src/lxc/Makefile.in b/src/lxc/Makefile.in
index 7d47ea5..66d323c 100644
--- a/src/lxc/Makefile.in
+++ b/src/lxc/Makefile.in
@@ -766,7 +766,7 @@ lxc_monitord_SOURCES = lxc_monitord.c
 @HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_SOURCES = tools/lxc_init.c \
 @HAVE_STATIC_LIBCAP_TRUE@	error.c log.c initutils.c caps.c \
 @HAVE_STATIC_LIBCAP_TRUE@	$(am__append_22)
-@HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_LDFLAGS = -static
+@HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_LDFLAGS = -all-static
 @HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_LDADD = @CAP_LIBS@
 @HAVE_STATIC_LIBCAP_TRUE@init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
 all: all-am
diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c
index 46d8e50..ac83994 100644
--- a/src/lxc/af_unix.c
+++ b/src/lxc/af_unix.c
@@ -55,8 +55,9 @@ int lxc_abstract_unix_open(const char *path, int type, int flags)
 
 	addr.sun_family = AF_UNIX;
 
-	len = strlen(&path[1]) + 1;
-	if (len >= sizeof(addr.sun_path) - 1) {
+	len = strlen(&path[1]);
+	/* do not enforce \0-termination */
+	if (len >= sizeof(addr.sun_path)) {
 		close(fd);
 		errno = ENAMETOOLONG;
 		return -1;
@@ -64,7 +65,7 @@ int lxc_abstract_unix_open(const char *path, int type, int flags)
 	/* addr.sun_path[0] has already been set to 0 by memset() */
 	strncpy(&addr.sun_path[1], &path[1], strlen(&path[1]));
 
-	if (bind(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len)) {
+	if (bind(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len + 1)) {
 		int tmp = errno;
 		close(fd);
 		errno = tmp;
@@ -109,8 +110,9 @@ int lxc_abstract_unix_connect(const char *path)
 
 	addr.sun_family = AF_UNIX;
 
-	len = strlen(&path[1]) + 1;
-	if (len >= sizeof(addr.sun_path) - 1) {
+	len = strlen(&path[1]);
+	/* do not enforce \0-termination */
+	if (len >= sizeof(addr.sun_path)) {
 		close(fd);
 		errno = ENAMETOOLONG;
 		return -1;
@@ -118,7 +120,7 @@ int lxc_abstract_unix_connect(const char *path)
 	/* addr.sun_path[0] has already been set to 0 by memset() */
 	strncpy(&addr.sun_path[1], &path[1], strlen(&path[1]));
 
-	if (connect(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len)) {
+	if (connect(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len + 1)) {
 		int tmp = errno;
 		/* special case to connect to older containers */
 		if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
@@ -136,8 +138,8 @@ int lxc_abstract_unix_send_fd(int fd, int sendfd, void *data, size_t size)
 	struct msghdr msg = { 0 };
 	struct iovec iov;
 	struct cmsghdr *cmsg;
-	char cmsgbuf[CMSG_SPACE(sizeof(int))];
-	char buf[1];
+	char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
+	char buf[1] = {0};
 	int *val;
 
 	msg.msg_control = cmsgbuf;
@@ -166,9 +168,9 @@ int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size)
 	struct msghdr msg = { 0 };
 	struct iovec iov;
 	struct cmsghdr *cmsg;
-	char cmsgbuf[CMSG_SPACE(sizeof(int))];
-	char buf[1];
 	int ret, *val;
+	char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
+	char buf[1] = {0};
 
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
@@ -210,8 +212,8 @@ int lxc_abstract_unix_send_credential(int fd, void *data, size_t size)
 		.uid = getuid(),
 		.gid = getgid(),
 	};
-	char cmsgbuf[CMSG_SPACE(sizeof(cred))];
-	char buf[1];
+	char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
+	char buf[1] = {0};
 
 	msg.msg_control = cmsgbuf;
 	msg.msg_controllen = sizeof(cmsgbuf);
@@ -239,9 +241,9 @@ int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size)
 	struct iovec iov;
 	struct cmsghdr *cmsg;
 	struct ucred cred;
-	char cmsgbuf[CMSG_SPACE(sizeof(cred))];
-	char buf[1];
 	int ret;
+	char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
+	char buf[1] = {0};
 
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h
index 3f5d01f..d25a211 100644
--- a/src/lxc/af_unix.h
+++ b/src/lxc/af_unix.h
@@ -24,8 +24,10 @@
 #ifndef __LXC_AF_UNIX_H
 #define __LXC_AF_UNIX_H
 
+/* does not enforce \0-termination */
 extern int lxc_abstract_unix_open(const char *path, int type, int flags);
 extern int lxc_abstract_unix_close(int fd);
+/* does not enforce \0-termination */
 extern int lxc_abstract_unix_connect(const char *path);
 extern int lxc_abstract_unix_send_fd(int fd, int sendfd, void *data, size_t size);
 extern int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size);
diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c
index b322002..a4633e4 100644
--- a/src/lxc/bdev/lxcloop.c
+++ b/src/lxc/bdev/lxcloop.c
@@ -35,19 +35,9 @@
 #include "lxcloop.h"
 #include "utils.h"
 
-#ifndef LO_FLAGS_AUTOCLEAR
-#define LO_FLAGS_AUTOCLEAR 4
-#endif
-
-#ifndef LOOP_CTL_GET_FREE
-#define LOOP_CTL_GET_FREE 0x4C82
-#endif
-
 lxc_log_define(lxcloop, lxc);
 
 static int do_loop_create(const char *path, uint64_t size, const char *fstype);
-static int find_free_loopdev_no_control(int *retfd, char *namep);
-static int find_free_loopdev(int *retfd, char *namep);
 
 /*
  * No idea what the original blockdev will be called, but the copy will be
@@ -174,47 +164,26 @@ int loop_detect(const char *path)
 
 int loop_mount(struct bdev *bdev)
 {
-	int lfd, ffd = -1, ret = -1;
-	struct loop_info64 lo;
-	char loname[100];
+	int ret, loopfd;
+	char loname[MAXPATHLEN];
 
 	if (strcmp(bdev->type, "loop"))
 		return -22;
 	if (!bdev->src || !bdev->dest)
 		return -22;
-	if (find_free_loopdev(&lfd, loname) < 0)
-		return -22;
-
-	ffd = open(bdev->src + 5, O_RDWR);
-	if (ffd < 0) {
-		SYSERROR("Error opening backing file %s", bdev->src);
-		goto out;
-	}
 
-	if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) {
-		SYSERROR("Error attaching backing file to loop dev");
-		goto out;
-	}
-	memset(&lo, 0, sizeof(lo));
-	lo.lo_flags = LO_FLAGS_AUTOCLEAR;
-	if (ioctl(lfd, LOOP_SET_STATUS64, &lo) < 0) {
-		SYSERROR("Error setting autoclear on loop dev");
-		goto out;
-	}
+	loopfd = lxc_prepare_loop_dev(bdev->src + 5, loname, LO_FLAGS_AUTOCLEAR);
+	if (loopfd < 0)
+		return -1;
+	DEBUG("prepared loop device \"%s\"", loname);
 
 	ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
 	if (ret < 0)
-		ERROR("Error mounting %s", bdev->src);
+		ERROR("failed to mount rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
 	else
-		bdev->lofd = lfd;
+		bdev->lofd = loopfd;
+	DEBUG("mounted rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
 
-out:
-	if (ffd > -1)
-		close(ffd);
-	if (ret < 0) {
-		close(lfd);
-		bdev->lofd = -1;
-	}
 	return ret;
 }
 
@@ -266,63 +235,3 @@ static int do_loop_create(const char *path, uint64_t size, const char *fstype)
 
 	return 0;
 }
-
-static int find_free_loopdev_no_control(int *retfd, char *namep)
-{
-	struct dirent *direntp;
-	struct loop_info64 lo;
-	DIR *dir;
-	int fd = -1;
-
-	dir = opendir("/dev");
-	if (!dir) {
-		SYSERROR("Error opening /dev");
-		return -1;
-	}
-	while ((direntp = readdir(dir))) {
-
-		if (!direntp)
-			break;
-		if (strncmp(direntp->d_name, "loop", 4) != 0)
-			continue;
-		fd = openat(dirfd(dir), direntp->d_name, O_RDWR);
-		if (fd < 0)
-			continue;
-		if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) {
-			close(fd);
-			fd = -1;
-			continue;
-		}
-		// We can use this fd
-		snprintf(namep, 100, "/dev/%s", direntp->d_name);
-		break;
-	}
-	closedir(dir);
-	if (fd == -1) {
-		ERROR("No loop device found");
-		return -1;
-	}
-
-	*retfd = fd;
-	return 0;
-}
-
-static int find_free_loopdev(int *retfd, char *namep)
-{
-	int rc, fd = -1;
-	int ctl = open("/dev/loop-control", O_RDWR);
-	if (ctl < 0)
-		return find_free_loopdev_no_control(retfd, namep);
-	rc = ioctl(ctl, LOOP_CTL_GET_FREE);
-	if (rc >= 0) {
-		snprintf(namep, 100, "/dev/loop%d", rc);
-		fd = open(namep, O_RDWR);
-	}
-	close(ctl);
-	if (fd == -1) {
-		ERROR("No loop device found");
-		return -1;
-	}
-	*retfd = fd;
-	return 0;
-}
diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c
index 75de17f..bcd8be8 100644
--- a/src/lxc/bdev/lxclvm.c
+++ b/src/lxc/bdev/lxclvm.c
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/sysmacros.h>
 #include <sys/wait.h>
 
 #include "bdev.h"
@@ -41,9 +42,6 @@
 #ifdef MAJOR_IN_MKDEV
 #    include <sys/mkdev.h>
 #endif
-#ifdef MAJOR_IN_SYSMACROS
-#    include <sys/sysmacros.h>
-#endif
 
 lxc_log_define(lxclvm, lxc);
 
diff --git a/src/lxc/caps.c b/src/lxc/caps.c
index 73b5516..195707f 100644
--- a/src/lxc/caps.c
+++ b/src/lxc/caps.c
@@ -36,7 +36,7 @@
 
 lxc_log_define(lxc_caps, lxc);
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 
 #ifndef PR_CAPBSET_READ
 #define PR_CAPBSET_READ 23
@@ -209,27 +209,61 @@ int lxc_caps_last_cap(void)
 	return last_cap;
 }
 
-bool lxc_cap_is_set(cap_value_t cap, cap_flag_t flag)
+static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
 {
 	int ret;
-	cap_t caps;
 	cap_flag_value_t flagval;
 
-	caps = cap_get_proc();
+	ret = cap_get_flag(caps, cap, flag, &flagval);
+	if (ret < 0) {
+		ERROR("Failed to perform cap_get_flag(): %s.", strerror(errno));
+		return false;
+	}
+
+	return flagval == CAP_SET;
+}
+
+bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
+{
+	#if LIBCAP_SUPPORTS_FILE_CAPABILITIES
+	bool cap_is_set;
+	cap_t caps;
+
+	caps = cap_get_file(path);
 	if (!caps) {
-		ERROR("Failed to perform cap_get_proc(): %s.", strerror(errno));
+		/* This is undocumented in the manpage but the source code show
+		 * that cap_get_file() may return NULL when successful for the
+		 * case where it didn't detect any file capabilities. In this
+		 * case errno will be set to ENODATA.
+		 */
+		if (errno != ENODATA)
+			ERROR("Failed to perform cap_get_file(): %s.\n", strerror(errno));
 		return false;
 	}
 
-	ret = cap_get_flag(caps, cap, flag, &flagval);
-	if (ret < 0) {
-		ERROR("Failed to perform cap_get_flag(): %s.", strerror(errno));
-		cap_free(caps);
+	cap_is_set = lxc_cap_is_set(caps, cap, flag);
+	cap_free(caps);
+	return cap_is_set;
+	#else
+	errno = ENODATA;
+	return false;
+	#endif
+}
+
+bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
+{
+	bool cap_is_set;
+	cap_t caps;
+
+	caps = cap_get_proc();
+	if (!caps) {
+		ERROR("Failed to perform cap_get_proc(): %s.\n", strerror(errno));
 		return false;
 	}
 
+	cap_is_set = lxc_cap_is_set(caps, cap, flag);
 	cap_free(caps);
-	return flagval == CAP_SET;
+	return cap_is_set;
 }
 
 #endif
diff --git a/src/lxc/caps.h b/src/lxc/caps.h
index 390dbdd..2a8c282 100644
--- a/src/lxc/caps.h
+++ b/src/lxc/caps.h
@@ -27,7 +27,7 @@
 #ifndef __LXC_CAPS_H
 #define __LXC_CAPS_H
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #include <sys/capability.h>
 
 extern int lxc_caps_down(void);
@@ -36,7 +36,8 @@ extern int lxc_caps_init(void);
 
 extern int lxc_caps_last_cap(void);
 
-extern bool lxc_cap_is_set(cap_value_t cap, cap_flag_t flag);
+extern bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag);
+extern bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag);
 #else
 static inline int lxc_caps_down(void) {
 	return 0;
@@ -54,8 +55,12 @@ static inline int lxc_caps_last_cap(void) {
 
 typedef int cap_value_t;
 typedef int cap_flag_t;
-static inline bool lxc_cap_is_set(cap_value_t cap, cap_flag_t flag) {
-	return true;
+static inline bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag) {
+	return false;
+}
+
+static inline bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag) {
+	return false;
 }
 #endif
 
diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
index 8499200..3bfa523 100644
--- a/src/lxc/cgroups/cgfs.c
+++ b/src/lxc/cgroups/cgfs.c
@@ -1880,7 +1880,7 @@ static int create_or_remove_cgroup(bool do_remove,
 		} else
 			r = rmdir(buf);
 	} else
-		r = mkdir(buf, 0777);
+		r = mkdir_p(buf, 0777);
 	saved_errno = errno;
 	free(buf);
 	errno = saved_errno;
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 2b772e2..ebd548b 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -101,6 +101,12 @@ struct hierarchy **hierarchies;
  */
 char *cgroup_use;
 
+/*
+ * @lxc_cgfsng_debug - whether to print debug info to stdout for the cgfsng
+ * driver
+ */
+static bool lxc_cgfsng_debug;
+
 static void free_string_list(char **clist)
 {
 	if (clist) {
@@ -986,45 +992,44 @@ static void get_existing_subsystems(char ***klist, char ***nlist)
 static void trim(char *s)
 {
 	size_t len = strlen(s);
-	while (s[len-1] == '\n')
+	while ((len > 1) && (s[len - 1] == '\n'))
 		s[--len] = '\0';
 }
 
-static void print_init_debuginfo(struct cgfsng_handler_data *d)
+static void lxc_cgfsng_print_handler_data(const struct cgfsng_handler_data *d)
+{
+	printf("Cgroup information:\n");
+	printf("  container name: %s\n", d->name ? d->name : "(null)");
+	printf("  lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(null)");
+	printf("  lxc.cgroup.pattern: %s\n", d->cgroup_pattern ? d->cgroup_pattern : "(null)");
+	printf("  cgroup: %s\n", d->container_cgroup ? d->container_cgroup : "(null)");
+}
+
+static void lxc_cgfsng_print_hierarchies()
 {
 	struct hierarchy **it;
 	int i;
 
-	if (!getenv("LXC_DEBUG_CGFSNG"))
-		return;
-
-	DEBUG("Cgroup information:");
-	DEBUG("  container name: %s", d->name ? d->name : "(null)");
-	DEBUG("  lxc.cgroup.use: %s", cgroup_use ? cgroup_use : "(null)");
-	DEBUG("  lxc.cgroup.pattern: %s", d->cgroup_pattern ? d->cgroup_pattern : "(null)");
-	DEBUG("  cgroup: %s", d->container_cgroup ? d->container_cgroup : "(null)");
 	if (!hierarchies) {
-		DEBUG("  No hierarchies found.");
+		printf("  No hierarchies found.");
 		return;
 	}
-	DEBUG("  Hierarchies:");
+	printf("  Hierarchies:\n");
 	for (i = 0, it = hierarchies; it && *it; it++, i++) {
 		char **cit;
 		int j;
-		DEBUG("  %d: base_cgroup %s", i, (*it)->base_cgroup ? (*it)->base_cgroup : "(null)");
-		DEBUG("      mountpoint %s", (*it)->mountpoint ? (*it)->mountpoint : "(null)");
-		DEBUG("      controllers:");
+		printf("  %d: base_cgroup %s\n", i, (*it)->base_cgroup ? (*it)->base_cgroup : "(null)");
+		printf("      mountpoint %s\n", (*it)->mountpoint ? (*it)->mountpoint : "(null)");
+		printf("      controllers:\n");
 		for (j = 0, cit = (*it)->controllers; cit && *cit; cit++, j++)
-			DEBUG("      %d: %s", j, *cit);
+			printf("      %d: %s\n", j, *cit);
 	}
 }
 
-static void print_basecg_debuginfo(char *basecginfo, char **klist, char **nlist)
+static void lxc_cgfsng_print_basecg_debuginfo(char *basecginfo, char **klist, char **nlist)
 {
 	int k;
 	char **it;
-	if (!getenv("LXC_DEBUG_CGFSNG"))
-		return;
 
 	printf("basecginfo is:\n");
 	printf("%s\n", basecginfo);
@@ -1035,6 +1040,12 @@ static void print_basecg_debuginfo(char *basecginfo, char **klist, char **nlist)
 		printf("named subsystem %d: %s\n", k, *it);
 }
 
+static void lxc_cgfsng_print_debuginfo(const struct cgfsng_handler_data *d)
+{
+	lxc_cgfsng_print_handler_data(d);
+	lxc_cgfsng_print_hierarchies();
+}
+
 /*
  * At startup, parse_hierarchies finds all the info we need about
  * cgroup mountpoints and current cgroups, and stores it in @d.
@@ -1064,7 +1075,8 @@ static bool parse_hierarchies(void)
 
 	get_existing_subsystems(&klist, &nlist);
 
-	print_basecg_debuginfo(basecginfo, klist, nlist);
+	if (lxc_cgfsng_debug)
+		lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist);
 
 	/* we support simple cgroup mounts and lxcfs mounts */
 	while (getline(&line, &len, f) != -1) {
@@ -1116,6 +1128,11 @@ static bool parse_hierarchies(void)
 	fclose(f);
 	free(line);
 
+	if (lxc_cgfsng_debug) {
+		printf("writeable subsystems:\n");
+		lxc_cgfsng_print_hierarchies();
+	}
+
 	/* verify that all controllers in cgroup.use and all crucial
 	 * controllers are accounted for
 	 */
@@ -1156,7 +1173,8 @@ static void *cgfsng_init(const char *name)
 	}
 	d->cgroup_pattern = must_copy_string(cgroup_pattern);
 
-	print_init_debuginfo(d);
+	if (lxc_cgfsng_debug)
+		lxc_cgfsng_print_debuginfo(d);
 
 	return d;
 
@@ -1294,8 +1312,12 @@ static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
 
 struct cgroup_ops *cgfsng_ops_init(void)
 {
+	if (getenv("LXC_DEBUG_CGFSNG"))
+		lxc_cgfsng_debug = true;
+
 	if (!collect_hierarchy_info())
 		return NULL;
+
 	return &cgfsng_ops;
 }
 
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index b17879b..27c8c08 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -74,14 +74,19 @@
 
 lxc_log_define(lxc_commands, lxc);
 
-static int fill_sock_name(char *path, int len, const char *name,
+static int fill_sock_name(char *path, int len, const char *lxcname,
 			  const char *lxcpath, const char *hashed_sock_name)
 {
+	const char *name;
 	char *tmppath;
 	size_t tmplen;
 	uint64_t hash;
 	int ret;
 
+	name = lxcname;
+	if (!name)
+		name = "";
+
 	if (hashed_sock_name != NULL) {
 		ret = snprintf(path, len, "lxc/%s/command", hashed_sock_name);
 		if (ret < 0 || ret >= len) {
@@ -193,8 +198,11 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
 		rsp->data = rspdata;
 	}
 
-	if (rsp->datalen == 0)
+	if (rsp->datalen == 0) {
+		DEBUG("command %s response data length is 0",
+		      lxc_cmd_str(cmd->req.cmd));
 		return ret;
+	}
 	if (rsp->datalen > LXC_CMD_DATA_MAX) {
 		ERROR("Command %s response data %d too long.",
 		      lxc_cmd_str(cmd->req.cmd), rsp->datalen);
@@ -274,7 +282,7 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
 	int sock, ret = -1;
 	char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
 	char *offset = &path[1];
-	int len;
+	size_t len;
 	int stay_connected = cmd->req.cmd == LXC_CMD_CONSOLE;
 
 	*stopped = 0;
@@ -982,7 +990,7 @@ int lxc_cmd_init(const char *name, struct lxc_handler *handler,
 	 * Although null termination isn't required by the API, we do it anyway
 	 * because we print the sockname out sometimes.
 	 */
-	len = sizeof(path)-2;
+	len = sizeof(path) - 2;
 	if (fill_sock_name(offset, len, name, lxcpath, NULL))
 		return -1;
 
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a93124b..923a4d9 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -47,6 +47,7 @@
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/sysmacros.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
@@ -56,9 +57,6 @@
 #ifdef MAJOR_IN_MKDEV
 #    include <sys/mkdev.h>
 #endif
-#ifdef MAJOR_IN_SYSMACROS
-#    include <sys/sysmacros.h>
-#endif
 
 #ifdef HAVE_STATVFS
 #include <sys/statvfs.h>
@@ -91,7 +89,7 @@
 #include "utils.h"
 #include "lsm/lsm.h"
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #include <sys/capability.h>
 #endif
 
@@ -107,7 +105,7 @@
 
 lxc_log_define(lxc_conf, lxc);
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #ifndef CAP_SETFCAP
 #define CAP_SETFCAP 31
 #endif
@@ -172,6 +170,10 @@ static int sethostname(const char * name, size_t len)
 #define MS_PRIVATE (1<<18)
 #endif
 
+#ifndef MS_LAZYTIME
+#define MS_LAZYTIME (1<<25)
+#endif
+
 /* memfd_create() */
 #ifndef MFD_CLOEXEC
 #define MFD_CLOEXEC 0x0001U
@@ -288,35 +290,36 @@ static  instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
 };
 
 static struct mount_opt mount_opt[] = {
+	{ "async",         1, MS_SYNCHRONOUS },
+	{ "atime",         1, MS_NOATIME     },
+	{ "bind",          0, MS_BIND        },
 	{ "defaults",      0, 0              },
-	{ "ro",            0, MS_RDONLY      },
-	{ "rw",            1, MS_RDONLY      },
-	{ "suid",          1, MS_NOSUID      },
-	{ "nosuid",        0, MS_NOSUID      },
 	{ "dev",           1, MS_NODEV       },
-	{ "nodev",         0, MS_NODEV       },
-	{ "exec",          1, MS_NOEXEC      },
-	{ "noexec",        0, MS_NOEXEC      },
-	{ "sync",          0, MS_SYNCHRONOUS },
-	{ "async",         1, MS_SYNCHRONOUS },
+	{ "diratime",      1, MS_NODIRATIME  },
 	{ "dirsync",       0, MS_DIRSYNC     },
-	{ "remount",       0, MS_REMOUNT     },
+	{ "exec",          1, MS_NOEXEC      },
+	{ "lazytime",	   0, MS_LAZYTIME    },
 	{ "mand",          0, MS_MANDLOCK    },
-	{ "nomand",        1, MS_MANDLOCK    },
-	{ "atime",         1, MS_NOATIME     },
 	{ "noatime",       0, MS_NOATIME     },
-	{ "diratime",      1, MS_NODIRATIME  },
+	{ "nodev",         0, MS_NODEV       },
 	{ "nodiratime",    0, MS_NODIRATIME  },
-	{ "bind",          0, MS_BIND        },
+	{ "noexec",        0, MS_NOEXEC      },
+	{ "nomand",        1, MS_MANDLOCK    },
+	{ "norelatime",    1, MS_RELATIME    },
+	{ "nostrictatime", 1, MS_STRICTATIME },
+	{ "nosuid",        0, MS_NOSUID      },
 	{ "rbind",         0, MS_BIND|MS_REC },
 	{ "relatime",      0, MS_RELATIME    },
-	{ "norelatime",    1, MS_RELATIME    },
+	{ "remount",       0, MS_REMOUNT     },
+	{ "ro",            0, MS_RDONLY      },
+	{ "rw",            1, MS_RDONLY      },
 	{ "strictatime",   0, MS_STRICTATIME },
-	{ "nostrictatime", 1, MS_STRICTATIME },
+	{ "suid",          1, MS_NOSUID      },
+	{ "sync",          0, MS_SYNCHRONOUS },
 	{ NULL,            0, 0              },
 };
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 static struct caps_opt caps_opt[] = {
 	{ "chown",             CAP_CHOWN             },
 	{ "dac_override",      CAP_DAC_OVERRIDE      },
@@ -516,7 +519,7 @@ static int run_script(const char *name, const char *section, const char *script,
 }
 
 static int mount_rootfs_dir(const char *rootfs, const char *target,
-			                const char *options)
+			    const char *options)
 {
 	unsigned long mntflags;
 	char *mntdata;
@@ -533,99 +536,21 @@ static int mount_rootfs_dir(const char *rootfs, const char *target,
 	return ret;
 }
 
-static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
-{
-	int rfd;
-	int ret = -1;
-
-	rfd = open(rootfs, O_RDWR);
-	if (rfd < 0) {
-		SYSERROR("failed to open '%s'", rootfs);
-		return -1;
-	}
-
-	memset(loinfo, 0, sizeof(*loinfo));
-
-	loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
-
-	if (ioctl(fd, LOOP_SET_FD, rfd)) {
-		SYSERROR("failed to LOOP_SET_FD");
-		goto out;
-	}
-
-	if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
-		SYSERROR("failed to LOOP_SET_STATUS64");
-		goto out;
-	}
-
-	ret = 0;
-out:
-	close(rfd);
-
-	return ret;
-}
-
-static int mount_rootfs_file(const char *rootfs, const char *target,
-				             const char *options)
+static int lxc_mount_rootfs_file(const char *rootfs, const char *target,
+			     const char *options)
 {
-	struct dirent *direntp;
-	struct loop_info64 loinfo;
-	int ret = -1, fd = -1, rc;
-	DIR *dir;
+	int ret, loopfd;
 	char path[MAXPATHLEN];
 
-	dir = opendir("/dev");
-	if (!dir) {
-		SYSERROR("failed to open '/dev'");
+	loopfd = lxc_prepare_loop_dev(rootfs, path, LO_FLAGS_AUTOCLEAR);
+	if (loopfd < 0)
 		return -1;
-	}
+	DEBUG("prepared loop device \"%s\"", path);
 
-	while ((direntp = readdir(dir))) {
+	ret = mount_unknown_fs(path, target, options);
+	close(loopfd);
 
-		if (!direntp)
-			break;
-
-		if (!strcmp(direntp->d_name, "."))
-			continue;
-
-		if (!strcmp(direntp->d_name, ".."))
-			continue;
-
-		if (strncmp(direntp->d_name, "loop", 4))
-			continue;
-
-		rc = snprintf(path, MAXPATHLEN, "/dev/%s", direntp->d_name);
-		if (rc < 0 || rc >= MAXPATHLEN)
-			continue;
-
-		fd = open(path, O_RDWR);
-		if (fd < 0)
-			continue;
-
-		if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) {
-			close(fd);
-			continue;
-		}
-
-		if (errno != ENXIO) {
-			WARN("unexpected error for ioctl on '%s': %m",
-			     direntp->d_name);
-			close(fd);
-			continue;
-		}
-
-		DEBUG("found '%s' free lodev", path);
-
-		ret = setup_lodev(rootfs, fd, &loinfo);
-		if (!ret)
-			ret = mount_unknown_fs(path, target, options);
-		close(fd);
-
-		break;
-	}
-
-	if (closedir(dir))
-		WARN("failed to close directory");
+	DEBUG("mounted rootfs \"%s\" on loop device \"%s\" via loop device \"%s\"", rootfs, target, path);
 
 	return ret;
 }
@@ -858,33 +783,32 @@ static int mount_rootfs(const char *rootfs, const char *target, const char *opti
 	} rtfs_type[] = {
 		{ S_IFDIR, mount_rootfs_dir },
 		{ S_IFBLK, mount_rootfs_block },
-		{ S_IFREG, mount_rootfs_file },
+		{ S_IFREG, lxc_mount_rootfs_file },
 	};
 
 	if (!realpath(rootfs, absrootfs)) {
-		SYSERROR("failed to get real path for '%s'", rootfs);
+		SYSERROR("Failed to get real path for \"%s\".", rootfs);
 		return -1;
 	}
 
 	if (access(absrootfs, F_OK)) {
-		SYSERROR("'%s' is not accessible", absrootfs);
+		SYSERROR("The rootfs \"%s\" is not accessible.", absrootfs);
 		return -1;
 	}
 
 	if (stat(absrootfs, &s)) {
-		SYSERROR("failed to stat '%s'", absrootfs);
+		SYSERROR("Failed to stat the rootfs \"%s\".", absrootfs);
 		return -1;
 	}
 
 	for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
-
 		if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
 			continue;
 
 		return rtfs_type[i].cb(absrootfs, target, options);
 	}
 
-	ERROR("unsupported rootfs type for '%s'", absrootfs);
+	ERROR("Unsupported rootfs type for rootfs \"%s\".", absrootfs);
 	return -1;
 }
 
@@ -1186,45 +1110,47 @@ static const struct lxc_devs lxc_devs[] = {
 	{ "urandom",	S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9	},
 	{ "random",	S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8	},
 	{ "tty",	S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0	},
-	{ "console",	S_IFCHR | S_IRUSR | S_IWUSR,	       5, 1	},
 };
 
-static int fill_autodev(const struct lxc_rootfs *rootfs, bool mount_console)
+static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
 {
 	int ret;
 	char path[MAXPATHLEN];
 	int i;
 	mode_t cmask;
 
-	INFO("Creating initial consoles under container /dev");
-
 	ret = snprintf(path, MAXPATHLEN, "%s/dev", rootfs->path ? rootfs->mount : "");
 	if (ret < 0 || ret >= MAXPATHLEN) {
 		ERROR("Error calculating container /dev location");
 		return -1;
 	}
 
-	if (!dir_exists(path)) // ignore, just don't try to fill in
+	/* ignore, just don't try to fill in */
+	if (!dir_exists(path))
 		return 0;
 
-	INFO("Populating container /dev");
+	INFO("populating container /dev");
 	cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
 	for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
 		const struct lxc_devs *d = &lxc_devs[i];
 
-		if (!strcmp(d->name, "console") && !mount_console)
-			continue;
-
 		ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", rootfs->path ? rootfs->mount : "", d->name);
 		if (ret < 0 || ret >= MAXPATHLEN)
 			return -1;
+
 		ret = mknod(path, d->mode, makedev(d->maj, d->min));
-		if (ret && errno != EEXIST) {
+		if (ret < 0) {
 			char hostpath[MAXPATHLEN];
 			FILE *pathfile;
 
-			// Unprivileged containers cannot create devices, so
-			// bind mount the device from the host
+			if (errno == EEXIST) {
+				DEBUG("\"%s\" device already existed", path);
+				continue;
+			}
+
+			/* Unprivileged containers cannot create devices, so
+			 * bind mount the device from the host.
+			 */
 			ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", d->name);
 			if (ret < 0 || ret >= MAXPATHLEN)
 				return -1;
@@ -1234,54 +1160,62 @@ static int fill_autodev(const struct lxc_rootfs *rootfs, bool mount_console)
 				return -1;
 			}
 			fclose(pathfile);
-			if (safe_mount(hostpath, path, 0, MS_BIND, NULL,
-						rootfs->path ? rootfs->mount : NULL) != 0) {
-				SYSERROR("Failed bind mounting device %s from host into container",
-					d->name);
+			if (safe_mount(hostpath, path, 0, MS_BIND, NULL, rootfs->path ? rootfs->mount : NULL) != 0) {
+				SYSERROR("Failed bind mounting device %s from host into container", d->name);
 				return -1;
 			}
+			DEBUG("bind mounted \"%s\" onto \"%s\"", hostpath, path);
+		} else {
+			DEBUG("created device node \"%s\"", path);
 		}
 	}
 	umask(cmask);
 
-	INFO("Populated container /dev");
+	INFO("populated container /dev");
 	return 0;
 }
 
 static int setup_rootfs(struct lxc_conf *conf)
 {
-	const struct lxc_rootfs *rootfs = &conf->rootfs;
+	struct bdev *bdev;
+	const struct lxc_rootfs *rootfs;
 
+	rootfs = &conf->rootfs;
 	if (!rootfs->path) {
-		if (mount("", "/", NULL, MS_SLAVE|MS_REC, 0)) {
-			SYSERROR("Failed to make / rslave");
+		if (mount("", "/", NULL, MS_SLAVE | MS_REC, 0)) {
+			SYSERROR("Failed to make / rslave.");
 			return -1;
 		}
 		return 0;
 	}
 
 	if (access(rootfs->mount, F_OK)) {
-		SYSERROR("failed to access to '%s', check it is present",
+		SYSERROR("Failed to access to \"%s\". Check it is present.",
 			 rootfs->mount);
 		return -1;
 	}
 
-	// First try mounting rootfs using a bdev
-	struct bdev *bdev = bdev_init(conf, rootfs->path, rootfs->mount, rootfs->options);
-	if (bdev && bdev->ops->mount(bdev) == 0) {
+	/* First try mounting rootfs using a bdev. */
+	bdev = bdev_init(conf, rootfs->path, rootfs->mount, rootfs->options);
+	if (bdev && !bdev->ops->mount(bdev)) {
 		bdev_put(bdev);
-		DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
+		DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".",
+		      rootfs->path, rootfs->mount,
+		      rootfs->options ? rootfs->options : "(null)");
 		return 0;
 	}
 	if (bdev)
 		bdev_put(bdev);
 	if (mount_rootfs(rootfs->path, rootfs->mount, rootfs->options)) {
-		ERROR("failed to mount rootfs");
+		ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".",
+		      rootfs->path, rootfs->mount,
+		      rootfs->options ? rootfs->options : "(null)");
 		return -1;
 	}
 
-	DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
-
+	DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".",
+	      rootfs->path, rootfs->mount,
+	      rootfs->options ? rootfs->options : "(null)");
 	return 0;
 }
 
@@ -1294,23 +1228,23 @@ int prepare_ramfs_root(char *root)
 	char *p2;
 
 	if (realpath(root, nroot) == NULL)
-		return -1;
+		return -errno;
 
 	if (chdir("/") == -1)
-		return -1;
+		return -errno;
 
 	/*
 	 * We could use here MS_MOVE, but in userns this mount is
 	 * locked and can't be moved.
 	 */
-	if (mount(root, "/", NULL, MS_REC | MS_BIND, NULL)) {
+	if (mount(root, "/", NULL, MS_REC | MS_BIND, NULL) < 0) {
 		SYSERROR("Failed to move %s into /", root);
-		return -1;
+		return -errno;
 	}
 
-	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
+	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) < 0) {
 		SYSERROR("Failed to make . rprivate");
-		return -1;
+		return -errno;
 	}
 
 	/*
@@ -1376,64 +1310,112 @@ int prepare_ramfs_root(char *root)
 
 static int setup_pivot_root(const struct lxc_rootfs *rootfs)
 {
-	if (!rootfs->path)
+	if (!rootfs->path) {
+		DEBUG("container does not have a rootfs, so not doing pivot root");
 		return 0;
+	}
 
 	if (detect_ramfs_rootfs()) {
-		if (prepare_ramfs_root(rootfs->mount))
+		DEBUG("detected that container is on ramfs");
+		if (prepare_ramfs_root(rootfs->mount)) {
+			ERROR("failed to prepare minimal ramfs root");
 			return -1;
-	} else if (setup_rootfs_pivot_root(rootfs->mount)) {
-		ERROR("failed to setup pivot root");
+		}
+
+		DEBUG("prepared ramfs root for container");
+		return 0;
+	}
+
+	if (setup_rootfs_pivot_root(rootfs->mount) < 0) {
+		ERROR("failed to pivot root");
 		return -1;
 	}
 
+	DEBUG("finished pivot root");
 	return 0;
 }
 
-static int setup_pts(int pts)
+static int lxc_setup_devpts(int num_pts)
 {
-	char target[PATH_MAX];
+	int ret;
+	const char *devpts_mntopts = "newinstance,ptmxmode=0666,mode=0620,gid=5";
 
-	if (!pts)
+	if (!num_pts) {
+		DEBUG("no new devpts instance will be mounted since no pts "
+		      "devices are requested");
 		return 0;
-
-	if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) {
-		SYSERROR("failed to umount 'dev/pts'");
-		return -1;
 	}
 
-	if (mkdir("/dev/pts", 0755)) {
-		if ( errno != EEXIST ) {
-		    SYSERROR("failed to create '/dev/pts'");
-		    return -1;
+	/* Unmount old devpts instance. */
+	ret = access("/dev/pts/ptmx", F_OK);
+	if (!ret) {
+		ret = umount("/dev/pts");
+		if (ret < 0) {
+			SYSERROR("failed to unmount old devpts instance");
+			return -1;
 		}
+		DEBUG("unmounted old /dev/pts instance");
 	}
 
-	if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
-		  "newinstance,ptmxmode=0666,mode=0620,gid=5")) {
-		SYSERROR("failed to mount a new instance of '/dev/pts'");
+	/* Create mountpoint for devpts instance. */
+	ret = mkdir("/dev/pts", 0755);
+	if (ret < 0 && errno != EEXIST) {
+		SYSERROR("failed to create the \"/dev/pts\" directory");
 		return -1;
 	}
 
-	if (access("/dev/ptmx", F_OK)) {
-		if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
-			goto out;
-		SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
+	/* Mount new devpts instance. */
+	ret = mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, devpts_mntopts);
+	if (ret < 0) {
+		SYSERROR("failed to mount new devpts instance");
 		return -1;
 	}
 
-	if (realpath("/dev/ptmx", target) && !strcmp(target, "/dev/pts/ptmx"))
-		goto out;
+	/* Remove any pre-existing /dev/ptmx file. */
+	ret = access("/dev/ptmx", F_OK);
+	if (!ret) {
+		ret = remove("/dev/ptmx");
+		if (ret < 0) {
+			SYSERROR("failed to remove existing \"/dev/ptmx\"");
+			return -1;
+		}
+		DEBUG("removed existing \"/dev/ptmx\"");
+	}
 
-	/* fallback here, /dev/pts/ptmx exists just mount bind */
-	if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
-		SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
+	/* Create dummy /dev/ptmx file as bind mountpoint for /dev/pts/ptmx. */
+	ret = open("/dev/ptmx", O_CREAT, 0666);
+	if (ret < 0) {
+		SYSERROR("failed to create dummy \"/dev/ptmx\" file as bind mount target");
 		return -1;
 	}
+	close(ret);
+	DEBUG("created dummy \"/dev/ptmx\" file as bind mount target");
 
-	INFO("created new pts instance");
+	/* Fallback option: create symlink /dev/ptmx -> /dev/pts/ptmx  */
+	ret = mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL);
+	if (!ret) {
+		DEBUG("bind mounted \"/dev/pts/ptmx\" to \"/dev/ptmx\"");
+		return 0;
+	} else {
+		/* Fallthrough and try to create a symlink. */
+		ERROR("failed to bind mount \"/dev/pts/ptmx\" to \"/dev/ptmx\"");
+	}
+
+	/* Remove the dummy /dev/ptmx file we created above. */
+	ret = remove("/dev/ptmx");
+	if (ret < 0) {
+		SYSERROR("failed to remove existing \"/dev/ptmx\"");
+		return -1;
+	}
+
+	/* Fallback option: Create symlink /dev/ptmx -> /dev/pts/ptmx. */
+	ret = symlink("/dev/pts/ptmx", "/dev/ptmx");
+	if (ret < 0) {
+		SYSERROR("failed to create symlink \"/dev/ptmx\" -> \"/dev/pts/ptmx\"");
+		return -1;
+	}
+	DEBUG("created symlink \"/dev/ptmx\" -> \"/dev/pts/ptmx\"");
 
-out:
 	return 0;
 }
 
@@ -1454,127 +1436,204 @@ static int setup_personality(int persona)
 	return 0;
 }
 
-static int setup_dev_console(const struct lxc_rootfs *rootfs,
-			 const struct lxc_console *console)
+static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs,
+				 const struct lxc_console *console)
 {
 	char path[MAXPATHLEN];
 	int ret, fd;
 
+	if (console->path && !strcmp(console->path, "none"))
+		return 0;
+
 	ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
-	if (ret >= sizeof(path)) {
-		ERROR("console path too long");
+	if (ret < 0 || (size_t)ret >= sizeof(path))
 		return -1;
+
+	/* When we are asked to setup a console we remove any previous
+	 * /dev/console bind-mounts.
+	 */
+	if (file_exists(path)) {
+		ret = lxc_unstack_mountpoint(path, false);
+		if (ret < 0) {
+			ERROR("failed to unmount \"%s\": %s", path, strerror(errno));
+			return -ret;
+		} else {
+			DEBUG("cleared all (%d) mounts from \"%s\"", ret, path);
+		}
+		ret = unlink(path);
+		if (ret < 0) {
+			SYSERROR("error unlinking %s", path);
+			return -errno;
+		}
 	}
 
+	/* For unprivileged containers autodev or automounts will already have
+	 * taken care of creating /dev/console.
+	 */
 	fd = open(path, O_CREAT | O_EXCL, S_IXUSR | S_IXGRP | S_IXOTH);
 	if (fd < 0) {
 		if (errno != EEXIST) {
 			SYSERROR("failed to create console");
-			return -1;
+			return -errno;
 		}
 	} else {
 		close(fd);
 	}
 
-	if (console->master < 0) {
-		INFO("no console");
-		return 0;
-	}
-
 	if (chmod(console->name, S_IXUSR | S_IXGRP | S_IXOTH)) {
-		SYSERROR("failed to set mode '0%o' to '%s'",
-			 S_IXUSR | S_IXGRP | S_IXOTH, console->name);
-		return -1;
+		SYSERROR("failed to set mode '0%o' to '%s'", S_IXUSR | S_IXGRP | S_IXOTH, console->name);
+		return -errno;
 	}
 
-	if (safe_mount(console->name, path, "none", MS_BIND, 0, rootfs->mount)) {
+	if (safe_mount(console->name, path, "none", MS_BIND, 0, rootfs->mount) < 0) {
 		ERROR("failed to mount '%s' on '%s'", console->name, path);
 		return -1;
 	}
 
-	INFO("console has been setup");
+	DEBUG("mounted pts device \"%s\" onto \"%s\"", console->name, path);
 	return 0;
 }
 
-static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
-			 const struct lxc_console *console,
-			 char *ttydir)
+static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
+				    const struct lxc_console *console,
+				    char *ttydir)
 {
-	char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
 	int ret;
+	char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
 
 	/* create rootfs/dev/<ttydir> directory */
-	ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount,
-		       ttydir);
-	if (ret >= sizeof(path))
+	ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount, ttydir);
+	if (ret < 0 || (size_t)ret >= sizeof(path))
 		return -1;
+
 	ret = mkdir(path, 0755);
 	if (ret && errno != EEXIST) {
 		SYSERROR("failed with errno %d to create %s", errno, path);
-		return -1;
-	}
-	INFO("created %s", path);
-
-	ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console",
-		       rootfs->mount, ttydir);
-	if (ret >= sizeof(lxcpath)) {
-		ERROR("console path too long");
-		return -1;
+		return -errno;
 	}
+ 	DEBUG("created directory for console and tty devices at \%s\"", path);
 
-	snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
-	ret = unlink(path);
-	if (ret && errno != ENOENT) {
-		SYSERROR("error unlinking %s", path);
+	ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console", rootfs->mount, ttydir);
+	if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
 		return -1;
-	}
 
 	ret = creat(lxcpath, 0660);
-	if (ret==-1 && errno != EEXIST) {
+	if (ret == -1 && errno != EEXIST) {
 		SYSERROR("error %d creating %s", errno, lxcpath);
-		return -1;
+		return -errno;
 	}
 	if (ret >= 0)
 		close(ret);
 
-	if (console->master < 0) {
-		INFO("no console");
-		return 0;
-	}
-
-	if (safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs->mount)) {
-		ERROR("failed to mount '%s' on '%s'", console->name, lxcpath);
+	ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
+	if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
 		return -1;
+
+	/* When we are asked to setup a console we remove any previous
+	 * /dev/console bind-mounts.
+	 */
+	if (console->path && !strcmp(console->path, "none")) {
+		struct stat st;
+		ret = stat(path, &st);
+		if (ret < 0) {
+			if (errno == ENOENT)
+				return 0;
+			SYSERROR("failed stat() \"%s\"", path);
+			return -errno;
+		}
+
+		/* /dev/console must be character device with major number 5 and
+		 * minor number 1. If not, give benefit of the doubt and assume
+		 * the user has mounted something else right there on purpose.
+		 */
+		if (((st.st_mode & S_IFMT) != S_IFCHR) || major(st.st_rdev) != 5 || minor(st.st_rdev) != 1)
+			return 0;
+
+		/* In case the user requested a bind-mount for /dev/console and
+		 * requests a ttydir we move the mount to the
+		 * /dev/<ttydir/console.
+		 * Note, we only move the uppermost mount and clear all other
+		 * mounts underneath for safety.
+		 * If it is a character device created via mknod() we simply
+		 * rename it.
+		 */
+		ret = safe_mount(path, lxcpath, "none", MS_MOVE, NULL, rootfs->mount);
+		if (ret < 0) {
+			if (errno != EINVAL) {
+				ERROR("failed to MS_MOVE \"%s\" to \"%s\": %s", path, lxcpath, strerror(errno));
+				return -errno;
+			}
+			/* path was not a mountpoint */
+			ret = rename(path, lxcpath);
+			if (ret < 0) {
+				ERROR("failed to rename \"%s\" to \"%s\": %s", path, lxcpath, strerror(errno));
+				return -errno;
+			}
+			DEBUG("renamed \"%s\" to \"%s\"", path, lxcpath);
+		} else {
+			DEBUG("moved mount \"%s\" to \"%s\"", path, lxcpath);
+		}
+
+		/* Clear all remaining bind-mounts. */
+		ret = lxc_unstack_mountpoint(path, false);
+		if (ret < 0) {
+			ERROR("failed to unmount \"%s\": %s", path, strerror(errno));
+			return -ret;
+		} else {
+			DEBUG("cleared all (%d) mounts from \"%s\"", ret, path);
+		}
+	} else {
+		if (file_exists(path)) {
+			ret = lxc_unstack_mountpoint(path, false);
+			if (ret < 0) {
+				ERROR("failed to unmount \"%s\": %s", path, strerror(errno));
+				return -ret;
+			} else {
+				DEBUG("cleared all (%d) mounts from \"%s\"", ret, path);
+			}
+		}
+
+		if (safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs->mount) < 0) {
+			ERROR("failed to mount '%s' on '%s'", console->name, lxcpath);
+			return -1;
+		}
+		DEBUG("mounted \"%s\" onto \"%s\"", console->name, lxcpath);
 	}
 
-	/* create symlink from rootfs/dev/console to 'lxc/console' */
+	/* create symlink from rootfs /dev/console to '<ttydir>/console' */
 	ret = snprintf(lxcpath, sizeof(lxcpath), "%s/console", ttydir);
-	if (ret >= sizeof(lxcpath)) {
-		ERROR("lxc/console path too long");
+	if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
 		return -1;
+
+	ret = unlink(path);
+	if (ret && errno != ENOENT) {
+		SYSERROR("error unlinking %s", path);
+		return -errno;
 	}
+
 	ret = symlink(lxcpath, path);
-	if (ret) {
-		SYSERROR("failed to create symlink for console");
+	if (ret < 0) {
+		SYSERROR("failed to create symlink for console from \"%s\" to \"%s\"", lxcpath, path);
 		return -1;
 	}
 
-	INFO("console has been setup on %s", lxcpath);
-
+	DEBUG("console has been setup under \"%s\" and symlinked to \"%s\"", lxcpath, path);
 	return 0;
 }
 
-static int setup_console(const struct lxc_rootfs *rootfs,
-			 const struct lxc_console *console,
-			 char *ttydir)
+static int lxc_setup_console(const struct lxc_rootfs *rootfs,
+			     const struct lxc_console *console, char *ttydir)
 {
-	/* We don't have a rootfs, /dev/console will be shared */
-	if (!rootfs->path)
+	/* We don't have a rootfs, /dev/console will be shared. */
+	if (!rootfs->path) {
+		DEBUG("/dev/console will be shared with the host");
 		return 0;
+	}
+
 	if (!ttydir)
-		return setup_dev_console(rootfs, console);
+		return lxc_setup_dev_console(rootfs, console);
 
-	return setup_ttydir_console(rootfs, console, ttydir);
+	return lxc_setup_ttydir_console(rootfs, console, ttydir);
 }
 
 static int setup_kmsg(const struct lxc_rootfs *rootfs,
@@ -3019,7 +3078,7 @@ bool lxc_delete_network(struct lxc_handler *handler)
 		/* Explicitly delete host veth device to prevent lingering
 		 * devices. We had issues in LXD around this.
 		 */
-		if (netdev->type == LXC_NET_VETH) {
+		if (netdev->type == LXC_NET_VETH && !am_unpriv()) {
 			char *hostveth;
 			if (netdev->priv.veth_attr.pair) {
 				hostveth = netdev->priv.veth_attr.pair;
@@ -3028,8 +3087,6 @@ bool lxc_delete_network(struct lxc_handler *handler)
 					WARN("Failed to remove interface \"%s\" from host: %s.", hostveth, strerror(-ret));
 				} else {
 					INFO("Removed interface \"%s\" from host.", hostveth);
-					free(netdev->priv.veth_attr.pair);
-					netdev->priv.veth_attr.pair = NULL;
 				}
 			} else if (strlen(netdev->priv.veth_attr.veth1) > 0) {
 				hostveth = netdev->priv.veth_attr.veth1;
@@ -3058,20 +3115,21 @@ static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
 	int bytes, pipefd[2];
 	char *token, *saveptr = NULL;
 	char buffer[MAX_BUFFER_SIZE];
-	char netdev_link[IFNAMSIZ+1];
+	char netdev_link[IFNAMSIZ + 1];
 
 	if (netdev->type != LXC_NET_VETH) {
 		ERROR("nic type %d not support for unprivileged use",
-			netdev->type);
+		      netdev->type);
 		return -1;
 	}
 
-	if(pipe(pipefd) < 0) {
+	if (pipe(pipefd) < 0) {
 		SYSERROR("pipe failed");
 		return -1;
 	}
 
-	if ((child = fork()) < 0) {
+	child = fork();
+	if (child < 0) {
 		SYSERROR("fork");
 		close(pipefd[0]);
 		close(pipefd[1]);
@@ -3079,35 +3137,45 @@ static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
 	}
 
 	if (child == 0) { // child
-		/* close the read-end of the pipe */
-		close(pipefd[0]);
-		/* redirect the stdout to write-end of the pipe */
-		dup2(pipefd[1], STDOUT_FILENO);
-		/* close the write-end of the pipe */
-		close(pipefd[1]);
+		/* Call lxc-user-nic pid type bridge. */
+		int ret;
+		char pidstr[LXC_NUMSTRLEN64];
 
-		// Call lxc-user-nic pid type bridge
-		char pidstr[20];
-		if (netdev->link) {
+		close(pipefd[0]); /* Close the read-end of the pipe. */
+
+		/* Redirect stdout to write-end of the pipe. */
+		ret = dup2(pipefd[1], STDOUT_FILENO);
+		close(pipefd[1]); /* Close the write-end of the pipe. */
+		if (ret < 0) {
+			SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
+			exit(EXIT_FAILURE);
+		}
+
+		if (netdev->link)
 			strncpy(netdev_link, netdev->link, IFNAMSIZ);
-		} else {
+		else
 			strncpy(netdev_link, "none", IFNAMSIZ);
-		}
-		snprintf(pidstr, 19, "%lu", (unsigned long) pid);
-		pidstr[19] = '\0';
+
+		ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
+		if (ret < 0 || ret >= LXC_NUMSTRLEN64)
+			exit(EXIT_FAILURE);
+		pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
+
+		INFO("Execing lxc-user-nic %s %s %s veth %s %s", lxcpath,
+		     lxcname, pidstr, netdev_link, netdev->name);
 		execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, lxcpath, lxcname,
-				pidstr, "veth", netdev_link, netdev->name, NULL);
-		SYSERROR("execvp lxc-user-nic");
-		exit(1);
+		       pidstr, "veth", netdev_link, netdev->name, NULL);
+
+		SYSERROR("Failed to exec lxc-user-nic.");
+		exit(EXIT_FAILURE);
 	}
 
 	/* close the write-end of the pipe */
 	close(pipefd[1]);
 
 	bytes = read(pipefd[0], &buffer, MAX_BUFFER_SIZE);
-	if (bytes < 0) {
-		SYSERROR("read failed");
-	}
+	if (bytes < 0)
+		SYSERROR("Failed to read from pipe file descriptor.");
 	buffer[bytes - 1] = '\0';
 
 	if (wait_for_pid(child) != 0) {
@@ -3122,21 +3190,23 @@ static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
 	token = strtok_r(buffer, ":", &saveptr);
 	if (!token)
 		return -1;
-	netdev->name = malloc(IFNAMSIZ+1);
+
+	netdev->name = malloc(IFNAMSIZ + 1);
 	if (!netdev->name) {
-		ERROR("Out of memory");
+		SYSERROR("Failed to allocate memory.");
 		return -1;
 	}
-	memset(netdev->name, 0, IFNAMSIZ+1);
+	memset(netdev->name, 0, IFNAMSIZ + 1);
 	strncpy(netdev->name, token, IFNAMSIZ);
 
 	/* fill netdev->veth_attr.pair field */
 	token = strtok_r(NULL, ":", &saveptr);
 	if (!token)
 		return -1;
+
 	netdev->priv.veth_attr.pair = strdup(token);
 	if (!netdev->priv.veth_attr.pair) {
-		ERROR("Out of memory");
+		ERROR("Failed to allocate memory.");
 		return -1;
 	}
 
@@ -3214,75 +3284,145 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
 	return ret < 0 ? ret : closeret;
 }
 
+/* Check whether a binary exist and has either CAP_SETUID, CAP_SETGID or both. */
+static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
+{
+	char *path;
+	int ret;
+	struct stat st;
+	int fret = 0;
+
+	path = on_path(binary, NULL);
+	if (!path)
+		return -ENOENT;
+
+	ret = stat(path, &st);
+	if (ret < 0) {
+		fret = -errno;
+		goto cleanup;
+	}
+
+	/* Check if the binary is setuid. */
+	if (st.st_mode & S_ISUID) {
+		DEBUG("The binary \"%s\" does have the setuid bit set.", path);
+		fret = 1;
+		goto cleanup;
+	}
+
+	#if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
+	/* Check if it has the CAP_SETUID capability. */
+	if ((cap & CAP_SETUID) &&
+	    lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) &&
+	    lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) {
+		DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE "
+		      "and CAP_PERMITTED sets.", path);
+		fret = 1;
+		goto cleanup;
+	}
+
+	/* Check if it has the CAP_SETGID capability. */
+	if ((cap & CAP_SETGID) &&
+	    lxc_file_cap_is_set(path, CAP_SETGID, CAP_EFFECTIVE) &&
+	    lxc_file_cap_is_set(path, CAP_SETGID, CAP_PERMITTED)) {
+		DEBUG("The binary \"%s\" has CAP_SETGID in its CAP_EFFECTIVE "
+		      "and CAP_PERMITTED sets.", path);
+		fret = 1;
+		goto cleanup;
+	}
+	#else
+	/* If we cannot check for file capabilities we need to give the benefit
+	 * of the doubt. Otherwise we might fail even though all the necessary
+	 * file capabilities are set.
+	 */
+	DEBUG("Cannot check for file capabilites as full capability support is "
+	      "missing. Manual intervention needed.");
+	fret = 1;
+	#endif
+
+cleanup:
+	free(path);
+	return fret;
+}
+
 int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
 {
-	struct lxc_list *iterator;
 	struct id_map *map;
-	int ret = 0, use_shadow = 0;
+	struct lxc_list *iterator;
 	enum idtype type;
-	char *buf = NULL, *pos, *cmdpath = NULL;
+	char *pos;
+	int euid;
+	int ret = 0, use_shadow = 0;
+	int uidmap = 0, gidmap = 0;
+	char *buf = NULL;
 
-	/*
-	 * If newuidmap exists, that is, if shadow is handing out subuid
-	 * ranges, then insist that root also reserve ranges in subuid.  This
+	euid = geteuid();
+
+	/* If new{g,u}idmap exists, that is, if shadow is handing out subuid
+	 * ranges, then insist that root also reserve ranges in subuid. This
 	 * will protected it by preventing another user from being handed the
 	 * range by shadow.
 	 */
-	cmdpath = on_path("newuidmap", NULL);
-	if (cmdpath) {
-		use_shadow = 1;
-		free(cmdpath);
-	}
-
-	if (!use_shadow && geteuid()) {
-		ERROR("Missing newuidmap/newgidmap");
+	uidmap = idmaptool_on_path_and_privileged("newuidmap", CAP_SETUID);
+	gidmap = idmaptool_on_path_and_privileged("newgidmap", CAP_SETGID);
+	if (uidmap > 0 && gidmap > 0) {
+		DEBUG("Functional newuidmap and newgidmap binary found.");
+		use_shadow = true;
+	} else if (uidmap == -ENOENT && gidmap == -ENOENT && !euid) {
+		DEBUG("No newuidmap and newgidmap binary found. Trying to "
+		      "write directly with euid 0.");
+		use_shadow = false;
+	} else {
+		DEBUG("Either one or both of the newuidmap and newgidmap "
+		      "binaries do not exist or are missing necessary "
+		      "privilege.");
 		return -1;
 	}
 
-	for(type = ID_TYPE_UID; type <= ID_TYPE_GID; type++) {
+	for (type = ID_TYPE_UID; type <= ID_TYPE_GID; type++) {
 		int left, fill;
-		int had_entry = 0;
+		bool had_entry = false;
 		if (!buf) {
-			buf = pos = malloc(4096);
+			buf = pos = malloc(LXC_IDMAPLEN);
 			if (!buf)
 				return -ENOMEM;
 		}
 		pos = buf;
 		if (use_shadow)
-			pos += sprintf(buf, "new%cidmap %d",
-				type == ID_TYPE_UID ? 'u' : 'g',
-				pid);
+			pos += sprintf(buf, "new%cidmap %d", type == ID_TYPE_UID ? 'u' : 'g', pid);
 
 		lxc_list_for_each(iterator, idmap) {
-			/* The kernel only takes <= 4k for writes to /proc/<nr>/[ug]id_map */
+			/* The kernel only takes <= 4k for writes to
+			 * /proc/<nr>/[ug]id_map
+			 */
 			map = iterator->elem;
 			if (map->idtype != type)
 				continue;
 
-			had_entry = 1;
-			left = 4096 - (pos - buf);
+			had_entry = true;
+
+			left = LXC_IDMAPLEN - (pos - buf);
 			fill = snprintf(pos, left, "%s%lu %lu %lu%s",
-					use_shadow ? " " : "",
-					map->nsid, map->hostid, map->range,
+					use_shadow ? " " : "", map->nsid,
+					map->hostid, map->range,
 					use_shadow ? "" : "\n");
 			if (fill <= 0 || fill >= left)
-				SYSERROR("snprintf failed, too many mappings");
+				SYSERROR("Too many {g,u}id mappings defined.");
+
 			pos += fill;
 		}
 		if (!had_entry)
 			continue;
 
 		if (!use_shadow) {
-			ret = write_id_mapping(type, pid, buf, pos-buf);
+			ret = write_id_mapping(type, pid, buf, pos - buf);
 		} else {
-			left = 4096 - (pos - buf);
+			left = LXC_IDMAPLEN - (pos - buf);
 			fill = snprintf(pos, left, "\n");
 			if (fill <= 0 || fill >= left)
-				SYSERROR("snprintf failed, too many mappings");
+				SYSERROR("Too many {g,u}id mappings defined.");
 			pos += fill;
 			ret = system(buf);
 		}
-
 		if (ret)
 			break;
 	}
@@ -3617,20 +3757,21 @@ int ttys_shift_ids(struct lxc_conf *c)
 	return 0;
 }
 
-/* NOTE: not to be called from inside the container namespace! */
-int tmp_proc_mount(struct lxc_conf *lxc_conf)
+/* NOTE: Must not be called from inside the container namespace! */
+int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
 {
 	int mounted;
 
-	mounted = mount_proc_if_needed(lxc_conf->rootfs.path ? lxc_conf->rootfs.mount : "");
+	mounted = lxc_mount_proc_if_needed(conf->rootfs.path ? conf->rootfs.mount : "");
 	if (mounted == -1) {
-		SYSERROR("failed to mount /proc in the container.");
+		SYSERROR("failed to mount /proc in the container");
 		/* continue only if there is no rootfs */
-		if (lxc_conf->rootfs.path)
+		if (conf->rootfs.path)
 			return -1;
 	} else if (mounted == 1) {
-		lxc_conf->tmp_umount_proc = 1;
+		conf->tmp_umount_proc = 1;
 	}
+
 	return 0;
 }
 
@@ -3892,19 +4033,17 @@ int lxc_setup(struct lxc_handler *handler)
 	}
 
 	if (lxc_conf->autodev > 0) {
-		bool mount_console = lxc_conf->console.path && !strcmp(lxc_conf->console.path, "none");
-
 		if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
 			ERROR("failed to run autodev hooks for container '%s'.", name);
 			return -1;
 		}
-		if (fill_autodev(&lxc_conf->rootfs, mount_console)) {
+		if (lxc_fill_autodev(&lxc_conf->rootfs)) {
 			ERROR("failed to populate /dev in the container");
 			return -1;
 		}
 	}
 
-	if (!lxc_conf->is_execute && setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
+	if (!lxc_conf->is_execute && lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
 		ERROR("failed to setup the console for '%s'", name);
 		return -1;
 	}
@@ -3920,7 +4059,7 @@ int lxc_setup(struct lxc_handler *handler)
 	}
 
 	/* mount /proc if it's not already there */
-	if (tmp_proc_mount(lxc_conf) < 0) {
+	if (lxc_create_tmp_proc_mount(lxc_conf) < 0) {
 		ERROR("failed to LSM mount proc for '%s'", name);
 		return -1;
 	}
@@ -3930,7 +4069,7 @@ int lxc_setup(struct lxc_handler *handler)
 		return -1;
 	}
 
-	if (setup_pts(lxc_conf->pts)) {
+	if (lxc_setup_devpts(lxc_conf->pts)) {
 		ERROR("failed to setup the new pts instance");
 		return -1;
 	}
@@ -4151,10 +4290,14 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
 {
 	struct lxc_list *it,*next;
 	bool all = false;
-	const char *k = key + 11;
+	const char *k = NULL;
 
 	if (strcmp(key, "lxc.cgroup") == 0)
 		all = true;
+	else if (strncmp(key, "lxc.cgroup.", sizeof("lxc.cgroup.")-1) == 0)
+		k = key + sizeof("lxc.cgroup.")-1;
+	else
+		return -1;
 
 	lxc_list_for_each_safe(it, &c->cgroup, next) {
 		struct lxc_cgroup *cg = it->elem;
@@ -4216,11 +4359,15 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
 {
 	struct lxc_list *it,*next;
 	bool all = false, done = false;
-	const char *k = key + 9;
+	const char *k = NULL;
 	int i;
 
 	if (strcmp(key, "lxc.hook") == 0)
 		all = true;
+	else if (strncmp(key, "lxc.hook.", sizeof("lxc.hook.")-1) == 0)
+		k = key + sizeof("lxc.hook.")-1;
+	else
+		return -1;
 
 	for (i=0; i<NUM_LXC_HOOKS; i++) {
 		if (all || strcmp(k, lxchook_names[i]) == 0) {
@@ -4548,7 +4695,7 @@ void suggest_default_idmap(void)
 	}
 	fclose(f);
 
-	f = fopen(subuidfile, "r");
+	f = fopen(subgidfile, "r");
 	if (!f) {
 		ERROR("Your system is not configured with subgids");
 		free(gname);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 2abde72..9b22c6d 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -790,6 +790,9 @@ static int config_network_ipv4(const char *key, const char *value,
 	struct lxc_list *list;
 	char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL;
 
+	if (!value || !strlen(value))
+		return lxc_clear_config_item(lxc_conf, key);
+
 	netdev = network_netdev(key, value, &lxc_conf->network);
 	if (!netdev)
 		return -1;
@@ -917,6 +920,9 @@ static int config_network_ipv6(const char *key, const char *value,
 	char *slash,*valdup;
 	char *netmask;
 
+	if (!value || !strlen(value))
+		return lxc_clear_config_item(lxc_conf, key);
+
 	netdev = network_netdev(key, value, &lxc_conf->network);
 	if (!netdev)
 		return -1;
@@ -2873,21 +2879,21 @@ next:
 	} \
 }
 
-static void new_hwaddr(char *hwaddr)
+static bool new_hwaddr(char *hwaddr)
 {
-	FILE *f;
-	f = fopen("/dev/urandom", "r");
-	if (f) {
-		unsigned int seed;
-		int ret = fread(&seed, sizeof(seed), 1, f);
-		if (ret != 1)
-			seed = time(NULL);
-		fclose(f);
-		srand(seed);
-	} else
-		srand(time(NULL));
-	snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x",
-			rand() % 255, rand() % 255, rand() % 255);
+	int ret;
+
+	/* COMMENT(brauner): Initialize random number generator. */
+	(void)randseed(true);
+
+	ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
+		       rand() % 255, rand() % 255);
+	if (ret < 0 || ret >= 18) {
+		SYSERROR("Failed to call snprintf().");
+		return false;
+	}
+
+	return true;
 }
 
 /*
@@ -2909,27 +2915,33 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
 
 	if (!conf->unexpanded_config)
 		return true;
+
 	while (*lstart) {
 		char newhwaddr[18], oldhwaddr[17];
+
 		lend = strchr(lstart, '\n');
 		if (!lend)
 			lend = lstart + strlen(lstart);
 		else
 			lend++;
+
 		if (strncmp(lstart, key, strlen(key)) != 0) {
 			lstart = lend;
 			continue;
 		}
+
 		p = strchr(lstart+strlen(key), '=');
 		if (!p) {
 			lstart = lend;
 			continue;
 		}
+
 		p++;
 		while (isblank(*p))
 			p++;
 		if (!*p)
 			return true;
+
 		p2 = p;
 		while (*p2 && !isblank(*p2) && *p2 != '\n')
 			p2++;
@@ -2938,8 +2950,12 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
 			lstart = lend;
 			continue;
 		}
+
 		memcpy(oldhwaddr, p, 17);
-		new_hwaddr(newhwaddr);
+
+		if (!new_hwaddr(newhwaddr))
+			return false;
+
 		memcpy(p, newhwaddr, 17);
 		lxc_list_for_each(it, &conf->network) {
 			struct lxc_netdev *n = it->elem;
@@ -2949,6 +2965,7 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
 
 		lstart = lend;
 	}
+
 	return true;
 }
 
diff --git a/src/lxc/console.c b/src/lxc/console.c
index 908ead0..3baaed4 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -257,6 +257,14 @@ int lxc_setup_tios(int fd, struct termios *oldtios)
 		return -1;
 	}
 
+	/* ensure we don't end up in an endless loop:
+	 * The kernel might fire SIGTTOU while an
+	 * ioctl() in tcsetattr() is executed. When the ioctl()
+	 * is resumed and retries, the signal handler interrupts it again.
+	 */
+	signal (SIGTTIN, SIG_IGN);
+	signal (SIGTTOU, SIG_IGN);
+
 	newtios = *oldtios;
 
 	/* We use the same settings that ssh does. */
@@ -265,7 +273,7 @@ int lxc_setup_tios(int fd, struct termios *oldtios)
 #ifdef IUCLC
 	newtios.c_iflag &= ~IUCLC;
 #endif
-	newtios.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+	newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
 #ifdef IEXTEN
 	newtios.c_lflag &= ~IEXTEN;
 #endif
@@ -407,16 +415,17 @@ void lxc_console_free(struct lxc_conf *conf, int fd)
 	}
 }
 
-static void lxc_console_peer_default(struct lxc_console *console)
+static int lxc_console_peer_default(struct lxc_console *console)
 {
 	struct lxc_tty_state *ts;
 	const char *path = console->path;
+	int fd;
+	int ret = 0;
 
-	/* if no console was given, try current controlling terminal, there
-	 * won't be one if we were started as a daemon (-d)
+	/* If no console was given, try current controlling terminal, there
+	 * won't be one if we were started as a daemon (-d).
 	 */
 	if (!path && !access("/dev/tty", F_OK)) {
-		int fd;
 		fd = open("/dev/tty", O_RDWR);
 		if (fd >= 0) {
 			close(fd);
@@ -424,25 +433,29 @@ static void lxc_console_peer_default(struct lxc_console *console)
 		}
 	}
 
-	if (!path)
-		goto out;
-
-	DEBUG("opening %s for console peer", path);
-	console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
-					O_APPEND, 0600));
-	if (console->peer < 0)
+	if (!path) {
+		errno = ENOTTY;
+		DEBUG("process does not have a controlling terminal");
 		goto out;
+	}
 
-	DEBUG("using '%s' as console", path);
+	console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
+	if (console->peer < 0) {
+		ERROR("failed to open \"%s\"", path);
+		return -ENOTTY;
+	}
+	DEBUG("using \"%s\" as peer tty device", path);
 
-	if (!isatty(console->peer))
-		goto err1;
+	if (!isatty(console->peer)) {
+		ERROR("file descriptor for file \"%s\" does not refer to a tty device", path);
+		goto on_error1;
+	}
 
 	ts = lxc_console_sigwinch_init(console->peer, console->master);
 	console->tty_state = ts;
 	if (!ts) {
-		WARN("Unable to install SIGWINCH");
-		goto err1;
+		WARN("unable to install SIGWINCH handler");
+		goto on_error1;
 	}
 
 	lxc_console_winsz(console->peer, console->master);
@@ -450,23 +463,27 @@ static void lxc_console_peer_default(struct lxc_console *console)
 	console->tios = malloc(sizeof(*console->tios));
 	if (!console->tios) {
 		SYSERROR("failed to allocate memory");
-		goto err1;
+		ret = -ENOMEM;
+		goto on_error1;
 	}
 
 	if (lxc_setup_tios(console->peer, console->tios) < 0)
-		goto err2;
-
-	return;
+		goto on_error2;
+	else
+		goto out;
 
-err2:
+on_error2:
 	free(console->tios);
 	console->tios = NULL;
-err1:
+	ret = -ENOTTY;
+
+on_error1:
 	close(console->peer);
 	console->peer = -1;
+	ret = -ENOTTY;
+
 out:
-	DEBUG("no console peer");
-	return;
+	return ret;
 }
 
 void lxc_console_delete(struct lxc_console *console)
@@ -495,21 +512,24 @@ int lxc_console_create(struct lxc_conf *conf)
 	int ret;
 
 	if (conf->is_execute) {
-		INFO("no console for lxc-execute.");
+		INFO("not allocating a console device for lxc-execute.");
 		return 0;
 	}
 
-	if (!conf->rootfs.path)
+	if (!conf->rootfs.path) {
+		INFO("container does not have a rootfs, console device will be shared with the host");
 		return 0;
+	}
 
-	if (console->path && !strcmp(console->path, "none"))
+	if (console->path && !strcmp(console->path, "none")) {
+		INFO("no console requested");
 		return 0;
+	}
 
 	process_lock();
-	ret = openpty(&console->master, &console->slave,
-		    console->name, NULL, NULL);
+	ret = openpty(&console->master, &console->slave, console->name, NULL, NULL);
 	process_unlock();
-	if (ret) {
+	if (ret < 0) {
 		SYSERROR("failed to allocate a pty");
 		return -1;
 	}
@@ -524,17 +544,19 @@ int lxc_console_create(struct lxc_conf *conf)
 		goto err;
 	}
 
-	lxc_console_peer_default(console);
+	ret = lxc_console_peer_default(console);
+	if (ret < 0) {
+		ERROR("failed to allocate peer tty device");
+		goto err;
+	}
 
 	if (console->log_path) {
-		console->log_fd = lxc_unpriv(open(console->log_path,
-						  O_CLOEXEC | O_RDWR |
-						  O_CREAT | O_APPEND, 0600));
+		console->log_fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
 		if (console->log_fd < 0) {
-			SYSERROR("failed to open '%s'", console->log_path);
+			SYSERROR("failed to open console log file \"%s\"", console->log_path);
 			goto err;
 		}
-		DEBUG("using '%s' as console log", console->log_path);
+		DEBUG("using \"%s\" as console log file", console->log_path);
 	}
 
 	return 0;
diff --git a/src/lxc/criu.c b/src/lxc/criu.c
index 8a0702f..d757bef 100644
--- a/src/lxc/criu.c
+++ b/src/lxc/criu.c
@@ -334,8 +334,18 @@ static void exec_criu(struct criu_opts *opts)
 		goto err;
 
 	while (getmntent_r(mnts, &mntent, buf, sizeof(buf))) {
-		char *fmt, *key, *val;
+		char *fmt, *key, *val, *mntdata;
 		char arg[2 * PATH_MAX + 2];
+		unsigned long flags;
+
+		if (parse_mntopts(mntent.mnt_opts, &flags, &mntdata) < 0)
+			goto err;
+
+		free(mntdata);
+
+		/* only add --ext-mount-map for actual bind mounts */
+		if (!(flags & MS_BIND))
+			continue;
 
 		if (strcmp(opts->action, "dump") == 0) {
 			fmt = "/%s:%s";
diff --git a/src/lxc/log.c b/src/lxc/log.c
index 678bec7..c9b54dc 100644
--- a/src/lxc/log.c
+++ b/src/lxc/log.c
@@ -106,7 +106,7 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
 	yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
 
 	/* Given year-of-era, and era, one can now compute the year. */
-	year = (yoe) + era * 400;
+	year = yoe + era * 400;
 
 	/* Also the day-of-year, again with the year beginning on Mar. 1, can be
 	 * computed from the day-of-era and year-of-era.
@@ -126,6 +126,11 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const struct timespec *time
 	 */
 	month = mp + (mp < 10 ? 3 : -9);
 
+	/* The algorithm assumes that a year begins on 1 March, so add 1 before
+	 * that. */
+	if (month < 3)
+		year++;
+
 	/* Transform days in the epoch to seconds. */
 	d_in_s = epoch_to_days * 86400;
 
diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c
index 409a53a..c93b4cc 100644
--- a/src/lxc/lxc_user_nic.c
+++ b/src/lxc/lxc_user_nic.c
@@ -18,37 +18,44 @@
  */
 
 #define _GNU_SOURCE             /* See feature_test_macros(7) */
+#include <alloca.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sched.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <alloca.h>
 #include <string.h>
-#include <sched.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <linux/netlink.h>
+#include <unistd.h>
 #include <arpa/inet.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "config.h"
-#include "utils.h"
 #include "network.h"
+#include "utils.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)
 {
@@ -66,9 +73,8 @@ static int open_and_lock(char *path)
 
 	fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
 	if (fd < 0) {
-		fprintf(stderr, "Failed to open %s: %s\n",
-			path, strerror(errno));
-		return(fd);
+		usernic_error("Failed to open %s: %s.\n", path, strerror(errno));
+		return -1;
 	}
 
 	lk.l_type = F_WRLCK;
@@ -76,8 +82,7 @@ static int open_and_lock(char *path)
 	lk.l_start = 0;
 	lk.l_len = 0;
 	if (fcntl(fd, F_SETLKW, &lk) < 0) {
-		fprintf(stderr, "Failed to lock %s: %s\n",
-			path, strerror(errno));
+		usernic_error("Failed to lock %s: %s.\n", path, strerror(errno));
 		close(fd);
 		return -1;
 	}
@@ -88,10 +93,11 @@ static int open_and_lock(char *path)
 
 static char *get_username(void)
 {
-	struct passwd *pwd = getpwuid(getuid());
+	struct passwd *pwd;
 
-	if (pwd == NULL) {
-		perror("getpwuid");
+	pwd = getpwuid(getuid());
+	if (!pwd) {
+		usernic_error("Failed to call get username: %s.\n", strerror(errno));
 		return NULL;
 	}
 
@@ -101,10 +107,13 @@ static char *get_username(void)
 static void free_groupnames(char **groupnames)
 {
 	int i;
+
 	if (!groupnames)
 		return;
+
 	for (i = 0; groupnames[i]; i++)
 		free(groupnames[i]);
+
 	free(groupnames);
 }
 
@@ -117,53 +126,56 @@ static char **get_groupnames(void)
 	struct group *gr;
 
 	ngroups = getgroups(0, NULL);
-
-	if (ngroups == -1) {
-		fprintf(stderr, "Failed to get number of groups user belongs to: %s\n", strerror(errno));
+	if (ngroups < 0) {
+		usernic_error(
+		    "Failed to get number of groups the user belongs to: %s.\n",
+		    strerror(errno));
 		return NULL;
 	}
 	if (ngroups == 0)
 		return NULL;
 
-	group_ids = (gid_t *)malloc(sizeof(gid_t)*ngroups);
-
-	if (group_ids == NULL) {
-		fprintf(stderr, "Out of memory while getting groups the user belongs to\n");
+	group_ids = malloc(sizeof(gid_t) * ngroups);
+	if (!group_ids) {
+		usernic_error("Failed to allocate memory while getting groups "
+			      "the user belongs to: %s.\n",
+			      strerror(errno));
 		return NULL;
 	}
 
 	ret = getgroups(ngroups, group_ids);
-
 	if (ret < 0) {
 		free(group_ids);
-		fprintf(stderr, "Failed to get process groups: %s\n", strerror(errno));
+		usernic_error("Failed to get process groups: %s.\n",
+			      strerror(errno));
 		return NULL;
 	}
 
-	groupnames = (char **)malloc(sizeof(char *)*(ngroups+1));
-
-	if (groupnames == NULL) {
+	groupnames = malloc(sizeof(char *) * (ngroups + 1));
+	if (!groupnames) {
 		free(group_ids);
-		fprintf(stderr, "Out of memory while getting group names\n");
+		usernic_error("Failed to allocate memory while getting group "
+			      "names: %s.\n",
+			      strerror(errno));
 		return NULL;
 	}
 
-	memset(groupnames, 0, sizeof(char *)*(ngroups+1));
+	memset(groupnames, 0, sizeof(char *) * (ngroups + 1));
 
-	for (i=0; i<ngroups; i++ ) {
+	for (i = 0; i < ngroups; i++) {
 		gr = getgrgid(group_ids[i]);
-
-		if (gr == NULL) {
-			fprintf(stderr, "Failed to get group name\n");
+		if (!gr) {
+			usernic_error("Failed to get group name: %s.\n",
+				      strerror(errno));
 			free(group_ids);
 			free_groupnames(groupnames);
 			return NULL;
 		}
 
 		groupnames[i] = strdup(gr->gr_name);
-
-		if (groupnames[i] == NULL) {
-			fprintf(stderr, "Failed to copy group name: %s", gr->gr_name);
+		if (!groupnames[i]) {
+			usernic_error("Failed to copy group name \"%s\".",
+				      gr->gr_name);
 			free(group_ids);
 			free_groupnames(groupnames);
 			return NULL;
@@ -177,8 +189,8 @@ static char **get_groupnames(void)
 
 static bool name_is_in_groupnames(char *name, char **groupnames)
 {
-	while (groupnames != NULL) {
-		if (strcmp(name, *groupnames) == 0)
+	while (groupnames) {
+		if (!strcmp(name, *groupnames))
 			return true;
 		groupnames++;
 	}
@@ -195,23 +207,20 @@ static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int
 {
 	struct alloted_s *cur, *al;
 
-	if (head == NULL || name == NULL) {
+	if (!head || !name) {
 		// sanity check. parameters should not be null
-		fprintf(stderr, "NULL parameters to append_alloted not allowed\n");
+		usernic_error("%s\n", "Unexpected NULL argument.");
 		return NULL;
 	}
 
-	al = (struct alloted_s *)malloc(sizeof(struct alloted_s));
-
-	if (al == NULL) {
-		// unable to allocate memory to new struct
-		fprintf(stderr, "Out of memory in append_alloted\n");
+	al = malloc(sizeof(struct alloted_s));
+	if (!al) {
+		usernic_error("Failed to allocate memory: %s.\n", strerror(errno));
 		return NULL;
 	}
 
 	al->name = strdup(name);
-
-	if (al->name == NULL) {
+	if (!al->name) {
 		free(al);
 		return NULL;
 	}
@@ -219,16 +228,16 @@ static struct alloted_s *append_alloted(struct alloted_s **head, char *name, int
 	al->allowed = n;
 	al->next = NULL;
 
-	if (*head == NULL) {
+	if (!*head) {
 		*head = al;
 		return al;
 	}
 
 	cur = *head;
-	while (cur->next != NULL)
+	while (cur->next)
 		cur = cur->next;
-
 	cur->next = al;
+
 	return al;
 }
 
@@ -236,13 +245,11 @@ static void free_alloted(struct alloted_s **head)
 {
 	struct alloted_s *cur;
 
-	if (head == NULL) {
+	if (!head)
 		return;
-	}
 
 	cur = *head;
-
-	while (cur != NULL) {
+	while (cur) {
 		cur = cur->next;
 		free((*head)->name);
 		free(*head);
@@ -261,49 +268,55 @@ static void free_alloted(struct alloted_s **head)
  */
 static int get_alloted(char *me, char *intype, char *link, struct alloted_s **alloted)
 {
-	FILE *fin = fopen(LXC_USERNIC_CONF, "r");
-	char *line = NULL;
+	int n, ret;
 	char name[100], type[100], br[100];
-	size_t len = 0;
-	int n, ret, count = 0;
 	char **groups;
+	FILE *fin;
+
+	int count = 0;
+	size_t len = 0;
+	char *line = NULL;
 
+	fin = fopen(LXC_USERNIC_CONF, "r");
 	if (!fin) {
-		fprintf(stderr, "Failed to open %s: %s\n", LXC_USERNIC_CONF,
-			strerror(errno));
+		usernic_error("Failed to open \"%s\": %s.\n", LXC_USERNIC_CONF, strerror(errno));
 		return -1;
 	}
 
 	groups = get_groupnames();
 	while ((getline(&line, &len, fin)) != -1) {
 		ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, type, br, &n);
-
 		if (ret != 4)
 			continue;
 
 		if (strlen(name) == 0)
 			continue;
 
-		if (strcmp(name, me) != 0)
-		{
+		if (strcmp(name, me)) {
 			if (name[0] != '@')
 				continue;
-			if (!name_is_in_groupnames(name+1, groups))
+
+			if (!name_is_in_groupnames(name + 1, groups))
 				continue;
 		}
-		if (strcmp(type, intype) != 0)
+
+		if (strcmp(type, intype))
 			continue;
-		if (strcmp(link, br) != 0)
+
+		if (strcmp(link, br))
 			continue;
 
-		/* found the user or group with the appropriate settings, therefore finish the search.
-		 * what to do if there are more than one applicable lines? not specified in the docs.
-		 * since getline is implemented with realloc, we don't need to free line until exiting func.
+		/* Found the user or group with the appropriate settings,
+		 * therefore finish the search. What to do if there are more
+		 * than one applicable lines? not specified in the docs. Since
+		 * getline is implemented with realloc, we don't need to free
+		 * line until exiting func.
 		 *
-		 * if append_alloted returns NULL, e.g. due to a malloc error, we set count to 0 and break the loop,
-		 * allowing cleanup and then exiting from main()
+		 * If append_alloted returns NULL, e.g. due to a malloc error,
+		 * we set count to 0 and break the loop, allowing cleanup and
+		 * then exiting from main().
 		 */
-		if (append_alloted(alloted, name, n) == NULL) {
+		if (!append_alloted(alloted, name, n)) {
 			count = 0;
 			break;
 		}
@@ -314,20 +327,20 @@ static int get_alloted(char *me, char *intype, char *link, struct alloted_s **al
 	fclose(fin);
 	free(line);
 
-	// now return the total number of nics that this user can create
+	/* Now return the total number of nics that this user can create. */
 	return count;
 }
 
 static char *get_eol(char *s, char *e)
 {
-	while (s<e && *s && *s != '\n')
+	while ((s < e) && *s && (*s != '\n'))
 		s++;
 	return s;
 }
 
 static char *get_eow(char *s, char *e)
 {
-	while (s<e && *s && !isblank(*s) && *s != '\n')
+	while ((s < e) && *s && !isblank(*s) && (*s != '\n'))
 		s++;
 	return s;
 }
@@ -336,24 +349,34 @@ 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) {
+	while ((p < e) && (p1 = get_eol(p, e)) < e) {
 		ret = p;
 		if (*p == '#')
 			goto next;
-		while (p<e && isblank(*p)) p++;
+
+		while ((p < e) && isblank(*p))
+			p++;
+
 		p2 = get_eow(p, e);
-		if (!p2 || p2-p != strlen(u) || strncmp(p, u, strlen(u)) != 0)
+		if (!p2 || ((size_t)(p2 - p)) != strlen(u) || strncmp(p, u, strlen(u)))
 			goto next;
-		p = p2+1;
-		while (p<e && isblank(*p)) p++;
+
+		p = p2 + 1;
+		while ((p < e) && isblank(*p))
+			p++;
+
 		p2 = get_eow(p, e);
-		if (!p2 || p2-p != strlen(t) || strncmp(p, t, strlen(t)) != 0)
+		if (!p2 || ((size_t)(p2 - p)) != strlen(t) || strncmp(p, t, strlen(t)))
 			goto next;
-		p = p2+1;
-		while (p<e && isblank(*p)) p++;
+
+		p = p2 + 1;
+		while ((p < e) && isblank(*p))
+			p++;
+
 		p2 = get_eow(p, e);
-		if (!p2 || p2-p != strlen(l) || strncmp(p, l, strlen(l)) != 0)
+		if (!p2 || ((size_t)(p2 - p)) != strlen(l) || strncmp(p, l, strlen(l)))
 			goto next;
+
 		return ret;
 next:
 		p = p1 + 1;
@@ -368,14 +391,17 @@ static bool nic_exists(char *nic)
 	int ret;
 	struct stat sb;
 
-	if (strcmp(nic, "none") == 0)
+	if (!strcmp(nic, "none"))
 		return true;
+
 	ret = snprintf(path, MAXPATHLEN, "/sys/class/net/%s", nic);
-	if (ret < 0 || ret >= MAXPATHLEN) // should never happen!
+	if (ret < 0 || ret >= MAXPATHLEN)
 		return false;
+
 	ret = stat(path, &sb);
-	if (ret != 0)
+	if (ret < 0)
 		return false;
+
 	return true;
 }
 
@@ -385,68 +411,81 @@ static int instantiate_veth(char *n1, char **n2)
 
 	err = snprintf(*n2, IFNAMSIZ, "%sp", n1);
 	if (err < 0 || err >= IFNAMSIZ) {
-		fprintf(stderr, "nic name too long\n");
+		usernic_error("%s\n", "Could not create nic name.");
 		return -1;
 	}
 
 	err = lxc_veth_create(n1, *n2);
 	if (err) {
-		fprintf(stderr, "failed to create %s-%s : %s\n", n1, *n2,
-		      strerror(-err));
+		usernic_error("Failed to create %s-%s : %s.\n", n1, *n2, strerror(-err));
 		return -1;
 	}
 
-	/* changing the high byte of the mac address to 0xfe, the bridge interface
-	 * will always keep the host's mac address and not take the mac address
-	 * of a container */
+	/* Changing the high byte of the mac address to 0xfe, the bridge
+	 * interface will always keep the host's mac address and not take the
+	 * mac address of a container. */
 	err = setup_private_host_hw_addr(n1);
-	if (err) {
-		fprintf(stderr, "failed to change mac address of host interface '%s' : %s\n",
-			n1, strerror(-err));
-	}
+	if (err)
+		usernic_error("Failed to change mac address of host interface "
+			      "%s : %s.\n",
+			      n1, strerror(-err));
 
 	return netdev_set_flag(n1, IFF_UP);
 }
 
 static int get_mtu(char *name)
 {
-	int idx = if_nametoindex(name);
+	int idx;
+
+	idx = if_nametoindex(name);
 	return netdev_get_mtu(idx);
 }
 
 static bool create_nic(char *nic, char *br, int pid, char **cnic)
 {
 	char *veth1buf, *veth2buf;
+	int mtu, ret;
+
 	veth1buf = alloca(IFNAMSIZ);
 	veth2buf = alloca(IFNAMSIZ);
-	int ret, mtu;
+	if (!veth1buf || !veth2buf) {
+		usernic_error("Failed allocate memory: %s.\n", strerror(errno));
+		return false;
+	}
 
 	ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
 	if (ret < 0 || ret >= IFNAMSIZ) {
-		fprintf(stderr, "host nic name too long\n");
+		usernic_error("%s", "Could not create nic name.\n");
 		return false;
 	}
 
 	/* create the nics */
 	if (instantiate_veth(veth1buf, &veth2buf) < 0) {
-		fprintf(stderr, "Error creating veth tunnel\n");
+		usernic_error("%s", "Error creating veth tunnel.\n");
 		return false;
 	}
 
-	if (strcmp(br, "none") != 0) {
+	if (strcmp(br, "none")) {
 		/* copy the bridge's mtu to both ends */
 		mtu = get_mtu(br);
-		if (mtu != -1) {
-			if (lxc_netdev_set_mtu(veth1buf, mtu) < 0 ||
-					lxc_netdev_set_mtu(veth2buf, mtu) < 0) {
-				fprintf(stderr, "Failed setting mtu\n");
+		if (mtu > 0) {
+			ret = lxc_netdev_set_mtu(veth1buf, mtu);
+			if (ret < 0) {
+				usernic_error("Failed to set mtu to %d on %s.\n", mtu, veth1buf);
+				goto out_del;
+			}
+
+			ret = lxc_netdev_set_mtu(veth2buf, mtu);
+			if (ret < 0) {
+				usernic_error("Failed to set mtu to %d on %s.\n", mtu, veth2buf);
 				goto out_del;
 			}
 		}
 
 		/* attach veth1 to bridge */
-		if (lxc_bridge_attach(lxcpath, lxcname, br, veth1buf) < 0) {
-			fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
+		ret = lxc_bridge_attach(lxcpath, lxcname, br, veth1buf);
+		if (ret < 0) {
+			usernic_error("Error attaching %s to %s.\n", veth1buf, br);
 			goto out_del;
 		}
 	}
@@ -454,10 +493,16 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
 	/* pass veth2 to target netns */
 	ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
 	if (ret < 0) {
-		fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
+		usernic_error("Error moving %s to network namespace of %d.\n", veth2buf, pid);
 		goto out_del;
 	}
+
 	*cnic = strdup(veth2buf);
+	if (!*cnic) {
+		usernic_error("Failed to copy string \"%s\".\n", veth2buf);
+		return false;
+	}
+
 	return true;
 
 out_del:
@@ -467,29 +512,34 @@ out_del:
 
 /*
  * Get a new nic.
- * *dest will container the name (vethXXXXXX) which is attached
+ * *dest will contain the name (vethXXXXXX) which is attached
  * on the host to the lxc bridge
  */
 static bool get_new_nicname(char **dest, char *br, int pid, char **cnic)
 {
+	int ret;
 	char template[IFNAMSIZ];
-	snprintf(template, sizeof(template), "vethXXXXXX");
-	*dest = lxc_mkifname(template);
 
-	if (!create_nic(*dest, br, pid, cnic)) {
+	ret = snprintf(template, sizeof(template), "vethXXXXXX");
+	if (ret < 0 || (size_t)ret >= sizeof(template))
 		return false;
-	}
+
+	*dest = lxc_mkifname(template);
+	if (!create_nic(*dest, br, pid, cnic))
+		return false;
+
 	return true;
 }
 
 static bool get_nic_from_line(char *p, char **nic)
 {
-	char user[100], type[100], br[100];
 	int ret;
+	char user[100], type[100], br[100];
 
 	ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user, type, br, *nic);
 	if (ret != 4)
 		return false;
+
 	return true;
 }
 
@@ -501,35 +551,42 @@ struct entry_line {
 
 static bool cull_entries(int fd, char *me, char *t, char *br)
 {
-	struct stat sb;
-	char *buf, *p, *e, *nic;
+	int i, n = 0;
 	off_t len;
+	char *buf, *p, *e, *nic;
+	struct stat sb;
 	struct entry_line *entry_lines = NULL;
-	int i, n = 0;
 
 	nic = alloca(100);
+	if (!nic)
+		return false;
 
 	if (fstat(fd, &sb) < 0) {
-		fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
+		usernic_error("Failed to fstat: %s.\n", strerror(errno));
 		return false;
 	}
+
 	len = sb.st_size;
 	if (len == 0)
 		return true;
+
 	buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 	if (buf == MAP_FAILED) {
-		fprintf(stderr, "Failed to create mapping: %s\n", strerror(errno));
+		usernic_error("Failed to establish shared memory mapping: %s.\n", strerror(errno));
 		return false;
 	}
 
 	p = buf;
 	e = buf + len;
-	while ((p = find_line(p, e, me, t, br)) != NULL) {
-		struct entry_line *newe = realloc(entry_lines, sizeof(*entry_lines)*(n+1));
+	while ((p = find_line(p, e, me, t, br))) {
+		struct entry_line *newe;
+
+		newe = realloc(entry_lines, sizeof(*entry_lines) * (n + 1));
 		if (!newe) {
 			free(entry_lines);
 			return false;
 		}
+
 		entry_lines = newe;
 		entry_lines[n].start = p;
 		entry_lines[n].len = get_eol(p, e) - entry_lines[n].start;
@@ -537,35 +594,43 @@ static bool cull_entries(int fd, char *me, char *t, char *br)
 		n++;
 		if (!get_nic_from_line(p, &nic))
 			continue;
+
 		if (nic && !nic_exists(nic))
-			entry_lines[n-1].keep = false;
-		p += entry_lines[n-1].len + 1;
+			entry_lines[n - 1].keep = false;
+
+		p += entry_lines[n - 1].len + 1;
 		if (p >= e)
 			break;
- 	}
+	}
+
 	p = buf;
-	for (i=0; i<n; i++) {
+	for (i = 0; i < n; i++) {
 		if (!entry_lines[i].keep)
 			continue;
+
 		memcpy(p, entry_lines[i].start, entry_lines[i].len);
 		p += entry_lines[i].len;
 		*p = '\n';
 		p++;
 	}
 	free(entry_lines);
+
 	munmap(buf, sb.st_size);
-	if (ftruncate(fd, p-buf))
-		fprintf(stderr, "Failed to set new file size\n");
+	if (ftruncate(fd, p - buf))
+		usernic_error("Failed to set new file size: %s.\n", strerror(errno));
+
 	return true;
 }
 
 static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
 {
-	char *e = &buf[len];
+	char *e;
 	int count = 0;
-	while ((buf = find_line(buf, e, me, t, br)) != NULL) {
+
+	e = &buf[len];
+	while ((buf = find_line(buf, e, me, t, br))) {
 		count++;
-		buf = get_eol(buf, e)+1;
+		buf = get_eol(buf, e) + 1;
 		if (buf >= e)
 			break;
 	}
@@ -577,16 +642,19 @@ static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
  * The dbfile has lines of the format:
  * user type bridge nicname
  */
-static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
+static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid,
+			     char *intype, char *br, int allowed,
+			     char **nicname, char **cnic)
 {
+	int ret;
 	off_t len, slen;
+	char *newline, *owner;
 	struct stat sb;
-	char *buf = NULL, *newline;
-	int ret, count = 0;
-	char *owner;
 	struct alloted_s *n;
+	int count = 0;
+	char *buf = NULL;
 
-	for (n=names; n!=NULL; n=n->next)
+	for (n = names; n != NULL; n = n->next)
 		cull_entries(fd, n->name, intype, br);
 
 	if (allowed == 0)
@@ -595,19 +663,20 @@ static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid, char *int
 	owner = names->name;
 
 	if (fstat(fd, &sb) < 0) {
-		fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
+		usernic_error("Failed to fstat: %s.\n", strerror(errno));
 		return false;
 	}
+
 	len = sb.st_size;
-	if (len != 0) {
+	if (len > 0) {
 		buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 		if (buf == MAP_FAILED) {
-			fprintf(stderr, "Failed to create mapping\n");
+			usernic_error("Failed to establish shared memory mapping: %s.\n", strerror(errno));
 			return false;
 		}
 
 		owner = NULL;
-		for (n=names; n!=NULL; n=n->next) {
+		for (n = names; n != NULL; n = n->next) {
 			count = count_entries(buf, len, n->name, intype, br);
 
 			if (count >= n->allowed)
@@ -623,115 +692,177 @@ static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid, char *int
 
 	if (!get_new_nicname(nicname, br, pid, cnic))
 		return false;
+
 	/* owner  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
 	slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
 	newline = alloca(slen);
+	if (!newline) {
+		usernic_error("Failed allocate memory: %s.\n", strerror(errno));
+		return false;
+	}
+
 	ret = snprintf(newline, slen, "%s %s %s %s\n", owner, intype, br, *nicname);
 	if (ret < 0 || ret >= slen) {
 		if (lxc_netdev_delete_by_name(*nicname) != 0)
-			fprintf(stderr, "Error unlinking %s!\n", *nicname);
+			usernic_error("Error unlinking %s.\n", *nicname);
 		return false;
 	}
 	if (len)
 		munmap(buf, len);
+
 	if (ftruncate(fd, len + slen))
-		fprintf(stderr, "Failed to set new file size\n");
+		usernic_error("Failed to set new file size: %s.\n", strerror(errno));
+
 	buf = mmap(NULL, len + slen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 	if (buf == MAP_FAILED) {
-		fprintf(stderr, "Failed to create mapping after extending: %s\n", strerror(errno));
+		usernic_error("Failed to establish shared memory mapping: %s.\n", strerror(errno));
 		if (lxc_netdev_delete_by_name(*nicname) != 0)
-			fprintf(stderr, "Error unlinking %s!\n", *nicname);
+			usernic_error("Error unlinking %s.\n", *nicname);
 		return false;
 	}
-	strcpy(buf+len, newline);
-	munmap(buf, len+slen);
+
+	strcpy(buf + len, newline);
+	munmap(buf, len + slen);
+
 	return true;
 }
 
 static bool create_db_dir(char *fnam)
 {
-	char *p = alloca(strlen(fnam)+1);
+	char *p;
 
+	p = alloca(strlen(fnam) + 1);
 	strcpy(p, fnam);
 	fnam = p;
 	p = p + 1;
+
 again:
-	while (*p && *p != '/') p++;
+	while (*p && *p != '/')
+		p++;
 	if (!*p)
 		return true;
+
 	*p = '\0';
 	if (mkdir(fnam, 0755) && errno != EEXIST) {
-		fprintf(stderr, "failed to create %s\n", fnam);
+		usernic_error("Failed to create %s: %s.\n", fnam, strerror(errno));
 		*p = '/';
 		return false;
 	}
 	*(p++) = '/';
+
 	goto again;
 }
 
 #define VETH_DEF_NAME "eth%d"
-
 static int rename_in_ns(int pid, char *oldname, char **newnamep)
 {
-	int fd = -1, ofd = -1, ret, ifindex = -1;
+	uid_t ruid, suid, euid;
+	int fret = -1;
+	int fd = -1, ifindex = -1, ofd = -1, ret;
 	bool grab_newname = false;
 
 	ofd = lxc_preserve_ns(getpid(), "net");
 	if (ofd < 0) {
-		fprintf(stderr, "Failed opening network namespace path for '%d'.", getpid());
-		return -1;
+		usernic_error("Failed opening network namespace path for '%d'.", getpid());
+		return fret;
 	}
 
 	fd = lxc_preserve_ns(pid, "net");
 	if (fd < 0) {
-		fprintf(stderr, "Failed opening network namespace path for '%d'.", pid);
-		return -1;
+		usernic_error("Failed opening network namespace path for '%d'.", pid);
+		goto do_partial_cleanup;
+	}
+
+	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;
 	}
 
-	if (setns(fd, 0) < 0) {
-		fprintf(stderr, "setns to container network namespace\n");
-		goto out_err;
+	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;
+			goto do_full_cleanup;
 	}
-	if (setns(ofd, 0) < 0) {
-		fprintf(stderr, "Error returning to original netns\n");
-		close(ofd);
-		return -1;
+
+	fret = 0;
+
+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.
 	}
-	close(ofd);
 
-	return 0;
+	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;
+	}
 
-out_err:
-	if (ofd >= 0)
-		close(ofd);
-	if (setns(ofd, 0) < 0)
-		fprintf(stderr, "Error returning to original network namespace\n");
+do_partial_cleanup:
 	if (fd >= 0)
 		close(fd);
-	return -1;
+	close(ofd);
+
+	return fret;
 }
 
 /*
@@ -747,61 +878,78 @@ static bool may_access_netns(int pid)
 	bool may_access = false;
 
 	ret = getresuid(&ruid, &euid, &suid);
-	if (ret) {
-		fprintf(stderr, "Failed to get my uids: %s\n", strerror(errno));
+	if (ret < 0) {
+		usernic_error("Failed to retrieve real, effective, and saved "
+			      "user IDs: %s\n",
+			      strerror(errno));
 		return false;
 	}
+
 	ret = setresuid(ruid, ruid, euid);
-	if (ret) {
-		fprintf(stderr, "Failed to set temp uids to (%d,%d,%d): %s\n",
-				(int)ruid, (int)ruid, (int)euid, strerror(errno));
+	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 %d: %s.\n",
+			      ruid, euid, strerror(errno));
 		return false;
 	}
+
 	ret = snprintf(s, 200, "/proc/%d/ns/net", pid);
-	if (ret < 0 || ret >= 200)  // can't happen
+	if (ret < 0 || ret >= 200)
 		return false;
+
 	ret = access(s, R_OK);
-	if (ret) {
-		fprintf(stderr, "Uid %d may not access %s: %s\n",
-				(int)ruid, s, strerror(errno));
+	may_access = true;
+	if (ret < 0)  {
+		may_access = false;
+		usernic_error("Uid %d may not access %s: %s\n", (int)ruid, s, strerror(errno));
 	}
-	may_access = ret == 0;
+
 	ret = setresuid(ruid, euid, suid);
-	if (ret) {
-		fprintf(stderr, "Failed to restore uids to (%d,%d,%d): %s\n",
-				(int)ruid, (int)euid, (int)suid, strerror(errno));
+	if (ret < 0) {
+		usernic_error("Failed to restore user id to %d, real user id "
+			      "to %d, and saved user ID to %d: %s.\n",
+			      ruid, euid, suid, strerror(errno));
 		may_access = false;
 	}
+
 	return may_access;
 }
 
 int main(int argc, char *argv[])
 {
 	int n, fd;
-	bool gotone = false;
 	char *me;
-	char *nicname = alloca(40);
-	char *cnic = NULL; // created nic name in container is returned here.
-	char *vethname = NULL;
+	char *nicname;
 	int pid;
+	char *cnic = NULL; /* Created nic name in container is returned here. */
+	char *vethname = NULL;
+	bool gotone = false;
 	struct alloted_s *alloted = NULL;
 
+	nicname = alloca(40);
+	if (!nicname) {
+		usernic_error("Failed allocate memory: %s.\n", strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
 	/* set a sane env, because we are setuid-root */
 	if (clearenv() < 0) {
-		fprintf(stderr, "Failed to clear environment");
-		exit(1);
+		usernic_error("%s", "Failed to clear environment.\n");
+		exit(EXIT_FAILURE);
 	}
 	if (setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1) < 0) {
-		fprintf(stderr, "Failed to set PATH, exiting\n");
-		exit(1);
+		usernic_error("%s", "Failed to set PATH, exiting.\n");
+		exit(EXIT_FAILURE);
 	}
 	if ((me = get_username()) == NULL) {
-		fprintf(stderr, "Failed to get username\n");
-		exit(1);
+		usernic_error("%s", "Failed to get username.\n");
+		exit(EXIT_FAILURE);
 	}
 
 	if (argc < 6)
 		usage(argv[0], true);
+
 	if (argc >= 7)
 		vethname = argv[6];
 
@@ -809,26 +957,25 @@ int main(int argc, char *argv[])
 	lxcname = argv[2];
 
 	errno = 0;
-	pid = (int) strtol(argv[3], NULL, 10);
+	pid = strtol(argv[3], NULL, 10);
 	if (errno) {
-		fprintf(stderr, "Could not read pid: %s\n", argv[1]);
-		exit(1);
+		usernic_error("Could not read pid: %s.\n", argv[1]);
+		exit(EXIT_FAILURE);
 	}
 
 	if (!create_db_dir(LXC_USERNIC_DB)) {
-		fprintf(stderr, "Failed to create directory for db file\n");
-		exit(1);
+		usernic_error("%s", "Failed to create directory for db file.\n");
+		exit(EXIT_FAILURE);
 	}
 
 	if ((fd = open_and_lock(LXC_USERNIC_DB)) < 0) {
-		fprintf(stderr, "Failed to lock %s\n", LXC_USERNIC_DB);
-		exit(1);
+		usernic_error("Failed to lock %s.\n", LXC_USERNIC_DB);
+		exit(EXIT_FAILURE);
 	}
 
 	if (!may_access_netns(pid)) {
-		fprintf(stderr, "User %s may not modify netns for pid %d\n",
-			me, pid);
-		exit(1);
+		usernic_error("User %s may not modify netns for pid %d.\n", me, pid);
+		exit(EXIT_FAILURE);
 	}
 
 	n = get_alloted(me, argv[4], argv[5], &alloted);
@@ -838,17 +985,21 @@ int main(int argc, char *argv[])
 	close(fd);
 	free_alloted(&alloted);
 	if (!gotone) {
-		fprintf(stderr, "Quota reached\n");
-		exit(1);
+		usernic_error("%s", "Quota reached.\n");
+		exit(EXIT_FAILURE);
 	}
 
-	// Now rename the link
+	/* Now rename the link. */
 	if (rename_in_ns(pid, cnic, &vethname) < 0) {
-		fprintf(stderr, "Failed to rename the link\n");
-		exit(1);
+		usernic_error("%s", "Failed to rename the link.\n");
+		if (lxc_netdev_delete_by_name(cnic) < 0)
+			usernic_error("Failed to delete link \"%s\" the link. Manual cleanup needed.\n", cnic);
+		exit(EXIT_FAILURE);
 	}
 
-	// write the name of the interface pair to the stdout - like eth0:veth9MT2L4
+	/* Write the name of the interface pair to the stdout - like
+	 * eth0:veth9MT2L4.
+	 */
 	fprintf(stdout, "%s:%s\n", vethname, nicname);
-	exit(0);
+	exit(EXIT_SUCCESS);
 }
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 0dbbf2c..dc1d955 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -31,6 +31,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <arpa/inet.h>
+#include <sys/sysmacros.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/syscall.h>
@@ -64,9 +65,6 @@
 #ifdef MAJOR_IN_MKDEV
 #    include <sys/mkdev.h>
 #endif
-#ifdef MAJOR_IN_SYSMACROS
-#    include <sys/sysmacros.h>
-#endif
 
 #if HAVE_IFADDRS_H
 #include <ifaddrs.h>
@@ -4372,7 +4370,10 @@ int list_active_containers(const char *lxcpath, char ***nret,
 		*p2 = '\0';
 
 		if (is_hashed) {
-			if (strncmp(lxcpath, lxc_cmd_get_lxcpath(p), lxcpath_len) != 0)
+			char *recvpath = lxc_cmd_get_lxcpath(p);
+			if (!recvpath)
+				continue;
+			if (strncmp(lxcpath, recvpath, lxcpath_len) != 0)
 				continue;
 			p = lxc_cmd_get_name(p);
 		}
diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c
index d9b3e21..1758402 100644
--- a/src/lxc/monitor.c
+++ b/src/lxc/monitor.c
@@ -153,36 +153,52 @@ int lxc_monitor_close(int fd)
 	return close(fd);
 }
 
+/* Enforces \0-termination for the abstract unix socket. This is not required
+ * but allows us to print it out.
+ *
+ * Older version of liblxc only allowed for 105 bytes to be used for the
+ * abstract unix domain socket name because the code for our abstract unix
+ * socket handling performed invalid checks. Since we \0-terminate we could now
+ * have a maximum of 106 chars. But to not break backwards compatibility we keep
+ * the limit at 105.
+ */
 int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr) {
 	size_t len;
 	int ret;
-	char *sockname;
 	char *path;
 	uint64_t hash;
 
 	/* addr.sun_path is only 108 bytes, so we hash the full name and
 	 * then append as much of the name as we can fit.
 	 */
-	sockname = &addr->sun_path[1];
 	memset(addr, 0, sizeof(*addr));
 	addr->sun_family = AF_UNIX;
 
+	/* strlen("lxc/") + strlen("/monitor-sock") + 1 = 18 */
 	len = strlen(lxcpath) + 18;
 	path = alloca(len);
 	ret = snprintf(path, len, "lxc/%s/monitor-sock", lxcpath);
 	if (ret < 0 || (size_t)ret >= len) {
-		ERROR("Failed to create path for monitor.");
+		ERROR("failed to create name for monitor socket");
 		return -1;
 	}
 
+	/* Note: snprintf() will \0-terminate addr->sun_path on the 106th byte
+	 * and so the abstract socket name has 105 "meaningful" characters. This
+	 * is absolutely intentional. For further info read the comment for this
+	 * function above!
+	 */
 	len = sizeof(addr->sun_path) - 1;
 	hash = fnv_64a_buf(path, ret, FNV1A_64_INIT);
-	ret = snprintf(sockname, len, "lxc/%016" PRIx64 "/%s", hash, lxcpath);
-	if (ret < 0)
+	ret = snprintf(addr->sun_path, len, "@lxc/%016" PRIx64 "/%s", hash, lxcpath);
+	if (ret < 0) {
+		ERROR("failed to create hashed name for monitor socket");
 		return -1;
+	}
 
-	sockname[sizeof(addr->sun_path)-3] = '\0';
-	INFO("Using monitor socket name \"%s\".", sockname);
+	/* replace @ with \0 */
+	addr->sun_path[0] = '\0';
+	INFO("using monitor socket name \"%s\" (length of socket name %zu must be <= %zu)", &addr->sun_path[1], strlen(&addr->sun_path[1]), sizeof(addr->sun_path) - 3);
 
 	return 0;
 }
@@ -193,7 +209,8 @@ int lxc_monitor_open(const char *lxcpath)
 	int fd;
 	size_t retry;
 	size_t len;
-	int ret = 0, backoff_ms[] = {10, 50, 100};
+	int ret = -1;
+	int backoff_ms[] = {10, 50, 100};
 
 	if (lxc_monitor_sock_name(lxcpath, &addr) < 0)
 		return -1;
@@ -201,28 +218,32 @@ int lxc_monitor_open(const char *lxcpath)
 	fd = socket(PF_UNIX, SOCK_STREAM, 0);
 	if (fd < 0) {
 		ERROR("Failed to create socket: %s.", strerror(errno));
-		return -1;
+		return -errno;
 	}
 
-	len = strlen(&addr.sun_path[1]) + 1;
+	len = strlen(&addr.sun_path[1]);
+	DEBUG("opening monitor socket %s with len %zu", &addr.sun_path[1], len);
 	if (len >= sizeof(addr.sun_path) - 1) {
-		ret = -1;
 		errno = ENAMETOOLONG;
+		ret = -errno;
+		ERROR("name of monitor socket too long (%zu bytes): %s", len, strerror(errno));
 		goto on_error;
 	}
 
 	for (retry = 0; retry < sizeof(backoff_ms) / sizeof(backoff_ms[0]); retry++) {
-		ret = connect(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len);
-		if (ret == 0 || errno != ECONNREFUSED)
+		fd = lxc_abstract_unix_connect(addr.sun_path);
+		if (fd < 0 || errno != ECONNREFUSED)
 			break;
-		ERROR("Failed to connect to monitor socket. Retrying in %d ms.", backoff_ms[retry]);
+		ERROR("Failed to connect to monitor socket. Retrying in %d ms: %s", backoff_ms[retry], strerror(errno));
 		usleep(backoff_ms[retry] * 1000);
 	}
 
-	if (ret < 0) {
+	if (fd < 0) {
+		ret = -errno;
 		ERROR("Failed to connect to monitor socket: %s.", strerror(errno));
 		goto on_error;
 	}
+	ret = 0;
 
 	return fd;
 
@@ -340,7 +361,7 @@ int lxc_monitord_spawn(const char *lxcpath)
 
 		close(pipefd[0]);
 
-		DEBUG("Sucessfully synced with child process.");
+		DEBUG("Successfully synced with child process.");
 		exit(EXIT_SUCCESS);
 	}
 
@@ -366,7 +387,7 @@ int lxc_monitord_spawn(const char *lxcpath)
 	DEBUG("Using pipe file descriptor %d for monitord.", pipefd[1]);
 
 	execvp(args[0], args);
-	ERROR("Failed to exec lxc-monitord.");
+	SYSERROR("failed to exec lxc-monitord");
 
 	exit(EXIT_FAILURE);
 }
diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c
index 83b1cb4..3b4d7ed 100644
--- a/src/lxc/seccomp.c
+++ b/src/lxc/seccomp.c
@@ -119,6 +119,7 @@ enum lxc_hostarch_t {
 	lxc_seccomp_arch_all = 0,
 	lxc_seccomp_arch_native,
 	lxc_seccomp_arch_i386,
+	lxc_seccomp_arch_x32,
 	lxc_seccomp_arch_amd64,
 	lxc_seccomp_arch_arm,
 	lxc_seccomp_arch_arm64,
@@ -152,6 +153,7 @@ int get_hostarch(void)
 	}
 	if (strcmp(uts.machine, "i686") == 0)
 		return lxc_seccomp_arch_i386;
+	// no x32 kernels
 	else if (strcmp(uts.machine, "x86_64") == 0)
 		return lxc_seccomp_arch_amd64;
 	else if (strncmp(uts.machine, "armv7", 5) == 0)
@@ -181,6 +183,7 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_
 
 	switch(n_arch) {
 	case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
+	case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
 	case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
 	case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
 #ifdef SCMP_ARCH_AARCH64
@@ -218,6 +221,11 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_
 		seccomp_release(ctx);
 		return NULL;
 	}
+#ifdef SCMP_FLTATR_ATL_TSKIP
+	if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+		WARN("Failed to turn on seccomp nop-skip, continuing");
+	}
+#endif
 	ret = seccomp_arch_add(ctx, arch);
 	if (ret != 0) {
 		ERROR("Seccomp error %d (%s) adding arch: %d", ret,
@@ -336,7 +344,10 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 		compat_arch[0] = SCMP_ARCH_X86;
 		compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
 				default_policy_action);
-		if (!compat_ctx[0])
+		compat_arch[1] = SCMP_ARCH_X32;
+		compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
+				default_policy_action);
+		if (!compat_ctx[0] || !compat_ctx[1])
 			goto bad;
 #ifdef SCMP_ARCH_PPC
 	} else if (native_arch == lxc_seccomp_arch_ppc64) {
@@ -390,6 +401,11 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 			ERROR("Failed to turn off n-new-privs.");
 			return -1;
 		}
+#ifdef SCMP_FLTATR_ATL_TSKIP
+		if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+			WARN("Failed to turn on seccomp nop-skip, continuing");
+		}
+#endif
 	}
 
 	while (fgets(line, 1024, f)) {
@@ -410,6 +426,13 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 					continue;
 				}
 				cur_rule_arch = lxc_seccomp_arch_i386;
+			} else if (strcmp(line, "[x32]") == 0 ||
+				   strcmp(line, "[X32]") == 0) {
+				if (native_arch != lxc_seccomp_arch_amd64) {
+					cur_rule_arch = lxc_seccomp_arch_unknown;
+					continue;
+				}
+				cur_rule_arch = lxc_seccomp_arch_x32;
 			} else if (strcmp(line, "[X86_64]") == 0 ||
 				   strcmp(line, "[x86_64]") == 0) {
 				if (native_arch != lxc_seccomp_arch_amd64) {
@@ -704,7 +727,7 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
 		return -1;
 	}
 
-/* turn of no-new-privs.  We don't want it in lxc, and it breaks
+/* turn off no-new-privs.  We don't want it in lxc, and it breaks
  * with apparmor */
 #if HAVE_SCMP_FILTER_CTX
 	check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
@@ -715,6 +738,11 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
 		ERROR("Failed to turn off n-new-privs.");
 		return -1;
 	}
+#ifdef SCMP_FLTATR_ATL_TSKIP
+	if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+		WARN("Failed to turn on seccomp nop-skip, continuing");
+	}
+#endif
 
 	f = fopen(conf->seccomp, "r");
 	if (!f) {
diff --git a/src/lxc/start.c b/src/lxc/start.c
index c2c14a7..bca7f8e 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -46,7 +46,7 @@
 #include <sys/un.h>
 #include <sys/wait.h>
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #include <sys/capability.h>
 #endif
 
@@ -319,7 +319,7 @@ static int signal_handler(int fd, uint32_t events, void *data,
 	 * by a process different from the container init.
 	 */
 	if (siginfo.ssi_pid != *pid) {
-		WARN("Invalid pid for SIGCHLD. Received pid %d, expected pid %d.", siginfo.ssi_pid, *pid);
+		NOTICE("Received SIGCHLD from pid %d instead of container init %d.", siginfo.ssi_pid, *pid);
 		return init_died ? 1 : 0;
 	}
 
@@ -361,7 +361,7 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
 	}
 
 	if (handler->conf->need_utmp_watch) {
-		#if HAVE_SYS_CAPABILITY_H
+		#if HAVE_LIBCAP
 		if (lxc_utmp_mainloop_add(&descr, handler)) {
 			ERROR("Failed to add utmp handler to LXC mainloop.");
 			goto out_mainloop_open;
@@ -773,7 +773,7 @@ static int do_start(void *data)
 		goto out_warn_father;
 	}
 
-	#if HAVE_SYS_CAPABILITY_H
+	#if HAVE_LIBCAP
 	if (handler->conf->need_utmp_watch) {
 		if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
 			SYSERROR("Failed to remove the CAP_SYS_BOOT capability.");
@@ -873,7 +873,11 @@ static int do_start(void *data)
 		 * further above. Only drop groups if we can, so ensure that we
 		 * have necessary privilege.
 		 */
-		have_cap_setgid = lxc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
+		#if HAVE_LIBCAP
+		have_cap_setgid = lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
+		#else
+		have_cap_setgid = false;
+		#endif
 		if (lxc_list_empty(&handler->conf->id_map) && have_cap_setgid) {
 			if (lxc_setgroups(0, NULL) < 0)
 				goto out_warn_father;
@@ -1042,6 +1046,13 @@ void resolve_clone_flags(struct lxc_handler *handler)
 		INFO("Inheriting a UTS namespace.");
 }
 
+/* lxc_spawn() performs crucial setup tasks and clone()s the new process which
+ * exec()s the requested container binary.
+ * Note that lxc_spawn() runs in the parent namespaces. Any operations performed
+ * right here should be double checked if they'd pose a security risk. (For
+ * example, any {u}mount() operations performed here will be reflected on the
+ * host!)
+ */
 static int lxc_spawn(struct lxc_handler *handler)
 {
 	int failed_before_rename = 0;
@@ -1255,9 +1266,6 @@ static int lxc_spawn(struct lxc_handler *handler)
 	if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CGROUP))
 		return -1;
 
-	if (detect_shared_rootfs())
-		umount2(handler->conf->rootfs.mount, MNT_DETACH);
-
 	if (handler->ops->post_start(handler, handler->data))
 		goto out_abort;
 
@@ -1308,7 +1316,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
 	handler->netnsfd = -1;
 
 	if (must_drop_cap_sys_boot(handler->conf)) {
-		#if HAVE_SYS_CAPABILITY_H
+		#if HAVE_LIBCAP
 		DEBUG("Dropping CAP_SYS_BOOT capability.");
 		#else
 		DEBUG("Not dropping CAP_SYS_BOOT capability as capabilities aren't supported.");
diff --git a/src/lxc/tools/lxc-checkconfig.in b/src/lxc/tools/lxc-checkconfig.in
index 61627e0..4182191 100644
--- a/src/lxc/tools/lxc-checkconfig.in
+++ b/src/lxc/tools/lxc-checkconfig.in
@@ -88,6 +88,24 @@ echo -n "Utsname namespace: " && is_enabled CONFIG_UTS_NS
 echo -n "Ipc namespace: " && is_enabled CONFIG_IPC_NS yes
 echo -n "Pid namespace: " && is_enabled CONFIG_PID_NS yes
 echo -n "User namespace: " && is_enabled CONFIG_USER_NS
+if is_set CONFIG_USER_NS; then
+	if type newuidmap > /dev/null 2>&1; then
+		f=`type -P newuidmap`
+		if [ ! -u "${f}" ]; then
+			echo "Warning: newuidmap is not setuid-root"
+		fi
+	else
+		echo "newuidmap is not installed"
+	fi
+	if type newgidmap > /dev/null 2>&1; then
+		f=`type -P newgidmap`
+		if [ ! -u "${f}" ]; then
+			echo "Warning: newgidmap is not setuid-root"
+		fi
+	else
+		echo "newgidmap is not installed"
+	fi
+fi
 echo -n "Network namespace: " && is_enabled CONFIG_NET_NS
 if ([ $KVER_MAJOR -lt 4 ]) || ([ $KVER_MAJOR -eq 4 ] && [ $KVER_MINOR -lt 7 ]); then
 	echo -n "Multiple /dev/pts instances: " && is_enabled DEVPTS_MULTIPLE_INSTANCES
diff --git a/src/lxc/tools/lxc-start-ephemeral.in b/src/lxc/tools/lxc-start-ephemeral.in
index 7e0c8ea..90d5f6f 100644
--- a/src/lxc/tools/lxc-start-ephemeral.in
+++ b/src/lxc/tools/lxc-start-ephemeral.in
@@ -28,6 +28,7 @@
 import argparse
 import gettext
 import lxc
+import locale
 import os
 import sys
 import subprocess
@@ -363,9 +364,14 @@ if os.path.exists("/proc/self/ns/pid"):
             if args.user:
                 username = args.user
 
-            line = subprocess.check_output(
-                ["getent", "passwd", username],
-                universal_newlines=True).rstrip("\n")
+            # This should really just use universal_newlines=True, but we do
+            # the decoding by hand instead for compatibility with Python
+            # 3.2; that used locale.getpreferredencoding() internally rather
+            # than locale.getpreferredencoding(False), and the former breaks
+            # here because we can't reload codecs at this point unless the
+            # container has the same version of Python installed.
+            line = subprocess.check_output(["getent", "passwd", username])
+            line = line.decode(locale.getpreferredencoding(False)).rstrip("\n")
             _, _, pw_uid, pw_gid, _, pw_dir, _ = line.split(":", 6)
             pw_uid = int(pw_uid)
             pw_gid = int(pw_gid)
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index ca66201..c5e319f 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -142,7 +142,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 		 *
 		 * then we memmove()
 		 *
-		 *	dest: del + 1 == ONT|PID
+		 *	dest: del + 1 == OUNT|PID
 		 *	src:  del + 3 == NT|PID
 		 */
 		while ((del = strstr(arg, "MOUNT")))
diff --git a/src/lxc/tools/lxc_execute.c b/src/lxc/tools/lxc_execute.c
index fae2dca..f26105a 100644
--- a/src/lxc/tools/lxc_execute.c
+++ b/src/lxc/tools/lxc_execute.c
@@ -166,5 +166,5 @@ int main(int argc, char *argv[])
 
 	if (ret < 0)
 		exit(EXIT_FAILURE);
-	exit(EXIT_SUCCESS);
+	exit(ret);
 }
diff --git a/src/lxc/tools/lxc_info.c b/src/lxc/tools/lxc_info.c
index 2888537..c977f29 100644
--- a/src/lxc/tools/lxc_info.c
+++ b/src/lxc/tools/lxc_info.c
@@ -204,7 +204,7 @@ static void print_net_stats(struct lxc_container *c)
 static void print_stats(struct lxc_container *c)
 {
 	int i, ret;
-	char buf[256];
+	char buf[4096];
 
 	ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
 	if (ret > 0 && ret < sizeof(buf)) {
diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c
index 363d3d2..63053b1 100644
--- a/src/lxc/tools/lxc_ls.c
+++ b/src/lxc/tools/lxc_ls.c
@@ -356,7 +356,7 @@ static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args,
 	}
 
 	/* Do not do more work than is necessary right from the start. */
-	if (args->ls_active || (args->ls_active && args->ls_frozen))
+	if (args->ls_active || args->ls_frozen)
 		num = list_active_containers(path, &containers, NULL);
 	else
 		num = list_all_containers(path, &containers, NULL);
diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c
index d8e7247..797ff3c 100644
--- a/src/lxc/tools/lxc_top.c
+++ b/src/lxc/tools/lxc_top.c
@@ -513,5 +513,5 @@ int main(int argc, char *argv[])
 err1:
 	lxc_mainloop_close(&descr);
 out:
-	exit(EXIT_FAILURE);
+	exit(ret);
 }
diff --git a/src/lxc/tools/lxc_unshare.c b/src/lxc/tools/lxc_unshare.c
index 82c8244..a0f943f 100644
--- a/src/lxc/tools/lxc_unshare.c
+++ b/src/lxc/tools/lxc_unshare.c
@@ -225,7 +225,7 @@ int main(int argc, char *argv[])
 	 *
 	 * then we memmove()
 	 *
-	 *	dest: del + 1 == ONT|PID
+	 *	dest: del + 1 == OUNT|PID
 	 *	src:  del + 3 == NT|PID
 	 */
 	while ((del = strstr(namespaces, "MOUNT")))
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 0227c32..778d4da 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1014,7 +1014,7 @@ int randseed(bool srand_it)
 	/*
 	   srand pre-seed function based on /dev/urandom
 	   */
-	unsigned int seed=time(NULL)+getpid();
+	unsigned int seed = time(NULL) + getpid();
 
 	FILE *f;
 	f = fopen("/dev/urandom", "r");
@@ -1199,7 +1199,7 @@ bool detect_ramfs_rootfs(void)
 	return false;
 }
 
-char *on_path(char *cmd, const char *rootfs) {
+char *on_path(const char *cmd, const char *rootfs) {
 	char *path = NULL;
 	char *entry = NULL;
 	char *saveptr = NULL;
@@ -1405,11 +1405,8 @@ char *get_template_path(const char *t)
 }
 
 /*
- * Sets the process title to the specified title. Note:
- *   1. this function requires root to succeed
- *   2. it clears /proc/self/environ
- *   3. it may not succed (e.g. if title is longer than /proc/self/environ +
- *      the original title)
+ * Sets the process title to the specified title. Note that this may fail if
+ * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
  */
 int setproctitle(char *title)
 {
@@ -1463,34 +1460,24 @@ int setproctitle(char *title)
 	if (!tmp)
 		return -1;
 
-	i = sscanf(tmp, "%lu %lu %lu %lu %lu %lu %lu",
+	i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
 		&start_data,
 		&end_data,
 		&start_brk,
-		&arg_start,
-		&arg_end,
 		&env_start,
 		&env_end);
-	if (i != 7)
+	if (i != 5)
 		return -1;
 
 	/* Include the null byte here, because in the calculations below we
 	 * want to have room for it. */
 	len = strlen(title) + 1;
 
-	/* If we don't have enough room by just overwriting the old proctitle,
-	 * let's allocate a new one.
-	 */
-	if (len > arg_end - arg_start) {
-		void *m;
-		m = realloc(proctitle, len);
-		if (!m)
-			return -1;
-		proctitle = m;
-
-		arg_start = (unsigned long) proctitle;
-	}
+	proctitle = realloc(proctitle, len);
+	if (!proctitle)
+		return -1;
 
+	arg_start = (unsigned long) proctitle;
 	arg_end = arg_start + len;
 
 	brk_val = syscall(__NR_brk, 0);
@@ -1767,7 +1754,7 @@ int safe_mount(const char *src, const char *dest, const char *fstype,
  *
  * NOTE: not to be called from inside the container namespace!
  */
-int mount_proc_if_needed(const char *rootfs)
+int lxc_mount_proc_if_needed(const char *rootfs)
 {
 	char path[MAXPATHLEN];
 	char link[20];
@@ -1779,37 +1766,48 @@ int mount_proc_if_needed(const char *rootfs)
 		SYSERROR("proc path name too long");
 		return -1;
 	}
+
 	memset(link, 0, 20);
 	linklen = readlink(path, link, 20);
 	mypid = (int)getpid();
-	INFO("I am %d, /proc/self points to '%s'", mypid, link);
+	INFO("I am %d, /proc/self points to \"%s\"", mypid, link);
+
 	ret = snprintf(path, MAXPATHLEN, "%s/proc", rootfs);
 	if (ret < 0 || ret >= MAXPATHLEN) {
 		SYSERROR("proc path name too long");
 		return -1;
 	}
-	if (linklen < 0) /* /proc not mounted */
+
+	/* /proc not mounted */
+	if (linklen < 0) {
+		if (mkdir(path, 0755) && errno != EEXIST)
+			return -1;
 		goto domount;
+	}
+
 	if (lxc_safe_int(link, &link_to_pid) < 0)
 		return -1;
+
+	/* wrong /procs mounted */
 	if (link_to_pid != mypid) {
-		/* wrong /procs mounted */
-		umount2(path, MNT_DETACH); /* ignore failure */
+		/* ignore failure */
+		umount2(path, MNT_DETACH);
 		goto domount;
 	}
+
 	/* the right proc is already mounted */
 	return 0;
 
 domount:
-	if (!strcmp(rootfs,"")) /* rootfs is NULL */
+	/* rootfs is NULL */
+	if (!strcmp(rootfs,""))
 		ret = mount("proc", path, "proc", 0, NULL);
 	else
 		ret = safe_mount("proc", path, "proc", 0, NULL, rootfs);
-
 	if (ret < 0)
 		return -1;
 
-	INFO("Mounted /proc in container for security transition");
+	INFO("mounted /proc in container for security transition");
 	return 1;
 }
 
@@ -2083,3 +2081,157 @@ int lxc_setgroups(int size, gid_t list[])
 
 	return 0;
 }
+
+static int lxc_get_unused_loop_dev_legacy(char *loop_name)
+{
+	struct dirent *dp;
+	struct loop_info64 lo64;
+	DIR *dir;
+	int dfd = -1, fd = -1, ret = -1;
+
+	dir = opendir("/dev");
+	if (!dir)
+		return -1;
+
+	while ((dp = readdir(dir))) {
+		if (!dp)
+			break;
+
+		if (strncmp(dp->d_name, "loop", 4) != 0)
+			continue;
+
+		dfd = dirfd(dir);
+		if (dfd < 0)
+			continue;
+
+		fd = openat(dfd, dp->d_name, O_RDWR);
+		if (fd < 0)
+			continue;
+
+		ret = ioctl(fd, LOOP_GET_STATUS64, &lo64);
+		if (ret < 0) {
+			if (ioctl(fd, LOOP_GET_STATUS64, &lo64) == 0 ||
+			    errno != ENXIO) {
+				close(fd);
+				fd = -1;
+				continue;
+			}
+		}
+
+		ret = snprintf(loop_name, LO_NAME_SIZE, "/dev/%s", dp->d_name);
+		if (ret < 0 || ret >= LO_NAME_SIZE) {
+			close(fd);
+			fd = -1;
+			continue;
+		}
+
+		break;
+	}
+
+	closedir(dir);
+
+	if (fd < 0)
+		return -1;
+
+	return fd;
+}
+
+static int lxc_get_unused_loop_dev(char *name_loop)
+{
+	int loop_nr, ret;
+	int fd_ctl = -1, fd_tmp = -1;
+
+	fd_ctl = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
+	if (fd_ctl < 0)
+		return -ENODEV;
+
+	loop_nr = ioctl(fd_ctl, LOOP_CTL_GET_FREE);
+	if (loop_nr < 0)
+		goto on_error;
+
+	ret = snprintf(name_loop, LO_NAME_SIZE, "/dev/loop%d", loop_nr);
+	if (ret < 0 || ret >= LO_NAME_SIZE)
+		goto on_error;
+
+	fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
+	if (fd_tmp < 0)
+		goto on_error;
+
+on_error:
+	close(fd_ctl);
+	return fd_tmp;
+}
+
+int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags)
+{
+	int ret;
+	struct loop_info64 lo64;
+	int fd_img = -1, fret = -1, fd_loop = -1;
+
+	fd_loop = lxc_get_unused_loop_dev(loop_dev);
+	if (fd_loop < 0) {
+		if (fd_loop == -ENODEV)
+			fd_loop = lxc_get_unused_loop_dev_legacy(loop_dev);
+		else
+			goto on_error;
+	}
+
+	fd_img = open(source, O_RDWR | O_CLOEXEC);
+	if (fd_img < 0)
+		goto on_error;
+
+	ret = ioctl(fd_loop, LOOP_SET_FD, fd_img);
+	if (ret < 0)
+		goto on_error;
+
+	memset(&lo64, 0, sizeof(lo64));
+	lo64.lo_flags = flags;
+
+	ret = ioctl(fd_loop, LOOP_SET_STATUS64, &lo64);
+	if (ret < 0)
+		goto on_error;
+
+	fret = 0;
+
+on_error:
+	if (fd_img >= 0)
+		close(fd_img);
+
+	if (fret < 0 && fd_loop >= 0) {
+		close(fd_loop);
+		fd_loop = -1;
+	}
+
+	return fd_loop;
+}
+
+int lxc_unstack_mountpoint(const char *path, bool lazy)
+{
+	int ret;
+	int umounts = 0;
+
+pop_stack:
+	ret = umount2(path, lazy ? MNT_DETACH : 0);
+	if (ret < 0) {
+		/* We consider anything else than EINVAL deadly to prevent going
+		 * into an infinite loop. (The other alternative is constantly
+		 * parsing /proc/self/mountinfo which is yucky and probably
+		 * racy.)
+		 */
+		if (errno != EINVAL)
+			return -errno;
+	} else {
+		/* Just stop counting when this happens. That'd just be so
+		 * stupid that we won't even bother trying to report back the
+		 * correct value anymore.
+		 */
+		if (umounts != INT_MAX)
+			umounts++;
+		/* We succeeded in umounting. Make sure that there's no other
+		 * mountpoint stacked underneath.
+		 */
+		goto pop_stack;
+	}
+
+	return umounts;
+}
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 2b56905..320aa6b 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -23,15 +23,19 @@
 #ifndef __LXC_UTILS_H
 #define __LXC_UTILS_H
 
+/* Properly support loop devices on 32bit systems. */
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdbool.h>
+#include <unistd.h>
+#include <linux/loop.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
-#include <unistd.h>
 
 #include "initutils.h"
 
@@ -39,6 +43,7 @@
 /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */
 #define LXC_NUMSTRLEN64 21
 #define LXC_LINELEN 4096
+#define LXC_IDMAPLEN 4096
 
 /* returns 1 on success, 0 if there were any failures */
 extern int lxc_rmdir_onedev(char *path, const char *exclude);
@@ -163,6 +168,15 @@ static inline int signalfd(int fd, const sigset_t *mask, int flags)
 }
 #endif
 
+/* loop devices */
+#ifndef LO_FLAGS_AUTOCLEAR
+#define LO_FLAGS_AUTOCLEAR 4
+#endif
+
+#ifndef LOOP_CTL_GET_FREE
+#define LOOP_CTL_GET_FREE 0x4C82
+#endif
+
 /* Struct to carry child pid from lxc_popen() to lxc_pclose().
  * Not an opaque struct to allow direct access to the underlying FILE *
  * (i.e., struct lxc_popen_FILE *file; fgets(buf, sizeof(buf), file->f))
@@ -301,7 +315,7 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
 
 int detect_shared_rootfs(void);
 bool detect_ramfs_rootfs(void);
-char *on_path(char *cmd, const char *rootfs);
+char *on_path(const char *cmd, const char *rootfs);
 bool file_exists(const char *f);
 bool cgns_supported(void);
 char *choose_init(const char *rootfs);
@@ -312,7 +326,7 @@ char *get_template_path(const char *t);
 int setproctitle(char *title);
 int safe_mount(const char *src, const char *dest, const char *fstype,
 		unsigned long flags, const void *data, const char *rootfs);
-int mount_proc_if_needed(const char *rootfs);
+int lxc_mount_proc_if_needed(const char *rootfs);
 int open_devnull(void);
 int set_stdfds(int fd);
 int null_stdfds(void);
@@ -331,4 +345,14 @@ int lxc_safe_long(const char *numstr, long int *converted);
 int lxc_switch_uid_gid(uid_t uid, gid_t gid);
 int lxc_setgroups(int size, gid_t list[]);
 
+/* Find an unused loop device and associate it with source. */
+int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags);
+
+/* Clear all mounts on a given node.
+ * >= 0 successfully cleared. The number returned is the number of umounts
+ *      performed.
+ * < 0  error umounting. Return -errno.
+ */
+int lxc_unstack_mountpoint(const char *path, bool lazy);
+
 #endif /* __LXC_UTILS_H */
diff --git a/src/lxc/version.h b/src/lxc/version.h
index 7ebf428..d65ed7e 100644
--- a/src/lxc/version.h
+++ b/src/lxc/version.h
@@ -26,8 +26,8 @@
 #define LXC_DEVEL 0
 #define LXC_VERSION_MAJOR 2
 #define LXC_VERSION_MINOR 0
-#define LXC_VERSION_MICRO 7
+#define LXC_VERSION_MICRO 8
 #define LXC_VERSION_ABI "1.2.0"
-#define LXC_VERSION "2.0.7"
+#define LXC_VERSION "2.0.8"
 
 #endif
diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c
index 4f637d0..5f15072 100644
--- a/src/python-lxc/lxc.c
+++ b/src/python-lxc/lxc.c
@@ -353,7 +353,14 @@ LXC_get_global_config_item(PyObject *self, PyObject *args, PyObject *kwds)
 static PyObject *
 LXC_get_version(PyObject *self, PyObject *args)
 {
-    return PyUnicode_FromString(lxc_get_version());
+    const char *rv = NULL;
+
+    rv = lxc_get_version();
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 static PyObject *
@@ -407,6 +414,10 @@ LXC_list_containers(PyObject *self, PyObject *args, PyObject *kwds)
     /* Generate the tuple */
     list = PyTuple_New(list_count);
     for (i = 0; i < list_count; i++) {
+        if (!names[i]) {
+            continue;
+        }
+
         PyTuple_SET_ITEM(list, i, PyUnicode_FromString(names[i]));
         free(names[i]);
     }
@@ -451,7 +462,7 @@ Container_init(Container *self, PyObject *args, PyObject *kwds)
         Py_XDECREF(fs_config_path);
 
         PyErr_Format(PyExc_RuntimeError, "%s:%s:%d: error during init for container '%s'.",
-			__FUNCTION__, __FILE__, __LINE__, name);
+            __FUNCTION__, __FILE__, __LINE__, name);
         return -1;
     }
 
@@ -473,8 +484,14 @@ Container_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 static PyObject *
 Container_config_file_name(Container *self, void *closure)
 {
-    return PyUnicode_FromString(
-                self->container->config_file_name(self->container));
+    char *rv = NULL;
+
+    rv = self->container->config_file_name(self->container);
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 static PyObject *
@@ -506,6 +523,10 @@ Container_init_pid(Container *self, void *closure)
 static PyObject *
 Container_name(Container *self, void *closure)
 {
+    if (!self->container->name) {
+        return PyUnicode_FromString("");
+    }
+
     return PyUnicode_FromString(self->container->name);
 }
 
@@ -522,7 +543,15 @@ Container_running(Container *self, void *closure)
 static PyObject *
 Container_state(Container *self, void *closure)
 {
-    return PyUnicode_FromString(self->container->state(self->container));
+    const char *rv = NULL;
+
+    rv = self->container->state(self->container);
+
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 /* Container Functions */
@@ -946,8 +975,15 @@ Container_get_config_item(Container *self, PyObject *args, PyObject *kwds)
 static PyObject *
 Container_get_config_path(Container *self, PyObject *args, PyObject *kwds)
 {
-    return PyUnicode_FromString(
-                self->container->get_config_path(self->container));
+    const char *rv = NULL;
+
+    rv = self->container->get_config_path(self->container);
+
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 static PyObject *
@@ -1011,6 +1047,11 @@ Container_get_interfaces(Container *self)
     /* Add the entries to the tuple and free the memory */
     i = 0;
     while (interfaces[i]) {
+        if (!interfaces[i]) {
+            i++;
+            continue;
+        }
+
         PyObject *unicode = PyUnicode_FromString(interfaces[i]);
         if (!unicode) {
             Py_DECREF(ret);
@@ -1066,6 +1107,11 @@ Container_get_ips(Container *self, PyObject *args, PyObject *kwds)
     /* Add the entries to the tuple and free the memory */
     i = 0;
     while (ips[i]) {
+        if (!ips[i]) {
+            i++;
+            continue;
+        }
+
         PyObject *unicode = PyUnicode_FromString(ips[i]);
         if (!unicode) {
             Py_DECREF(ret);
diff --git a/src/tests/lxc-test-apparmor-mount b/src/tests/lxc-test-apparmor-mount
index 74fd8c6..bb9b1fc 100755
--- a/src/tests/lxc-test-apparmor-mount
+++ b/src/tests/lxc-test-apparmor-mount
@@ -167,7 +167,7 @@ if [ "x$profile" != "x${default_profile}" ]; then
 	echo "FAIL: confined container was in profile $profile"
 	exit 1
 fi
-run_cmd lxc-stop -n $cname
+run_cmd lxc-stop -n $cname -k
 
 echo "test regular unconfined container"
 echo "lxc.aa_profile = unconfined" >> $HDIR/.local/share/lxc/$cname/config
@@ -179,7 +179,7 @@ if [ "x$profile" != "xunconfined" ]; then
 	echo "FAIL: unconfined container was in profile $profile"
 	exit 1
 fi
-run_cmd lxc-stop -n $cname
+run_cmd lxc-stop -n $cname -k
 
 echo "masking $MOUNTSR"
 mount --bind $dnam $MOUNTSR
@@ -209,7 +209,7 @@ if [ "x$profile" != "xunconfined" ]; then
 	echo "FAIL: confined container was in profile $profile"
 	exit 1
 fi
-run_cmd lxc-stop -n $cname
+run_cmd lxc-stop -n $cname -k
 
 echo "testing override"
 sed -i '/aa_profile/d' $HDIR/.local/share/lxc/$cname/config
@@ -226,6 +226,6 @@ if [ "x$profile" != "x${default_profile}" ]; then
 	echo "FAIL: confined container was in profile $profile"
 	exit 1
 fi
-run_cmd lxc-stop -n $cname
+run_cmd lxc-stop -n $cname -k
 
 DONE=1
diff --git a/src/tests/lxc-test-checkpoint-restore b/src/tests/lxc-test-checkpoint-restore
index 4c91339..2adb131 100755
--- a/src/tests/lxc-test-checkpoint-restore
+++ b/src/tests/lxc-test-checkpoint-restore
@@ -48,5 +48,5 @@ lxc-checkpoint -n $name -v -s -D /tmp/checkpoint || FAIL "failed checkpointing"
 lxc-wait -n $name -s STOPPED
 lxc-checkpoint -n $name -v -r -D /tmp/checkpoint || FAIL "failed restoring"
 
-lxc-stop -n $name -t 1
+lxc-stop -n $name -k
 lxc-destroy -f -n $name
diff --git a/src/tests/lxc-test-ubuntu b/src/tests/lxc-test-ubuntu
index dc06804..a5e6204 100755
--- a/src/tests/lxc-test-ubuntu
+++ b/src/tests/lxc-test-ubuntu
@@ -61,7 +61,12 @@ for template in ubuntu ubuntu-cloud; do
 	done
 	[ -n "$lxcip" ] || FAIL "to start networking in $template container"
 
-	ping -c 1 $lxcip || FAIL "to ping $template container"
+	if echo "${lxcip}" | grep -q ":"; then
+		ping6 -c 1 $lxcip || FAIL "to ping $template container"
+	else
+		ping -c 1 $lxcip || FAIL "to ping $template container"
+	fi
+
 	# Check apparmor
 	lxcpid=`lxc-info -n $name -p -H`
 	aa=`cat /proc/$lxcpid/attr/current`
diff --git a/src/tests/lxc-test-unpriv b/src/tests/lxc-test-unpriv
index 8ba216f..8486fbd 100755
--- a/src/tests/lxc-test-unpriv
+++ b/src/tests/lxc-test-unpriv
@@ -185,7 +185,7 @@ for count in `seq 1 2`; do
     run_cmd lxc-info -n c1
     run_cmd lxc-attach -n c1 -- /bin/true
 
-    run_cmd lxc-stop -n c1
+    run_cmd lxc-stop -n c1 -k
 done
 
 run_cmd lxc-copy -s -n c1 -N c2
@@ -193,7 +193,7 @@ run_cmd lxc-start -n c2 -d
 p1=$(run_cmd lxc-info -n c2 -p -H)
 [ "$p1" != "-1" ] || { echo "Failed to start container c2"; false; }
 
-run_cmd lxc-stop -n c2
+run_cmd lxc-stop -n c2 -k
 
 if which cgm >/dev/null 2>&1; then
     echo "Testing containers under different cgroups per subsystem"
diff --git a/templates/lxc-alpine.in b/templates/lxc-alpine.in
index 06616b3..e66c469 100644
--- a/templates/lxc-alpine.in
+++ b/templates/lxc-alpine.in
@@ -46,7 +46,7 @@ ebf31683b56410ecc4c00acd9f6e2839e237a3b62b5ae7ef686705c7ba0396a9  alpine-devel@l
 12f899e55a7691225603d6fb3324940fc51cd7f133e7ead788663c2b7eecb00c  alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub"
 
 readonly APK_KEYS_URI='http://alpinelinux.org/keys'
-readonly MIRRORS_LIST_URL='http://rsync.alpinelinux.org/alpine/MIRRORS.txt'
+readonly DEFAULT_MIRROR_URL='http://dl-cdn.alpinelinux.org/alpine'
 
 : ${APK_KEYS_DIR:=/etc/apk/keys}
 if ! ls "$APK_KEYS_DIR"/alpine* >/dev/null 2>&1; then
@@ -76,7 +76,7 @@ usage() {
 		                          to the host arch.
 		   -d, --debug            Run this script in a debug mode (set -x and wget w/o -q).
 		   -F, --flush-cache      Remove cached files before build.
-		   -m URL --mirror=URL    The Alpine mirror to use; defaults to random mirror.
+		   -m URL --mirror=URL    The Alpine mirror to use; defaults to $DEFAULT_MIRROR_URL.
 		   -r VER, --release=VER  The Alpine release branch to install; default is the
 		                          latest stable.
 
@@ -130,11 +130,6 @@ parse_arch() {
 	esac
 }
 
-random_mirror_url() {
-	local url=$(fetch "$MIRRORS_LIST_URL" | shuf -n 1)
-	[ -n "$url" ] && echo "$url"
-}
-
 run_exclusively() {
 	local lock_name="$1"
 	local timeout=$2
@@ -266,8 +261,8 @@ install() {
 }
 
 install_packages() {
-	local arch="$1"; shift
-	local packages="$@"
+	local arch="$1"
+	local packages="$2"
 
 	$APK --arch="$arch" --root=. --keys-dir="$APK_KEYS_DIR" \
 		--update-cache --initdb add $packages
@@ -475,7 +470,7 @@ extra_packages="$@"
 # Set global variables.
 readonly DEBUG="$debug"
 readonly FLUSH_CACHE="$flush_cache"
-readonly MIRROR_URL="${mirror_url:-$(random_mirror_url)}"
+readonly MIRROR_URL="${mirror_url:-$DEFAULT_MIRROR_URL}"
 
 # Validate options.
 [ -n "$name" ] || die 1 'Missing required option --name'
diff --git a/templates/lxc-altlinux.in b/templates/lxc-altlinux.in
index 69c18d4..7accf24 100644
--- a/templates/lxc-altlinux.in
+++ b/templates/lxc-altlinux.in
@@ -43,7 +43,6 @@ cache_base=@LOCALSTATEDIR@/cache/lxc/altlinux/$arch
 default_path=@LXCPATH@
 default_profile=default
 profile_dir=/etc/lxc/profiles
-root_password=rooter
 lxc_network_type=veth
 lxc_network_link=virbr0
 
@@ -156,8 +155,10 @@ EOF
     mkdir -m 755 ${dev_path}/net
     mknod -m 666 ${dev_path}/net/tun c 10 200
 
-    echo "setting root passwd to $root_password"
-    echo "root:$root_password" | chroot $rootfs_path chpasswd
+    if [ -n "${root_password}" ]; then
+        echo "setting root passwd to $root_password"
+        echo "root:$root_password" | chroot $rootfs_path chpasswd
+    fi
 
     return 0
 }
diff --git a/templates/lxc-archlinux.in b/templates/lxc-archlinux.in
index c52459d..200b84e 100644
--- a/templates/lxc-archlinux.in
+++ b/templates/lxc-archlinux.in
@@ -42,7 +42,6 @@ export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
 arch=$(uname -m)
 default_path="@LXCPATH@"
 default_locale="en-US.UTF-8"
-default_timezone="UTC"
 pacman_config="/etc/pacman.conf"
 common_config="@LXCTEMPLATECONFIG@/common.conf"
 shared_config="@LXCTEMPLATECONFIG@/archlinux.common.conf"
@@ -87,9 +86,6 @@ configure_arch() {
 
     # hostname and nameservers
     echo "${name}" > "${rootfs_path}/etc/hostname"
-    while read r; do
-       [ "${r#nameserver}" = "$r" ] || echo "$r"
-    done < /etc/resolv.conf > "${rootfs_path}/etc/resolv.conf"
 
     # network configuration
     cat > "${rootfs_path}/etc/systemd/network/eth0.network" << EOF
@@ -104,7 +100,6 @@ EOF
     arch-chroot "${rootfs_path}" /bin/bash -s << EOF
 mkdir /run/lock
 locale-gen
-ln -s /usr/share/zoneinfo/${default_timezone} /etc/localtime
 # set default boot target
 ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
 # override getty@.service for container ttys
diff --git a/templates/lxc-busybox.in b/templates/lxc-busybox.in
index 336fa12..0d8db33 100644
--- a/templates/lxc-busybox.in
+++ b/templates/lxc-busybox.in
@@ -330,35 +330,6 @@ configure_busybox()
     chmod +s $rootfs/bin/passwd
     touch $rootfs/etc/shadow
 
-    # setting passwd for root
-    CHPASSWD_FILE=$rootfs/root/chpasswd.sh
-
-    cat <<EOF >$CHPASSWD_FILE
-echo "setting root password to \"root\""
-
-mount -n --bind /lib $rootfs/lib
-if [ \$? -ne 0 ]; then
-    echo "Failed bind-mounting /lib at $rootfs/lib"
-    exit 1
-fi
-
-chroot $rootfs chpasswd <<EOFF 2>/dev/null
-root:root
-EOFF
-
-
-if [ \$? -ne 0 ]; then
-    echo "Failed to change root password"
-    exit 1
-fi
-
-umount $rootfs/lib
-
-EOF
-
-    lxc-unshare -s MOUNT -- /bin/sh < $CHPASSWD_FILE
-    rm $CHPASSWD_FILE
-
     return 0
 }
 
diff --git a/templates/lxc-debian.in b/templates/lxc-debian.in
index f752ccd..4477aff 100644
--- a/templates/lxc-debian.in
+++ b/templates/lxc-debian.in
@@ -158,9 +158,6 @@ EOF
         echo "Timezone in container is not configured. Adjust it manually."
     fi
 
-    echo "root:root" | chroot "$rootfs" chpasswd
-    echo "Root password is 'root', please change !"
-
     return 0
 }
 
@@ -291,9 +288,6 @@ openssh-server
     if [ ! -f $releasekeyring ]; then
         releasekeyring="$cache/archive-key.gpg"
         case $release in
-            "squeeze")
-                gpgkeyname="archive-key-6.0"
-                ;;
             "wheezy")
                 gpgkeyname="archive-key-7.0"
                 ;;
diff --git a/templates/lxc-download.in b/templates/lxc-download.in
index e0ffdb2..f09475d 100644
--- a/templates/lxc-download.in
+++ b/templates/lxc-download.in
@@ -34,7 +34,6 @@ DOWNLOAD_FLUSH_CACHE="false"
 DOWNLOAD_FORCE_CACHE="false"
 DOWNLOAD_INTERACTIVE="false"
 DOWNLOAD_KEYID="0xE7FB0CAEC8173D669066514CBAEFF88C22F6E216"
-DOWNLOAD_KEYSERVER="hkp://pool.sks-keyservers.net"
 DOWNLOAD_LIST_IMAGES="false"
 DOWNLOAD_MODE="system"
 DOWNLOAD_READY_GPG="false"
@@ -54,9 +53,13 @@ LXC_NAME=
 LXC_PATH=
 LXC_ROOTFS=
 
-# Deal with GPG over http proxy
-if [ -n "${http_proxy:-}" ]; then
-    DOWNLOAD_KEYSERVER="hkp://p80.pool.sks-keyservers.net:80"
+if [ -z "${DOWNLOAD_KEYSERVER:-}" ]; then
+	DOWNLOAD_KEYSERVER="hkp://pool.sks-keyservers.net"
+
+	# Deal with GPG over http proxy
+	if [ -n "${http_proxy:-}" ]; then
+	    DOWNLOAD_KEYSERVER="hkp://p80.pool.sks-keyservers.net:80"
+	fi
 fi
 
 # Make sure the usual locations are in PATH
@@ -201,7 +204,7 @@ Optional arguments:
 [ --variant <variant> ]: Variant of the image (default: "default")
 [ --server <server> ]: Image server (default: "images.linuxcontainers.org")
 [ --keyid <keyid> ]: GPG keyid (default: 0x...)
-[ --keyserver <keyserver> ]: GPG keyserver to use
+[ --keyserver <keyserver> ]: GPG keyserver to use. Environment variable: DOWNLOAD_KEYSERVER
 [ --no-validate ]: Disable GPG validation (not recommended)
 [ --flush-cache ]: Flush the local copy (if present)
 [ --force-cache ]: Force the use of the local copy even if expired
@@ -212,6 +215,11 @@ LXC internal arguments (do not pass manually!):
 [ --rootfs <rootfs> ]: The path to the container's rootfs
 [ --mapped-uid <map> ]: A uid map (user namespaces)
 [ --mapped-gid <map> ]: A gid map (user namespaces)
+
+Environment Variables:
+DOWNLOAD_KEYSERVER : The URL of the key server to use, instead of the default.
+                     Can be further overridden by using optional argument --keyserver
+
 EOF
     return 0
 }
diff --git a/templates/lxc-gentoo.in b/templates/lxc-gentoo.in
index 2ad16e8..47f24d0 100644
--- a/templates/lxc-gentoo.in
+++ b/templates/lxc-gentoo.in
@@ -654,8 +654,6 @@ container_auth()
         printf "  => done. if you didn't specify , default is 'toor'\n"
         if [[ -n "${forced_password}" ]]; then
             store_user_message "${user} has the password you give for him"
-        else
-            store_user_message "${user} has the default password 'toor', please change it ASAP"
         fi
     fi
 
@@ -779,7 +777,6 @@ set_default_arch
 
 mirror="http://distfiles.gentoo.org";
 user="root"
-password="toor"
 tty=1
 settings="common"
 options=$(getopt -o hp:n:a:FcPv:t:S:u:w:s:m: -l help,rootfs:,path:,name:,arch:,flush-cache,cache-only,private-portage,variant:,portage-dir:,tarball:,auth-key:,user:,autologin,password:,settings:,mirror:,tty: -- "$@")
diff --git a/templates/lxc-openmandriva.in b/templates/lxc-openmandriva.in
index 12f9985..daba812 100644
--- a/templates/lxc-openmandriva.in
+++ b/templates/lxc-openmandriva.in
@@ -46,7 +46,6 @@ hostarch=$(uname -m)
 cache_base="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/openmandriva/$arch}"
 default_path=@LXCPATH@
 default_profile=default
-root_password=root
 lxc_network_type=veth
 lxc_network_link=br0
 
diff --git a/templates/lxc-opensuse.in b/templates/lxc-opensuse.in
index 66176c3..5e8686b 100644
--- a/templates/lxc-opensuse.in
+++ b/templates/lxc-opensuse.in
@@ -112,7 +112,6 @@ EOF
     touch $rootfs/etc/sysconfig/kernel
 
     echo "Please change root-password !"
-    echo "root:root" | chpasswd -R $rootfs
 
     return 0
 }
@@ -459,7 +458,7 @@ fi
 if [ -z "$DISTRO" ]; then
     echo ""
     echo "No release selected, using openSUSE Leap 42.2"
-    DISTRO=42.2
+    DISTRO="leap/42.2"
 else
     echo ""
     case "$DISTRO" in
diff --git a/templates/lxc-oracle.in b/templates/lxc-oracle.in
index 20c212b..19fe912 100644
--- a/templates/lxc-oracle.in
+++ b/templates/lxc-oracle.in
@@ -462,12 +462,10 @@ EOF
         fi
     fi
 
-    # add oracle user, set root password
+    # add oracle user
     chroot $container_rootfs useradd -m -s /bin/bash oracle
-    echo "oracle:oracle" | chroot $container_rootfs chpasswd
-    echo "root:root" | chroot $container_rootfs chpasswd
-    printf "Added container user:\033[1moracle\033[0m password:\033[1moracle\033[0m\n"
-    printf "Added container user:\033[1mroot\033[0m password:\033[1mroot\033[0m\n"
+    printf "Added container user:\033[1moracle\033[0m\n"
+    printf "Added container user:\033[1mroot\033[0m\n"
 }
 
 # create the container's lxc config file
diff --git a/templates/lxc-plamo.in b/templates/lxc-plamo.in
index 009fa4f..c96e23e 100644
--- a/templates/lxc-plamo.in
+++ b/templates/lxc-plamo.in
@@ -186,9 +186,6 @@ configure_plamo() {
   # glibc configure
   mv $rootfs/etc/ld.so.conf{.new,}
   chroot $rootfs ldconfig
-  # root password
-  echo "Setting root password to 'root'..."
-  echo "root:root" | chroot $rootfs chpasswd
   echo "Please change root password!"
   ed - $rootfs/etc/rc.d/rc.S <<- "EOF"
 	/^mount -w -n -t proc/;/^mkdir \/dev\/shm/-1d
diff --git a/templates/lxc-slackware.in b/templates/lxc-slackware.in
index 5005918..216c7a7 100644
--- a/templates/lxc-slackware.in
+++ b/templates/lxc-slackware.in
@@ -471,10 +471,6 @@ sed -i 's/.*genpowerfail.*//' $rootfs/etc/inittab
 # add a message to rc.local that confirms successful container startup
 echo "echo ; echo \"* container $name started. *\" ; echo" >> $rootfs/etc/rc.d/rc.local
 
-# set a default combination for the luggage
-echo "root:root" | chroot $rootfs chpasswd
-echo "Root default password is 'root', please change it!"
-
 # borrow the time configuration from the local machine
 cp -a /etc/localtime $rootfs/etc/localtime
 
diff --git a/templates/lxc-sparclinux.in b/templates/lxc-sparclinux.in
index 70616ba..124c50b 100644
--- a/templates/lxc-sparclinux.in
+++ b/templates/lxc-sparclinux.in
@@ -296,12 +296,10 @@ EOF
         echo "Timezone in container is not configured. Adjust it manually."
     fi
 
-    # add oracle user, set root password
+    # add oracle user
     chroot $container_rootfs useradd -m -s /bin/bash oracle
-    echo "oracle:oracle" | chroot $container_rootfs chpasswd
-    echo "root:root" | chroot $container_rootfs chpasswd
-    printf "Added container user:\033[1moracle\033[0m password:\033[1moracle\033[0m\n"
-    printf "Added container user:\033[1mroot\033[0m password:\033[1mroot\033[0m\n"
+    printf "Added container user:\033[1moracle\033[0m\n"
+    printf "Added container user:\033[1mroot\033[0m\n"
 }
 
 # create the container's lxc config file
diff --git a/templates/lxc-sshd.in b/templates/lxc-sshd.in
index 9b07ea6..7db13cc 100644
--- a/templates/lxc-sshd.in
+++ b/templates/lxc-sshd.in
@@ -38,7 +38,6 @@ install_sshd()
     rootfs=$1
 
     tree="\
-$rootfs/var/run/sshd \
 $rootfs/var/empty/sshd \
 $rootfs/var/lib/empty/sshd \
 $rootfs/etc/init.d \
@@ -46,7 +45,7 @@ $rootfs/etc/rc.d \
 $rootfs/etc/ssh \
 $rootfs/etc/sysconfig/network-scripts \
 $rootfs/dev/shm \
-$rootfs/run/shm \
+$rootfs/run/sshd \
 $rootfs/proc \
 $rootfs/sys \
 $rootfs/bin \
@@ -63,6 +62,11 @@ $rootfs/lib64"
         return 1
     fi
 
+    ln -s /run $rootfs/var/run
+    if [ $? -ne 0 ]; then
+        return 1
+    fi
+
     return 0
 }
 
@@ -90,17 +94,13 @@ Protocol 2
 HostKey /etc/ssh/ssh_host_rsa_key
 HostKey /etc/ssh/ssh_host_dsa_key
 UsePrivilegeSeparation yes
-KeyRegenerationInterval 3600
-ServerKeyBits 768
 SyslogFacility AUTH
 LogLevel INFO
 LoginGraceTime 120
 PermitRootLogin yes
 StrictModes yes
-RSAAuthentication yes
 PubkeyAuthentication yes
 IgnoreRhosts yes
-RhostsRSAAuthentication no
 HostbasedAuthentication no
 PermitEmptyPasswords yes
 ChallengeResponseAuthentication no
@@ -141,7 +141,7 @@ lxc.mount.entry = /lib lib none ro,bind 0 0
 lxc.mount.entry = /bin bin none ro,bind 0 0
 lxc.mount.entry = /usr usr none ro,bind 0 0
 lxc.mount.entry = /sbin sbin none ro,bind 0 0
-lxc.mount.entry = tmpfs var/run/sshd tmpfs mode=0644 0 0
+lxc.mount.entry = tmpfs run/sshd tmpfs mode=0644 0 0
 lxc.mount.entry = @LXCTEMPLATEDIR@/lxc-sshd $init_path none ro,bind 0 0
 lxc.mount.entry = /etc/init.d etc/init.d none ro,bind 0 0
 
diff --git a/templates/lxc-ubuntu.in b/templates/lxc-ubuntu.in
index 8320993..ae3a22a 100644
--- a/templates/lxc-ubuntu.in
+++ b/templates/lxc-ubuntu.in
@@ -674,7 +674,7 @@ $1 -h|--help [-a|--arch] [-b|--bindhome <user>] [-d|--debug]
    [-F | --flush-cache] [-r|--release <release>] [-v|--variant] [ -S | --auth-key <keyfile>]
    [--rootfs <rootfs>] [--packages <packages>] [-u|--user <user>] [--password <password>]
    [--mirror <url>] [--security-mirror <url>]
-release: the ubuntu release (e.g. precise): defaults to host release on ubuntu, otherwise uses latest LTS
+release: the ubuntu release (e.g. xenial): defaults to host release on ubuntu, otherwise uses latest LTS
 variant: debootstrap variant to use (see debootstrap(8))
 bindhome: bind <user>'s home into the container
           The ubuntu user will not be created, and <user> will have
@@ -694,7 +694,7 @@ if [ $? -ne 0 ]; then
 fi
 eval set -- "$options"
 
-release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems
+release=xenial # Default to the last Ubuntu LTS release for non-Ubuntu systems
 if [ -f /etc/lsb-release ]; then
     . /etc/lsb-release
     if [ "$DISTRIB_ID" = "Ubuntu" ]; then

--- End Message ---
--- Begin Message ---
Hi,

On Sat, May 20, 2017 at 10:14:29AM +0200, Evgeni Golov wrote:
> Niels asked on IRC if the diff can be filtered a bit.
> 
> It can, but it still does not look magically awesome then:
>  54 files changed, 1548 insertions(+), 955 deletions(-)
> 
> Generated with:
>  git diff debian/1%2.0.7-2.. |filterdiff -x a/debian/patches/\* -x a/configure -x a/src/tests/\* -x a/README -x a/doc/\* -x \*/Makefile.in

I'm sorry, but I think it's too late to consider this change now, given that
we are very close to the release date.

> Also, as it was asked, lxc and lxcfs are not coupled, we can update them independently.

lxcfs was unblocked earlier.

Cheers,

Ivo

--- End Message ---

Reply to: