Bug#862468: (pre-approval) unblock: lxc/1:2.0.8-1
Ohai,
On Sat, May 13, 2017 at 09:44:42AM +0100, Evgeni Golov wrote:
> 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.
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
Bear in mind that the above still contains the upstream versions of
the two dropped patches:
lxc-2.0-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
src/lxc/lxc_user_nic.c | 119 ++++++++++++++++++++++++++++++++++++-------------
0010-lxc-debian-root-password.patch
templates/lxc-debian.in | 3 ---
And I have no way to filter that out.
New debdiff attached.
Also, as it was asked, lxc and lxcfs are not coupled, we can update them independently.
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/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.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/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/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/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
Reply to: