diff -Nru lxc-1.0.7/config/apparmor/abstractions/container-base lxc-1.0.8/config/apparmor/abstractions/container-base --- lxc-1.0.7/config/apparmor/abstractions/container-base 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/apparmor/abstractions/container-base 2015-11-09 22:49:15.000000000 +0000 @@ -70,9 +70,10 @@ mount fstype=efivarfs -> /sys/firmware/efi/efivars/, # block some other dangerous paths - deny @{PROC}/sysrq-trigger rwklx, - deny @{PROC}/mem rwklx, + deny @{PROC}/kcore rwklx, deny @{PROC}/kmem rwklx, + deny @{PROC}/mem rwklx, + deny @{PROC}/sysrq-trigger rwklx, # deny writes in /sys except for /sys/fs/cgroup, also allow # fusectl, securityfs and debugfs to be mounted there (read-only) diff -Nru lxc-1.0.7/config/apparmor/abstractions/container-base.in lxc-1.0.8/config/apparmor/abstractions/container-base.in --- lxc-1.0.7/config/apparmor/abstractions/container-base.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/apparmor/abstractions/container-base.in 2015-11-09 22:49:15.000000000 +0000 @@ -70,9 +70,10 @@ mount fstype=efivarfs -> /sys/firmware/efi/efivars/, # block some other dangerous paths - deny @{PROC}/sysrq-trigger rwklx, - deny @{PROC}/mem rwklx, + deny @{PROC}/kcore rwklx, deny @{PROC}/kmem rwklx, + deny @{PROC}/mem rwklx, + deny @{PROC}/sysrq-trigger rwklx, # deny writes in /sys except for /sys/fs/cgroup, also allow # fusectl, securityfs and debugfs to be mounted there (read-only) diff -Nru lxc-1.0.7/config/apparmor/abstractions/start-container lxc-1.0.8/config/apparmor/abstractions/start-container --- lxc-1.0.7/config/apparmor/abstractions/start-container 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/apparmor/abstractions/start-container 2015-11-09 22:49:15.000000000 +0000 @@ -13,7 +13,8 @@ mount -> /usr/lib/lxc/{**,}, mount fstype=devpts -> /dev/pts/, mount options=bind /dev/pts/ptmx/ -> /dev/ptmx/, - mount options=(rw, slave) -> /, + mount options=bind /dev/pts/** -> /dev/**, + mount options=(rw, make-slave) -> **, mount fstype=debugfs, # allow pre-mount hooks to stage mounts under /var/lib/lxc// mount -> /var/lib/lxc/{**,}, diff -Nru lxc-1.0.7/config/apparmor/profiles/lxc-default-with-nesting lxc-1.0.8/config/apparmor/profiles/lxc-default-with-nesting --- lxc-1.0.7/config/apparmor/profiles/lxc-default-with-nesting 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/apparmor/profiles/lxc-default-with-nesting 2015-11-09 22:49:15.000000000 +0000 @@ -8,7 +8,9 @@ # Uncomment the line below if you are not using cgmanager # mount fstype=cgroup -> /sys/fs/cgroup/**, + deny /dev/.lxc/proc/** rw, + deny /dev/.lxc/sys/** rw, mount fstype=proc -> /var/cache/lxc/**, mount fstype=sysfs -> /var/cache/lxc/**, - mount options=(rw,bind) /var/cache/lxc/**/dev/shm/ -> /var/cache/lxc/**/run/shm/, + mount options=(rw,bind), } diff -Nru lxc-1.0.7/config/bash/lxc lxc-1.0.8/config/bash/lxc --- lxc-1.0.7/config/bash/lxc 2014-12-05 20:50:37.000000000 +0000 +++ lxc-1.0.8/config/bash/lxc 2015-11-09 22:49:28.000000000 +0000 @@ -11,7 +11,7 @@ COMPREPLY=( $( compgen -W "$(ls /usr/local/share/lxc/templates/ | sed -e 's|^lxc-||' )" "$cur" ) ) } - _lxc-generic-n() { + _lxc_generic_n() { local cur prev COMPREPLY=() @@ -27,7 +27,7 @@ return 1 } - _lxc-generic-ns() { + _lxc_generic_ns() { local cur prev COMPREPLY=() @@ -48,7 +48,7 @@ return 1 } - _lxc-generic-t() { + _lxc_generic_t() { local cur prev COMPREPLY=() @@ -64,7 +64,7 @@ return 1 } - _lxc-generic-o() { + _lxc_generic_o() { local cur prev COMPREPLY=() @@ -80,24 +80,24 @@ return 1 } - complete -o default -F _lxc-generic-n lxc-attach - complete -o default -F _lxc-generic-n lxc-cgroup - complete -o default -F _lxc-generic-n lxc-console - complete -o default -F _lxc-generic-n lxc-destroy - complete -o default -F _lxc-generic-n lxc-device - complete -o default -F _lxc-generic-n lxc-execute - complete -o default -F _lxc-generic-n lxc-freeze - complete -o default -F _lxc-generic-n lxc-info - complete -o default -F _lxc-generic-n lxc-monitor - complete -o default -F _lxc-generic-n lxc-snapshot - complete -o default -F _lxc-generic-n lxc-start - complete -o default -F _lxc-generic-n lxc-stop - complete -o default -F _lxc-generic-n lxc-unfreeze + complete -o default -F _lxc_generic_n lxc-attach + complete -o default -F _lxc_generic_n lxc-cgroup + complete -o default -F _lxc_generic_n lxc-console + complete -o default -F _lxc_generic_n lxc-destroy + complete -o default -F _lxc_generic_n lxc-device + complete -o default -F _lxc_generic_n lxc-execute + complete -o default -F _lxc_generic_n lxc-freeze + complete -o default -F _lxc_generic_n lxc-info + complete -o default -F _lxc_generic_n lxc-monitor + complete -o default -F _lxc_generic_n lxc-snapshot + complete -o default -F _lxc_generic_n lxc-start + complete -o default -F _lxc_generic_n lxc-stop + complete -o default -F _lxc_generic_n lxc-unfreeze - complete -o default -F _lxc-generic-ns lxc-wait + complete -o default -F _lxc_generic_ns lxc-wait - complete -o default -F _lxc-generic-t lxc-create + complete -o default -F _lxc_generic_t lxc-create - complete -o default -F _lxc-generic-o lxc-clone - complete -o default -F _lxc-generic-o lxc-start-ephemeral + complete -o default -F _lxc_generic_o lxc-clone + complete -o default -F _lxc_generic_o lxc-start-ephemeral } diff -Nru lxc-1.0.7/config/bash/lxc.in lxc-1.0.8/config/bash/lxc.in --- lxc-1.0.7/config/bash/lxc.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/bash/lxc.in 2015-11-09 22:49:15.000000000 +0000 @@ -11,7 +11,7 @@ COMPREPLY=( $( compgen -W "$(ls @LXCTEMPLATEDIR@/ | sed -e 's|^lxc-||' )" "$cur" ) ) } - _lxc-generic-n() { + _lxc_generic_n() { local cur prev COMPREPLY=() @@ -27,7 +27,7 @@ return 1 } - _lxc-generic-ns() { + _lxc_generic_ns() { local cur prev COMPREPLY=() @@ -48,7 +48,7 @@ return 1 } - _lxc-generic-t() { + _lxc_generic_t() { local cur prev COMPREPLY=() @@ -64,7 +64,7 @@ return 1 } - _lxc-generic-o() { + _lxc_generic_o() { local cur prev COMPREPLY=() @@ -80,24 +80,24 @@ return 1 } - complete -o default -F _lxc-generic-n lxc-attach - complete -o default -F _lxc-generic-n lxc-cgroup - complete -o default -F _lxc-generic-n lxc-console - complete -o default -F _lxc-generic-n lxc-destroy - complete -o default -F _lxc-generic-n lxc-device - complete -o default -F _lxc-generic-n lxc-execute - complete -o default -F _lxc-generic-n lxc-freeze - complete -o default -F _lxc-generic-n lxc-info - complete -o default -F _lxc-generic-n lxc-monitor - complete -o default -F _lxc-generic-n lxc-snapshot - complete -o default -F _lxc-generic-n lxc-start - complete -o default -F _lxc-generic-n lxc-stop - complete -o default -F _lxc-generic-n lxc-unfreeze + complete -o default -F _lxc_generic_n lxc-attach + complete -o default -F _lxc_generic_n lxc-cgroup + complete -o default -F _lxc_generic_n lxc-console + complete -o default -F _lxc_generic_n lxc-destroy + complete -o default -F _lxc_generic_n lxc-device + complete -o default -F _lxc_generic_n lxc-execute + complete -o default -F _lxc_generic_n lxc-freeze + complete -o default -F _lxc_generic_n lxc-info + complete -o default -F _lxc_generic_n lxc-monitor + complete -o default -F _lxc_generic_n lxc-snapshot + complete -o default -F _lxc_generic_n lxc-start + complete -o default -F _lxc_generic_n lxc-stop + complete -o default -F _lxc_generic_n lxc-unfreeze - complete -o default -F _lxc-generic-ns lxc-wait + complete -o default -F _lxc_generic_ns lxc-wait - complete -o default -F _lxc-generic-t lxc-create + complete -o default -F _lxc_generic_t lxc-create - complete -o default -F _lxc-generic-o lxc-clone - complete -o default -F _lxc-generic-o lxc-start-ephemeral + complete -o default -F _lxc_generic_o lxc-clone + complete -o default -F _lxc_generic_o lxc-start-ephemeral } diff -Nru lxc-1.0.7/config/bash/Makefile.in lxc-1.0.8/config/bash/Makefile.in --- lxc-1.0.7/config/bash/Makefile.in 2014-12-05 20:50:26.000000000 +0000 +++ lxc-1.0.8/config/bash/Makefile.in 2015-11-09 22:49:20.000000000 +0000 @@ -378,8 +378,8 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@ENABLE_BASH_FALSE@uninstall-local: @ENABLE_BASH_FALSE@install-data-local: +@ENABLE_BASH_FALSE@uninstall-local: clean: clean-am clean-am: clean-generic mostlyclean-am diff -Nru lxc-1.0.7/config/init/upstart/lxc.conf lxc-1.0.8/config/init/upstart/lxc.conf --- lxc-1.0.7/config/init/upstart/lxc.conf 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/init/upstart/lxc.conf 2015-11-09 22:49:15.000000000 +0000 @@ -36,7 +36,10 @@ # don't load profiles if mount mediation is not supported SYSF=/sys/kernel/security/apparmor/features/mount/mask if [ -f $SYSF ]; then - if [ -x /lib/init/apparmor-profile-load ]; then + if [ -x /lib/apparmor/profile-load ]; then + /lib/apparmor/profile-load usr.bin.lxc-start + /lib/apparmor/profile-load lxc-containers + elif [ -x /lib/init/apparmor-profile-load ]; then /lib/init/apparmor-profile-load usr.bin.lxc-start /lib/init/apparmor-profile-load lxc-containers fi diff -Nru lxc-1.0.7/config/init/upstart/lxc-net.conf lxc-1.0.8/config/init/upstart/lxc-net.conf --- lxc-1.0.7/config/init/upstart/lxc-net.conf 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/init/upstart/lxc-net.conf 2015-11-09 22:49:15.000000000 +0000 @@ -23,6 +23,7 @@ use_iptables_lock="-w" iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock="" cleanup() { + set +e # dnsmasq failed to start, clean up the bridge iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT @@ -34,6 +35,7 @@ iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill ifconfig ${LXC_BRIDGE} down || true brctl delbr ${LXC_BRIDGE} || true + set -e } if [ -d /sys/class/net/${LXC_BRIDGE} ]; then @@ -73,6 +75,7 @@ ls /sys/class/net/${LXC_BRIDGE}/brif/* > /dev/null 2>&1 && exit 0; if [ -d /sys/class/net/${LXC_BRIDGE} ]; then + set +e use_iptables_lock="-w" iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock="" ifconfig ${LXC_BRIDGE} down @@ -87,6 +90,7 @@ pid=`cat ${varrun}/dnsmasq.pid 2>/dev/null` && kill -9 $pid || true rm -f ${varrun}/dnsmasq.pid brctl delbr ${LXC_BRIDGE} + set -e fi rm -f ${varrun}/network_up end script diff -Nru lxc-1.0.7/config/init/upstart/Makefile.in lxc-1.0.8/config/init/upstart/Makefile.in --- lxc-1.0.7/config/init/upstart/Makefile.in 2014-12-05 20:50:26.000000000 +0000 +++ lxc-1.0.8/config/init/upstart/Makefile.in 2015-11-09 22:49:20.000000000 +0000 @@ -375,8 +375,8 @@ maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -@INIT_SCRIPT_UPSTART_FALSE@uninstall-local: @INIT_SCRIPT_UPSTART_FALSE@install-data-local: +@INIT_SCRIPT_UPSTART_FALSE@uninstall-local: clean: clean-am clean-am: clean-generic mostlyclean-am diff -Nru lxc-1.0.7/config/templates/centos.common.conf.in lxc-1.0.8/config/templates/centos.common.conf.in --- lxc-1.0.7/config/templates/centos.common.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/centos.common.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -27,8 +27,9 @@ # lxc.cap.drop = setuid # breaks sshd,nfs statd # lxc.cap.drop = audit_control # breaks sshd (set_loginuid failed) # lxc.cap.drop = audit_write +# lxc.cap.drop = setpcap # big big login delays in CentOS 7 systemd # -lxc.cap.drop = mac_admin mac_override setfcap setpcap +lxc.cap.drop = mac_admin mac_override setfcap lxc.cap.drop = sys_module sys_nice sys_pacct lxc.cap.drop = sys_rawio sys_time diff -Nru lxc-1.0.7/config/templates/centos.userns.conf.in lxc-1.0.8/config/templates/centos.userns.conf.in --- lxc-1.0.7/config/templates/centos.userns.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/centos.userns.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -18,7 +18,3 @@ # Extra fstab entries as mountall can't mount those by itself lxc.mount.entry = /sys/firmware/efi/efivars sys/firmware/efi/efivars none bind,optional 0 0 lxc.mount.entry = /proc/sys/fs/binfmt_misc proc/sys/fs/binfmt_misc none bind,optional 0 0 - -# Default seccomp policy is not needed for unprivileged containers, and -# non-root users cannot use seccmp without NNP anyway. -lxc.seccomp = diff -Nru lxc-1.0.7/config/templates/common.seccomp lxc-1.0.8/config/templates/common.seccomp --- lxc-1.0.7/config/templates/common.seccomp 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/common.seccomp 2015-11-09 22:49:15.000000000 +0000 @@ -1,5 +1,6 @@ 2 blacklist +reject_force_umount # comment this to allow umount -f; not recommended [all] kexec_load errno 1 open_by_handle_at errno 1 diff -Nru lxc-1.0.7/config/templates/debian.userns.conf.in lxc-1.0.8/config/templates/debian.userns.conf.in --- lxc-1.0.7/config/templates/debian.userns.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/debian.userns.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -10,7 +10,3 @@ lxc.mount.entry = /dev/tty dev/tty none bind,create=file 0 0 lxc.mount.entry = /dev/urandom dev/urandom none bind,create=file 0 0 lxc.mount.entry = /dev/zero dev/zero none bind,create=file 0 0 - -# Default seccomp policy is not needed for unprivileged containers, and -# non-root users cannot use seccmp without NNP anyway. -lxc.seccomp = diff -Nru lxc-1.0.7/config/templates/fedora.userns.conf.in lxc-1.0.8/config/templates/fedora.userns.conf.in --- lxc-1.0.7/config/templates/fedora.userns.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/fedora.userns.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -18,7 +18,3 @@ # Extra fstab entries as mountall can't mount those by itself lxc.mount.entry = /sys/firmware/efi/efivars sys/firmware/efi/efivars none bind,optional 0 0 lxc.mount.entry = /proc/sys/fs/binfmt_misc proc/sys/fs/binfmt_misc none bind,optional 0 0 - -# Default seccomp policy is not needed for unprivileged containers, and -# non-root users cannot use seccmp without NNP anyway. -lxc.seccomp = diff -Nru lxc-1.0.7/config/templates/gentoo.common.conf.in lxc-1.0.8/config/templates/gentoo.common.conf.in --- lxc-1.0.7/config/templates/gentoo.common.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/gentoo.common.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -56,3 +56,7 @@ # Blacklist some syscalls which are not safe in privileged # containers lxc.seccomp = @LXCTEMPLATECONFIG@/common.seccomp + +# /dev/shm needs to be mounted as tmpfs. It's needed by python (bug #496328) +# and possibly other packages. +lxc.mount.entry = none dev/shm tmpfs rw,nosuid,nodev,create=dir diff -Nru lxc-1.0.7/config/templates/gentoo.moresecure.conf.in lxc-1.0.8/config/templates/gentoo.moresecure.conf.in --- lxc-1.0.7/config/templates/gentoo.moresecure.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/gentoo.moresecure.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -7,8 +7,8 @@ # do not mount sysfs, see http://blog.bofh.it/debian/id_413 # lxc.mount.entry=sys sys sysfs rw 0 0 lxc.mount.entry=proc proc proc ro,nodev,noexec,nosuid 0 0 -lxc.mount.entry=mqueue dev/mqueue mqueue rw,nodev,noexec,nosuid 0 0 -lxc.mount.entry=shm dev/shm tmpfs rw,nosuid,nodev,noexec,relatime 0 0 +lxc.mount.entry=mqueue dev/mqueue mqueue rw,nodev,noexec,nosuid,create=dir 0 0 +lxc.mount.entry=shm dev/shm tmpfs rw,nosuid,nodev,noexec,relatime,create=dir 0 0 lxc.mount.entry=run run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0 # console access diff -Nru lxc-1.0.7/config/templates/gentoo.userns.conf.in lxc-1.0.8/config/templates/gentoo.userns.conf.in --- lxc-1.0.7/config/templates/gentoo.userns.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/gentoo.userns.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -17,7 +17,3 @@ # Extra fstab entries as mountall can't mount those by itself lxc.mount.entry = /sys/firmware/efi/efivars sys/firmware/efi/efivars none bind,optional 0 0 lxc.mount.entry = /proc/sys/fs/binfmt_misc proc/sys/fs/binfmt_misc none bind,optional 0 0 - -# Default seccomp policy is not needed for unprivileged containers, and -# non-root users cannot use seccmp without NNP anyway. -lxc.seccomp = diff -Nru lxc-1.0.7/config/templates/Makefile.am lxc-1.0.8/config/templates/Makefile.am --- lxc-1.0.7/config/templates/Makefile.am 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/Makefile.am 2015-11-09 22:49:15.000000000 +0000 @@ -13,6 +13,7 @@ gentoo.common.conf \ gentoo.moresecure.conf \ gentoo.userns.conf \ + nesting.conf \ oracle.common.conf \ oracle.userns.conf \ plamo.common.conf \ diff -Nru lxc-1.0.7/config/templates/Makefile.in lxc-1.0.8/config/templates/Makefile.in --- lxc-1.0.7/config/templates/Makefile.in 2014-12-05 20:50:26.000000000 +0000 +++ lxc-1.0.8/config/templates/Makefile.in 2015-11-09 22:49:20.000000000 +0000 @@ -88,7 +88,7 @@ $(srcdir)/fedora.userns.conf.in \ $(srcdir)/gentoo.common.conf.in \ $(srcdir)/gentoo.moresecure.conf.in \ - $(srcdir)/gentoo.userns.conf.in \ + $(srcdir)/gentoo.userns.conf.in $(srcdir)/nesting.conf.in \ $(srcdir)/oracle.common.conf.in \ $(srcdir)/oracle.userns.conf.in $(srcdir)/plamo.common.conf.in \ $(srcdir)/plamo.userns.conf.in \ @@ -107,10 +107,11 @@ CONFIG_CLEAN_FILES = centos.common.conf centos.userns.conf \ debian.common.conf debian.userns.conf fedora.common.conf \ fedora.userns.conf gentoo.common.conf gentoo.moresecure.conf \ - gentoo.userns.conf oracle.common.conf oracle.userns.conf \ - plamo.common.conf plamo.userns.conf ubuntu-cloud.common.conf \ - ubuntu-cloud.lucid.conf ubuntu-cloud.userns.conf \ - ubuntu.common.conf ubuntu.lucid.conf ubuntu.userns.conf + gentoo.userns.conf nesting.conf oracle.common.conf \ + oracle.userns.conf plamo.common.conf plamo.userns.conf \ + ubuntu-cloud.common.conf ubuntu-cloud.lucid.conf \ + ubuntu-cloud.userns.conf ubuntu.common.conf ubuntu.lucid.conf \ + ubuntu.userns.conf CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) @@ -336,6 +337,7 @@ gentoo.common.conf \ gentoo.moresecure.conf \ gentoo.userns.conf \ + nesting.conf \ oracle.common.conf \ oracle.userns.conf \ plamo.common.conf \ @@ -398,6 +400,8 @@ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ gentoo.userns.conf: $(top_builddir)/config.status $(srcdir)/gentoo.userns.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +nesting.conf: $(top_builddir)/config.status $(srcdir)/nesting.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ oracle.common.conf: $(top_builddir)/config.status $(srcdir)/oracle.common.conf.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ oracle.userns.conf: $(top_builddir)/config.status $(srcdir)/oracle.userns.conf.in diff -Nru lxc-1.0.7/config/templates/nesting.conf.in lxc-1.0.8/config/templates/nesting.conf.in --- lxc-1.0.7/config/templates/nesting.conf.in 1970-01-01 00:00:00.000000000 +0000 +++ lxc-1.0.8/config/templates/nesting.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -0,0 +1,8 @@ +# Use a profile which allows nesting +lxc.aa_profile = lxc-container-default-with-nesting + +# Add uncovered mounts of proc and sys, else unprivileged users +# cannot remount those + +lxc.mount.entry = proc dev/.lxc/proc proc create=dir,optional 0 0 +lxc.mount.entry = sys dev/.lxc/sys sysfs create=dir,optional 0 0 diff -Nru lxc-1.0.7/config/templates/oracle.userns.conf.in lxc-1.0.8/config/templates/oracle.userns.conf.in --- lxc-1.0.7/config/templates/oracle.userns.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/oracle.userns.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -17,7 +17,3 @@ # Extra fstab entries as mountall can't mount those by itself lxc.mount.entry = /sys/firmware/efi/efivars sys/firmware/efi/efivars none bind,optional 0 0 lxc.mount.entry = /proc/sys/fs/binfmt_misc proc/sys/fs/binfmt_misc none bind,optional 0 0 - -# Default seccomp policy is not needed for unprivileged containers, and -# non-root users cannot use seccmp without NNP anyway. -lxc.seccomp = diff -Nru lxc-1.0.7/config/templates/plamo.userns.conf.in lxc-1.0.8/config/templates/plamo.userns.conf.in --- lxc-1.0.7/config/templates/plamo.userns.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/plamo.userns.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -10,7 +10,3 @@ lxc.mount.entry = /dev/tty dev/tty none bind,create=file 0 0 lxc.mount.entry = /dev/urandom dev/urandom none bind,create=file 0 0 lxc.mount.entry = /dev/zero dev/zero none bind,create=file 0 0 - -# Default seccomp policy is not needed for unprivileged containers, and -# non-root users cannot use seccmp without NNP anyway. -lxc.seccomp = diff -Nru lxc-1.0.7/config/templates/ubuntu.userns.conf.in lxc-1.0.8/config/templates/ubuntu.userns.conf.in --- lxc-1.0.7/config/templates/ubuntu.userns.conf.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/config/templates/ubuntu.userns.conf.in 2015-11-09 22:49:15.000000000 +0000 @@ -17,7 +17,3 @@ # Extra fstab entries as mountall can't mount those by itself lxc.mount.entry = /sys/firmware/efi/efivars sys/firmware/efi/efivars none bind,optional 0 0 lxc.mount.entry = /proc/sys/fs/binfmt_misc proc/sys/fs/binfmt_misc none bind,optional 0 0 - -# Default seccomp policy is not needed for unprivileged containers, and -# non-root users cannot use seccmp without NNP anyway. -lxc.seccomp = diff -Nru lxc-1.0.7/configure lxc-1.0.8/configure --- lxc-1.0.7/configure 2014-12-05 20:50:25.000000000 +0000 +++ lxc-1.0.8/configure 2015-11-09 22:49:19.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for lxc 1.0.7. +# Generated by GNU Autoconf 2.69 for lxc 1.0.8. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ # Identity of this package. PACKAGE_NAME='lxc' PACKAGE_TARNAME='lxc' -PACKAGE_VERSION='1.0.7' -PACKAGE_STRING='lxc 1.0.7' +PACKAGE_VERSION='1.0.8' +PACKAGE_STRING='lxc 1.0.8' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1430,7 +1430,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures lxc 1.0.7 to adapt to many kinds of systems. +\`configure' configures lxc 1.0.8 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1500,7 +1500,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lxc 1.0.7:";; + short | recursive ) echo "Configuration of lxc 1.0.8:";; esac cat <<\_ACEOF @@ -1658,7 +1658,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lxc configure 1.0.7 +lxc configure 1.0.8 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2123,7 +2123,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by lxc $as_me 1.0.7, which was +It was created by lxc $as_me 1.0.8, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2594,7 +2594,7 @@ fi fi -LXC_VERSION_BASE=1.0.7 +LXC_VERSION_BASE=1.0.8 @@ -2602,9 +2602,9 @@ LXC_VERSION_MINOR=0 -LXC_VERSION_MICRO=7 +LXC_VERSION_MICRO=8 -LXC_VERSION=1.0.7 +LXC_VERSION=1.0.8 @@ -3125,7 +3125,7 @@ # Define the identity of the package. PACKAGE='lxc' - VERSION='1.0.7' + VERSION='1.0.8' cat >>confdefs.h <<_ACEOF @@ -6352,6 +6352,80 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cgmanager_list_controllers" >&5 +$as_echo_n "checking for cgmanager_list_controllers... " >&6; } +save_LIBS=$LIBS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing cgmanager_list_controllers_sync" >&5 +$as_echo_n "checking for library containing cgmanager_list_controllers_sync... " >&6; } +if ${ac_cv_search_cgmanager_list_controllers_sync+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char cgmanager_list_controllers_sync (); +int +main () +{ +return cgmanager_list_controllers_sync (); + ; + return 0; +} +_ACEOF +for ac_lib in '' cgmanager; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib -lnih -lnih-dbus -ldbus-1 $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_cgmanager_list_controllers_sync=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_cgmanager_list_controllers_sync+:} false; then : + break +fi +done +if ${ac_cv_search_cgmanager_list_controllers_sync+:} false; then : + +else + ac_cv_search_cgmanager_list_controllers_sync=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_cgmanager_list_controllers_sync" >&5 +$as_echo "$ac_cv_search_cgmanager_list_controllers_sync" >&6; } +ac_res=$ac_cv_search_cgmanager_list_controllers_sync +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + have_list_controllers=yes +else + have_list_controllers=no +fi + +LIBS=$save_LIBS +if test "x$have_list_controllers" = "xyes"; then + +$as_echo "#define HAVE_CGMANAGER_LIST_CONTROLLERS 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + # Linux capabilities # Check whether --enable-capabilities was given. if test "${enable_capabilities+set}" = set; then : @@ -9107,7 +9181,7 @@ fi # Files requiring some variable expansion -ac_config_files="$ac_config_files Makefile lxc.pc lxc.spec config/Makefile config/apparmor/Makefile config/selinux/Makefile config/bash/Makefile config/bash/lxc config/init/Makefile config/init/sysvinit/Makefile config/init/sysvinit/lxc config/init/systemd/Makefile config/init/systemd/lxc.service config/init/upstart/Makefile config/etc/Makefile config/templates/Makefile config/templates/centos.common.conf config/templates/centos.userns.conf config/templates/debian.common.conf config/templates/debian.userns.conf config/templates/fedora.common.conf config/templates/fedora.userns.conf config/templates/gentoo.common.conf config/templates/gentoo.moresecure.conf config/templates/gentoo.userns.conf config/templates/oracle.common.conf config/templates/oracle.userns.conf config/templates/plamo.common.conf config/templates/plamo.userns.conf config/templates/ubuntu-cloud.common.conf config/templates/ubuntu-cloud.lucid.conf config/templates/ubuntu-cloud.userns.conf config/templates/ubuntu.common.conf config/templates/ubuntu.lucid.conf config/templates/ubuntu.userns.conf config/yum/Makefile doc/Makefile doc/api/Makefile doc/legacy/lxc-ls.sgml doc/lxc-attach.sgml doc/lxc-autostart.sgml doc/lxc-cgroup.sgml doc/lxc-checkconfig.sgml doc/lxc-clone.sgml doc/lxc-config.sgml doc/lxc-console.sgml doc/lxc-create.sgml doc/lxc-destroy.sgml doc/lxc-device.sgml doc/lxc-execute.sgml doc/lxc-freeze.sgml doc/lxc-info.sgml doc/lxc-ls.sgml doc/lxc-monitor.sgml doc/lxc-snapshot.sgml doc/lxc-start-ephemeral.sgml doc/lxc-start.sgml doc/lxc-stop.sgml doc/lxc-top.sgml doc/lxc-unfreeze.sgml doc/lxc-unshare.sgml doc/lxc-user-nic.sgml doc/lxc-usernsexec.sgml doc/lxc-wait.sgml doc/lxc.conf.sgml doc/lxc.container.conf.sgml doc/lxc.system.conf.sgml doc/lxc-usernet.sgml doc/lxc.sgml doc/common_options.sgml doc/see_also.sgml doc/rootfs/Makefile doc/examples/Makefile doc/examples/lxc-macvlan.conf doc/examples/lxc-vlan.conf doc/examples/lxc-no-netns.conf doc/examples/lxc-empty-netns.conf doc/examples/lxc-phys.conf doc/examples/lxc-veth.conf doc/examples/lxc-complex.conf doc/ja/Makefile doc/ja/legacy/lxc-ls.sgml doc/ja/lxc-attach.sgml doc/ja/lxc-autostart.sgml doc/ja/lxc-cgroup.sgml doc/ja/lxc-checkconfig.sgml doc/ja/lxc-clone.sgml doc/ja/lxc-config.sgml doc/ja/lxc-console.sgml doc/ja/lxc-create.sgml doc/ja/lxc-destroy.sgml doc/ja/lxc-device.sgml doc/ja/lxc-execute.sgml doc/ja/lxc-freeze.sgml doc/ja/lxc-info.sgml doc/ja/lxc-ls.sgml doc/ja/lxc-monitor.sgml doc/ja/lxc-snapshot.sgml doc/ja/lxc-start-ephemeral.sgml doc/ja/lxc-start.sgml doc/ja/lxc-stop.sgml doc/ja/lxc-top.sgml doc/ja/lxc-unfreeze.sgml doc/ja/lxc-unshare.sgml doc/ja/lxc-user-nic.sgml doc/ja/lxc-usernsexec.sgml doc/ja/lxc-wait.sgml doc/ja/lxc.conf.sgml doc/ja/lxc.container.conf.sgml doc/ja/lxc.system.conf.sgml doc/ja/lxc-usernet.sgml doc/ja/lxc.sgml doc/ja/common_options.sgml doc/ja/see_also.sgml hooks/Makefile templates/Makefile templates/lxc-alpine templates/lxc-altlinux templates/lxc-archlinux templates/lxc-busybox templates/lxc-centos templates/lxc-cirros templates/lxc-debian templates/lxc-download templates/lxc-fedora templates/lxc-gentoo templates/lxc-openmandriva templates/lxc-opensuse templates/lxc-oracle templates/lxc-plamo templates/lxc-sshd templates/lxc-ubuntu templates/lxc-ubuntu-cloud src/Makefile src/lxc/Makefile src/lxc/lxc-checkconfig src/lxc/lxc-ls src/lxc/lxc-start-ephemeral src/lxc/legacy/lxc-ls src/lxc/lxc.functions src/lxc/version.h src/python-lxc/Makefile src/python-lxc/setup.py src/lua-lxc/Makefile src/tests/Makefile src/tests/lxc-test-usernic" +ac_config_files="$ac_config_files Makefile lxc.pc lxc.spec config/Makefile config/apparmor/Makefile config/selinux/Makefile config/bash/Makefile config/bash/lxc config/init/Makefile config/init/sysvinit/Makefile config/init/sysvinit/lxc config/init/systemd/Makefile config/init/systemd/lxc.service config/init/upstart/Makefile config/etc/Makefile config/templates/Makefile config/templates/centos.common.conf config/templates/centos.userns.conf config/templates/debian.common.conf config/templates/debian.userns.conf config/templates/fedora.common.conf config/templates/fedora.userns.conf config/templates/gentoo.common.conf config/templates/gentoo.moresecure.conf config/templates/gentoo.userns.conf config/templates/nesting.conf config/templates/oracle.common.conf config/templates/oracle.userns.conf config/templates/plamo.common.conf config/templates/plamo.userns.conf config/templates/ubuntu-cloud.common.conf config/templates/ubuntu-cloud.lucid.conf config/templates/ubuntu-cloud.userns.conf config/templates/ubuntu.common.conf config/templates/ubuntu.lucid.conf config/templates/ubuntu.userns.conf config/yum/Makefile doc/Makefile doc/api/Makefile doc/legacy/lxc-ls.sgml doc/lxc-attach.sgml doc/lxc-autostart.sgml doc/lxc-cgroup.sgml doc/lxc-checkconfig.sgml doc/lxc-clone.sgml doc/lxc-config.sgml doc/lxc-console.sgml doc/lxc-create.sgml doc/lxc-destroy.sgml doc/lxc-device.sgml doc/lxc-execute.sgml doc/lxc-freeze.sgml doc/lxc-info.sgml doc/lxc-ls.sgml doc/lxc-monitor.sgml doc/lxc-snapshot.sgml doc/lxc-start-ephemeral.sgml doc/lxc-start.sgml doc/lxc-stop.sgml doc/lxc-top.sgml doc/lxc-unfreeze.sgml doc/lxc-unshare.sgml doc/lxc-user-nic.sgml doc/lxc-usernsexec.sgml doc/lxc-wait.sgml doc/lxc.conf.sgml doc/lxc.container.conf.sgml doc/lxc.system.conf.sgml doc/lxc-usernet.sgml doc/lxc.sgml doc/common_options.sgml doc/see_also.sgml doc/rootfs/Makefile doc/examples/Makefile doc/examples/lxc-macvlan.conf doc/examples/lxc-vlan.conf doc/examples/lxc-no-netns.conf doc/examples/lxc-empty-netns.conf doc/examples/lxc-phys.conf doc/examples/lxc-veth.conf doc/examples/lxc-complex.conf doc/ja/Makefile doc/ja/legacy/lxc-ls.sgml doc/ja/lxc-attach.sgml doc/ja/lxc-autostart.sgml doc/ja/lxc-cgroup.sgml doc/ja/lxc-checkconfig.sgml doc/ja/lxc-clone.sgml doc/ja/lxc-config.sgml doc/ja/lxc-console.sgml doc/ja/lxc-create.sgml doc/ja/lxc-destroy.sgml doc/ja/lxc-device.sgml doc/ja/lxc-execute.sgml doc/ja/lxc-freeze.sgml doc/ja/lxc-info.sgml doc/ja/lxc-ls.sgml doc/ja/lxc-monitor.sgml doc/ja/lxc-snapshot.sgml doc/ja/lxc-start-ephemeral.sgml doc/ja/lxc-start.sgml doc/ja/lxc-stop.sgml doc/ja/lxc-top.sgml doc/ja/lxc-unfreeze.sgml doc/ja/lxc-unshare.sgml doc/ja/lxc-user-nic.sgml doc/ja/lxc-usernsexec.sgml doc/ja/lxc-wait.sgml doc/ja/lxc.conf.sgml doc/ja/lxc.container.conf.sgml doc/ja/lxc.system.conf.sgml doc/ja/lxc-usernet.sgml doc/ja/lxc.sgml doc/ja/common_options.sgml doc/ja/see_also.sgml hooks/Makefile templates/Makefile templates/lxc-alpine templates/lxc-altlinux templates/lxc-archlinux templates/lxc-busybox templates/lxc-centos templates/lxc-cirros templates/lxc-debian templates/lxc-download templates/lxc-fedora templates/lxc-gentoo templates/lxc-openmandriva templates/lxc-opensuse templates/lxc-oracle templates/lxc-plamo templates/lxc-sshd templates/lxc-ubuntu templates/lxc-ubuntu-cloud src/Makefile src/lxc/Makefile src/lxc/lxc-checkconfig src/lxc/lxc-ls src/lxc/lxc-start-ephemeral src/lxc/legacy/lxc-ls src/lxc/lxc.functions src/lxc/version.h src/python-lxc/Makefile src/python-lxc/setup.py src/lua-lxc/Makefile src/tests/Makefile src/tests/lxc-test-usernic" ac_config_commands="$ac_config_commands default" @@ -9745,7 +9819,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by lxc $as_me 1.0.7, which was +This file was extended by lxc $as_me 1.0.8, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9815,7 +9889,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -lxc config.status 1.0.7 +lxc config.status 1.0.8 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -9973,6 +10047,7 @@ "config/templates/gentoo.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/gentoo.common.conf" ;; "config/templates/gentoo.moresecure.conf") CONFIG_FILES="$CONFIG_FILES config/templates/gentoo.moresecure.conf" ;; "config/templates/gentoo.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/gentoo.userns.conf" ;; + "config/templates/nesting.conf") CONFIG_FILES="$CONFIG_FILES config/templates/nesting.conf" ;; "config/templates/oracle.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/oracle.common.conf" ;; "config/templates/oracle.userns.conf") CONFIG_FILES="$CONFIG_FILES config/templates/oracle.userns.conf" ;; "config/templates/plamo.common.conf") CONFIG_FILES="$CONFIG_FILES config/templates/plamo.common.conf" ;; diff -Nru lxc-1.0.7/configure.ac lxc-1.0.8/configure.ac --- lxc-1.0.7/configure.ac 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/configure.ac 2015-11-09 22:49:15.000000000 +0000 @@ -3,7 +3,7 @@ m4_define([lxc_version_major], 1) 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_version_base], [lxc_version_major.lxc_version_minor.lxc_version_micro]) @@ -268,6 +268,18 @@ else AC_MSG_RESULT([no]) fi + +AC_MSG_CHECKING(for cgmanager_list_controllers) +save_LIBS=$LIBS +AC_SEARCH_LIBS([cgmanager_list_controllers_sync], [cgmanager], [have_list_controllers=yes], [have_list_controllers=no], [-lnih -lnih-dbus -ldbus-1]) +LIBS=$save_LIBS +if test "x$have_list_controllers" = "xyes"; then + AC_DEFINE([HAVE_CGMANAGER_LIST_CONTROLLERS], 1, [Have cgmanager_list_controllers]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + # Linux capabilities AC_ARG_ENABLE([capabilities], [AC_HELP_STRING([--enable-capabilities], [enable kernel capabilities support [default=auto]])], @@ -593,6 +605,7 @@ config/templates/gentoo.common.conf config/templates/gentoo.moresecure.conf config/templates/gentoo.userns.conf + config/templates/nesting.conf config/templates/oracle.common.conf config/templates/oracle.userns.conf config/templates/plamo.common.conf diff -Nru lxc-1.0.7/CONTRIBUTING lxc-1.0.8/CONTRIBUTING --- lxc-1.0.7/CONTRIBUTING 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/CONTRIBUTING 2015-11-09 22:49:15.000000000 +0000 @@ -1,13 +1,12 @@ - - Contributing to this project - ---------------------------- - +Contributing to this project +---------------------------- This project accepts contributions. In order to contribute, you should pay attention to a few things: 1 - your code must follow the coding style rules - 2 - the format of the submission must be email patches + 2 - the format of the submission must be email patches or github + pull requests 3 - your work must be signed @@ -26,15 +25,15 @@ Submitting Modifications: ------------------------- -The contributions should be email patches. The guidelines are the same -as the patch submission for the Linux kernel except for the DCO which -is defined below. The guidelines are defined in the +The contributions should be email patches or github pull requests. +The guidelines are the same as the patch submission for the Linux kernel +except for the DCO which is defined below. The guidelines are defined in the 'SubmittingPatches' file, available in the directory 'Documentation' of the Linux kernel source tree. It can be accessed online too: -http://lxr.linux.no/linux+v2.6.27/Documentation/SubmittingPatches +https://www.kernel.org/doc/Documentation/SubmittingPatches You can submit your patches to the lxc-devel@lists.linuxcontainers.org mailing list. Use http://lists.linuxcontainers.org/listinfo/lxc-devel to subscribe @@ -107,4 +106,8 @@ Signed-off-by: Random J Developer +You can do it by using option -s or --signoff when you commit + + git commit --signoff ... + using your real name (sorry, no pseudonyms or anonymous contributions.) diff -Nru lxc-1.0.7/debian/changelog lxc-1.0.8/debian/changelog --- lxc-1.0.7/debian/changelog 2015-10-28 17:22:21.000000000 +0000 +++ lxc-1.0.8/debian/changelog 2015-11-18 18:42:24.000000000 +0000 @@ -1,3 +1,35 @@ +lxc (1.0.8-0ubuntu0.3) trusty; urgency=medium + + * Cherry-pick from upstream: + - Fix preserve_ns to work on < 3.8 kernels. (LP: #1516971) + + -- Stéphane Graber Wed, 18 Nov 2015 13:42:07 -0500 + +lxc (1.0.8-0ubuntu0.2) trusty; urgency=medium + + * Cherry-pick from upstream: + - Fix ubuntu-cloud template to detect compression algorithm instead + of hardcoding xz. Also update list of supported releases and use trusty + as the fallback release. (LP: #1515463) + * Update lxc-tests description to make it clear that this package is + meant to be used by developers and by automated testing. + + -- Stéphane Graber Fri, 13 Nov 2015 12:53:17 -0500 + +lxc (1.0.8-0ubuntu0.1) trusty; urgency=medium + + * New upstream bugfix release. (MRE tracking bug: LP: #1514623) + (LP: #1429140) + - Changelog at: https://linuxcontainers.org/lxc/news/ + * Drop proxy detection from the autopkgtest exercise script. + * Add patch: + - 0001-Trusty-Swap-out-the-CVE-2015-1335-fix-with-the-trust.patch + This is a patch by Serge Hallyn to cope with the trusty 3.13 kernel. + It updates the upstream CVE fix to the version which trusty ended + up with after the few round of fixes. + + -- Stéphane Graber Mon, 09 Nov 2015 18:15:31 -0500 + lxc (1.0.7-0ubuntu0.10) trusty; urgency=medium * Update the /proc/self/mountinfo no-symlink verification to accomodate diff -Nru lxc-1.0.7/debian/control lxc-1.0.8/debian/control --- lxc-1.0.7/debian/control 2014-12-18 22:45:06.000000000 +0000 +++ lxc-1.0.8/debian/control 2015-11-18 18:41:56.000000000 +0000 @@ -105,7 +105,9 @@ created using the Control Group and Namespace features included in the Linux kernel. . - This package contains the test binaries. + This package contains the test binaries. Those binaries are primarily + used for autopkgtest and by some developers. They are not meant to be + installed on regular user systems. Package: liblxc1 Architecture: linux-any diff -Nru lxc-1.0.7/debian/.git-dpm lxc-1.0.8/debian/.git-dpm --- lxc-1.0.7/debian/.git-dpm 2014-12-18 22:45:29.000000000 +0000 +++ lxc-1.0.8/debian/.git-dpm 2015-11-18 18:41:56.000000000 +0000 @@ -1,8 +1,8 @@ # see git-dpm(1) from git-dpm package -39f59fe820baf8055b9285e1fb7f9d083db5d2ba -39f59fe820baf8055b9285e1fb7f9d083db5d2ba -39f59fe820baf8055b9285e1fb7f9d083db5d2ba -39f59fe820baf8055b9285e1fb7f9d083db5d2ba -lxc_1.0.7.orig.tar.gz -aeb101a6f18a5a40be96f960178d6c06dd188e88 -797696 +3d3ff990d7ed8f30ac1fc5508cb7c81b14d5c235 +3d3ff990d7ed8f30ac1fc5508cb7c81b14d5c235 +4d4ae2d76b719cb54dbdeea8f371aedb309b820a +4d4ae2d76b719cb54dbdeea8f371aedb309b820a +lxc_1.0.8.orig.tar.gz +5ceec2289d2f25f8b6a13f8ec8731025294ef4da +807754 diff -Nru lxc-1.0.7/debian/patches/00004-update-apparmor.patch lxc-1.0.8/debian/patches/00004-update-apparmor.patch --- lxc-1.0.7/debian/patches/00004-update-apparmor.patch 2015-10-14 20:59:46.000000000 +0000 +++ lxc-1.0.8/debian/patches/00004-update-apparmor.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -Get AppArmor profile fixes from stable-1.0 branch to fix current -incompatibility with 3.13. - -Index: lxc-1.0.7/config/apparmor/abstractions/container-base -=================================================================== ---- lxc-1.0.7.orig/config/apparmor/abstractions/container-base -+++ lxc-1.0.7/config/apparmor/abstractions/container-base -@@ -70,9 +70,10 @@ - mount fstype=efivarfs -> /sys/firmware/efi/efivars/, - - # block some other dangerous paths -- deny @{PROC}/sysrq-trigger rwklx, -- deny @{PROC}/mem rwklx, -+ deny @{PROC}/kcore rwklx, - deny @{PROC}/kmem rwklx, -+ deny @{PROC}/mem rwklx, -+ deny @{PROC}/sysrq-trigger rwklx, - - # deny writes in /sys except for /sys/fs/cgroup, also allow - # fusectl, securityfs and debugfs to be mounted there (read-only) -Index: lxc-1.0.7/config/apparmor/abstractions/container-base.in -=================================================================== ---- lxc-1.0.7.orig/config/apparmor/abstractions/container-base.in -+++ lxc-1.0.7/config/apparmor/abstractions/container-base.in -@@ -70,9 +70,10 @@ - mount fstype=efivarfs -> /sys/firmware/efi/efivars/, - - # block some other dangerous paths -- deny @{PROC}/sysrq-trigger rwklx, -- deny @{PROC}/mem rwklx, -+ deny @{PROC}/kcore rwklx, - deny @{PROC}/kmem rwklx, -+ deny @{PROC}/mem rwklx, -+ deny @{PROC}/sysrq-trigger rwklx, - - # deny writes in /sys except for /sys/fs/cgroup, also allow - # fusectl, securityfs and debugfs to be mounted there (read-only) -Index: lxc-1.0.7/config/apparmor/abstractions/start-container -=================================================================== ---- lxc-1.0.7.orig/config/apparmor/abstractions/start-container -+++ lxc-1.0.7/config/apparmor/abstractions/start-container -@@ -13,7 +13,8 @@ - mount -> /usr/lib/lxc/{**,}, - mount fstype=devpts -> /dev/pts/, - mount options=bind /dev/pts/ptmx/ -> /dev/ptmx/, -- mount options=(rw, slave) -> /, -+ mount options=bind /dev/pts/** -> /dev/**, -+ mount options=(rw, make-slave) -> **, - mount fstype=debugfs, - # allow pre-mount hooks to stage mounts under /var/lib/lxc// - mount -> /var/lib/lxc/{**,}, -Index: lxc-1.0.7/config/apparmor/profiles/lxc-default-with-nesting -=================================================================== ---- lxc-1.0.7.orig/config/apparmor/profiles/lxc-default-with-nesting -+++ lxc-1.0.7/config/apparmor/profiles/lxc-default-with-nesting -@@ -8,7 +8,9 @@ profile lxc-container-default-with-nesti - # Uncomment the line below if you are not using cgmanager - # mount fstype=cgroup -> /sys/fs/cgroup/**, - -+ deny /dev/.lxc/proc/** rw, -+ deny /dev/.lxc/sys/** rw, - mount fstype=proc -> /var/cache/lxc/**, - mount fstype=sysfs -> /var/cache/lxc/**, -- mount options=(rw,bind) /var/cache/lxc/**/dev/shm/ -> /var/cache/lxc/**/run/shm/, -+ mount options=(rw,bind), - } diff -Nru lxc-1.0.7/debian/patches/0001-CVE-2015-1331.patch lxc-1.0.8/debian/patches/0001-CVE-2015-1331.patch --- lxc-1.0.7/debian/patches/0001-CVE-2015-1331.patch 2015-07-07 05:04:18.000000000 +0000 +++ lxc-1.0.8/debian/patches/0001-CVE-2015-1331.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -From 9db431b17f023ec776e10c59383783f94eb18821 Mon Sep 17 00:00:00 2001 -From: Serge Hallyn -Date: Fri, 3 Jul 2015 09:26:17 -0500 -Subject: [PATCH] lxclock: use /run/lxc/lock rather than /run/lock/lxc - -Signed-off-by: Serge Hallyn -[tyhicks: Remove fallback path construction in /tmp] -Signed-off-by: Tyler Hicks - -Origin: backport -Bug-Ubuntu: https://launchpad.net/bugs/1470842 ---- - src/lxc/lxclock.c | 47 ++++++++++------------------------------------- - src/tests/locktests.c | 2 +- - 2 files changed, 11 insertions(+), 38 deletions(-) - -diff --git a/src/lxc/lxclock.c b/src/lxc/lxclock.c -index fe13898..e9e95f7 100644 ---- a/src/lxc/lxclock.c -+++ b/src/lxc/lxclock.c -@@ -103,13 +103,13 @@ static char *lxclock_name(const char *p, const char *n) - char *rundir; - - /* lockfile will be: -- * "/run" + "/lock/lxc/$lxcpath/$lxcname + '\0' if root -+ * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root - * or -- * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root -+ * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root - */ - -- /* length of "/lock/lxc/" + $lxcpath + "/" + $lxcname + '\0' */ -- len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 2; -+ /* length of "/lxc/lock/" + $lxcpath + "/" + $lxcname + '\0' */ -+ len = strlen("/lxc/lock/") + strlen(n) + strlen(p) + 2; - rundir = get_rundir(); - if (!rundir) - return NULL; -@@ -120,7 +120,7 @@ static char *lxclock_name(const char *p, const char *n) - return NULL; - } - -- ret = snprintf(dest, len, "%s/lock/lxc/%s", rundir, p); -+ ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p); - if (ret < 0 || ret >= len) { - free(dest); - free(rundir); -@@ -128,31 +128,13 @@ static char *lxclock_name(const char *p, const char *n) - } - ret = mkdir_p(dest, 0755); - if (ret < 0) { -- /* fall back to "/tmp/" $(id -u) "/lxc/" $lxcpath / $lxcname + '\0' */ -- int l2 = 33 + strlen(n) + strlen(p); -- if (l2 > len) { -- char *d; -- d = realloc(dest, l2); -- if (!d) { -- free(dest); -- free(rundir); -- return NULL; -- } -- len = l2; -- dest = d; -- } -- ret = snprintf(dest, len, "/tmp/%d/lxc/%s", geteuid(), p); -- if (ret < 0 || ret >= len) { -- free(dest); -- free(rundir); -- return NULL; -- } -- ret = snprintf(dest, len, "/tmp/%d/lxc/%s/%s", geteuid(), p, n); -- } else -- ret = snprintf(dest, len, "%s/lock/lxc/%s/%s", rundir, p, n); -+ free(dest); -+ free(rundir); -+ return NULL; -+ } - -+ ret = snprintf(dest, len, "%s/lxc/lock/%s/%s", rundir, p, n); - free(rundir); -- - if (ret < 0 || ret >= len) { - free(dest); - return NULL; -diff --git a/src/tests/locktests.c b/src/tests/locktests.c -index dd3393a..233ca12 100644 ---- a/src/tests/locktests.c -+++ b/src/tests/locktests.c -@@ -122,7 +122,7 @@ int main(int argc, char *argv[]) - exit(1); - } - struct stat sb; -- char *pathname = RUNTIME_PATH "/lock/lxc/var/lib/lxc/"; -+ char *pathname = RUNTIME_PATH "/lxc/lock/var/lib/lxc/"; - ret = stat(pathname, &sb); - if (ret != 0) { - fprintf(stderr, "%d: filename %s not created\n", __LINE__, --- -2.1.4 - diff -Nru lxc-1.0.7/debian/patches/0001-Trusty-Swap-out-the-CVE-2015-1335-fix-with-the-trust.patch lxc-1.0.8/debian/patches/0001-Trusty-Swap-out-the-CVE-2015-1335-fix-with-the-trust.patch --- lxc-1.0.7/debian/patches/0001-Trusty-Swap-out-the-CVE-2015-1335-fix-with-the-trust.patch 1970-01-01 00:00:00.000000000 +0000 +++ lxc-1.0.8/debian/patches/0001-Trusty-Swap-out-the-CVE-2015-1335-fix-with-the-trust.patch 2015-11-18 18:41:56.000000000 +0000 @@ -0,0 +1,369 @@ +From 3e3c933900c23edf4e378127b6520c91e9f87546 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Wed, 28 Oct 2015 13:51:07 -0500 +Subject: Trusty: Swap out the CVE-2015-1335 fix with the + trusty-kernel-friendly one + +The upstream fix for CVE-2015-1335 exposes bugs in trusty's kernel's +overlayfs+apparmor behavior, breaking lxc-test-unpriv. In trusty we +use a separate lxc patch for CVE-2015-1335 for this reason. + +This patch against upstream stable-1.0 replaces the upstream fix with +the trusty-compatible one. + +Signed-off-by: Serge Hallyn +--- + src/lxc/utils.c | 286 +++++++++++++++------------------------------ + src/tests/lxc-test-symlink | 4 + + 2 files changed, 100 insertions(+), 190 deletions(-) + +diff --git a/src/lxc/utils.c b/src/lxc/utils.c +index 214c5a8..fb45e1f 100644 +--- a/src/lxc/utils.c ++++ b/src/lxc/utils.c +@@ -1155,234 +1155,140 @@ err: + } + + /* +- * @path: a pathname where / replaced with '\0'. +- * @offsetp: pointer to int showing which path segment was last seen. +- * Updated on return to reflect the next segment. +- * @fulllen: full original path length. +- * Returns a pointer to the next path segment, or NULL if done. ++ * ws points into an array of \0-separate path elements. ++ * ws should be pointing to one of the path elements or ++ * the next \0. It will return the first character of the ++ * next path element. + */ +-static char *get_nextpath(char *path, int *offsetp, int fulllen) +-{ +- int offset = *offsetp; +- +- if (offset >= fulllen) +- return NULL; +- +- while (path[offset] != '\0' && offset < fulllen) +- offset++; +- while (path[offset] == '\0' && offset < fulllen) +- offset++; +- +- *offsetp = offset; +- return (offset < fulllen) ? &path[offset] : NULL; ++static char *next_word(char *ws) { ++ while (*ws && *ws != ' ') ws++; ++ while (*ws && *ws == ' ') ws++; ++ return ws; + } + + /* +- * Check that @subdir is a subdir of @dir. @len is the length of +- * @dir (to avoid having to recalculate it). ++ * copy src to dest, collapsing multiple '/' into one and ++ * collapsing '/./' to '/' + */ +-static bool is_subdir(const char *subdir, const char *dir, size_t len) ++static void copy_cleanedup(char *dest, const char *src) + { +- size_t subdirlen = strlen(subdir); +- +- if (subdirlen < len) +- return false; +- if (strncmp(subdir, dir, len) != 0) +- return false; +- if (dir[len-1] == '/') +- return true; +- if (subdir[len] == '/' || subdirlen == len) +- return true; +- return false; ++ char *orig = dest; ++ while (*src) { ++ if (*src == '/' && *(src+1) == '/') { ++ src++; ++ continue; ++ } ++ if (*src == '/' && *(src+1) == '.' && ++ (*(src+2) == '/' || *(src+2) == '\0')) { ++ src += 2; ++ continue; ++ } ++ *(dest++) = *(src++); ++ } ++ *dest = '\0'; ++ /* remove trailing / */ ++ dest--; ++ while (dest > orig && *dest == '/') ++ *(dest--) = '\0'; + } + +-/* +- * Check if the open fd is a symlink. Return -ELOOP if it is. Return +- * -ENOENT if we couldn't fstat. Return 0 if the fd is ok. +- */ +-static int check_symlink(int fd) ++static size_t count_mountinfo_lines(void) + { +- struct stat sb; +- int ret = fstat(fd, &sb); +- if (ret < 0) +- return -ENOENT; +- if (S_ISLNK(sb.st_mode)) +- return -ELOOP; +- return 0; +-} ++ FILE *f = fopen("/proc/self/mountinfo", "r"); ++ char *line = NULL; ++ size_t len = 0, i = 0; ++ if (!f) ++ return 0; + +-/* +- * Open a file or directory, provided that it contains no symlinks. +- * +- * CAVEAT: This function must not be used for other purposes than container +- * setup before executing the container's init +- */ +-static int open_if_safe(int dirfd, const char *nextpath) +-{ +- int newfd = openat(dirfd, nextpath, O_RDONLY | O_NOFOLLOW); +- if (newfd >= 0) // was not a symlink, all good +- return newfd; +- +- if (errno == ELOOP) +- return newfd; +- +- if (errno == EPERM || errno == EACCES) { +- /* we're not root (cause we got EPERM) so +- try opening with O_PATH */ +- newfd = openat(dirfd, nextpath, O_PATH | O_NOFOLLOW); +- if (newfd >= 0) { +- /* O_PATH will return an fd for symlinks. We know +- * nextpath wasn't a symlink at last openat, so if fd +- * is now a link, then something * fishy is going on +- */ +- int ret = check_symlink(newfd); +- if (ret < 0) { +- close(newfd); +- newfd = ret; +- } +- } +- } ++ while (getline(&line, &len, f) != -1) ++ i++; ++ fclose(f); + +- return newfd; ++ free(line); ++ return i; + } + + /* +- * Open a path intending for mounting, ensuring that the final path +- * is inside the container's rootfs. +- * +- * CAVEAT: This function must not be used for other purposes than container +- * setup before executing the container's init +- * +- * @target: path to be opened +- * @prefix_skip: a part of @target in which to ignore symbolic links. This +- * would be the container's rootfs. +- * +- * Return an open fd for the path, or <0 on error. ++ * This is only used during container startup. So we know we won't race ++ * with anyone else mounting. Check the last line in /proc/self/mountinfo ++ * to make sure the target is under the container root. + */ +-static int open_without_symlink(const char *target, const char *prefix_skip) ++static bool ensure_not_symlink(const char *target, const char *croot, size_t prevlines) + { +- int curlen = 0, dirfd, fulllen, i; +- char *dup = NULL; +- +- fulllen = strlen(target); +- +- /* make sure prefix-skip makes sense */ +- if (prefix_skip) { +- curlen = strlen(prefix_skip); +- if (!is_subdir(target, prefix_skip, curlen)) { +- ERROR("WHOA there - target '%s' didn't start with prefix '%s'", +- target, prefix_skip); +- return -EINVAL; +- } +- /* +- * get_nextpath() expects the curlen argument to be +- * on a (turned into \0) / or before it, so decrement +- * curlen to make sure that happens +- */ +- if (curlen) +- curlen--; +- } else { +- prefix_skip = "/"; +- curlen = 0; ++ FILE *f = fopen("/proc/self/mountinfo", "r"); ++ char *line = NULL, *ws = NULL, *we = NULL, *tgtcopy; ++ size_t len = 0, i = 0; ++ bool ret = false; ++ ++ if (!croot || croot[0] == '\0') ++ return true; ++ ++ if (!f) { ++ ERROR("Cannot open /proc/self/mountinfo"); ++ return false; + } + +- /* Make a copy of target which we can hack up, and tokenize it */ +- if ((dup = strdup(target)) == NULL) { +- SYSERROR("Out of memory checking for symbolic link"); +- return -ENOMEM; ++ while (getline(&line, &len, f) != -1 && i < prevlines) { ++ i++; + } +- for (i = 0; i < fulllen; i++) { +- if (dup[i] == '/') +- dup[i] = '\0'; ++ fclose(f); ++ ++ if (!line) ++ return false; ++ ws = line; ++ for (i = 0; i < 4; i++) ++ ws = next_word(ws); ++ if (!*ws) ++ goto out; ++ we = ws; ++ while (*we && *we != ' ') ++ we++; ++ if (!*we) ++ goto out; ++ *we = '\0'; ++ ++ tgtcopy = alloca(strlen(target) + 1); ++ copy_cleanedup(tgtcopy, target); ++ /* now make sure that ws starts with croot and ends with rest of target */ ++ if (croot && strncmp(ws, croot, strlen(croot)) != 0) { ++ ERROR("Mount onto %s resulted in %s, does not match root %s\n", ++ target, ws, croot); ++ goto out; + } + +- dirfd = open(prefix_skip, O_RDONLY); +- if (dirfd < 0) ++ size_t start = croot ? strlen(croot) : 0; ++ if (strcmp(ws + start, tgtcopy + start) != 0) { ++ ERROR("Mount onto %s resulted in %s, not %s\n", target, ws, tgtcopy); + goto out; +- while (1) { +- int newfd, saved_errno; +- char *nextpath; +- +- if ((nextpath = get_nextpath(dup, &curlen, fulllen)) == NULL) +- goto out; +- newfd = open_if_safe(dirfd, nextpath); +- saved_errno = errno; +- close(dirfd); +- dirfd = newfd; +- if (newfd < 0) { +- errno = saved_errno; +- if (errno == ELOOP) +- SYSERROR("%s in %s was a symbolic link!", nextpath, target); +- else +- SYSERROR("Error examining %s in %s", nextpath, target); +- goto out; +- } + } + ++ ret = true; ++ + out: +- free(dup); +- return dirfd; ++ free(line); ++ return ret; + } +- + /* + * Safely mount a path into a container, ensuring that the mount target + * is under the container's @rootfs. (If @rootfs is NULL, then the container + * uses the host's /) +- * +- * CAVEAT: This function must not be used for other purposes than container +- * setup before executing the container's init + */ + int safe_mount(const char *src, const char *dest, const char *fstype, + unsigned long flags, const void *data, const char *rootfs) + { +- int srcfd = -1, destfd, ret, saved_errno; +- char srcbuf[50], destbuf[50]; // only needs enough for /proc/self/fd/ +- const char *mntsrc = src; +- +- if (!rootfs) +- rootfs = ""; +- +- /* todo - allow symlinks for relative paths if 'allowsymlinks' option is passed */ +- if (flags & MS_BIND && src && src[0] != '/') { +- INFO("this is a relative bind mount"); +- srcfd = open_without_symlink(src, NULL); +- if (srcfd < 0) +- return srcfd; +- ret = snprintf(srcbuf, 50, "/proc/self/fd/%d", srcfd); +- if (ret < 0 || ret > 50) { +- close(srcfd); +- ERROR("Out of memory"); +- return -EINVAL; +- } +- mntsrc = srcbuf; +- } +- +- destfd = open_without_symlink(dest, rootfs); +- if (destfd < 0) { +- if (srcfd != -1) +- close(srcfd); +- return destfd; +- } +- +- ret = snprintf(destbuf, 50, "/proc/self/fd/%d", destfd); +- if (ret < 0 || ret > 50) { +- if (srcfd != -1) +- close(srcfd); +- close(destfd); +- ERROR("Out of memory"); +- return -EINVAL; +- } ++ int ret; ++ size_t nlines = count_mountinfo_lines(); + +- ret = mount(mntsrc, destbuf, fstype, flags, data); +- saved_errno = errno; +- if (srcfd != -1) +- close(srcfd); +- close(destfd); ++ ret = mount(src, dest, fstype, flags, data); + if (ret < 0) { +- errno = saved_errno; +- SYSERROR("Failed to mount %s onto %s", src, dest); ++ SYSERROR("Mount of '%s' onto '%s' failed", src, dest); + return ret; + } + ++ if (!ensure_not_symlink(dest, rootfs, nlines)) { ++ ERROR("Mount of '%s' onto '%s' was onto a symlink!", src, dest); ++ umount(dest); ++ return -1; ++ } + return 0; + } +diff --git a/src/tests/lxc-test-symlink b/src/tests/lxc-test-symlink +index 56b7cf6..1e32d66 100644 +--- a/src/tests/lxc-test-symlink ++++ b/src/tests/lxc-test-symlink +@@ -51,6 +51,10 @@ lxc.mount.entry = $dirname opt/xxx/dir none bind,create=dir + lxc.mount.entry = $fname opt/xxx/file none bind,create=file + lxc.mount.entry = $fname2 opt/xxx/file2 none bind + lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx/dir2 none bind,create=dir ++lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir2 none bind,create=dir ++lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir3// none bind,create=dir ++lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir4/. none bind,create=dir ++ + EOF + + # Regular - should succeed diff -Nru lxc-1.0.7/debian/patches/0002-CVE-2014-1334.patch lxc-1.0.8/debian/patches/0002-CVE-2014-1334.patch --- lxc-1.0.7/debian/patches/0002-CVE-2014-1334.patch 2015-07-17 00:05:33.000000000 +0000 +++ lxc-1.0.8/debian/patches/0002-CVE-2014-1334.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,183 +0,0 @@ -From 94bdaef2e636351cc2966387d02e4412bda1d613 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?St=C3=A9phane=20Graber?= -Date: Thu, 16 Jul 2015 16:37:51 -0400 -Subject: [PATCH] Don't use the container's /proc during attach -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -A user could otherwise over-mount /proc and prevent the apparmor profile -or selinux label from being written which combined with a modified -/bin/sh or other commonly used binary would lead to unconfined code -execution. - -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1475050 -Reported-by: Roman Fiedler -Signed-off-by: Stéphane Graber ---- - src/lxc/attach.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 93 insertions(+), 4 deletions(-) - -diff --git a/src/lxc/attach.c b/src/lxc/attach.c -index ed6ea8d..16d942c 100644 ---- a/src/lxc/attach.c -+++ b/src/lxc/attach.c -@@ -76,6 +76,82 @@ - - lxc_log_define(lxc_attach, lxc); - -+int lsm_set_label_at(int procfd, int on_exec, char* lsm_label) { -+ int labelfd = -1; -+ int ret = 0; -+ const char* name; -+ char* command = NULL; -+ -+ name = lsm_name(); -+ -+ if (strcmp(name, "nop") == 0) -+ goto out; -+ -+ if (strcmp(name, "none") == 0) -+ goto out; -+ -+ /* We don't support on-exec with AppArmor */ -+ if (strcmp(name, "AppArmor") == 0) -+ on_exec = 0; -+ -+ if (on_exec) { -+ labelfd = openat(procfd, "self/attr/exec", O_RDWR); -+ } -+ else { -+ labelfd = openat(procfd, "self/attr/current", O_RDWR); -+ } -+ -+ if (labelfd < 0) { -+ SYSERROR("Unable to open LSM label"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (strcmp(name, "AppArmor") == 0) { -+ int size; -+ -+ command = malloc(strlen(lsm_label) + strlen("changeprofile ") + 1); -+ if (!command) { -+ SYSERROR("Failed to write apparmor profile"); -+ ret = -1; -+ goto out; -+ } -+ -+ size = sprintf(command, "changeprofile %s", lsm_label); -+ if (size < 0) { -+ SYSERROR("Failed to write apparmor profile"); -+ ret = -1; -+ goto out; -+ } -+ -+ if (write(labelfd, command, size + 1) < 0) { -+ SYSERROR("Unable to set LSM label"); -+ ret = -1; -+ goto out; -+ } -+ } -+ else if (strcmp(name, "SELinux") == 0) { -+ if (write(labelfd, lsm_label, strlen(lsm_label) + 1) < 0) { -+ SYSERROR("Unable to set LSM label"); -+ ret = -1; -+ goto out; -+ } -+ } -+ else { -+ ERROR("Unable to restore label for unknown LSM: %s", name); -+ ret = -1; -+ goto out; -+ } -+ -+out: -+ free(command); -+ -+ if (labelfd != -1) -+ close(labelfd); -+ -+ return ret; -+} -+ - static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) - { - struct lxc_proc_context_info *info = calloc(1, sizeof(*info)); -@@ -573,6 +649,7 @@ struct attach_clone_payload { - struct lxc_proc_context_info* init_ctx; - lxc_attach_exec_t exec_function; - void* exec_payload; -+ int procfd; - }; - - static int attach_child_main(void* data); -@@ -625,6 +702,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun - char* cwd; - char* new_cwd; - int ipc_sockets[2]; -+ int procfd; - signed long personality; - - if (!options) -@@ -836,6 +914,13 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun - rexit(-1); - } - -+ procfd = open("/proc", O_DIRECTORY | O_RDONLY); -+ if (procfd < 0) { -+ SYSERROR("Unable to open /proc"); -+ shutdown(ipc_sockets[1], SHUT_RDWR); -+ rexit(-1); -+ } -+ - /* attach now, create another subprocess later, since pid namespaces - * only really affect the children of the current process - */ -@@ -863,7 +948,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun - .options = options, - .init_ctx = init_ctx, - .exec_function = exec_function, -- .exec_payload = exec_payload -+ .exec_payload = exec_payload, -+ .procfd = procfd - }; - /* We use clone_parent here to make this subprocess a direct child of - * the initial process. Then this intermediate process can exit and -@@ -901,6 +987,7 @@ static int attach_child_main(void* data) - { - struct attach_clone_payload* payload = (struct attach_clone_payload*)data; - int ipc_socket = payload->ipc_socket; -+ int procfd = payload->procfd; - lxc_attach_options_t* options = payload->options; - struct lxc_proc_context_info* init_ctx = payload->init_ctx; - #if HAVE_SYS_PERSONALITY_H -@@ -1026,12 +1113,11 @@ static int attach_child_main(void* data) - close(ipc_socket); - - /* set new apparmor profile/selinux context */ -- if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM)) { -+ if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) { - int on_exec; - - on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0; -- ret = lsm_process_label_set(init_ctx->lsm_label, 0, on_exec); -- if (ret < 0) { -+ if (lsm_set_label_at(procfd, on_exec, init_ctx->lsm_label) < 0) { - rexit(-1); - } - } -@@ -1082,6 +1168,9 @@ static int attach_child_main(void* data) - } - } - -+ /* we don't need proc anymore */ -+ close(procfd); -+ - /* we're done, so we can now do whatever the user intended us to do */ - rexit(payload->exec_function(payload->exec_payload)); - } --- -1.9.1 - diff -Nru lxc-1.0.7/debian/patches/0002-ubuntu-cloud-Various-fixes.patch lxc-1.0.8/debian/patches/0002-ubuntu-cloud-Various-fixes.patch --- lxc-1.0.7/debian/patches/0002-ubuntu-cloud-Various-fixes.patch 1970-01-01 00:00:00.000000000 +0000 +++ lxc-1.0.8/debian/patches/0002-ubuntu-cloud-Various-fixes.patch 2015-11-18 18:41:56.000000000 +0000 @@ -0,0 +1,65 @@ +From 2452a0458c96ebbf0b14b8f9b71c581036e8fad9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?St=C3=A9phane=20Graber?= +Date: Thu, 12 Nov 2015 12:44:38 -0500 +Subject: ubuntu-cloud: Various fixes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + - Update list of supported releases + - Make the fallback release trusty + - Don't specify the compression algorithm (use auto-detection) so that + people passing tarballs to the template don't see regressions. + +Signed-off-by: Stéphane Graber +Acked-by: Serge E. Hallyn +--- + templates/lxc-ubuntu-cloud.in | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/templates/lxc-ubuntu-cloud.in b/templates/lxc-ubuntu-cloud.in +index 3f30a61..d277fec 100644 +--- a/templates/lxc-ubuntu-cloud.in ++++ b/templates/lxc-ubuntu-cloud.in +@@ -25,7 +25,7 @@ STATE_DIR="@LOCALSTATEDIR@" + HOOK_DIR="@LXCHOOKDIR@" + CLONE_HOOK_FN="$HOOK_DIR/ubuntu-cloud-prep" + LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@" +-KNOWN_RELEASES="precise trusty utopic vivid" ++KNOWN_RELEASES="precise trusty vivid wily xenial" + skip_arch_check=${UCTEMPLATE_SKIP_ARCH_CHECK:-0} + + # Make sure the usual locations are in PATH +@@ -159,8 +159,8 @@ eval set -- "$options" + + mapped_uid=-1 + mapped_gid=-1 +-# default release is precise, or the systems release if recognized +-release=precise ++# default release is trusty, or the systems release if recognized ++release=trusty + if [ -f /etc/lsb-release ]; then + . /etc/lsb-release + rels=$(ubuntu-distro-info --supported 2>/dev/null) || +@@ -183,7 +183,7 @@ else + arch="amd64" + elif [ "$arch" = "armv7l" ]; then + # note: arm images don't exist before oneiric; are called armhf in +- # precise and later; and are not supported by the query, so we don't actually ++ # trusty and later; and are not supported by the query, so we don't actually + # support them yet (see check later on). When Query2 is available, + # we'll use that to enable arm images. + arch="armhf" +@@ -330,10 +330,10 @@ do_extract_rootfs() { + mkdir -p $rootfs + cd $rootfs + if [ $in_userns -eq 1 ]; then +- tar --anchored --exclude="dev/*" --numeric-owner -xpJf "$cache/$filename" ++ tar --anchored --exclude="dev/*" --numeric-owner -xpf "$cache/$filename" + mkdir -p $rootfs/dev/pts/ + else +- tar --numeric-owner -xpJf "$cache/$filename" ++ tar --numeric-owner -xpf "$cache/$filename" + fi + } + diff -Nru lxc-1.0.7/debian/patches/0003-Better-handle-preserve_ns-behavior.patch lxc-1.0.8/debian/patches/0003-Better-handle-preserve_ns-behavior.patch --- lxc-1.0.7/debian/patches/0003-Better-handle-preserve_ns-behavior.patch 1970-01-01 00:00:00.000000000 +0000 +++ lxc-1.0.8/debian/patches/0003-Better-handle-preserve_ns-behavior.patch 2015-11-18 18:41:56.000000000 +0000 @@ -0,0 +1,121 @@ +From 3d3ff990d7ed8f30ac1fc5508cb7c81b14d5c235 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Tue, 17 Nov 2015 12:59:05 -0600 +Subject: Better handle preserve_ns behavior + +Commit b6b2b194a8 preserves the container's namespaces for +possible later use in stop hook. But some kernels don't have +/proc/pid/ns/ns for all the namespaces we may be interested in. +So warn but continue if this is the case. + +Implement stgraber's suggested semantics. + + - User requests some namespaces be preserved: + - If /proc/self/ns is missing => fail (saying kernel misses setns) + - If /proc/self/ns/ entry is missing => fail (saying kernel misses setns for ) + - User doesn't request some namespaces be preserved: + - If /proc/self/ns is missing => log an INFO message (kernel misses setns) and continue + - If /proc/self/ns/ entry is missing => log an INFO message (kernel misses setns for ) and continue + +Signed-off-by: Serge Hallyn +--- + src/lxc/start.c | 47 ++++++++++++++++++++++++++++++++++------------- + 1 file changed, 34 insertions(+), 13 deletions(-) + +diff --git a/src/lxc/start.c b/src/lxc/start.c +index 3cbb049..c481630 100644 +--- a/src/lxc/start.c ++++ b/src/lxc/start.c +@@ -117,8 +117,15 @@ static void close_ns(int ns_fd[LXC_NS_MAX]) { + } + } + +-static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid) { +- int i, saved_errno; ++/* ++ * preserve_ns: open /proc/@pid/ns/@ns for each namespace specified ++ * in clone_flags. ++ * Return true on success, false on failure. On failure, leave an error ++ * message in *errmsg, which caller must free. ++ */ ++static ++bool preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid, char **errmsg) { ++ int i, ret; + char path[MAXPATHLEN]; + + for (i = 0; i < LXC_NS_MAX; i++) +@@ -126,8 +133,9 @@ static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid) { + + snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid); + if (access(path, X_OK)) { +- WARN("Kernel does not support attach; preserve_ns ignored"); +- return 0; ++ if (asprintf(errmsg, "Kernel does not support setns.") == -1) ++ *errmsg = NULL; ++ return false; + } + + for (i = 0; i < LXC_NS_MAX; i++) { +@@ -140,14 +148,20 @@ static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid) { + goto error; + } + +- return 0; ++ return true; + + error: +- saved_errno = errno; ++ if (errno == ENOENT) { ++ ret = asprintf(errmsg, "Kernel does not support setns for %s", ++ ns_info[i].proc_name); ++ } else { ++ ret = asprintf(errmsg, "Failed to open %s: %s", ++ path, strerror(errno)); ++ } ++ if (ret == -1) ++ *errmsg = NULL; + close_ns(ns_fd); +- errno = saved_errno; +- SYSERROR("failed to open '%s'", path); +- return -1; ++ return false; + } + + static int attach_ns(const int ns_fd[LXC_NS_MAX]) { +@@ -798,6 +812,7 @@ static int lxc_spawn(struct lxc_handler *handler) + { + int failed_before_rename = 0; + const char *name = handler->name; ++ char *errmsg = NULL; + bool cgroups_connected = false; + int saved_ns_fd[LXC_NS_MAX]; + int preserve_mask = 0, i; +@@ -889,8 +904,12 @@ static int lxc_spawn(struct lxc_handler *handler) + INFO("failed to pin the container's rootfs"); + } + +- if (preserve_ns(saved_ns_fd, preserve_mask, getpid()) < 0) ++ if (!preserve_ns(saved_ns_fd, preserve_mask, getpid(), &errmsg)) { ++ SYSERROR("Failed to preserve requested namespaces: %s", ++ errmsg ? errmsg : "(Out of memory)"); ++ free(errmsg); + goto out_delete_net; ++ } + if (attach_ns(handler->conf->inherit_ns_fd) < 0) + goto out_delete_net; + +@@ -910,9 +929,11 @@ static int lxc_spawn(struct lxc_handler *handler) + goto out_delete_net; + } + +- if (preserve_ns(handler->nsfd, handler->clone_flags, handler->pid) < 0) { +- ERROR("failed to store namespace references"); +- goto out_delete_net; ++ if (preserve_ns(handler->nsfd, handler->clone_flags, handler->pid, ++ &errmsg) < 0) { ++ INFO("Failed to store namespace references for stop hook: %s", ++ errmsg ? errmsg : "(Out of memory)"); ++ free(errmsg); + } + + if (attach_ns(saved_ns_fd)) diff -Nru lxc-1.0.7/debian/patches/0003-CVE-2015-1335.patch lxc-1.0.8/debian/patches/0003-CVE-2015-1335.patch --- lxc-1.0.7/debian/patches/0003-CVE-2015-1335.patch 2015-09-26 15:58:51.000000000 +0000 +++ lxc-1.0.8/debian/patches/0003-CVE-2015-1335.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,475 +0,0 @@ -From 3c62cae308e8e66dcc616c5bd34671e1d2eea5a6 Mon Sep 17 00:00:00 2001 -From: Serge Hallyn -Date: Mon, 31 Aug 2015 12:57:20 -0500 -Subject: [PATCH 1/1] Protect container mounts against symlinks - -When a container starts up, lxc sets up the container's inital fstree -by doing a bunch of mounting, guided by the container configuration -file. The container config is owned by the admin or user on the host, -so we do not try to guard against bad entries. However, since the -mount target is in the container, it's possible that the container admin -could divert the mount with symbolic links. This could bypass proper -container startup (i.e. confinement of a root-owned container by the -restrictive apparmor policy, by diverting the required write to -/proc/self/attr/current), or bypass the (path-based) apparmor policy -by diverting, say, /proc to /mnt in the container. - -To prevent this, - -1. do not allow mounts to paths containing symbolic links - -2. do not allow bind mounts from relative paths containing symbolic -links. - -Details: - -This patch causes lxc to check /proc/self/mountinfo after each -mount into a container rootfs (that is, where we are not chrooted -into the container), making sure that the mount target wasn't a -symlink. - -Use safe_mount() in mount_entry(), when mounting container proc, -and when needed. In particular, safe_mount() need not be used in -any case where: - -1. the mount is done in the container's namespace -2. the mount is for the container's rootfs -3. the mount is relative to a tmpfs or proc/sysfs which we have - just safe_mount()ed ourselves - -Since we were using proc/net as a temporary placeholder for /proc/sys/net -during container startup, and proc/net is a symbolic link, use proc/tty -instead. - -Update the lxc.container.conf manpage with details about the new -restrictions. - -Finally, add a testcase to test some symbolic link possibilities. - -lxc-test-symlink: background lxc-start - -CVE-2015-1335 - -Signed-off-by: Serge Hallyn ---- - doc/lxc.container.conf.sgml.in | 12 ++++++ - src/lxc/cgfs.c | 5 ++- - src/lxc/cgmanager.c | 4 +- - src/lxc/conf.c | 30 +++++++------- - src/lxc/utils.c | 90 ++++++++++++++++++++++++++++++++++++++++++ - src/lxc/utils.h | 2 + - src/tests/Makefile.am | 3 +- - src/tests/lxc-test-symlink | 88 +++++++++++++++++++++++++++++++++++++++++ - 8 files changed, 216 insertions(+), 18 deletions(-) - create mode 100644 src/tests/lxc-test-symlink - -diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in -index 9cd0c57..6f06762 100644 ---- a/doc/lxc.container.conf.sgml.in -+++ b/doc/lxc.container.conf.sgml.in -@@ -676,6 +676,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - container. This is useful to mount /etc, /var or /home for - examples. - -+ -+ NOTE - LXC will generally ensure that mount targets and relative -+ bind-mount sources are properly confined under the container -+ root, to avoid attacks involving over-mounting host directories -+ and files. (Symbolic links in absolute mount sources are ignored) -+ However, if the container configuration first mounts a directory which -+ is under the control of the container user, such as /home/joe, into -+ the container at some path, and then mounts -+ under path, then a TOCTTOU attack would be -+ possible where the container user modifies a symbolic link under -+ his home directory at just the right time. -+ - - - -diff --git a/src/lxc/cgfs.c b/src/lxc/cgfs.c -index 15346dc..df4ad46 100644 ---- a/src/lxc/cgfs.c -+++ b/src/lxc/cgfs.c -@@ -1363,7 +1363,10 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type) - if (!path) - return false; - snprintf(path, bufsz, "%s/sys/fs/cgroup", root); -- r = mount("cgroup_root", path, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "size=10240k,mode=755"); -+ r = safe_mount("cgroup_root", path, "tmpfs", -+ MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, -+ "size=10240k,mode=755", -+ root); - if (r < 0) { - SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container"); - return false; -diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c -index 1872f03..79af751 100644 ---- a/src/lxc/cgmanager.c -+++ b/src/lxc/cgmanager.c -@@ -1332,7 +1332,7 @@ static bool cgm_bind_dir(const char *root, const char *dirname) - } - - /* mount a tmpfs there so we can create subdirs */ -- if (mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755")) { -+ if (safe_mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755", root)) { - SYSERROR("Failed to mount tmpfs at %s", cgpath); - return false; - } -@@ -1343,7 +1343,7 @@ static bool cgm_bind_dir(const char *root, const char *dirname) - return false; - } - -- if (mount(dirname, cgpath, "none", MS_BIND, 0)) { -+ if (safe_mount(dirname, cgpath, "none", MS_BIND, 0, root)) { - SYSERROR("Failed to bind mount %s to %s", dirname, cgpath); - return false; - } -diff --git a/src/lxc/conf.c b/src/lxc/conf.c -index 320b6c9..8acee5a 100644 ---- a/src/lxc/conf.c -+++ b/src/lxc/conf.c -@@ -795,7 +795,7 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha - } - mflags = add_required_remount_flags(source, destination, - default_mounts[i].flags); -- r = mount(source, destination, default_mounts[i].fstype, mflags, default_mounts[i].options); -+ r = safe_mount(source, destination, default_mounts[i].fstype, mflags, default_mounts[i].options, conf->rootfs.path ? conf->rootfs.mount : NULL); - saved_errno = errno; - if (r < 0) - SYSERROR("error mounting %s on %s flags %lu", source, destination, mflags); -@@ -989,7 +989,8 @@ static int setup_tty(const struct lxc_rootfs *rootfs, - return -1; - } - -- if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) { -+ if (safe_mount(pty_info->name, lxcpath, "none", MS_BIND, 0, -+ rootfs->mount)) { - WARN("failed to mount '%s'->'%s'", - pty_info->name, path); - continue; -@@ -1016,7 +1017,8 @@ static int setup_tty(const struct lxc_rootfs *rootfs, - close(ret); - } - } -- if (mount(pty_info->name, path, "none", MS_BIND, 0)) { -+ if (safe_mount(pty_info->name, path, "none", MS_BIND, 0, -+ rootfs->mount)) { - WARN("failed to mount '%s'->'%s'", - pty_info->name, path); - continue; -@@ -1442,16 +1444,16 @@ static int mount_autodev(const char *name, char *root, const char *lxcpath) - SYSERROR("WARNING: Failed to create symlink '%s'->'%s'", host_path, devtmpfs_path); - } - DEBUG("Bind mounting %s to %s", devtmpfs_path , path ); -- ret = mount(devtmpfs_path, path, NULL, MS_BIND, 0 ); -+ ret = safe_mount(devtmpfs_path, path, NULL, MS_BIND, 0, root ); - } else { - /* Only mount a tmpfs on here if we don't already a mount */ - if ( ! mount_check_fs( host_path, NULL ) ) { - DEBUG("Mounting tmpfs to %s", host_path ); -- ret = mount("none", path, "tmpfs", 0, "size=100000,mode=755"); -+ ret = safe_mount("none", path, "tmpfs", 0, "size=100000,mode=755", root); - } else { - /* This allows someone to manually set up a mount */ - DEBUG("Bind mounting %s to %s", host_path, path ); -- ret = mount(host_path , path, NULL, MS_BIND, 0 ); -+ ret = safe_mount(host_path , path, NULL, MS_BIND, 0, root ); - } - } - if (ret) { -@@ -1828,7 +1830,7 @@ static int setup_dev_console(const struct lxc_rootfs *rootfs, - return -1; - } - -- if (mount(console->name, path, "none", MS_BIND, 0)) { -+ if (safe_mount(console->name, path, "none", MS_BIND, 0, rootfs->mount)) { - ERROR("failed to mount '%s' on '%s'", console->name, path); - return -1; - } -@@ -1883,7 +1885,7 @@ static int setup_ttydir_console(const struct lxc_rootfs *rootfs, - return 0; - } - -- if (mount(console->name, lxcpath, "none", MS_BIND, 0)) { -+ if (safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs->mount)) { - ERROR("failed to mount '%s' on '%s'", console->name, lxcpath); - return -1; - } -@@ -2033,13 +2035,13 @@ static char *get_field(char *src, int nfields) - - static int mount_entry(const char *fsname, const char *target, - const char *fstype, unsigned long mountflags, -- const char *data, int optional) -+ const char *data, int optional, const char *rootfs) - { - #ifdef HAVE_STATVFS - struct statvfs sb; - #endif - -- if (mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data)) { -+ if (safe_mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data, rootfs)) { - if (optional) { - INFO("failed to mount '%s' on '%s' (optional): %s", fsname, - target, strerror(errno)); -@@ -2172,7 +2174,7 @@ static inline int mount_entry_on_systemfs(struct mntent *mntent) - } - - ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir, -- mntent->mnt_type, mntflags, mntdata, optional); -+ mntent->mnt_type, mntflags, mntdata, optional, NULL); - - free(pathdirname); - free(mntdata); -@@ -2259,7 +2261,7 @@ skipabs: - } - - ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, -- mntflags, mntdata, optional); -+ mntflags, mntdata, optional, rootfs->mount); - - free(mntdata); - -@@ -2315,7 +2317,7 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent, - } - - ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, -- mntflags, mntdata, optional); -+ mntflags, mntdata, optional, rootfs); - - free(pathdirname); - free(mntdata); -@@ -3981,7 +3983,7 @@ static int do_tmp_proc_mount(const char *rootfs) - return 0; - - domount: -- if (mount("proc", path, "proc", 0, NULL)) -+ if (safe_mount("proc", path, "proc", 0, NULL, rootfs)) - return -1; - INFO("Mounted /proc in container for security transition"); - return 1; -diff --git a/src/lxc/utils.c b/src/lxc/utils.c -index 5ef04fc..f84af33 100644 ---- a/src/lxc/utils.c -+++ b/src/lxc/utils.c -@@ -1322,3 +1322,93 @@ next_loop: - free(path); - return NULL; - } -+ -+/* -+ * ws points into an array of \0-separate path elements. -+ * ws should be pointing to one of the path elements or -+ * the next \0. It will return the first character of the -+ * next path element. -+ */ -+static char *next_word(char *ws) { -+ while (*ws && *ws != ' ') ws++; -+ while (*ws && *ws == ' ') ws++; -+ return ws; -+} -+ -+/* -+ * This is only used during container startup. So we know we won't race -+ * with anyone else mounting. Check the last line in /proc/self/mountinfo -+ * to make sure the target is under the container root. -+ */ -+static bool ensure_not_symlink(const char *target, const char *croot) -+{ -+ FILE *f = fopen("/proc/self/mountinfo", "r"); -+ char *line = NULL, *ws = NULL, *we = NULL; -+ size_t len = 0, i; -+ bool ret = false; -+ -+ if (!croot || croot[0] == '\0') -+ return true; -+ -+ if (!f) { -+ ERROR("Cannot open /proc/self/mountinfo"); -+ return false; -+ } -+ -+ while (getline(&line, &len, f) != -1) { -+ } -+ fclose(f); -+ -+ if (!line) -+ return false; -+ ws = line; -+ for (i = 0; i < 4; i++) -+ ws = next_word(ws); -+ if (!*ws) -+ goto out; -+ we = ws; -+ while (*we && *we != ' ') -+ we++; -+ if (!*we) -+ goto out; -+ *we = '\0'; -+ -+ /* now make sure that ws starts with croot and ends with rest of target */ -+ if (croot && strncmp(ws, croot, strlen(croot)) != 0) { -+ ERROR("Mount onto %s resulted in %s\n", target, ws); -+ goto out; -+ } -+ -+ size_t start = croot ? strlen(croot) : 0; -+ if (strcmp(ws + start, target + start) != 0) { -+ ERROR("Mount onto %s resulted in %s\n", target, ws); -+ goto out; -+ } -+ -+ ret = true; -+ -+out: -+ free(line); -+ return ret; -+} -+/* -+ * Safely mount a path into a container, ensuring that the mount target -+ * is under the container's @rootfs. (If @rootfs is NULL, then the container -+ * uses the host's /) -+ */ -+int safe_mount(const char *src, const char *dest, const char *fstype, -+ unsigned long flags, const void *data, const char *rootfs) -+{ -+ int ret; -+ ret = mount(src, dest, fstype, flags, data); -+ if (ret < 0) { -+ SYSERROR("Mount of '%s' onto '%s' failed", src, dest); -+ return ret; -+ } -+ if (!ensure_not_symlink(dest, rootfs)) { -+ ERROR("Mount of '%s' onto '%s' was onto a symlink!", src, dest); -+ umount(dest); -+ return -1; -+ } -+ return 0; -+} -diff --git a/src/lxc/utils.h b/src/lxc/utils.h -index f48f403..30e8a98 100644 ---- a/src/lxc/utils.h -+++ b/src/lxc/utils.h -@@ -280,3 +280,5 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval); - int detect_shared_rootfs(void); - int detect_ramfs_rootfs(void); - char *on_path(char *cmd); -+int safe_mount(const char *src, const char *dest, const char *fstype, -+ unsigned long flags, const void *data, const char *rootfs); -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index 19a4205..edb62d6 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -48,7 +48,7 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \ - lxc-test-reboot lxc-test-list lxc-test-attach lxc-test-device-add-remove \ - lxc-test-apparmor - --bin_SCRIPTS = lxc-test-autostart -+bin_SCRIPTS = lxc-test-autostart lxc-test-symlink - - if DISTRO_UBUNTU - bin_SCRIPTS += lxc-test-usernic lxc-test-ubuntu lxc-test-unpriv -@@ -71,6 +71,7 @@ EXTRA_DIST = \ - locktests.c \ - lxcpath.c \ - lxc-test-autostart \ -+ lxc-test-symlink \ - lxc-test-ubuntu \ - lxc-test-unpriv \ - may_control.c \ -diff --git a/src/tests/lxc-test-symlink b/src/tests/lxc-test-symlink -new file mode 100644 -index 0000000..b014a66 ---- /dev/null -+++ b/src/tests/lxc-test-symlink -@@ -0,0 +1,88 @@ -+#!/bin/bash -+ -+set -ex -+ -+# lxc: linux Container library -+ -+# Authors: -+# Serge Hallyn -+# -+# This is a regression test for symbolic links -+ -+dirname=`mktemp -d` -+fname=`mktemp` -+fname2=`mktemp` -+ -+lxcpath=/var/lib/lxcsym1 -+ -+cleanup() { -+ lxc-destroy -P $lxcpath -f -n symtest1 || true -+ rm -f $lxcpath -+ rmdir $dirname || true -+ rm -f $fname || true -+ rm -f $fname2 || true -+} -+ -+trap cleanup EXIT SIGHUP SIGINT SIGTERM -+ -+testrun() { -+ expected=$1 -+ run=$2 -+ pass="pass" -+ lxc-start -d -P $lxcpath -n symtest1 -l trace -o $lxcpath/log || pass="fail" -+ [ $pass = "pass" ] && lxc-wait -P $lxcpath -n symtest1 -t 10 -s RUNNING || pass="fail" -+ if [ "$pass" != "$expected" ]; then -+ echo "Test $run: expected $expected but container did not. Start log:" -+ cat $lxcpath/log -+ echo "FAIL: Test $run: expected $expected but container did not." -+ false -+ fi -+ lxc-stop -P $lxcpath -n symtest1 -k || true -+} -+ -+# make lxcpath a symlink - this should NOT cause failure -+ln -s /var/lib/lxc $lxcpath -+ -+lxc-destroy -P $lxcpath -f -n symtest1 || true -+lxc-create -P $lxcpath -t busybox -n symtest1 -+ -+cat >> /var/lib/lxc/symtest1/config << EOF -+lxc.mount.entry = $dirname opt/xxx/dir none bind,create=dir -+lxc.mount.entry = $fname opt/xxx/file none bind,create=file -+lxc.mount.entry = $fname2 opt/xxx/file2 none bind -+EOF -+ -+# Regular - should succeed -+mkdir -p /var/lib/lxc/symtest1/rootfs/opt/xxx -+touch /var/lib/lxc/symtest1/rootfs/opt/xxx/file2 -+testrun pass 1 -+ -+# symlink - should fail -+rm -rf /var/lib/lxc/symtest1/rootfs/opt/xxx -+mkdir -p /var/lib/lxc/symtest1/rootfs/opt/xxx2 -+ln -s /var/lib/lxc/symtest1/rootfs/opt/xxx2 /var/lib/lxc/symtest1/rootfs/opt/xxx -+touch /var/lib/lxc/symtest1/rootfs/opt/xxx/file2 -+testrun fail 2 -+ -+# final final symlink - should fail -+rm -rf $lxcpath/symtest1/rootfs/opt/xxx -+mkdir -p $lxcpath/symtest1/rootfs/opt/xxx -+mkdir -p $lxcpath/symtest1/rootfs/opt/xxx/dir -+touch $lxcpath/symtest1/rootfs/opt/xxx/file -+touch $lxcpath/symtest1/rootfs/opt/xxx/file2src -+ln -s $lxcpath/symtest1/rootfs/opt/xxx/file2src $lxcpath/symtest1/rootfs/opt/xxx/file2 -+testrun fail 3 -+ -+# Ideally we'd also try a loop device, but that won't work in nested containers -+# anyway - TODO -+ -+# what about /proc itself -+ -+rm -rf $lxcpath/symtest1/rootfs/opt/xxx -+mkdir -p $lxcpath/symtest1/rootfs/opt/xxx -+touch $lxcpath/symtest1/rootfs/opt/xxx/file2 -+mv $lxcpath/symtest1/rootfs/proc $lxcpath/symtest1/rootfs/proc1 -+ln -s $lxcpath/symtest1/rootfs/proc1 $lxcpath/symtest1/rootfs/proc -+testrun fail 4 -+ -+echo "all tests passed" --- -2.5.0 - diff -Nru lxc-1.0.7/debian/patches/avoid-dot.patch lxc-1.0.8/debian/patches/avoid-dot.patch --- lxc-1.0.7/debian/patches/avoid-dot.patch 2015-10-01 06:56:21.000000000 +0000 +++ lxc-1.0.8/debian/patches/avoid-dot.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -Description: also avoid /./ -Author: Serge Hallyn -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1501491 - -Index: lxc-1.0.7/src/lxc/utils.c -=================================================================== ---- lxc-1.0.7.orig/src/lxc/utils.c -+++ lxc-1.0.7/src/lxc/utils.c -@@ -1335,15 +1335,30 @@ static char *next_word(char *ws) { - return ws; - } - --/* copy src to dest, collapsing multiple '/' into one */ -+/* -+ * copy src to dest, collapsing multiple '/' into one and -+ * collapsing '/./' to '/' -+ */ - static void copy_cleanedup(char *dest, const char *src) - { -+ char *orig = dest; - while (*src) { -- while (*src == '/' && *(src+1) == '/') -+ if (*src == '/' && *(src+1) == '/') { - src++; -+ continue; -+ } -+ if (*src == '/' && *(src+1) == '.' && -+ (*(src+2) == '/' || *(src+2) == '\0')) { -+ src += 2; -+ continue; -+ } - *(dest++) = *(src++); - } - *dest = '\0'; -+ /* remove trailing / */ -+ dest--; -+ while (dest > orig && *dest == '/') -+ *(dest--) = '\0'; - } - - /* -@@ -1395,7 +1410,7 @@ static bool ensure_not_symlink(const cha - - size_t start = croot ? strlen(croot) : 0; - if (strcmp(ws + start, tgtcopy + start) != 0) { -- ERROR("Mount onto %s resulted in %s\n", target, ws); -+ ERROR("Mount onto %s resulted in %s, not %s\n", target, ws, tgtcopy); - goto out; - } - -Index: lxc-1.0.7/src/tests/lxc-test-symlink -=================================================================== ---- lxc-1.0.7.orig/src/tests/lxc-test-symlink -+++ lxc-1.0.7/src/tests/lxc-test-symlink -@@ -50,6 +50,9 @@ cat >> /var/lib/lxc/symtest1/config << E - lxc.mount.entry = $dirname opt/xxx/dir none bind,create=dir - lxc.mount.entry = $fname opt/xxx/file none bind,create=file - lxc.mount.entry = $fname2 opt/xxx/file2 none bind -+lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir2 none bind,create=dir -+lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir3// none bind,create=dir -+lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx//././//dir4/. none bind,create=dir - EOF - - # Regular - should succeed diff -Nru lxc-1.0.7/debian/patches/fix-multislash.patch lxc-1.0.8/debian/patches/fix-multislash.patch --- lxc-1.0.7/debian/patches/fix-multislash.patch 2015-09-30 16:04:59.000000000 +0000 +++ lxc-1.0.8/debian/patches/fix-multislash.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -Description: fix mount target mismatches due to multiple slashes - The patch to fix symlink tocttou's in mount entries at container start - notices that target and actual mount point don't match. - We introduce a // when the user specifies an absolute mount target, but - rather than fix that, check for all '//' since user may have them in - their container configuration, and we don't want to break configs which - worked before. -Author: Serge Hallyn -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1476662 -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1501310 - -Index: lxc-1.0.7/src/lxc/utils.c -=================================================================== ---- lxc-1.0.7.orig/src/lxc/utils.c -+++ lxc-1.0.7/src/lxc/utils.c -@@ -1335,6 +1335,17 @@ static char *next_word(char *ws) { - return ws; - } - -+/* copy src to dest, collapsing multiple '/' into one */ -+static void copy_cleanedup(char *dest, const char *src) -+{ -+ while (*src) { -+ while (*src == '/' && *(src+1) == '/') -+ src++; -+ *(dest++) = *(src++); -+ } -+ *dest = '\0'; -+} -+ - /* - * This is only used during container startup. So we know we won't race - * with anyone else mounting. Check the last line in /proc/self/mountinfo -@@ -1343,7 +1354,7 @@ static char *next_word(char *ws) { - static bool ensure_not_symlink(const char *target, const char *croot) - { - FILE *f = fopen("/proc/self/mountinfo", "r"); -- char *line = NULL, *ws = NULL, *we = NULL; -+ char *line = NULL, *ws = NULL, *we = NULL, *tgtcopy; - size_t len = 0, i; - bool ret = false; - -@@ -1373,14 +1384,17 @@ static bool ensure_not_symlink(const cha - goto out; - *we = '\0'; - -+ tgtcopy = alloca(strlen(target) + 1); -+ copy_cleanedup(tgtcopy, target); - /* now make sure that ws starts with croot and ends with rest of target */ - if (croot && strncmp(ws, croot, strlen(croot)) != 0) { -- ERROR("Mount onto %s resulted in %s\n", target, ws); -+ ERROR("Mount onto %s resulted in %s, does not match root %s\n", -+ target, ws, croot); - goto out; - } - - size_t start = croot ? strlen(croot) : 0; -- if (strcmp(ws + start, target + start) != 0) { -+ if (strcmp(ws + start, tgtcopy + start) != 0) { - ERROR("Mount onto %s resulted in %s\n", target, ws); - goto out; - } diff -Nru lxc-1.0.7/debian/patches/fix-rbind-mounts.patch lxc-1.0.8/debian/patches/fix-rbind-mounts.patch --- lxc-1.0.7/debian/patches/fix-rbind-mounts.patch 2015-10-28 17:17:46.000000000 +0000 +++ lxc-1.0.8/debian/patches/fix-rbind-mounts.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -Description: Fix recursive bind mounts - If a lxc.mount.entry is a recursive bind mount, then more than one new - line is appended to /proc/self/mountinfo. But our patch to detect - symbolic links only checks the last line. So instead find the number - of lines before we do the mount, and only verify the next line. -Author: Serge Hallyn -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1509752 - -Index: lxc-1.0.7/src/lxc/utils.c -=================================================================== ---- lxc-1.0.7.orig/src/lxc/utils.c 2015-10-28 16:18:39.000000000 +0000 -+++ lxc-1.0.7/src/lxc/utils.c 2015-10-28 17:15:19.329046439 +0000 -@@ -1361,16 +1361,32 @@ - *(dest--) = '\0'; - } - -+static size_t count_mountinfo_lines(void) -+{ -+ FILE *f = fopen("/proc/self/mountinfo", "r"); -+ char *line = NULL; -+ size_t len = 0, i = 0; -+ if (!f) -+ return 0; -+ -+ while (getline(&line, &len, f) != -1) -+ i++; -+ fclose(f); -+ -+ free(line); -+ return i; -+} -+ - /* - * This is only used during container startup. So we know we won't race - * with anyone else mounting. Check the last line in /proc/self/mountinfo - * to make sure the target is under the container root. - */ --static bool ensure_not_symlink(const char *target, const char *croot) -+static bool ensure_not_symlink(const char *target, const char *croot, size_t prevlines) - { - FILE *f = fopen("/proc/self/mountinfo", "r"); - char *line = NULL, *ws = NULL, *we = NULL, *tgtcopy; -- size_t len = 0, i; -+ size_t len = 0, i = 0; - bool ret = false; - - if (!croot || croot[0] == '\0') -@@ -1381,7 +1397,8 @@ - return false; - } - -- while (getline(&line, &len, f) != -1) { -+ while (getline(&line, &len, f) != -1 && i < prevlines) { -+ i++; - } - fclose(f); - -@@ -1429,12 +1446,15 @@ - unsigned long flags, const void *data, const char *rootfs) - { - int ret; -+ size_t nlines = count_mountinfo_lines(); -+ - ret = mount(src, dest, fstype, flags, data); - if (ret < 0) { - SYSERROR("Mount of '%s' onto '%s' failed", src, dest); - return ret; - } -- if (!ensure_not_symlink(dest, rootfs)) { -+ -+ if (!ensure_not_symlink(dest, rootfs, nlines)) { - ERROR("Mount of '%s' onto '%s' was onto a symlink!", src, dest); - umount(dest); - return -1; diff -Nru lxc-1.0.7/debian/patches/series lxc-1.0.8/debian/patches/series --- lxc-1.0.7/debian/patches/series 2015-10-28 17:16:18.000000000 +0000 +++ lxc-1.0.8/debian/patches/series 2015-11-18 18:41:56.000000000 +0000 @@ -1,7 +1,3 @@ -0001-CVE-2015-1331.patch -0002-CVE-2014-1334.patch -0003-CVE-2015-1335.patch -fix-multislash.patch -avoid-dot.patch -00004-update-apparmor.patch -fix-rbind-mounts.patch +0001-Trusty-Swap-out-the-CVE-2015-1335-fix-with-the-trust.patch +0002-ubuntu-cloud-Various-fixes.patch +0003-Better-handle-preserve_ns-behavior.patch diff -Nru lxc-1.0.7/debian/tests/exercise lxc-1.0.8/debian/tests/exercise --- lxc-1.0.7/debian/tests/exercise 2014-12-18 22:44:44.000000000 +0000 +++ lxc-1.0.8/debian/tests/exercise 2015-11-18 18:41:56.000000000 +0000 @@ -10,18 +10,6 @@ IGNORE_LIST="" -# FIXME: This should be done in default adt environment -# Detect the ubuntu-ci setup -if echo "" | nc -w 2 squid.internal 3128 >/dev/null 2>&1; then - echo "Running in the Canonical CI environment" - export http_proxy="http://squid.internal:3128" - export https_proxy="http://squid.internal:3128" -elif echo "" | nc -w 2 10.245.64.1 3128 >/dev/null 2>&1; then - echo "Running in the Canonical enablement environment" - export http_proxy="http://10.245.64.1:3128" - export https_proxy="http://10.245.64.1:3128" -fi - # Helper functions pass() { TEST_PASS=$((${TEST_PASS}+1)) diff -Nru lxc-1.0.7/doc/common_options.sgml.in lxc-1.0.8/doc/common_options.sgml.in --- lxc-1.0.7/doc/common_options.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/common_options.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -105,6 +105,15 @@ + + + + + + Show the version number. + + + diff -Nru lxc-1.0.7/doc/ja/common_options.sgml.in lxc-1.0.8/doc/ja/common_options.sgml.in --- lxc-1.0.7/doc/ja/common_options.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/common_options.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -139,6 +139,18 @@ + + + + + + + バージョン番号を表示します。 + + + diff -Nru lxc-1.0.7/doc/ja/lxc-autostart.sgml.in lxc-1.0.8/doc/ja/lxc-autostart.sgml.in --- lxc-1.0.7/doc/ja/lxc-autostart.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-autostart.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -158,9 +158,9 @@ - 実際の動作は行わず、コンテナ名の表示だけを行います。 + 実際の動作は行わず、コンテナ名と次のコンテナを開始するまでの間隔の表示だけを行います。 @@ -311,7 +311,7 @@ &seealso; - Author + <!-- Author -->作者 Stéphane Graber stgraber@ubuntu.com diff -Nru lxc-1.0.7/doc/ja/lxc-clone.sgml.in lxc-1.0.8/doc/ja/lxc-clone.sgml.in --- lxc-1.0.7/doc/ja/lxc-clone.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-clone.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -145,9 +145,11 @@ - 新しいコンテナの rootfs は、オリジナルの LVM か btrfs のスナップショットになります。 + 新しいコンテナの rootfs はオリジナルのスナップショットとなります。 + このオプションはバッキングストアが LVM か btrfs か zfs の時に使用できます。 + また、スナップショットを aufs か overlayfs で取得したい場合は指定する必要があります。 diff -Nru lxc-1.0.7/doc/ja/lxc-config.sgml.in lxc-1.0.8/doc/ja/lxc-config.sgml.in --- lxc-1.0.7/doc/ja/lxc-config.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-config.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -106,7 +106,7 @@ &seealso; - Author + <!-- Author -->作者 Stéphane Graber stgraber@ubuntu.com diff -Nru lxc-1.0.7/doc/ja/lxc.conf.sgml.in lxc-1.0.8/doc/ja/lxc.conf.sgml.in --- lxc-1.0.7/doc/ja/lxc.conf.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc.conf.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -170,7 +170,7 @@ - Author + <!-- Author -->作者 Stéphane Graber stgraber@ubuntu.com diff -Nru lxc-1.0.7/doc/ja/lxc.container.conf.sgml.in lxc-1.0.8/doc/ja/lxc.container.conf.sgml.in --- lxc-1.0.7/doc/ja/lxc.container.conf.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc.container.conf.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -335,34 +335,34 @@ ループバックインターフェースだけを作成します。 - + - 一方がコンテナに、もう一方が で指定されるブリッジにアタッチされる、ピアネットワークデバイスを作成します。 - もし、ブリッジが指定されていない場合、veth ペアデバイスは作成されますが、ブリッジにはアタッチされません。 - ブリッジはシステムで事前に設定する必要があります。 - さもなければ、lxc はコンテナ外のいかなる設定も扱うことはできないでしょう。 - デフォルトでは、lxc はコンテナの外部に属するネットワークデバイスに対する名前を決定し、lxc はこの名前を使います。 + a virtual ethernet pair + device is created with one side assigned to the container + and the other side attached to a bridge specified by + the option. + If the bridge is not specified, then the veth pair device + will be created but not attached to any bridge. + Otherwise, the bridge has to be created on the system + before starting the container. + lxc won't handle any + configuration outside of the container. + By default, lxc chooses a name for the + network device belonging to the outside of the + container, but if you wish to handle + this name yourselves, you can tell lxc + to set a specific name with + the option (except for + unprivileged containers where this option is ignored for security + reasons). + --> + 一方がコンテナに、もう一方が オプションで指定されたブリッジに接続されるペアの仮想イーサネットデバイスを作成します。 + もし、ブリッジが指定されていない場合、veth ペアデバイスは作成されますが、ブリッジには接続されません。 + ブリッジはコンテナが開始する前にシステムで事前に設定しておく必要があります。 + lxc はコンテナ外の設定を扱うことはありません。 + デフォルトでは、lxc がコンテナの外部に属するネットワークデバイスに対する名前を決定します。 しかし、もしこの名前を自分で指定したい場合、 オプションを使って名前を設定し、lxc に対して指定をすることができます (非特権コンテナの場合をのぞきます。セキュリティ上の理由からこのオプションは無視されます)。 - + + 注意: 通常 LXC は、マウント対象と相対パス指定のバインドマウントを、適切にコンテナルート以下に閉じ込めます。 + これは、ホストのディレクトリやファイルに対して重ね合わせを行うようなマウントによる攻撃を防ぎます。(絶対パス指定のマウントソース中の各パスがシンボリックリンクである場合は無視されます。) + しかし、もしコンテナの設定が最初に、/home/joe のようなコンテナユーザのコントロール配下にあるディレクトリを、コンテナ中のある path にマウントし、その後 path 以下でマウントが行われるような場合、コンテナユーザがタイミングを見計らって自身のホームディレクトリ以下でシンボリックリンクを操作するような TOCTTOU 攻撃が成立する可能性があります。 + @@ -996,6 +1013,16 @@ fstab format. --> fstab フォーマットの一行と同じフォーマットのマウントポイントの指定をします。 + + + fstab フォーマットに加えて、LXC ではマウントに対して独自の 2 つのオプションが使えます。 + は、マウントが失敗しても失敗を返さずに無視します。 + は、マウントポイントをマウントする際にディレクトリもしくはファイルを作成します。 @@ -2072,7 +2099,7 @@ containers. --> コンテナを追加したいコンテナグループ名を指定します。 - (複数回使用される可能性のある) 複数の値を設定可能です。 + 複数の値を設定でき、複数回指定することもできます。 設定されたグループは、関連する一連のコンテナを起動させるために使われます。 diff -Nru lxc-1.0.7/doc/ja/lxc-create.sgml.in lxc-1.0.8/doc/ja/lxc-create.sgml.in --- lxc-1.0.7/doc/ja/lxc-create.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-create.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -199,6 +199,12 @@ --fssize SIZE はデフォルト値である 1G の代わりに SIZE で指定したサイズで LV を作成します。 + + backingstore が 'loop' の場合、'lvm' と同様に --fstype FSTYPE--fssize SIZE が使えます。これらの値のデフォルト値は 'lvm' の場合と同じです。 + + 説明 - lxc-destroy は、lxc-create で以前に作成したシステムオブジェクトを破壊します。 + lxc-destroy は、lxc-create で以前に作成したシステムオブジェクトを削除します。 @@ -80,7 +80,7 @@ - + @@ -90,27 +90,16 @@ lxc-destroy will be aborted. --> コンテナが実行中の場合、まずコンテナを停止させます。 - このオプションが指定されていない場合でコンテナが実行中の場合、lxc-destroy コマンドは実行を中断します。 + このオプションが指定されていない場合、コンテナが実行中のときは lxc-destroy コマンドは実行を中断します。 - - - - - - - コンテナパスを指定します。デフォルトは @LXCPATH@ です。 - - - - + &commonoptions; + <!-- Diagnostic -->診断 @@ -126,8 +115,8 @@ destroyed.You can use the lxc-ls command to list the available containers on the system. --> - 破壊するために指定したコンテナが見つかりません。 - おそらくそのコンテナが存在しないのか、既に破壊された後なのでしょう。 + 削除するために指定したコンテナが見つかりません。 + おそらくそのコンテナが存在しないのか、既に削除された後なのでしょう。 lxc-ls コマンドを使って、システム上に存在するコンテナのリストを得ることができます。 diff -Nru lxc-1.0.7/doc/ja/lxc-ls.sgml.in lxc-1.0.8/doc/ja/lxc-ls.sgml.in --- lxc-1.0.7/doc/ja/lxc-ls.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-ls.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -55,6 +55,7 @@ lxc-ls -1 + -P lxcpath --active --frozen --running @@ -63,6 +64,7 @@ -F format --nesting filter + --version @@ -95,6 +97,20 @@ + + + + + + + デフォルトと別のコンテナパスを使用します。デフォルトは @LXCPATH@ です。 + + + + + @@ -212,6 +228,19 @@ + + + + + + + + バージョン番号を表示します。 + + + diff -Nru lxc-1.0.7/doc/ja/lxc-snapshot.sgml.in lxc-1.0.8/doc/ja/lxc-snapshot.sgml.in --- lxc-1.0.7/doc/ja/lxc-snapshot.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-snapshot.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -183,7 +183,7 @@ &seealso; - Author + <!-- Author -->作者 Serge Hallyn serge.hallyn@ubuntu.com diff -Nru lxc-1.0.7/doc/ja/lxc-start-ephemeral.sgml.in lxc-1.0.8/doc/ja/lxc-start-ephemeral.sgml.in --- lxc-1.0.7/doc/ja/lxc-start-ephemeral.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-start-ephemeral.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -59,6 +59,7 @@ --bdir --user --key + --storage-type --union-type --keep-data COMMAND @@ -171,6 +172,20 @@ + + + + + + コンテナが使うストレージのタイプ。tmpfs か dir を指定できます。 + + + + + + @@ -209,10 +224,12 @@ - 即座に指定したコマンドをコンテナ内で実行します。現時点では (attach ではなく) ssh を使用します。そしてデーモンモードと両方を指定することはできません。 + 即座に指定したコマンドをコンテナ内で実行します。 + コマンドを実行する際、カーネルがサポートしている場合は lxc-start-ephemeral は attach を使います。 + カーネルがサポートしていない場合は ssh を使います。 diff -Nru lxc-1.0.7/doc/ja/lxc.system.conf.sgml.in lxc-1.0.8/doc/ja/lxc.system.conf.sgml.in --- lxc-1.0.7/doc/ja/lxc.system.conf.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc.system.conf.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -220,7 +220,7 @@ &seealso; - Author + <!-- Author -->作者 Stéphane Graber stgraber@ubuntu.com diff -Nru lxc-1.0.7/doc/ja/lxc-usernet.sgml.in lxc-1.0.8/doc/ja/lxc-usernet.sgml.in --- lxc-1.0.7/doc/ja/lxc-usernet.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-usernet.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -164,7 +164,7 @@ - Author + <!-- Author -->作者 Daniel Lezcano daniel.lezcano@free.fr diff -Nru lxc-1.0.7/doc/ja/lxc-user-nic.sgml.in lxc-1.0.8/doc/ja/lxc-user-nic.sgml.in --- lxc-1.0.7/doc/ja/lxc-user-nic.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-user-nic.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -166,8 +166,6 @@ - &commonoptions; - See Also @@ -190,7 +188,7 @@ - Author + <!-- Author -->作者 Daniel Lezcano daniel.lezcano@free.fr diff -Nru lxc-1.0.7/doc/ja/lxc-usernsexec.sgml.in lxc-1.0.8/doc/ja/lxc-usernsexec.sgml.in --- lxc-1.0.7/doc/ja/lxc-usernsexec.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/ja/lxc-usernsexec.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -170,7 +170,7 @@ &seealso; - Author + <!-- Author -->作者 Serge Hallyn serge.hallyn@ubuntu.com diff -Nru lxc-1.0.7/doc/lxc-autostart.sgml.in lxc-1.0.8/doc/lxc-autostart.sgml.in --- lxc-1.0.7/doc/lxc-autostart.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc-autostart.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -131,7 +131,7 @@ Rather than performing the action, just print - the container name. + the container name and wait delays until starting the next container. diff -Nru lxc-1.0.7/doc/lxc-clone.sgml.in lxc-1.0.8/doc/lxc-clone.sgml.in --- lxc-1.0.7/doc/lxc-clone.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc-clone.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -121,7 +121,7 @@ - The new container's rootfs should be a LVM or btrfs snapshot of the original. + The new container's rootfs will be a snapshot of the original. This option can be specified when the backing store is LVM, btrfs or zfs, and must be specified when you want to snapshot using aufs or overlayfs. diff -Nru lxc-1.0.7/doc/lxc.container.conf.sgml.in lxc-1.0.8/doc/lxc.container.conf.sgml.in --- lxc-1.0.7/doc/lxc.container.conf.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc.container.conf.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -244,20 +244,20 @@ - a peer network device is created - with one side assigned to the container and the other - side is attached to a bridge specified by - the . If the bridge is - not specified, then the veth pair device will be created - but not attached to any bridge. Otherwise, the bridge - has to be setup before on the - system, lxc won't handle any - configuration outside of the container. By - default lxc choose a name for the + a virtual ethernet pair + device is created with one side assigned to the container + and the other side attached to a bridge specified by + the option. + If the bridge is not specified, then the veth pair device + will be created but not attached to any bridge. + Otherwise, the bridge has to be created on the system + before starting the container. + lxc won't handle any + configuration outside of the container. + By default, lxc chooses a name for the network device belonging to the outside of the - container, this name is handled - by lxc, but if you wish to handle - this name yourself, you can tell lxc + container, but if you wish to handle + this name yourselves, you can tell lxc to set a specific name with the option (except for unprivileged containers where this option is ignored for security @@ -676,6 +676,18 @@ container. This is useful to mount /etc, /var or /home for examples. + + NOTE - LXC will generally ensure that mount targets and relative + bind-mount sources are properly confined under the container + root, to avoid attacks involving over-mounting host directories + and files. (Symbolic links in absolute mount sources are ignored) + However, if the container configuration first mounts a directory which + is under the control of the container user, such as /home/joe, into + the container at some path, and then mounts + under path, then a TOCTTOU attack would be + possible where the container user modifies a symbolic link under + his home directory at just the right time. + @@ -719,6 +731,11 @@ specify a mount point corresponding to a line in the fstab format. + + Moreover lxc add two options to mount. + don't fail if mount does not work. + or + to create dir (or file) when the point will be mounted. diff -Nru lxc-1.0.7/doc/lxc-create.sgml.in lxc-1.0.8/doc/lxc-create.sgml.in --- lxc-1.0.7/doc/lxc-create.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc-create.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -115,6 +115,7 @@ for details of the expected script structure. Alternatively, the full path to an executable template script can also be passed as a parameter. + "none" can be used to force lxc-create to skip rootfs creation. @@ -154,6 +155,9 @@ filesystem) of size SIZE rather than the default, which is 1G. + If backingstore is 'loop', you can use --fstype FSTYPE and --fssize SIZE as 'lvm'. The default values for these options are the same as 'lvm'. + + If backingstore is 'best', then lxc will try, in order, btrfs, zfs, lvm, and finally a directory backing store. diff -Nru lxc-1.0.7/doc/lxc-destroy.sgml.in lxc-1.0.8/doc/lxc-destroy.sgml.in --- lxc-1.0.7/doc/lxc-destroy.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc-destroy.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -71,7 +71,7 @@ - + @@ -81,18 +81,12 @@ - - - - - Use an alternate container path. The default is @LXCPATH@. - - - + &commonoptions; + Diagnostic diff -Nru lxc-1.0.7/doc/lxc-ls.sgml.in lxc-1.0.8/doc/lxc-ls.sgml.in --- lxc-1.0.7/doc/lxc-ls.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc-ls.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -50,6 +50,7 @@ lxc-ls -1 + -P lxcpath --active --frozen --running @@ -58,6 +59,7 @@ -F format --nesting filter + --version @@ -85,6 +87,17 @@ + + + + + Use an alternate container path. The default is @LXCPATH@. + + + + + + @@ -172,6 +185,17 @@ + + + + + + + + Show the version number. + + + diff -Nru lxc-1.0.7/doc/lxc-start-ephemeral.sgml.in lxc-1.0.8/doc/lxc-start-ephemeral.sgml.in --- lxc-1.0.7/doc/lxc-start-ephemeral.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc-start-ephemeral.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -53,6 +53,7 @@ --bdir --user --key + --storage-type --union-type --keep-data COMMAND @@ -141,6 +142,17 @@ + + + + + Specify the type of storage used by the container. Valid types are tmpfs or dir. + + + + + + @@ -171,8 +183,8 @@ Immediately run the provided command in the container. - This currently uses ssh (not attach) and is incompatible - with daemon mode. + This uses attach if the kernel supports it, otherwise uses ssh. + This is incompatible with daemon mode. diff -Nru lxc-1.0.7/doc/lxc-user-nic.sgml.in lxc-1.0.8/doc/lxc-user-nic.sgml.in --- lxc-1.0.7/doc/lxc-user-nic.sgml.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/doc/lxc-user-nic.sgml.in 2015-11-09 22:49:15.000000000 +0000 @@ -136,8 +136,6 @@ - &commonoptions; - See Also diff -Nru lxc-1.0.7/lxc.spec lxc-1.0.8/lxc.spec --- lxc-1.0.7/lxc.spec 2014-12-05 20:50:37.000000000 +0000 +++ lxc-1.0.8/lxc.spec 2015-11-09 22:49:28.000000000 +0000 @@ -45,7 +45,7 @@ %endif Name: lxc -Version: 1.0.7 +Version: 1.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 @@ -54,6 +54,7 @@ License: LGPLv2+ BuildRoot: %{_tmppath}/%{name}-%{version}-build Requires: openssl rsync +Requires: %{name}-libs = %{version}-%{release} BuildRequires: libcap libcap-devel docbook2X graphviz %if %{with_python} diff -Nru lxc-1.0.7/lxc.spec.in lxc-1.0.8/lxc.spec.in --- lxc-1.0.7/lxc.spec.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/lxc.spec.in 2015-11-09 22:49:15.000000000 +0000 @@ -54,6 +54,7 @@ License: LGPLv2+ BuildRoot: %{_tmppath}/%{name}-%{version}-build Requires: openssl rsync +Requires: %{name}-libs = %{version}-%{release} BuildRequires: libcap libcap-devel docbook2X graphviz %if %{with_python} diff -Nru lxc-1.0.7/MAINTAINERS lxc-1.0.8/MAINTAINERS --- lxc-1.0.7/MAINTAINERS 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/MAINTAINERS 2015-11-09 22:49:15.000000000 +0000 @@ -4,8 +4,9 @@ Maintainer ---------- -Person : Daniel Lezcano, Serge Hallyn, Stéphane Graber -Mail patches to : lxc-devel@lists.linuxcontainers.org -Mailing lists : lxc-devel@lists.linuxcontainers.org, lxc-users@lists.linuxcontainers.org -Web page : http://linuxcontainers.org -GIT location : git://github.com/lxc/lxc +Committers : Daniel Lezcano (inactive), Serge Hallyn, Stéphane Graber and Dwight Engen +Mail patches to : lxc-devel@lists.linuxcontainers.org +Send pull requests at : https://github.com/lxc/lxc +Mailing lists : lxc-devel@lists.linuxcontainers.org, lxc-users@lists.linuxcontainers.org +Web page : https://linuxcontainers.org/lxc +GIT location : git://github.com/lxc/lxc diff -Nru lxc-1.0.7/README lxc-1.0.8/README --- lxc-1.0.7/README 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/README 2015-11-09 22:49:15.000000000 +0000 @@ -9,7 +9,7 @@ The linux containers, lxc, aims to use these new functionalities to pro- vide a userspace container object which provides full resource isolation - and resource control for an applications or a system. + and resource control for an application or a system. The first objective of this project is to make the life easier for the ker- nel developers involved in the containers project and especially to con- diff -Nru lxc-1.0.7/src/config.h.in lxc-1.0.8/src/config.h.in --- lxc-1.0.7/src/config.h.in 2014-12-05 20:51:16.000000000 +0000 +++ lxc-1.0.8/src/config.h.in 2015-11-09 22:49:19.000000000 +0000 @@ -6,6 +6,9 @@ /* Have cgmanager_get_pid_cgroup_abs_sync */ #undef HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC +/* Have cgmanager_list_controllers */ +#undef HAVE_CGMANAGER_LIST_CONTROLLERS + /* Define to 1 if you have the `confstr' function. */ #undef HAVE_CONFSTR diff -Nru lxc-1.0.7/src/lua-lxc/core.c lxc-1.0.8/src/lua-lxc/core.c --- lxc-1.0.7/src/lua-lxc/core.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lua-lxc/core.c 2015-11-09 22:49:15.000000000 +0000 @@ -38,6 +38,12 @@ #define luaL_checkunsigned(L,n) luaL_checknumber(L,n) #endif +#if LUA_VERSION_NUM >= 503 +#ifndef luaL_checkunsigned +#define luaL_checkunsigned(L,n) ((lua_Unsigned)luaL_checkinteger(L,n)) +#endif +#endif + #ifdef NO_CHECK_UDATA #define checkudata(L,i,tname) lua_touserdata(L, i) #else diff -Nru lxc-1.0.7/src/lua-lxc/lxc.lua lxc-1.0.8/src/lua-lxc/lxc.lua --- lxc-1.0.7/src/lua-lxc/lxc.lua 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lua-lxc/lxc.lua 2015-11-09 22:49:15.000000000 +0000 @@ -271,6 +271,10 @@ local val local lines = self:get_cgroup_item(item) + if (lines == nil) then + return 0 + end + for line in lines:gmatch("[^\r\n]+") do if (string.find(line, match)) then local col diff -Nru lxc-1.0.7/src/lxc/attach.c lxc-1.0.8/src/lxc/attach.c --- lxc-1.0.7/src/lxc/attach.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/attach.c 2015-11-09 22:49:15.000000000 +0000 @@ -76,6 +76,82 @@ lxc_log_define(lxc_attach, lxc); +int lsm_set_label_at(int procfd, int on_exec, char* lsm_label) { + int labelfd = -1; + int ret = 0; + const char* name; + char* command = NULL; + + name = lsm_name(); + + if (strcmp(name, "nop") == 0) + goto out; + + if (strcmp(name, "none") == 0) + goto out; + + /* We don't support on-exec with AppArmor */ + if (strcmp(name, "AppArmor") == 0) + on_exec = 0; + + if (on_exec) { + labelfd = openat(procfd, "self/attr/exec", O_RDWR); + } + else { + labelfd = openat(procfd, "self/attr/current", O_RDWR); + } + + if (labelfd < 0) { + SYSERROR("Unable to open LSM label"); + ret = -1; + goto out; + } + + if (strcmp(name, "AppArmor") == 0) { + int size; + + command = malloc(strlen(lsm_label) + strlen("changeprofile ") + 1); + if (!command) { + SYSERROR("Failed to write apparmor profile"); + ret = -1; + goto out; + } + + size = sprintf(command, "changeprofile %s", lsm_label); + if (size < 0) { + SYSERROR("Failed to write apparmor profile"); + ret = -1; + goto out; + } + + if (write(labelfd, command, size + 1) < 0) { + SYSERROR("Unable to set LSM label"); + ret = -1; + goto out; + } + } + else if (strcmp(name, "SELinux") == 0) { + if (write(labelfd, lsm_label, strlen(lsm_label) + 1) < 0) { + SYSERROR("Unable to set LSM label"); + ret = -1; + goto out; + } + } + else { + ERROR("Unable to restore label for unknown LSM: %s", name); + ret = -1; + goto out; + } + +out: + free(command); + + if (labelfd != -1) + close(labelfd); + + return ret; +} + static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid) { struct lxc_proc_context_info *info = calloc(1, sizeof(*info)); @@ -108,8 +184,7 @@ } } - if (line) - free(line); + free(line); fclose(proc_file); if (!found) { @@ -129,8 +204,7 @@ static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx) { - if (ctx->lsm_label) - free(ctx->lsm_label); + free(ctx->lsm_label); if (ctx->container) lxc_container_put(ctx->container); free(ctx); @@ -444,8 +518,7 @@ } if (!token) continue; - if (result) - free(result); + free(result); result = strdup(token); /* sanity check that there are no fields after that */ @@ -573,12 +646,13 @@ struct lxc_proc_context_info* init_ctx; lxc_attach_exec_t exec_function; void* exec_payload; + int procfd; }; static int attach_child_main(void* data); /* help the optimizer along if it doesn't know that exit always exits */ -#define rexit(c) do { int __c = (c); exit(__c); return __c; } while(0) +#define rexit(c) do { int __c = (c); _exit(__c); return __c; } while(0) /* define default options if no options are supplied by the user */ static lxc_attach_options_t attach_static_default_options = LXC_ATTACH_OPTIONS_DEFAULT; @@ -625,6 +699,7 @@ char* cwd; char* new_cwd; int ipc_sockets[2]; + int procfd; signed long personality; if (!options) @@ -836,6 +911,13 @@ rexit(-1); } + procfd = open("/proc", O_DIRECTORY | O_RDONLY); + if (procfd < 0) { + SYSERROR("Unable to open /proc"); + shutdown(ipc_sockets[1], SHUT_RDWR); + rexit(-1); + } + /* attach now, create another subprocess later, since pid namespaces * only really affect the children of the current process */ @@ -863,7 +945,8 @@ .options = options, .init_ctx = init_ctx, .exec_function = exec_function, - .exec_payload = exec_payload + .exec_payload = exec_payload, + .procfd = procfd }; /* We use clone_parent here to make this subprocess a direct child of * the initial process. Then this intermediate process can exit and @@ -901,6 +984,7 @@ { struct attach_clone_payload* payload = (struct attach_clone_payload*)data; int ipc_socket = payload->ipc_socket; + int procfd = payload->procfd; lxc_attach_options_t* options = payload->options; struct lxc_proc_context_info* init_ctx = payload->init_ctx; #if HAVE_SYS_PERSONALITY_H @@ -987,6 +1071,21 @@ if (options->gid != (gid_t)-1) new_gid = options->gid; + /* setup the control tty */ + if (options->stdin_fd && isatty(options->stdin_fd)) { + if (setsid() < 0) { + SYSERROR("unable to setsid"); + shutdown(ipc_socket, SHUT_RDWR); + rexit(-1); + } + + if (ioctl(options->stdin_fd, TIOCSCTTY, (char *)NULL) < 0) { + SYSERROR("unable to TIOCSTTY"); + shutdown(ipc_socket, SHUT_RDWR); + rexit(-1); + } + } + /* try to set the uid/gid combination */ if ((new_gid != 0 || options->namespaces & CLONE_NEWUSER)) { if (setgid(new_gid) || setgroups(0, NULL)) { @@ -1026,12 +1125,11 @@ close(ipc_socket); /* set new apparmor profile/selinux context */ - if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM)) { + if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) { int on_exec; on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0; - ret = lsm_process_label_set(init_ctx->lsm_label, 0, on_exec); - if (ret < 0) { + if (lsm_set_label_at(procfd, on_exec, init_ctx->lsm_label) < 0) { rexit(-1); } } @@ -1082,6 +1180,9 @@ } } + /* we don't need proc anymore */ + close(procfd); + /* we're done, so we can now do whatever the user intended us to do */ rexit(payload->exec_function(payload->exec_payload)); } diff -Nru lxc-1.0.7/src/lxc/bdev.c lxc-1.0.8/src/lxc/bdev.c --- lxc-1.0.7/src/lxc/bdev.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/bdev.c 2015-11-09 22:49:15.000000000 +0000 @@ -62,11 +62,20 @@ #define LO_FLAGS_AUTOCLEAR 4 #endif +#ifndef LOOP_CTL_GET_FREE +#define LOOP_CTL_GET_FREE 0x4C82 +#endif + #define DEFAULT_FS_SIZE 1073741824 #define DEFAULT_FSTYPE "ext3" lxc_log_define(bdev, lxc); +struct ovl_rsync_data { + struct bdev *orig; + struct bdev *new; +}; + struct rsync_data_char { char *src; char *dest; @@ -93,7 +102,7 @@ s[l-2] = '/'; s[l-1] = '\0'; - execlp("rsync", "rsync", "-a", s, dest, (char *)NULL); + execlp("rsync", "rsync", "-aHX", "--delete", s, dest, (char *)NULL); exit(1); } @@ -223,12 +232,8 @@ // If the file is not a block device, we don't want mkfs to ask // us about whether to proceed. - close(0); - close(1); - close(2); - open("/dev/zero", O_RDONLY); - open("/dev/null", O_RDWR); - open("/dev/null", O_RDWR); + if (null_stdfds() < 0) + exit(1); execlp("mkfs", "mkfs", "-t", fstype, path, NULL); exit(1); } @@ -329,17 +334,17 @@ if (!f) exit(1); while (getline(&line, &linelen, f) != -1) { - sp1 = index(line, ' '); + sp1 = strchr(line, ' '); if (!sp1) exit(1); *sp1 = '\0'; if (strcmp(line, l)) continue; - sp2 = index(sp1+1, ' '); + sp2 = strchr(sp1+1, ' '); if (!sp2) exit(1); *sp2 = '\0'; - sp3 = index(sp2+1, ' '); + sp3 = strchr(sp2+1, ' '); if (!sp3) exit(1); *sp3 = '\0'; @@ -611,7 +616,7 @@ if (zfs_list_entry(opath, output, MAXPATHLEN)) { // zfsroot is output up to ' ' - if ((p = index(output, ' ')) == NULL) + if ((p = strchr(output, ' ')) == NULL) return -1; *p = '\0'; if ((p = strrchr(output, '/')) == NULL) @@ -731,7 +736,7 @@ } // zfs mount is output up to ' ' - if ((p = index(output, ' ')) == NULL) + if ((p = strchr(output, ' ')) == NULL) return -1; *p = '\0'; @@ -1261,7 +1266,7 @@ return 0; } -static bool is_btrfs_fs(const char *path) +bool is_btrfs_fs(const char *path) { int fd, ret; struct btrfs_ioctl_space_args sargs; @@ -1447,8 +1452,7 @@ close(fddst); if (fd != -1) close(fd); - if (newfull) - free(newfull); + free(newfull); return ret; } @@ -1540,7 +1544,7 @@ fd = open(newfull, O_RDONLY); if (fd < 0) { - ERROR("Error opening %s", newfull); + SYSERROR("Error opening %s", newfull); free(newfull); return -1; } @@ -1838,6 +1842,13 @@ return btrfs_do_destroy_subvol(path); } +bool btrfs_try_remove_subvol(const char *path) +{ + if (!btrfs_detect(path)) + return false; + return btrfs_recursive_destroy(path) == 0; +} + static int btrfs_destroy(struct bdev *orig) { return btrfs_recursive_destroy(orig->src); @@ -1874,7 +1885,7 @@ return 0; } -static int find_free_loopdev(int *retfd, char *namep) +static int find_free_loopdev_no_control(int *retfd, char *namep) { struct dirent dirent, *direntp; struct loop_info64 lo; @@ -1914,6 +1925,26 @@ 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; +} + static int loop_mount(struct bdev *bdev) { int lfd, ffd = -1, ret = -1; @@ -2147,6 +2178,28 @@ return 0; } +static char *overlayfs_name; +static char *detect_overlayfs_name(void) +{ + char *v = "overlayfs"; + char *line = NULL; + size_t len = 0; + FILE *f = fopen("/proc/filesystems", "r"); + if (!f) + return v; + + while (getline(&line, &len, f) != -1) { + if (strcmp(line, "nodev\toverlay\n") == 0) { + v = "overlay"; + break; + } + } + + fclose(f); + free(line); + return v; +} + // // XXXXXXX plain directory bind mount ops // @@ -2165,17 +2218,24 @@ if (!bdev->src || !bdev->dest) return -22; + if (!overlayfs_name) + overlayfs_name = detect_overlayfs_name(); + // separately mount it first // mount -t overlayfs -oupperdir=${upper},lowerdir=${lower} lower dest dup = alloca(strlen(bdev->src)+1); strcpy(dup, bdev->src); - if (!(lower = index(dup, ':'))) + if (!(lower = strchr(dup, ':'))) return -22; - if (!(upper = index(++lower, ':'))) + if (!(upper = strchr(++lower, ':'))) return -22; *upper = '\0'; upper++; + // if delta doesn't yet exist, create it + if (mkdir_p(upper, 0755) < 0 && errno != EEXIST) + return -22; + // overlayfs.v22 or higher needs workdir option // if upper is /var/lib/lxc/c2/delta0, // then workdir is /var/lib/lxc/c2/olwork @@ -2194,6 +2254,11 @@ return -22; } + if (mkdir_p(work, 0755) < 0 && errno != EEXIST) { + free(mntdata); + return -22; + } + // TODO We should check whether bdev->src is a blockdev, and if so // but for now, only support overlays of a basic directory @@ -2225,13 +2290,13 @@ } // mount without workdir option for overlayfs before v21 - ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL | mntflags, options); + ret = mount(lower, bdev->dest, overlayfs_name, MS_MGC_VAL | mntflags, options); if (ret < 0) { INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir", lower, bdev->dest, options); // retry with workdir option for overlayfs v22 and higher - ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL | mntflags, options_work); + ret = mount(lower, bdev->dest, overlayfs_name, MS_MGC_VAL | mntflags, options_work); if (ret < 0) SYSERROR("overlayfs: error mounting %s onto %s options %s", lower, bdev->dest, options_work); @@ -2280,6 +2345,75 @@ return rsync_delta(arg); } +static int ovl_rsync(struct ovl_rsync_data *data) +{ + int ret; + + if (setgid(0) < 0) { + ERROR("Failed to setgid to 0"); + return -1; + } + if (setgroups(0, NULL) < 0) + WARN("Failed to clear groups"); + if (setuid(0) < 0) { + ERROR("Failed to setuid to 0"); + return -1; + } + + if (unshare(CLONE_NEWNS) < 0) { + SYSERROR("Unable to unshare mounts ns"); + return -1; + } + if (detect_shared_rootfs()) { + if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { + SYSERROR("Failed to make / rslave"); + ERROR("Continuing..."); + } + } + if (overlayfs_mount(data->orig) < 0) { + ERROR("Failed mounting original container fs"); + return -1; + } + if (overlayfs_mount(data->new) < 0) { + ERROR("Failed mounting new container fs"); + return -1; + } + ret = do_rsync(data->orig->dest, data->new->dest); + + overlayfs_umount(data->new); + overlayfs_umount(data->orig); + + if (ret < 0) { + ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest); + return -1; + } + + return 0; +} + +static int ovl_rsync_wrapper(void *data) +{ + struct ovl_rsync_data *arg = data; + return ovl_rsync(arg); +} + +static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf) +{ + int ret = -1; + struct ovl_rsync_data rdata; + + rdata.orig = orig; + rdata.new = new; + if (am_unpriv()) + ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata); + else + ret = ovl_rsync(&rdata); + if (ret) + ERROR("copying overlayfs delta"); + + return ret; +} + static int overlayfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, const char *cname, const char *oldpath, const char *lxcpath, int snap, uint64_t newsize, struct lxc_conf *conf) @@ -2335,12 +2469,15 @@ // and needs to be on the same filesystem as upperdir, // so it's OK for it to be empty. work = malloc(lastslashidx + 7); - if (!work) + if (!work) { + free(delta); return -1; + } strncpy(work, new->dest, lastslashidx+1); strcpy(work+lastslashidx, "olwork"); if (mkdir(work, 0755) < 0) { SYSERROR("error: mkdir %s", work); + free(delta); free(work); return -1; } @@ -2369,8 +2506,8 @@ int len, ret, lastslashidx; if (!(osrc = strdup(orig->src))) return -22; - nsrc = index(osrc, ':') + 1; - if (nsrc != osrc + 10 || (odelta = index(nsrc, ':')) == NULL) { + nsrc = strchr(osrc, ':') + 1; + if (nsrc != osrc + 10 || (odelta = strchr(nsrc, ':')) == NULL) { free(osrc); return -22; } @@ -2412,19 +2549,6 @@ WARN("Failed to update ownership of %s", work); free(work); - struct rsync_data_char rdata; - rdata.src = odelta; - rdata.dest = ndelta; - if (am_unpriv()) - ret = userns_exec_1(conf, rsync_delta_wrapper, &rdata); - else - ret = rsync_delta(&rdata); - if (ret) { - free(osrc); - free(ndelta); - ERROR("copying overlayfs delta"); - return -1; - } len = strlen(nsrc) + strlen(ndelta) + 12; new->src = malloc(len); if (!new->src) { @@ -2437,6 +2561,8 @@ free(ndelta); if (ret < 0 || ret >= len) return -ENOMEM; + + return ovl_do_rsync(orig, new, conf); } else { ERROR("overlayfs clone of %s container is not yet supported", orig->type); @@ -2454,7 +2580,7 @@ if (strncmp(orig->src, "overlayfs:", 10) != 0) return -22; - upper = index(orig->src + 10, ':'); + upper = strchr(orig->src + 10, ':'); if (!upper) return -22; upper++; @@ -2536,12 +2662,12 @@ // static int aufs_mount(struct bdev *bdev) { - char *options, *dup, *lower, *upper, *rundir; + char *options, *dup, *lower, *upper; int len; unsigned long mntflags; char *mntdata; - char *runpath; int ret; + const char *xinopath = "/dev/shm/aufs.xino"; if (strcmp(bdev->type, "aufs")) return -22; @@ -2552,9 +2678,9 @@ // mount -t aufs -obr=${upper}=rw:${lower}=ro lower dest dup = alloca(strlen(bdev->src)+1); strcpy(dup, bdev->src); - if (!(lower = index(dup, ':'))) + if (!(lower = strchr(dup, ':'))) return -22; - if (!(upper = index(++lower, ':'))) + if (!(upper = strchr(++lower, ':'))) return -22; *upper = '\0'; upper++; @@ -2567,41 +2693,24 @@ // TODO We should check whether bdev->src is a blockdev, and if so // but for now, only support aufs of a basic directory - rundir = get_rundir(); - if (!rundir) - return -1; - - len = strlen(rundir) + strlen("/lxc") + 1; - runpath = alloca(len); - ret = snprintf(runpath, len, "%s/lxc", rundir); - if (ret < 0 || ret >= len) { - free(mntdata); - free(rundir); - return -1; - } - if (mkdir_p(runpath, 0755) < 0) { - free(mntdata); - free(rundir); - return -1; - } - // AUFS does not work on top of certain filesystems like (XFS or Btrfs) - // so add xino=RUNDIR/lxc/aufs.xino parameter to mount options + // so add xino=/dev/shm/aufs.xino parameter to mount options. + // The same xino option can be specified to multiple aufs mounts, and + // a xino file is not shared among multiple aufs mounts. // // see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html + // http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html if (mntdata) { - len = strlen(lower) + strlen(upper) + strlen(runpath) + strlen("br==rw:=ro,,xino=/aufs.xino") + strlen(mntdata) + 1; + len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,,xino=") + strlen(mntdata) + 1; options = alloca(len); - ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s/aufs.xino", upper, lower, mntdata, runpath); + ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s", upper, lower, mntdata, xinopath); } else { - len = strlen(lower) + strlen(upper) + strlen(runpath) + strlen("br==rw:=ro,xino=/aufs.xino") + 1; + len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,xino=") + 1; options = alloca(len); - ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s/aufs.xino", upper, lower, runpath); + ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s", upper, lower, xinopath); } - free(rundir); - if (ret < 0 || ret >= len) { free(mntdata); return -1; @@ -2644,6 +2753,9 @@ if (mkdir_p(new->dest, 0755) < 0) return -1; + if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0) + WARN("Failed to update ownership of %s", new->dest); + if (strcmp(orig->type, "dir") == 0) { char *delta, *lastslash; int ret, len, lastslashidx; @@ -2668,6 +2780,8 @@ free(delta); return -1; } + if (am_unpriv() && chown_mapped_root(delta, conf) < 0) + WARN("Failed to update ownership of %s", delta); // the src will be 'aufs:lowerdir:upperdir' len = strlen(delta) + strlen(orig->src) + 12; @@ -2689,8 +2803,8 @@ int len, ret; if (!(osrc = strdup(orig->src))) return -22; - nsrc = index(osrc, ':') + 1; - if (nsrc != osrc + 5 || (odelta = index(nsrc, ':')) == NULL) { + nsrc = strchr(osrc, ':') + 1; + if (nsrc != osrc + 5 || (odelta = strchr(nsrc, ':')) == NULL) { free(osrc); return -22; } @@ -2701,7 +2815,23 @@ free(osrc); return -ENOMEM; } - if (do_rsync(odelta, ndelta) < 0) { + if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) { + SYSERROR("error: mkdir %s", ndelta); + free(osrc); + free(ndelta); + return -1; + } + if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0) + WARN("Failed to update ownership of %s", ndelta); + + struct rsync_data_char rdata; + rdata.src = odelta; + rdata.dest = ndelta; + if (am_unpriv()) + ret = userns_exec_1(conf, rsync_delta_wrapper, &rdata); + else + ret = rsync_delta(&rdata); + if (ret) { free(osrc); free(ndelta); ERROR("copying aufs delta"); @@ -2736,7 +2866,7 @@ if (strncmp(orig->src, "aufs:", 5) != 0) return -22; - upper = index(orig->src + 5, ':'); + upper = strchr(orig->src + 5, ':'); if (!upper) return -22; upper++; @@ -2817,12 +2947,9 @@ void bdev_put(struct bdev *bdev) { - if (bdev->mntopts) - free(bdev->mntopts); - if (bdev->src) - free(bdev->src); - if (bdev->dest) - free(bdev->dest); + free(bdev->mntopts); + free(bdev->src); + free(bdev->dest); free(bdev); } @@ -2978,6 +3105,7 @@ // (unless snap && b->type == dir, in which case it will be // overlayfs -- which is also allowed) if (strcmp(b->type, "dir") == 0 || + strcmp(b->type, "aufs") == 0 || strcmp(b->type, "overlayfs") == 0 || strcmp(b->type, "btrfs") == 0 || strcmp(b->type, "loop") == 0) @@ -2987,8 +3115,11 @@ // unprivileged users can copy and snapshot dir, overlayfs, // and loop. In particular, not zfs, btrfs, or lvm. - if (strcmp(t, "dir") == 0 || strcmp(t, "overlayfs") == 0 || - strcmp(t, "btrfs") == 0 || strcmp(t, "loop") == 0) + if (strcmp(t, "dir") == 0 || + strcmp(t, "aufs") == 0 || + strcmp(t, "overlayfs") == 0 || + strcmp(t, "btrfs") == 0 || + strcmp(t, "loop") == 0) return true; return false; } @@ -3012,7 +3143,6 @@ const char *oldname = c0->name; const char *oldpath = c0->config_path; struct rsync_data data; - char *rootfs; /* if the container name doesn't show up in the rootfs path, then * we don't know how to come up with a new name @@ -3031,25 +3161,26 @@ if (!orig->dest) { int ret; - orig->dest = malloc(MAXPATHLEN); + size_t len; + struct stat sb; + + len = strlen(oldpath) + strlen(oldname) + strlen("/rootfs") + 2; + orig->dest = malloc(len); if (!orig->dest) { ERROR("out of memory"); bdev_put(orig); return NULL; } - rootfs = strrchr(orig->src, '/'); - if (!rootfs) { - ERROR("invalid rootfs path"); - bdev_put(orig); - return NULL; - } - rootfs++; - ret = snprintf(orig->dest, MAXPATHLEN, "%s/%s/%s", oldpath, oldname, rootfs); - if (ret < 0 || ret >= MAXPATHLEN) { + ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname); + if (ret < 0 || ret >= len) { ERROR("rootfs path too long"); bdev_put(orig); return NULL; } + ret = stat(orig->dest, &sb); + if (ret < 0 && errno == ENOENT) + if (mkdir_p(orig->dest, 0755) < 0) + WARN("Error creating '%s', continuing.", orig->dest); } /* @@ -3075,8 +3206,12 @@ *needs_rdep = 0; if (bdevtype && strcmp(orig->type, "dir") == 0 && (strcmp(bdevtype, "aufs") == 0 || - strcmp(bdevtype, "overlayfs") == 0)) + strcmp(bdevtype, "overlayfs") == 0)) { *needs_rdep = 1; + } else if (snap && strcmp(orig->type, "lvm") == 0 && + !lvm_is_thin_volume(orig->src)) { + *needs_rdep = 1; + } new = bdev_get(bdevtype ? bdevtype : orig->type); if (!new) { @@ -3199,7 +3334,7 @@ } // -B lvm,dir - if (index(type, ',') != NULL) { + if (strchr(type, ',') != NULL) { char *dup = alloca(strlen(type)+1), *saveptr = NULL, *token; strcpy(dup, type); for (token = strtok_r(dup, ",", &saveptr); token; @@ -3214,7 +3349,7 @@ char *overlay_getlower(char *p) { - char *p1 = index(p, ':'); + char *p1 = strchr(p, ':'); if (p1) *p1 = '\0'; return p; diff -Nru lxc-1.0.7/src/lxc/bdev.h lxc-1.0.8/src/lxc/bdev.h --- lxc-1.0.7/src/lxc/bdev.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/bdev.h 2015-11-09 22:49:15.000000000 +0000 @@ -31,6 +31,33 @@ #include "config.h" #include #include +#include + + +/* define constants if the kernel/glibc headers don't define them */ +#ifndef MS_DIRSYNC +#define MS_DIRSYNC 128 +#endif + +#ifndef MS_REC +#define MS_REC 16384 +#endif + +#ifndef MNT_DETACH +#define MNT_DETACH 2 +#endif + +#ifndef MS_SLAVE +#define MS_SLAVE (1<<19) +#endif + +#ifndef MS_RELATIME +#define MS_RELATIME (1 << 21) +#endif + +#ifndef MS_STRICTATIME +#define MS_STRICTATIME (1 << 24) +#endif struct bdev; @@ -96,30 +123,4 @@ void bdev_put(struct bdev *bdev); bool rootfs_is_blockdev(struct lxc_conf *conf); - -/* define constants if the kernel/glibc headers don't define them */ -#ifndef MS_DIRSYNC -#define MS_DIRSYNC 128 -#endif - -#ifndef MS_REC -#define MS_REC 16384 -#endif - -#ifndef MNT_DETACH -#define MNT_DETACH 2 -#endif - -#ifndef MS_SLAVE -#define MS_SLAVE (1<<19) -#endif - -#ifndef MS_RELATIME -#define MS_RELATIME (1 << 21) -#endif - -#ifndef MS_STRICTATIME -#define MS_STRICTATIME (1 << 24) -#endif - #endif diff -Nru lxc-1.0.7/src/lxc/caps.c lxc-1.0.8/src/lxc/caps.c --- lxc-1.0.7/src/lxc/caps.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/caps.c 2015-11-09 22:49:15.000000000 +0000 @@ -71,7 +71,7 @@ out: cap_free(caps); - return 0; + return 0; } int lxc_caps_up(void) @@ -121,7 +121,7 @@ out: cap_free(caps); - return 0; + return 0; } int lxc_caps_init(void) diff -Nru lxc-1.0.7/src/lxc/caps.h lxc-1.0.8/src/lxc/caps.h --- lxc-1.0.7/src/lxc/caps.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/caps.h 2015-11-09 22:49:15.000000000 +0000 @@ -33,17 +33,17 @@ extern int lxc_caps_last_cap(void); #else static inline int lxc_caps_down(void) { - return 0; + return 0; } static inline int lxc_caps_up(void) { - return 0; + return 0; } static inline int lxc_caps_init(void) { - return 0; + return 0; } static inline int lxc_caps_last_cap(void) { - return 0; + return 0; } #endif diff -Nru lxc-1.0.7/src/lxc/cgfs.c lxc-1.0.8/src/lxc/cgfs.c --- lxc-1.0.7/src/lxc/cgfs.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/cgfs.c 2015-11-09 22:49:15.000000000 +0000 @@ -1220,6 +1220,7 @@ info = find_info_for_subsystem(info, subsystem); if (!info) return NULL; + prune_init_scope(info->cgroup_path); return info->cgroup_path; } @@ -1280,7 +1281,7 @@ subsystem = alloca(strlen(filename) + 1); strcpy(subsystem, filename); - if ((p = index(subsystem, '.')) != NULL) + if ((p = strchr(subsystem, '.')) != NULL) *p = '\0'; path = lxc_cgroup_get_hierarchy_abs_path_data(subsystem, d); @@ -1298,7 +1299,7 @@ subsystem = alloca(strlen(filename) + 1); strcpy(subsystem, filename); - if ((p = index(subsystem, '.')) != NULL) + if ((p = strchr(subsystem, '.')) != NULL) *p = '\0'; path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath); @@ -1316,7 +1317,7 @@ subsystem = alloca(strlen(filename) + 1); strcpy(subsystem, filename); - if ((p = index(subsystem, '.')) != NULL) + if ((p = strchr(subsystem, '.')) != NULL) *p = '\0'; path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath); @@ -1363,7 +1364,10 @@ if (!path) return false; snprintf(path, bufsz, "%s/sys/fs/cgroup", root); - r = mount("cgroup_root", path, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "size=10240k,mode=755"); + r = safe_mount("cgroup_root", path, "tmpfs", + MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, + "size=10240k,mode=755", + root); if (r < 0) { SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container"); return false; @@ -1886,14 +1890,19 @@ static int do_setup_cgroup_limits(struct cgfs_data *d, struct lxc_list *cgroup_settings, bool do_devices) { - struct lxc_list *iterator; + struct lxc_list *iterator, *sorted_cgroup_settings, *next; struct lxc_cgroup *cg; int ret = -1; if (lxc_list_empty(cgroup_settings)) return 0; - lxc_list_for_each(iterator, cgroup_settings) { + sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings); + if (!sorted_cgroup_settings) { + return -1; + } + + lxc_list_for_each(iterator, sorted_cgroup_settings) { cg = iterator->elem; if (do_devices == !strncmp("devices", cg->subsystem, 7)) { @@ -1916,6 +1925,11 @@ ret = 0; INFO("cgroup has been setup"); out: + lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) { + lxc_list_del(iterator); + free(iterator); + } + free(sorted_cgroup_settings); return ret; } @@ -2187,8 +2201,7 @@ SYSERROR("failed writing %s", childfile); out: - if (parentfile) - free(parentfile); + free(parentfile); free(childfile); return ok; } @@ -2248,12 +2261,9 @@ if (!d) return; - if (d->name) - free(d->name); - if (d->info) - lxc_cgroup_process_info_free_and_remove(d->info); - if (d->meta) - lxc_cgroup_put_meta(d->meta); + free(d->name); + lxc_cgroup_process_info_free_and_remove(d->info); + lxc_cgroup_put_meta(d->meta); free(d); } diff -Nru lxc-1.0.7/src/lxc/cgmanager.c lxc-1.0.8/src/lxc/cgmanager.c --- lxc-1.0.7/src/lxc/cgmanager.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/cgmanager.c 2015-11-09 22:49:15.000000000 +0000 @@ -39,6 +39,7 @@ #include #include #include +#include #include "error.h" #include "commands.h" @@ -121,13 +122,13 @@ static void cgm_dbus_disconnect(void) { - if (cgroup_manager) { - dbus_connection_flush(cgroup_manager->connection); - dbus_connection_close(cgroup_manager->connection); - nih_free(cgroup_manager); - } - cgroup_manager = NULL; - cgm_unlock(); + if (cgroup_manager) { + dbus_connection_flush(cgroup_manager->connection); + dbus_connection_close(cgroup_manager->connection); + nih_free(cgroup_manager); + } + cgroup_manager = NULL; + cgm_unlock(); } #define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock" @@ -246,11 +247,12 @@ } if (strcmp(prevpath, colon) != 0) { cgm_all_controllers_same = false; - fclose(f); - return; + break; } } + fclose(f); + free(line); } static int send_creds(int sock, int rpid, int ruid, int rgid) @@ -346,6 +348,7 @@ { int sv[2] = {-1, -1}, optval = 1, ret = -1; char buf[1]; + struct pollfd fds; if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) { SYSERROR("Error creating socketpair"); @@ -369,10 +372,10 @@ } /* now send credentials */ - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(sv[0], &rfds); - if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) { + fds.fd = sv[0]; + fds.events = POLLIN; + fds.revents = 0; + if (poll(&fds, 1, -1) <= 0) { ERROR("Error getting go-ahead from server: %s", strerror(errno)); goto out; } @@ -384,9 +387,10 @@ SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__); goto out; } - FD_ZERO(&rfds); - FD_SET(sv[0], &rfds); - if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) { + fds.fd = sv[0]; + fds.events = POLLIN; + fds.revents = 0; + if (poll(&fds, 1, -1) <= 0) { ERROR("Error getting go-ahead from server: %s", strerror(errno)); goto out; } @@ -398,9 +402,10 @@ SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__); goto out; } - FD_ZERO(&rfds); - FD_SET(sv[0], &rfds); - if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) { + fds.fd = sv[0]; + fds.events = POLLIN; + fds.revents = 0; + if (poll(&fds, 1, -1) <= 0) { ERROR("Error getting go-ahead from server: %s", strerror(errno)); goto out; } @@ -577,8 +582,7 @@ cgm_remove_cgroup(slist[i], d->cgroup_path); free(d->name); - if (d->cgroup_path) - free(d->cgroup_path); + free(d->cgroup_path); free(d); cgm_dbus_disconnect(); } @@ -763,6 +767,7 @@ nerr = nih_error_get(); nih_free(nerr); } + prune_init_scope(cgroup); return cgroup; } @@ -805,6 +810,32 @@ return pids_len; } +#if HAVE_CGMANAGER_LIST_CONTROLLERS +static bool lxc_list_controllers(char ***list) +{ + if (!cgm_dbus_connect()) { + ERROR("Error connecting to cgroup manager"); + return false; + } + if (cgmanager_list_controllers_sync(NULL, cgroup_manager, list) != 0) { + NihError *nerr; + nerr = nih_error_get(); + ERROR("call to cgmanager_list_controllers_sync failed: %s", nerr->message); + nih_free(nerr); + cgm_dbus_disconnect(); + return false; + } + + cgm_dbus_disconnect(); + return true; +} +#else +static bool lxc_list_controllers(char ***list) +{ + return false; +} +#endif + static inline void free_abs_cgroup(char *cgroup) { if (!cgroup) @@ -1080,11 +1111,82 @@ } } +static bool in_comma_list(const char *inword, const char *cgroup_use) +{ + char *e; + size_t inlen = strlen(inword), len; + + do { + e = strchr(cgroup_use, ','); + len = e ? e - cgroup_use : strlen(cgroup_use); + if (len == inlen && strncmp(inword, cgroup_use, len) == 0) + return true; + cgroup_use = e + 1; + } while (e); + + return false; +} + +static bool in_subsystem_list(const char *c) +{ + int i; + + for (i = 0; i < nr_subsystems; i++) { + if (strcmp(c, subsystems[i]) == 0) + return true; + } + + return false; +} + +/* + * If /etc/lxc/lxc.conf specifies lxc.cgroup.use = "freezer,memory", + * then clear out any other subsystems, and make sure that freezer + * and memory are both enabled + */ +static bool verify_and_prune(const char *cgroup_use) +{ + const char *p; + char *e; + int i, j; + + for (p = cgroup_use; p && *p; p = e + 1) { + e = strchr(p, ','); + if (e) + *e = '\0'; + + if (!in_subsystem_list(p)) { + ERROR("Controller %s required by lxc.cgroup.use but not available\n", p); + return false; + } + + if (e) + *e = ','; + if (!e) + break; + } + + for (i = 0; i < nr_subsystems;) { + if (in_comma_list(subsystems[i], cgroup_use)) { + i++; + continue; + } + free(subsystems[i]); + for (j = i; j < nr_subsystems-1; j++) + subsystems[j] = subsystems[j+1]; + subsystems[nr_subsystems-1] = NULL; + nr_subsystems--; + } + + return true; +} + static bool collect_subsytems(void) { char *line = NULL; + nih_local char **cgm_subsys_list = NULL; size_t sz = 0; - FILE *f; + FILE *f = NULL; if (subsystems) // already initialized return true; @@ -1095,6 +1197,20 @@ subsystems_inone[0] = "all"; subsystems_inone[1] = NULL; + if (lxc_list_controllers(&cgm_subsys_list)) { + while (cgm_subsys_list[nr_subsystems]) { + char **tmp = NIH_MUST( realloc(subsystems, + (nr_subsystems+2)*sizeof(char *)) ); + tmp[nr_subsystems] = NIH_MUST( + strdup(cgm_subsys_list[nr_subsystems++]) ); + subsystems = tmp; + } + if (nr_subsystems) + subsystems[nr_subsystems] = NULL; + goto collected; + } + + INFO("cgmanager_list_controllers failed, falling back to /proc/self/cgroups"); f = fopen_cloexec("/proc/self/cgroup", "r"); if (!f) { f = fopen_cloexec("/proc/1/cgroup", "r"); @@ -1134,18 +1250,37 @@ } } fclose(f); + f = NULL; free(line); + line = NULL; + +collected: if (!nr_subsystems) { ERROR("No cgroup subsystems found"); return false; } + /* make sure that cgroup.use can be and is honored */ + const char *cgroup_use = lxc_global_config_value("lxc.cgroup.use"); + if (!cgroup_use && errno != 0) + goto out_good; + if (cgroup_use) { + if (!verify_and_prune(cgroup_use)) { + free_subsystems(); + return false; + } + subsystems_inone[0] = NIH_MUST( strdup(cgroup_use) ); + cgm_all_controllers_same = false; + } + +out_good: return true; out_free: free(line); - fclose(f); + if (f) + fclose(f); free_subsystems(); return false; } @@ -1205,7 +1340,7 @@ static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices) { struct cgm_data *d = hdata; - struct lxc_list *iterator; + struct lxc_list *iterator, *sorted_cgroup_settings, *next; struct lxc_cgroup *cg; bool ret = false; @@ -1220,7 +1355,12 @@ return false; } - lxc_list_for_each(iterator, cgroup_settings) { + sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings); + if (!sorted_cgroup_settings) { + return false; + } + + lxc_list_for_each(iterator, sorted_cgroup_settings) { char controller[100], *p; cg = iterator->elem; if (do_devices != !strncmp("devices", cg->subsystem, 7)) @@ -1248,6 +1388,11 @@ ret = true; INFO("cgroup limits have been setup"); out: + lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) { + lxc_list_del(iterator); + free(iterator); + } + free(sorted_cgroup_settings); cgm_dbus_disconnect(); return ret; } @@ -1288,16 +1433,8 @@ return false; } - check_supports_multiple_controllers(pid); - - if (cgm_all_controllers_same) - slist = subsystems_inone; - for (i = 0; slist[i]; i++) { - if (slist == subsystems_inone) - cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]); - else - cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]); + cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]); if (!cgroup) { ERROR("Failed to get cgroup for controller %s", slist[i]); cgm_dbus_disconnect(); @@ -1332,7 +1469,7 @@ } /* mount a tmpfs there so we can create subdirs */ - if (mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755")) { + if (safe_mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755", root)) { SYSERROR("Failed to mount tmpfs at %s", cgpath); return false; } @@ -1343,7 +1480,7 @@ return false; } - if (mount(dirname, cgpath, "none", MS_BIND, 0)) { + if (safe_mount(dirname, cgpath, "none", MS_BIND, 0, root)) { SYSERROR("Failed to bind mount %s to %s", dirname, cgpath); return false; } diff -Nru lxc-1.0.7/src/lxc/cgroup.c lxc-1.0.8/src/lxc/cgroup.c --- lxc-1.0.7/src/lxc/cgroup.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/cgroup.c 2015-11-09 22:49:15.000000000 +0000 @@ -173,3 +173,17 @@ if (ops && ops->disconnect) ops->disconnect(); } + +#define INIT_SCOPE "/init.scope" +void prune_init_scope(char *cg) +{ + char *point = cg + strlen(cg) - strlen(INIT_SCOPE); + if (point < cg) + return; + if (strcmp(point, INIT_SCOPE) == 0) { + if (point == cg) + *(point+1) = '\0'; + else + *point = '\0'; + } +} diff -Nru lxc-1.0.7/src/lxc/cgroup.h lxc-1.0.8/src/lxc/cgroup.h --- lxc-1.0.7/src/lxc/cgroup.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/cgroup.h 2015-11-09 22:49:15.000000000 +0000 @@ -67,4 +67,6 @@ extern bool cgroup_unfreeze(struct lxc_handler *handler); extern void cgroup_disconnect(void); +extern void prune_init_scope(char *cg); + #endif diff -Nru lxc-1.0.7/src/lxc/commands.c lxc-1.0.8/src/lxc/commands.c --- lxc-1.0.7/src/lxc/commands.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/commands.c 2015-11-09 22:49:15.000000000 +0000 @@ -279,7 +279,12 @@ *stopped = 0; - len = sizeof(path)-1; + /* -2 here because this is an abstract unix socket so it needs a + * leading \0, and we null terminate, so it needs a trailing \0. + * Although null termination isn't required by the API, we do it anyway + * because we print the sockname out sometimes. + */ + len = sizeof(path)-2; if (fill_sock_name(offset, len, name, lxcpath, hashed_sock_name)) return -1; @@ -972,7 +977,12 @@ char *offset = &path[1]; int len; - len = sizeof(path)-1; + /* -2 here because this is an abstract unix socket so it needs a + * leading \0, and we null terminate, so it needs a trailing \0. + * Although null termination isn't required by the API, we do it anyway + * because we print the sockname out sometimes. + */ + len = sizeof(path)-2; if (fill_sock_name(offset, len, name, lxcpath, NULL)) return -1; diff -Nru lxc-1.0.7/src/lxc/conf.c lxc-1.0.8/src/lxc/conf.c --- lxc-1.0.7/src/lxc/conf.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/conf.c 2015-11-09 22:49:15.000000000 +0000 @@ -275,6 +275,9 @@ { "sys_tty_config", CAP_SYS_TTY_CONFIG }, { "mknod", CAP_MKNOD }, { "lease", CAP_LEASE }, +#ifdef CAP_AUDIT_READ + { "audit_read", CAP_AUDIT_READ }, +#endif #ifdef CAP_AUDIT_WRITE { "audit_write", CAP_AUDIT_WRITE }, #endif @@ -290,6 +293,9 @@ #ifdef CAP_WAKE_ALARM { "wake_alarm", CAP_WAKE_ALARM }, #endif +#ifdef CAP_BLOCK_SUSPEND + { "block_suspend", CAP_BLOCK_SUSPEND }, +#endif }; #else static struct caps_opt caps_opt[] = {}; @@ -735,7 +741,7 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_handler *handler) { int r; - size_t i; + int i; static struct { int match_mask; int match_flag; @@ -776,28 +782,34 @@ if (default_mounts[i].source) { /* will act like strdup if %r is not present */ - source = lxc_string_replace("%r", conf->rootfs.mount, default_mounts[i].source); + source = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].source); if (!source) { SYSERROR("memory allocation error"); return -1; } } - if (default_mounts[i].destination) { - /* will act like strdup if %r is not present */ - destination = lxc_string_replace("%r", conf->rootfs.mount, default_mounts[i].destination); - if (!destination) { - saved_errno = errno; - SYSERROR("memory allocation error"); - free(source); - errno = saved_errno; - return -1; - } + if (!default_mounts[i].destination) { + ERROR("BUG: auto mounts destination %d was NULL", i); + return -1; + } + /* will act like strdup if %r is not present */ + destination = lxc_string_replace("%r", conf->rootfs.path ? conf->rootfs.mount : "", default_mounts[i].destination); + if (!destination) { + saved_errno = errno; + SYSERROR("memory allocation error"); + free(source); + errno = saved_errno; + return -1; } mflags = add_required_remount_flags(source, destination, default_mounts[i].flags); - r = mount(source, destination, default_mounts[i].fstype, mflags, default_mounts[i].options); + r = safe_mount(source, destination, default_mounts[i].fstype, mflags, default_mounts[i].options, conf->rootfs.path ? conf->rootfs.mount : NULL); saved_errno = errno; - if (r < 0) + if (r < 0 && errno == ENOENT) { + INFO("Mount source or target for %s on %s doesn't exist. Skipping.", source, destination); + r = 0; + } + else if (r < 0) SYSERROR("error mounting %s on %s flags %lu", source, destination, mflags); free(source); free(destination); @@ -834,7 +846,7 @@ } } - if (!cgroup_mount(conf->rootfs.mount, handler, cg_flags)) { + if (!cgroup_mount(conf->rootfs.path ? conf->rootfs.mount : "", handler, cg_flags)) { SYSERROR("error mounting /sys/fs/cgroup"); return -1; } @@ -923,7 +935,7 @@ for (i = 0; i < sizeof(dev_symlinks) / sizeof(dev_symlinks[0]); i++) { const struct dev_symlinks *d = &dev_symlinks[i]; - ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount, d->name); + ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->path ? rootfs->mount : "", d->name); if (ret < 0 || ret >= MAXPATHLEN) return -1; @@ -989,7 +1001,8 @@ return -1; } - if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) { + if (safe_mount(pty_info->name, lxcpath, "none", MS_BIND, 0, + rootfs->mount)) { WARN("failed to mount '%s'->'%s'", pty_info->name, path); continue; @@ -1016,7 +1029,8 @@ close(ret); } } - if (mount(pty_info->name, path, "none", MS_BIND, 0)) { + if (safe_mount(pty_info->name, path, "none", MS_BIND, 0, + rootfs->mount)) { WARN("failed to mount '%s'->'%s'", pty_info->name, path); continue; @@ -1407,7 +1421,7 @@ * Do we want to add options for max size of /dev and a file to * specify which devices to create? */ -static int mount_autodev(const char *name, char *root, const char *lxcpath) +static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, const char *lxcpath) { int ret; struct stat s; @@ -1415,13 +1429,13 @@ char host_path[MAXPATHLEN]; char devtmpfs_path[MAXPATHLEN]; - INFO("Mounting /dev under %s", root); + INFO("Mounting container /dev"); ret = snprintf(host_path, MAXPATHLEN, "%s/%s/rootfs.dev", lxcpath, name); if (ret < 0 || ret > MAXPATHLEN) return -1; - ret = snprintf(path, MAXPATHLEN, "%s/dev", root); + ret = snprintf(path, MAXPATHLEN, "%s/dev", rootfs->path ? rootfs->mount : ""); if (ret < 0 || ret > MAXPATHLEN) return -1; @@ -1442,23 +1456,23 @@ SYSERROR("WARNING: Failed to create symlink '%s'->'%s'", host_path, devtmpfs_path); } DEBUG("Bind mounting %s to %s", devtmpfs_path , path ); - ret = mount(devtmpfs_path, path, NULL, MS_BIND, 0 ); + ret = safe_mount(devtmpfs_path, path, NULL, MS_BIND, 0, rootfs->path ? rootfs->mount : NULL ); } else { /* Only mount a tmpfs on here if we don't already a mount */ if ( ! mount_check_fs( host_path, NULL ) ) { DEBUG("Mounting tmpfs to %s", host_path ); - ret = mount("none", path, "tmpfs", 0, "size=100000,mode=755"); + ret = safe_mount("none", path, "tmpfs", 0, "size=100000,mode=755", rootfs->path ? rootfs->mount : NULL); } else { /* This allows someone to manually set up a mount */ DEBUG("Bind mounting %s to %s", host_path, path ); - ret = mount(host_path , path, NULL, MS_BIND, 0 ); + ret = safe_mount(host_path , path, NULL, MS_BIND, 0, rootfs->path ? rootfs->mount : NULL ); } } if (ret) { - SYSERROR("Failed to mount /dev at %s", root); + SYSERROR("Failed to mount container /dev"); return -1; } - ret = snprintf(path, MAXPATHLEN, "%s/dev/pts", root); + ret = snprintf(path, MAXPATHLEN, "%s/dev/pts", rootfs->path ? rootfs->mount : ""); if (ret < 0 || ret >= MAXPATHLEN) return -1; /* @@ -1473,7 +1487,7 @@ } } - INFO("Mounted /dev under %s", root); + INFO("Mounted container /dev"); return 0; } @@ -1494,26 +1508,26 @@ { "console", S_IFCHR | S_IRUSR | S_IWUSR, 5, 1 }, }; -static int setup_autodev(const char *root) +static int setup_autodev(const struct lxc_rootfs *rootfs) { int ret; char path[MAXPATHLEN]; int i; mode_t cmask; - INFO("Creating initial consoles under %s/dev", root); + INFO("Creating initial consoles under container /dev"); - ret = snprintf(path, MAXPATHLEN, "%s/dev", root); + ret = snprintf(path, MAXPATHLEN, "%s/dev", rootfs->path ? rootfs->mount : ""); if (ret < 0 || ret >= MAXPATHLEN) { ERROR("Error calculating container /dev location"); return -1; } - INFO("Populating /dev under %s", root); + 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]; - ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", root, d->name); + 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)); @@ -1524,7 +1538,7 @@ } umask(cmask); - INFO("Populated /dev under %s", root); + INFO("Populated container /dev"); return 0; } @@ -1646,7 +1660,7 @@ return -1; } - if (mount(".", NULL, NULL, MS_REC | MS_PRIVATE, NULL)) { + if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) { SYSERROR("Failed to make . rprivate"); return -1; } @@ -1695,10 +1709,8 @@ break; } - if (umount2("./proc", MNT_DETACH)) { - SYSERROR("Unable to umount /proc"); - return -1; - } + /* This also can be skipped if a container uses unserns */ + umount2("./proc", MNT_DETACH); /* It is weird, but chdir("..") moves us in a new root */ if (chdir("..") == -1) { @@ -1828,7 +1840,7 @@ return -1; } - if (mount(console->name, path, "none", MS_BIND, 0)) { + if (safe_mount(console->name, path, "none", MS_BIND, 0, rootfs->mount)) { ERROR("failed to mount '%s' on '%s'", console->name, path); return -1; } @@ -1883,7 +1895,7 @@ return 0; } - if (mount(console->name, lxcpath, "none", MS_BIND, 0)) { + if (safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs->mount)) { ERROR("failed to mount '%s' on '%s'", console->name, lxcpath); return -1; } @@ -2033,13 +2045,13 @@ static int mount_entry(const char *fsname, const char *target, const char *fstype, unsigned long mountflags, - const char *data, int optional) + const char *data, int optional, const char *rootfs) { #ifdef HAVE_STATVFS struct statvfs sb; #endif - if (mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data)) { + if (safe_mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data, rootfs)) { if (optional) { INFO("failed to mount '%s' on '%s' (optional): %s", fsname, target, strerror(errno)); @@ -2133,36 +2145,223 @@ } } -static inline int mount_entry_on_systemfs(struct mntent *mntent) +static char *ovl_get_rootfs_dir(const char *rootfs_path, size_t *rootfslen) { - unsigned long mntflags; - char *mntdata; - int ret; + char *rootfsdir = NULL; + char *s1 = NULL; + char *s2 = NULL; + char *s3 = NULL; + + if (!rootfs_path || !rootfslen) + return NULL; + + s1 = strdup(rootfs_path); + if (!s1) + return NULL; + + if ((s2 = strstr(s1, ":/"))) { + s2 = s2 + 1; + if ((s3 = strstr(s2, ":/"))) + *s3 = '\0'; + rootfsdir = strdup(s2); + if (!rootfsdir) { + free(s1); + return NULL; + } + } + + if (!rootfsdir) + rootfsdir = s1; + else + free(s1); + + *rootfslen = strlen(rootfsdir); + + return rootfsdir; +} + +static int mount_entry_create_overlay_dirs(const struct mntent *mntent, + const struct lxc_rootfs *rootfs, + const char *lxc_name, + const char *lxc_path) +{ + char lxcpath[MAXPATHLEN]; + char *rootfsdir = NULL; + char *upperdir = NULL; + char *workdir = NULL; + char **opts = NULL; + int fret = -1; + int ret = 0; + size_t arrlen = 0; + size_t dirlen = 0; + size_t i; + size_t len = 0; + size_t rootfslen = 0; + + if (!rootfs->path || !lxc_name || !lxc_path) + goto err; + + opts = lxc_string_split(mntent->mnt_opts, ','); + if (opts) + arrlen = lxc_array_len((void **)opts); + else + goto err; + + for (i = 0; i < arrlen; i++) { + if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir=")))) + upperdir = opts[i] + len; + else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir=")))) + workdir = opts[i] + len; + } + + ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name); + if (ret < 0 || ret >= MAXPATHLEN) + goto err; + + rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen); + if (!rootfsdir) + goto err; + + dirlen = strlen(lxcpath); + + /* We neither allow users to create upperdirs and workdirs outside the + * containerdir nor inside the rootfs. The latter might be debatable. */ + if (upperdir) + if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0)) + if (mkdir_p(upperdir, 0755) < 0) { + WARN("Failed to create upperdir"); + } + + if (workdir) + if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0)) + if (mkdir_p(workdir, 0755) < 0) { + WARN("Failed to create workdir"); + } + + fret = 0; + +err: + free(rootfsdir); + lxc_free_array((void **)opts, free); + return fret; +} + +static int mount_entry_create_aufs_dirs(const struct mntent *mntent, + const struct lxc_rootfs *rootfs, + const char *lxc_name, + const char *lxc_path) +{ + char lxcpath[MAXPATHLEN]; + char *rootfsdir = NULL; + char *scratch = NULL; + char *tmp = NULL; + char *upperdir = NULL; + char **opts = NULL; + int fret = -1; + int ret = 0; + size_t arrlen = 0; + size_t i; + size_t len = 0; + size_t rootfslen = 0; + + if (!rootfs->path || !lxc_name || !lxc_path) + goto err; + + opts = lxc_string_split(mntent->mnt_opts, ','); + if (opts) + arrlen = lxc_array_len((void **)opts); + else + goto err; + + for (i = 0; i < arrlen; i++) { + if (strstr(opts[i], "br=") && (strlen(opts[i]) > (len = strlen("br=")))) + tmp = opts[i] + len; + } + if (!tmp) + goto err; + + upperdir = strtok_r(tmp, ":=", &scratch); + if (!upperdir) + goto err; + + ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name); + if (ret < 0 || ret >= MAXPATHLEN) + goto err; + + rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen); + if (!rootfsdir) + goto err; + + /* We neither allow users to create upperdirs outside the containerdir + * nor inside the rootfs. The latter might be debatable. */ + if ((strncmp(upperdir, lxcpath, strlen(lxcpath)) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0)) + if (mkdir_p(upperdir, 0755) < 0) { + WARN("Failed to create upperdir"); + } + + fret = 0; + +err: + free(rootfsdir); + lxc_free_array((void **)opts, free); + return fret; +} + + +static int mount_entry_create_dir_file(const struct mntent *mntent, + const char* path, const struct lxc_rootfs *rootfs, + const char *lxc_name, const char *lxc_path) +{ + char *pathdirname = NULL; + int ret = 0; FILE *pathfile = NULL; - char* pathdirname = NULL; - bool optional = hasmntopt(mntent, "optional") != NULL; + + if (strncmp(mntent->mnt_type, "overlay", 7) == 0) { + if (mount_entry_create_overlay_dirs(mntent, rootfs, lxc_name, lxc_path) < 0) + return -1; + } else if (strncmp(mntent->mnt_type, "aufs", 4) == 0) { + if (mount_entry_create_aufs_dirs(mntent, rootfs, lxc_name, lxc_path) < 0) + return -1; + } if (hasmntopt(mntent, "create=dir")) { - if (mkdir_p(mntent->mnt_dir, 0755) < 0) { - WARN("Failed to create mount target '%s'", mntent->mnt_dir); + if (mkdir_p(path, 0755) < 0) { + WARN("Failed to create mount target '%s'", path); ret = -1; } } - if (hasmntopt(mntent, "create=file") && access(mntent->mnt_dir, F_OK)) { - pathdirname = strdup(mntent->mnt_dir); + if (hasmntopt(mntent, "create=file") && access(path, F_OK)) { + pathdirname = strdup(path); pathdirname = dirname(pathdirname); if (mkdir_p(pathdirname, 0755) < 0) { WARN("Failed to create target directory"); } - pathfile = fopen(mntent->mnt_dir, "wb"); + pathfile = fopen(path, "wb"); if (!pathfile) { - WARN("Failed to create mount target '%s'", mntent->mnt_dir); + WARN("Failed to create mount target '%s'", path); ret = -1; - } - else + } else { fclose(pathfile); + } } + free(pathdirname); + return ret; +} + +static inline int mount_entry_on_generic(struct mntent *mntent, + const char* path, const struct lxc_rootfs *rootfs, + const char *lxc_name, const char *lxc_path) +{ + unsigned long mntflags; + char *mntdata; + int ret; + bool optional = hasmntopt(mntent, "optional") != NULL; + + ret = mount_entry_create_dir_file(mntent, path, rootfs, lxc_name, lxc_path); + + if (ret < 0) + return optional ? 0 : -1; cull_mntent_opt(mntent); @@ -2171,28 +2370,28 @@ return -1; } - ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir, - mntent->mnt_type, mntflags, mntdata, optional); + ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags, + mntdata, optional, + rootfs->path ? rootfs->mount : NULL); - free(pathdirname); free(mntdata); - return ret; } +static inline int mount_entry_on_systemfs(struct mntent *mntent) +{ + return mount_entry_on_generic(mntent, mntent->mnt_dir, NULL, NULL, NULL); +} + static int mount_entry_on_absolute_rootfs(struct mntent *mntent, const struct lxc_rootfs *rootfs, - const char *lxc_name) + const char *lxc_name, + const char *lxc_path) { char *aux; char path[MAXPATHLEN]; - unsigned long mntflags; - char *mntdata; int r, ret = 0, offset; const char *lxcpath; - FILE *pathfile = NULL; - char *pathdirname = NULL; - bool optional = hasmntopt(mntent, "optional") != NULL; lxcpath = lxc_global_config_value("lxc.lxcpath"); if (!lxcpath) { @@ -2216,7 +2415,7 @@ aux = strstr(mntent->mnt_dir, rootfs->path); if (!aux) { WARN("ignoring mount point '%s'", mntent->mnt_dir); - goto out; + return ret; } offset = strlen(rootfs->path); @@ -2226,105 +2425,32 @@ aux + offset); if (r < 0 || r >= MAXPATHLEN) { WARN("pathnme too long for '%s'", mntent->mnt_dir); - ret = -1; - goto out; - } - - if (hasmntopt(mntent, "create=dir")) { - if (mkdir_p(path, 0755) < 0) { - WARN("Failed to create mount target '%s'", path); - ret = -1; - } - } - - if (hasmntopt(mntent, "create=file") && access(path, F_OK)) { - pathdirname = strdup(path); - pathdirname = dirname(pathdirname); - if (mkdir_p(pathdirname, 0755) < 0) { - WARN("Failed to create target directory"); - } - pathfile = fopen(path, "wb"); - if (!pathfile) { - WARN("Failed to create mount target '%s'", path); - ret = -1; - } - else - fclose(pathfile); - } - cull_mntent_opt(mntent); - - if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { - free(mntdata); return -1; } - ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, - mntflags, mntdata, optional); - - free(mntdata); - -out: - free(pathdirname); - return ret; + return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path); } static int mount_entry_on_relative_rootfs(struct mntent *mntent, - const char *rootfs) + const struct lxc_rootfs *rootfs, + const char *lxc_name, + const char *lxc_path) { char path[MAXPATHLEN]; - unsigned long mntflags; - char *mntdata; int ret; - FILE *pathfile = NULL; - char *pathdirname = NULL; - bool optional = hasmntopt(mntent, "optional") != NULL; /* relative to root mount point */ - ret = snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir); + ret = snprintf(path, sizeof(path), "%s/%s", rootfs->mount, mntent->mnt_dir); if (ret >= sizeof(path)) { ERROR("path name too long"); return -1; } - if (hasmntopt(mntent, "create=dir")) { - if (mkdir_p(path, 0755) < 0) { - WARN("Failed to create mount target '%s'", path); - ret = -1; - } - } - - if (hasmntopt(mntent, "create=file") && access(path, F_OK)) { - pathdirname = strdup(path); - pathdirname = dirname(pathdirname); - if (mkdir_p(pathdirname, 0755) < 0) { - WARN("Failed to create target directory"); - } - pathfile = fopen(path, "wb"); - if (!pathfile) { - WARN("Failed to create mount target '%s'", path); - ret = -1; - } - else - fclose(pathfile); - } - cull_mntent_opt(mntent); - - if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { - free(mntdata); - return -1; - } - - ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, - mntflags, mntdata, optional); - - free(pathdirname); - free(mntdata); - - return ret; + return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path); } static int mount_file_entries(const struct lxc_rootfs *rootfs, FILE *file, - const char *lxc_name) + const char *lxc_name, const char *lxc_path) { struct mntent mntent; char buf[4096]; @@ -2340,13 +2466,12 @@ /* We have a separate root, mounts are relative to it */ if (mntent.mnt_dir[0] != '/') { - if (mount_entry_on_relative_rootfs(&mntent, - rootfs->mount)) + if (mount_entry_on_relative_rootfs(&mntent, rootfs, lxc_name, lxc_path)) goto out; continue; } - if (mount_entry_on_absolute_rootfs(&mntent, rootfs, lxc_name)) + if (mount_entry_on_absolute_rootfs(&mntent, rootfs, lxc_name, lxc_path)) goto out; } @@ -2358,7 +2483,7 @@ } static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab, - const char *lxc_name) + const char *lxc_name, const char *lxc_path) { FILE *file; int ret; @@ -2372,14 +2497,14 @@ return -1; } - ret = mount_file_entries(rootfs, file, lxc_name); + ret = mount_file_entries(rootfs, file, lxc_name, lxc_path); endmntent(file); return ret; } static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list *mount, - const char *lxc_name) + const char *lxc_name, const char *lxc_path) { FILE *file; struct lxc_list *iterator; @@ -2399,7 +2524,7 @@ rewind(file); - ret = mount_file_entries(rootfs, file, lxc_name); + ret = mount_file_entries(rootfs, file, lxc_name, lxc_path); fclose(file); return ret; @@ -2919,9 +3044,11 @@ char veth2buf[IFNAMSIZ], *veth2; int err; - if (netdev->priv.veth_attr.pair) + if (netdev->priv.veth_attr.pair) { veth1 = netdev->priv.veth_attr.pair; - else { + if (handler->conf->reboot) + lxc_netdev_delete_by_name(veth1); + } else { err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX"); if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */ ERROR("veth1 name too long"); @@ -3006,10 +3133,9 @@ out_delete: lxc_netdev_delete_by_name(veth1); - if (!netdev->priv.veth_attr.pair && veth1) + if (!netdev->priv.veth_attr.pair) free(veth1); - if(veth2) - free(veth2); + free(veth2); return -1; } @@ -3102,13 +3228,14 @@ { char peer[IFNAMSIZ]; int err; + static uint16_t vlan_cntr = 0; if (!netdev->link) { ERROR("no link specified for vlan netdev"); return -1; } - err = snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid); + err = snprintf(peer, sizeof(peer), "vlan%d-%d", netdev->priv.vlan_attr.vid, vlan_cntr++); if (err >= sizeof(peer)) { ERROR("peer name too long"); return -1; @@ -3522,8 +3649,7 @@ break; } - if (buf) - free(buf); + free(buf); return ret; } @@ -3884,7 +4010,7 @@ #define MAX_SYMLINK_DEPTH 32 -static int check_autodev( const char *rootfs, void *data ) +static int check_autodev( const struct lxc_rootfs *rootfs, void *data ) { struct start_args *arg = data; int ret; @@ -3895,10 +4021,9 @@ char abs_path[MAXPATHLEN]; char *command = "/sbin/init"; - if (rootfs == NULL || strlen(rootfs) == 0) - return -2; - - if (!realpath(rootfs, absrootfs)) + if (!rootfs->path) + *absrootfs = '\0'; + else if (!realpath(rootfs->mount, absrootfs)) return -2; if( arg && arg->argv[0] ) { @@ -3981,7 +4106,7 @@ return 0; domount: - if (mount("proc", path, "proc", 0, NULL)) + if (safe_mount("proc", path, "proc", 0, NULL, rootfs)) return -1; INFO("Mounted /proc in container for security transition"); return 1; @@ -3991,17 +4116,12 @@ { int mounted; - if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0) { - if (mount("proc", "/proc", "proc", 0, NULL)) { - SYSERROR("Failed mounting /proc, proceeding"); - mounted = 0; - } else - mounted = 1; - } else - mounted = do_tmp_proc_mount(lxc_conf->rootfs.mount); + mounted = do_tmp_proc_mount(lxc_conf->rootfs.path ? lxc_conf->rootfs.mount : ""); if (mounted == -1) { SYSERROR("failed to mount /proc in the container."); - return -1; + /* continue only if there is no rootfs */ + if (lxc_conf->rootfs.path) + return -1; } else if (mounted == 1) { lxc_conf->tmp_umount_proc = 1; } @@ -4047,8 +4167,7 @@ } } fclose(f); - if (line) - free(line); + free(line); } /* @@ -4096,12 +4215,12 @@ int ret; ret = snprintf(path, MAXPATHLEN, "%s%s", - conf->rootfs.mount, hookname); + conf->rootfs.path ? conf->rootfs.mount : "", hookname); if (ret < 0 || ret >= MAXPATHLEN) return false; ret = stat(path, &st); if (ret) { - SYSERROR("Start hook %s not found in container rootfs", + SYSERROR("Start hook %s not found in container", hookname); return false; } @@ -4136,11 +4255,11 @@ } if (lxc_conf->autodev < 0) { - lxc_conf->autodev = check_autodev(lxc_conf->rootfs.mount, data); + lxc_conf->autodev = check_autodev(&lxc_conf->rootfs, data); } if (lxc_conf->autodev > 0) { - if (mount_autodev(name, lxc_conf->rootfs.mount, lxcpath)) { + if (mount_autodev(name, &lxc_conf->rootfs, lxcpath)) { ERROR("failed to mount /dev in the container"); return -1; } @@ -4154,17 +4273,17 @@ return -1; } - if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) { + if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath)) { ERROR("failed to setup the mounts for '%s'", name); return -1; } - if (!lxc_list_empty(&lxc_conf->mount_list) && setup_mount_entries(&lxc_conf->rootfs, &lxc_conf->mount_list, name)) { + if (!lxc_list_empty(&lxc_conf->mount_list) && setup_mount_entries(&lxc_conf->rootfs, &lxc_conf->mount_list, name, lxcpath)) { ERROR("failed to setup the mount entries for '%s'", name); return -1; } - /* Make sure any start hooks are in the rootfs */ + /* Make sure any start hooks are in the container */ if (!verify_start_hooks(lxc_conf)) return -1; @@ -4187,7 +4306,7 @@ ERROR("failed to run autodev hooks for container '%s'.", name); return -1; } - if (setup_autodev(lxc_conf->rootfs.mount)) { + if (setup_autodev(&lxc_conf->rootfs)) { ERROR("failed to populate /dev in the container"); return -1; } @@ -4234,20 +4353,18 @@ return -1; } - if (lxc_list_empty(&lxc_conf->id_map)) { - if (!lxc_list_empty(&lxc_conf->keepcaps)) { - if (!lxc_list_empty(&lxc_conf->caps)) { - ERROR("Simultaneously requested dropping and keeping caps"); - return -1; - } - if (dropcaps_except(&lxc_conf->keepcaps)) { - ERROR("failed to keep requested caps"); - return -1; - } - } else if (setup_caps(&lxc_conf->caps)) { - ERROR("failed to drop capabilities"); + if (!lxc_list_empty(&lxc_conf->keepcaps)) { + if (!lxc_list_empty(&lxc_conf->caps)) { + ERROR("Simultaneously requested dropping and keeping caps"); return -1; } + if (dropcaps_except(&lxc_conf->keepcaps)) { + ERROR("failed to keep requested caps"); + return -1; + } + } else if (setup_caps(&lxc_conf->caps)) { + ERROR("failed to drop capabilities"); + return -1; } NOTICE("'%s' is setup.", name); @@ -4294,22 +4411,15 @@ lxc_list_del(it); - if (netdev->link) - free(netdev->link); - if (netdev->name) - free(netdev->name); - if (netdev->type == LXC_NET_VETH && netdev->priv.veth_attr.pair) + free(netdev->link); + free(netdev->name); + if (netdev->type == LXC_NET_VETH) free(netdev->priv.veth_attr.pair); - if (netdev->upscript) - free(netdev->upscript); - if (netdev->hwaddr) - free(netdev->hwaddr); - if (netdev->mtu) - free(netdev->mtu); - if (netdev->ipv4_gateway) - free(netdev->ipv4_gateway); - if (netdev->ipv6_gateway) - free(netdev->ipv6_gateway); + free(netdev->upscript); + free(netdev->hwaddr); + free(netdev->mtu); + free(netdev->ipv4_gateway); + free(netdev->ipv6_gateway); lxc_list_for_each_safe(it2, &netdev->ipv4, next) { lxc_list_del(it2); free(it2->elem); @@ -4332,7 +4442,7 @@ struct lxc_list *it; struct lxc_netdev *netdev; - p1 = index(key, '.'); + p1 = strchr(key, '.'); if (!p1 || *(p1+1) == '\0') p1 = NULL; @@ -4372,40 +4482,26 @@ free(it2); } } else if (strcmp(p1, ".link") == 0) { - if (netdev->link) { - free(netdev->link); - netdev->link = NULL; - } + free(netdev->link); + netdev->link = NULL; } else if (strcmp(p1, ".name") == 0) { - if (netdev->name) { - free(netdev->name); - netdev->name = NULL; - } + free(netdev->name); + netdev->name = NULL; } else if (strcmp(p1, ".script.up") == 0) { - if (netdev->upscript) { - free(netdev->upscript); - netdev->upscript = NULL; - } + free(netdev->upscript); + netdev->upscript = NULL; } else if (strcmp(p1, ".hwaddr") == 0) { - if (netdev->hwaddr) { - free(netdev->hwaddr); - netdev->hwaddr = NULL; - } + free(netdev->hwaddr); + netdev->hwaddr = NULL; } else if (strcmp(p1, ".mtu") == 0) { - if (netdev->mtu) { - free(netdev->mtu); - netdev->mtu = NULL; - } + free(netdev->mtu); + netdev->mtu = NULL; } else if (strcmp(p1, ".ipv4.gateway") == 0) { - if (netdev->ipv4_gateway) { - free(netdev->ipv4_gateway); - netdev->ipv4_gateway = NULL; - } + free(netdev->ipv4_gateway); + netdev->ipv4_gateway = NULL; } else if (strcmp(p1, ".ipv6.gateway") == 0) { - if (netdev->ipv6_gateway) { - free(netdev->ipv6_gateway); - netdev->ipv6_gateway = NULL; - } + free(netdev->ipv6_gateway); + netdev->ipv6_gateway = NULL; } else return -1; @@ -4556,33 +4652,20 @@ { if (!conf) return; - if (conf->console.log_path) - free(conf->console.log_path); - if (conf->console.path) - free(conf->console.path); - if (conf->rootfs.mount) - free(conf->rootfs.mount); - if (conf->rootfs.options) - free(conf->rootfs.options); - if (conf->rootfs.path) - free(conf->rootfs.path); - if (conf->rootfs.pivot) - free(conf->rootfs.pivot); - if (conf->logfile) - free(conf->logfile); - if (conf->utsname) - free(conf->utsname); - if (conf->ttydir) - free(conf->ttydir); - if (conf->fstab) - free(conf->fstab); - if (conf->rcfile) - free(conf->rcfile); + free(conf->console.log_path); + free(conf->console.path); + free(conf->rootfs.mount); + free(conf->rootfs.options); + free(conf->rootfs.path); + free(conf->rootfs.pivot); + free(conf->logfile); + free(conf->utsname); + free(conf->ttydir); + free(conf->fstab); + free(conf->rcfile); lxc_clear_config_network(conf); - if (conf->lsm_aa_profile) - free(conf->lsm_aa_profile); - if (conf->lsm_se_context) - free(conf->lsm_se_context); + free(conf->lsm_aa_profile); + free(conf->lsm_se_context); lxc_seccomp_free(conf); lxc_clear_config_caps(conf); lxc_clear_config_keepcaps(conf); @@ -4853,8 +4936,7 @@ } fclose(f); - if (line) - free(line); + free(line); if (!urange || !grange) { ERROR("You do not have subuids or subgids allocated"); @@ -4872,3 +4954,58 @@ free(gname); free(uname); } + +static void free_cgroup_settings(struct lxc_list *result) +{ + struct lxc_list *iterator, *next; + + lxc_list_for_each_safe(iterator, result, next) { + lxc_list_del(iterator); + free(iterator); + } + free(result); +} + +/* + * Return the list of cgroup_settings sorted according to the following rules + * 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes + */ +struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings) +{ + struct lxc_list *result; + struct lxc_list *memsw_limit = NULL; + struct lxc_list *it = NULL; + struct lxc_cgroup *cg = NULL; + struct lxc_list *item = NULL; + + result = malloc(sizeof(*result)); + if (!result) { + ERROR("failed to allocate memory to sort cgroup settings"); + return NULL; + } + lxc_list_init(result); + + /*Iterate over the cgroup settings and copy them to the output list*/ + lxc_list_for_each(it, cgroup_settings) { + item = malloc(sizeof(*item)); + if (!item) { + ERROR("failed to allocate memory to sort cgroup settings"); + free_cgroup_settings(result); + return NULL; + } + item->elem = it->elem; + cg = it->elem; + if (strcmp(cg->subsystem, "memory.memsw.limit_in_bytes") == 0) { + /* Store the memsw_limit location */ + memsw_limit = item; + } else if (strcmp(cg->subsystem, "memory.limit_in_bytes") == 0 && memsw_limit != NULL) { + /* lxc.cgroup.memory.memsw.limit_in_bytes is found before + * lxc.cgroup.memory.limit_in_bytes, swap these two items */ + item->elem = memsw_limit->elem; + memsw_limit->elem = it->elem; + } + lxc_list_add_tail(result, item); + } + + return result; +} diff -Nru lxc-1.0.7/src/lxc/conf.h lxc-1.0.8/src/lxc/conf.h --- lxc-1.0.7/src/lxc/conf.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/conf.h 2015-11-09 22:49:15.000000000 +0000 @@ -401,4 +401,5 @@ extern void tmp_proc_unmount(struct lxc_conf *lxc_conf); void remount_all_slave(void); extern void suggest_default_idmap(void); +struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings); #endif diff -Nru lxc-1.0.7/src/lxc/confile.c lxc-1.0.8/src/lxc/confile.c --- lxc-1.0.7/src/lxc/confile.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/confile.c 2015-11-09 22:49:15.000000000 +0000 @@ -64,6 +64,8 @@ static int config_loglevel(const char *, const char *, struct lxc_conf *); static int config_logfile(const char *, const char *, struct lxc_conf *); static int config_mount(const char *, const char *, struct lxc_conf *); +static int config_mount_auto(const char *, const char *, struct lxc_conf *); +static int config_fstab(const char *, const char *, struct lxc_conf *); static int config_rootfs(const char *, const char *, struct lxc_conf *); static int config_rootfs_mount(const char *, const char *, struct lxc_conf *); static int config_rootfs_options(const char *, const char *, struct lxc_conf *); @@ -111,7 +113,9 @@ { "lxc.id_map", config_idmap }, { "lxc.loglevel", config_loglevel }, { "lxc.logfile", config_logfile }, - { "lxc.mount", config_mount }, + { "lxc.mount.entry", config_mount }, + { "lxc.mount.auto", config_mount_auto }, + { "lxc.mount", config_fstab }, { "lxc.rootfs.mount", config_rootfs_mount }, { "lxc.rootfs.options", config_rootfs_options }, { "lxc.rootfs", config_rootfs }, @@ -181,6 +185,63 @@ { SIGTSTP, "TSTP" }, { SIGTTIN, "TTIN" }, { SIGTTOU, "TTOU" }, +#ifdef SIGTRAP + { SIGTRAP, "TRAP" }, +#endif +#ifdef SIGIOT + { SIGIOT, "IOT" }, +#endif +#ifdef SIGEMT + { SIGEMT, "EMT" }, +#endif +#ifdef SIGBUS + { SIGBUS, "BUS" }, +#endif +#ifdef SIGSTKFLT + { SIGSTKFLT, "STKFLT" }, +#endif +#ifdef SIGCLD + { SIGCLD, "CLD" }, +#endif +#ifdef SIGURG + { SIGURG, "URG" }, +#endif +#ifdef SIGXCPU + { SIGXCPU, "XCPU" }, +#endif +#ifdef SIGXFSZ + { SIGXFSZ, "XFSZ" }, +#endif +#ifdef SIGVTALRM + { SIGVTALRM, "VTALRM" }, +#endif +#ifdef SIGPROF + { SIGPROF, "PROF" }, +#endif +#ifdef SIGWINCH + { SIGWINCH, "WINCH" }, +#endif +#ifdef SIGIO + { SIGIO, "IO" }, +#endif +#ifdef SIGPOLL + { SIGPOLL, "POLL" }, +#endif +#ifdef SIGINFO + { SIGINFO, "INFO" }, +#endif +#ifdef SIGLOST + { SIGLOST, "LOST" }, +#endif +#ifdef SIGPWR + { SIGPWR, "PWR" }, +#endif +#ifdef SIGUNUSED + { SIGUNUSED, "UNUSED" }, +#endif +#ifdef SIGSYS + { SIGSYS, "SYS" }, +#endif }; static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t); @@ -230,8 +291,7 @@ char *new_value; if (!value || strlen(value) == 0) { - if (*conf_item) - free(*conf_item); + free(*conf_item); *conf_item = NULL; return 0; } @@ -242,8 +302,7 @@ return -1; } - if (*conf_item) - free(*conf_item); + free(*conf_item); *conf_item = new_value; return 0; } @@ -289,7 +348,7 @@ */ if (*(key+12) < '0' || *(key+12) > '9') goto out; - p = index(key+12, '.'); + p = strchr(key+12, '.'); if (!p) goto out; strcpy(copy+12, p+1); @@ -767,29 +826,27 @@ struct lxc_conf *lxc_conf) { struct lxc_netdev *netdev; - struct in_addr *gw; netdev = network_netdev(key, value, &lxc_conf->network); if (!netdev) return -1; - gw = malloc(sizeof(*gw)); - if (!gw) { - SYSERROR("failed to allocate ipv4 gateway address"); - return -1; - } - - if (!value) { - ERROR("no ipv4 gateway address specified"); - free(gw); - return -1; - } + free(netdev->ipv4_gateway); - if (!strcmp(value, "auto")) { - free(gw); + if (!value || strlen(value) == 0) { + netdev->ipv4_gateway = NULL; + } else if (!strcmp(value, "auto")) { netdev->ipv4_gateway = NULL; netdev->ipv4_gateway_auto = true; } else { + struct in_addr *gw; + + gw = malloc(sizeof(*gw)); + if (!gw) { + SYSERROR("failed to allocate ipv4 gateway address"); + return -1; + } + if (!inet_pton(AF_INET, value, gw)) { SYSERROR("invalid ipv4 gateway address: %s", value); free(gw); @@ -872,12 +929,11 @@ if (!netdev) return -1; - if (!value) { - ERROR("no ipv6 gateway address specified"); - return -1; - } + free(netdev->ipv6_gateway); - if (!strcmp(value, "auto")) { + if (!value || strlen(value) == 0) { + netdev->ipv4_gateway = NULL; + } else if (!strcmp(value, "auto")) { netdev->ipv6_gateway = NULL; netdev->ipv6_gateway_auto = true; } else { @@ -1039,10 +1095,10 @@ /* in case several groups are specified in a single line * split these groups in a single element for the list */ for (groupptr = groups;;groupptr = NULL) { - token = strtok_r(groupptr, " \t", &sptr); - if (!token) { + token = strtok_r(groupptr, " \t", &sptr); + if (!token) { ret = 0; - break; + break; } grouplist = malloc(sizeof(*grouplist)); @@ -1059,7 +1115,7 @@ } lxc_list_add_tail(&lxc_conf->groups, grouplist); - } + } free(groups); @@ -1272,15 +1328,12 @@ return 0; out: - if (cglist) - free(cglist); + free(cglist); if (cgelem) { - if (cgelem->subsystem) - free(cgelem->subsystem); + free(cgelem->subsystem); - if (cgelem->value) - free(cgelem->value); + free(cgelem->value); free(cgelem); } @@ -1340,8 +1393,7 @@ return 0; out: - if (idmaplist) - free(idmaplist); + free(idmaplist); if (idmap) { free(idmap); @@ -1377,7 +1429,7 @@ { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED }, { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO }, { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW }, - /* NB: For adding anything that ist just a single on/off, but has + /* NB: For adding anything that is just a single on/off, but has * no options: keep mask and flag identical and just define the * enum value as an unused bit so far */ @@ -1398,10 +1450,10 @@ } for (autoptr = autos; ; autoptr = NULL) { - token = strtok_r(autoptr, " \t", &sptr); - if (!token) { + token = strtok_r(autoptr, " \t", &sptr); + if (!token) { ret = 0; - break; + break; } for (i = 0; allowed_auto_mounts[i].token; i++) { @@ -1416,47 +1468,19 @@ lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask; lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag; - } + } free(autos); return ret; } -/* - * TODO - * This fn is handling lxc.mount, lxc.mount.entry, and lxc.mount.auto. - * It should probably be split into 3 separate functions indexed by - * the config[] entries at top. - */ static int config_mount(const char *key, const char *value, struct lxc_conf *lxc_conf) { - char *fstab_token = "lxc.mount"; - char *token = "lxc.mount.entry"; - char *auto_token = "lxc.mount.auto"; - char *subkey; char *mntelem; struct lxc_list *mntlist; - subkey = strstr(key, token); - - if (!subkey) { - subkey = strstr(key, auto_token); - - if (!subkey) { - subkey = strstr(key, fstab_token); - - if (!subkey) - return -1; - - return config_fstab(key, value, lxc_conf); - } - - return config_mount_auto(key, value, lxc_conf); - } - - /* At this point we definitely have key = lxc.mount.entry */ if (!value || strlen(value) == 0) return lxc_clear_mount_entries(lxc_conf); @@ -1495,10 +1519,10 @@ /* in case several capability keep is specified in a single line * split these caps in a single element for the list */ for (keepptr = keepcaps;;keepptr = NULL) { - token = strtok_r(keepptr, " \t", &sptr); - if (!token) { + token = strtok_r(keepptr, " \t", &sptr); + if (!token) { ret = 0; - break; + break; } keeplist = malloc(sizeof(*keeplist)); @@ -1515,7 +1539,7 @@ } lxc_list_add_tail(&lxc_conf->keepcaps, keeplist); - } + } free(keepcaps); @@ -1541,10 +1565,10 @@ /* in case several capability drop is specified in a single line * split these caps in a single element for the list */ for (dropptr = dropcaps;;dropptr = NULL) { - token = strtok_r(dropptr, " \t", &sptr); - if (!token) { + token = strtok_r(dropptr, " \t", &sptr); + if (!token) { ret = 0; - break; + break; } droplist = malloc(sizeof(*droplist)); @@ -1561,7 +1585,7 @@ } lxc_list_add_tail(&lxc_conf->caps, droplist); - } + } free(dropcaps); @@ -1629,8 +1653,7 @@ } strcpy(utsname->nodename, value); - if (lxc_conf->utsname) - free(lxc_conf->utsname); + free(lxc_conf->utsname); lxc_conf->utsname = utsname; return 0; @@ -1791,7 +1814,7 @@ /* for the sake of backward compatibility, drop all privileges if none is specified */ for (i = 0; all_privs[i].token; i++) { - *flags |= all_privs[i].flag; + *flags |= all_privs[i].flag; } return 0; } @@ -1888,8 +1911,8 @@ int i; /* "lxc.hook.mount" */ - subkey = index(key, '.'); - if (subkey) subkey = index(subkey+1, '.'); + subkey = strchr(key, '.'); + if (subkey) subkey = strchr(subkey+1, '.'); if (!subkey) return -1; subkey++; @@ -2037,7 +2060,7 @@ else memset(retv, 0, inlen); - p1 = index(key, '.'); + p1 = strchr(key, '.'); if (!p1 || *(p1+1) == '\0') return -1; p1++; diff -Nru lxc-1.0.7/src/lxc/execute.c lxc-1.0.8/src/lxc/execute.c --- lxc-1.0.7/src/lxc/execute.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/execute.c 2015-11-09 22:49:15.000000000 +0000 @@ -134,7 +134,7 @@ initpath = choose_init(); if (!initpath) { - ERROR("Failed to find an lxc-init"); + ERROR("Failed to find an lxc-init or init.lxc"); goto out2; } argv[i++] = initpath; diff -Nru lxc-1.0.7/src/lxc/genl.c lxc-1.0.8/src/lxc/genl.c --- lxc-1.0.7/src/lxc/genl.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/genl.c 2015-11-09 22:49:15.000000000 +0000 @@ -53,10 +53,10 @@ request->nlmsghdr.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); request->nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - request->nlmsghdr.nlmsg_type = GENL_ID_CTRL; + request->nlmsghdr.nlmsg_type = GENL_ID_CTRL; genlmsghdr = NLMSG_DATA(&request->nlmsghdr); - genlmsghdr->cmd = CTRL_CMD_GETFAMILY; + genlmsghdr->cmd = CTRL_CMD_GETFAMILY; ret = netlink_open(&handler, NETLINK_GENERIC); if (ret) diff -Nru lxc-1.0.7/src/lxc/genl.h lxc-1.0.8/src/lxc/genl.h --- lxc-1.0.7/src/lxc/genl.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/genl.h 2015-11-09 22:49:15.000000000 +0000 @@ -59,7 +59,7 @@ static inline int genetlink_len(const struct genlmsg *genlmsg) { - return ((genlmsg->nlmsghdr.nlmsg_len) - GENL_HDRLEN - NLMSG_HDRLEN); + return ((genlmsg->nlmsghdr.nlmsg_len) - GENL_HDRLEN - NLMSG_HDRLEN); } /* diff -Nru lxc-1.0.7/src/lxc/initutils.c lxc-1.0.8/src/lxc/initutils.c --- lxc-1.0.7/src/lxc/initutils.c 1970-01-01 00:00:00.000000000 +0000 +++ lxc-1.0.8/src/lxc/initutils.c 2015-11-09 22:49:15.000000000 +0000 @@ -0,0 +1,293 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "initutils.h" +#include "log.h" + +lxc_log_define(lxc_initutils, lxc); + +static int mount_fs(const char *source, const char *target, const char *type) +{ + /* the umount may fail */ + if (umount(target)) + WARN("failed to unmount %s : %s", target, strerror(errno)); + + if (mount(source, target, type, 0, NULL)) { + ERROR("failed to mount %s : %s", target, strerror(errno)); + return -1; + } + + DEBUG("'%s' mounted on '%s'", source, target); + + return 0; +} + +extern void lxc_setup_fs(void) +{ + if (mount_fs("proc", "/proc", "proc")) + INFO("failed to remount proc"); + + /* if we can't mount /dev/shm, continue anyway */ + if (mount_fs("shmfs", "/dev/shm", "tmpfs")) + INFO("failed to mount /dev/shm"); + + /* If we were able to mount /dev/shm, then /dev exists */ + /* Sure, but it's read-only per config :) */ + if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) { + DEBUG("failed to create '/dev/mqueue'"); + return; + } + + /* continue even without posix message queue support */ + if (mount_fs("mqueue", "/dev/mqueue", "mqueue")) + INFO("failed to mount /dev/mqueue"); +} + +static char *copy_global_config_value(char *p) +{ + int len = strlen(p); + char *retbuf; + + if (len < 1) + return NULL; + if (p[len-1] == '\n') { + p[len-1] = '\0'; + len--; + } + retbuf = malloc(len+1); + if (!retbuf) + return NULL; + strcpy(retbuf, p); + return retbuf; +} + +const char *lxc_global_config_value(const char *option_name) +{ + static const char * const options[][2] = { + { "lxc.bdev.lvm.vg", DEFAULT_VG }, + { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL }, + { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT }, + { "lxc.lxcpath", NULL }, + { "lxc.default_config", NULL }, + { "lxc.cgroup.pattern", NULL }, + { "lxc.cgroup.use", NULL }, + { NULL, NULL }, + }; + + /* placed in the thread local storage pool for non-bionic targets */ +#ifdef HAVE_TLS + static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; +#else + static const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; +#endif + + /* user_config_path is freed as soon as it is used */ + char *user_config_path = NULL; + + /* + * The following variables are freed at bottom unconditionally. + * So NULL the value if it is to be returned to the caller + */ + char *user_default_config_path = NULL; + char *user_lxc_path = NULL; + char *user_cgroup_pattern = NULL; + + if (geteuid() > 0) { + const char *user_home = getenv("HOME"); + if (!user_home) + user_home = "/"; + + user_config_path = malloc(sizeof(char) * (22 + strlen(user_home))); + user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home))); + user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home))); + + sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home); + sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home); + sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home); + user_cgroup_pattern = strdup("lxc/%n"); + } + else { + user_config_path = strdup(LXC_GLOBAL_CONF); + user_default_config_path = strdup(LXC_DEFAULT_CONFIG); + user_lxc_path = strdup(LXCPATH); + user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN); + } + + const char * const (*ptr)[2]; + size_t i; + char buf[1024], *p, *p2; + FILE *fin = NULL; + + for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) { + if (!strcmp(option_name, (*ptr)[0])) + break; + } + if (!(*ptr)[0]) { + free(user_config_path); + free(user_default_config_path); + free(user_lxc_path); + free(user_cgroup_pattern); + errno = EINVAL; + return NULL; + } + + if (values[i]) { + free(user_config_path); + free(user_default_config_path); + free(user_lxc_path); + free(user_cgroup_pattern); + return values[i]; + } + + fin = fopen_cloexec(user_config_path, "r"); + free(user_config_path); + if (fin) { + while (fgets(buf, 1024, fin)) { + if (buf[0] == '#') + continue; + p = strstr(buf, option_name); + if (!p) + continue; + /* see if there was just white space in front + * of the option name + */ + for (p2 = buf; p2 < p; p2++) { + if (*p2 != ' ' && *p2 != '\t') + break; + } + if (p2 < p) + continue; + p = strchr(p, '='); + if (!p) + continue; + /* see if there was just white space after + * the option name + */ + for (p2 += strlen(option_name); p2 < p; p2++) { + if (*p2 != ' ' && *p2 != '\t') + break; + } + if (p2 < p) + continue; + p++; + while (*p && (*p == ' ' || *p == '\t')) p++; + if (!*p) + continue; + + if (strcmp(option_name, "lxc.lxcpath") == 0) { + free(user_lxc_path); + user_lxc_path = copy_global_config_value(p); + remove_trailing_slashes(user_lxc_path); + values[i] = user_lxc_path; + user_lxc_path = NULL; + goto out; + } + + values[i] = copy_global_config_value(p); + goto out; + } + } + /* could not find value, use default */ + if (strcmp(option_name, "lxc.lxcpath") == 0) { + remove_trailing_slashes(user_lxc_path); + values[i] = user_lxc_path; + user_lxc_path = NULL; + } + else if (strcmp(option_name, "lxc.default_config") == 0) { + values[i] = user_default_config_path; + user_default_config_path = NULL; + } + else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) { + values[i] = user_cgroup_pattern; + user_cgroup_pattern = NULL; + } + else + values[i] = (*ptr)[1]; + + /* special case: if default value is NULL, + * and there is no config, don't view that + * as an error... */ + if (!values[i]) + errno = 0; + +out: + if (fin) + fclose(fin); + + free(user_cgroup_pattern); + free(user_default_config_path); + free(user_lxc_path); + + return values[i]; +} + +extern void remove_trailing_slashes(char *p) +{ + int l = strlen(p); + while (--l >= 0 && (p[l] == '/' || p[l] == '\n')) + p[l] = '\0'; +} + +FILE *fopen_cloexec(const char *path, const char *mode) +{ + int open_mode = 0; + int step = 0; + int fd; + int saved_errno = 0; + FILE *ret; + + if (!strncmp(mode, "r+", 2)) { + open_mode = O_RDWR; + step = 2; + } else if (!strncmp(mode, "r", 1)) { + open_mode = O_RDONLY; + step = 1; + } else if (!strncmp(mode, "w+", 2)) { + open_mode = O_RDWR | O_TRUNC | O_CREAT; + step = 2; + } else if (!strncmp(mode, "w", 1)) { + open_mode = O_WRONLY | O_TRUNC | O_CREAT; + step = 1; + } else if (!strncmp(mode, "a+", 2)) { + open_mode = O_RDWR | O_CREAT | O_APPEND; + step = 2; + } else if (!strncmp(mode, "a", 1)) { + open_mode = O_WRONLY | O_CREAT | O_APPEND; + step = 1; + } + for (; mode[step]; step++) + if (mode[step] == 'x') + open_mode |= O_EXCL; + open_mode |= O_CLOEXEC; + + fd = open(path, open_mode, 0666); + if (fd < 0) + return NULL; + + ret = fdopen(fd, mode); + saved_errno = errno; + if (!ret) + close(fd); + errno = saved_errno; + return ret; +} diff -Nru lxc-1.0.7/src/lxc/initutils.h lxc-1.0.8/src/lxc/initutils.h --- lxc-1.0.7/src/lxc/initutils.h 1970-01-01 00:00:00.000000000 +0000 +++ lxc-1.0.8/src/lxc/initutils.h 2015-11-09 22:49:15.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __LXC_INITUTILS_H +#define __LXC_INITUTILS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "config.h" + +#define DEFAULT_VG "lxc" +#define DEFAULT_THIN_POOL "lxc" +#define DEFAULT_ZFSROOT "lxc" + +extern void lxc_setup_fs(void); +extern const char *lxc_global_config_value(const char *option_name); + +/* open a file with O_CLOEXEC */ +extern void remove_trailing_slashes(char *p); +FILE *fopen_cloexec(const char *path, const char *mode); + +#endif /* __LXC_INITUTILS_H */ diff -Nru lxc-1.0.7/src/lxc/list.h lxc-1.0.8/src/lxc/list.h --- lxc-1.0.7/src/lxc/list.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/list.h 2015-11-09 22:49:15.000000000 +0000 @@ -72,10 +72,10 @@ struct lxc_list *prev, struct lxc_list *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } static inline void lxc_list_add(struct lxc_list *head, struct lxc_list *list) diff -Nru lxc-1.0.7/src/lxc/log.c lxc-1.0.8/src/lxc/log.c --- lxc-1.0.7/src/lxc/log.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/log.c 2015-11-09 22:49:15.000000000 +0000 @@ -350,8 +350,8 @@ if (!lxcpath) lxcpath = LOGPATH; - /* try LOGPATH if lxcpath is the default */ - if (strcmp(lxcpath, lxc_global_config_value("lxc.lxcpath")) == 0) + /* try LOGPATH if lxcpath is the default for the privileged containers */ + if (!geteuid() && strcmp(LXCPATH, lxcpath) == 0) ret = _lxc_log_set_file(name, NULL, 0); /* try in lxcpath */ diff -Nru lxc-1.0.7/src/lxc/lsm/apparmor.c lxc-1.0.8/src/lxc/lsm/apparmor.c --- lxc-1.0.7/src/lxc/lsm/apparmor.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lsm/apparmor.c 2015-11-09 22:49:15.000000000 +0000 @@ -77,8 +77,7 @@ f = fopen(path, "r"); if (!f) { SYSERROR("opening %s", path); - if (buf) - free(buf); + free(buf); return NULL; } sz += 1024; @@ -100,10 +99,10 @@ } if (ret >= sz) goto again; - space = index(buf, '\n'); + space = strchr(buf, '\n'); if (space) *space = '\0'; - space = index(buf, ' '); + space = strchr(buf, ' '); if (space) *space = '\0'; return buf; @@ -115,8 +114,7 @@ int ret = 0; if (!p || strcmp(p, "unconfined") == 0) ret = 1; - if (p) - free(p); + free(p); return ret; } diff -Nru lxc-1.0.7/src/lxc/lxc_attach.c lxc-1.0.8/src/lxc/lxc_attach.c --- lxc-1.0.7/src/lxc/lxc_attach.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_attach.c 2015-11-09 22:49:15.000000000 +0000 @@ -113,12 +113,12 @@ /* -s implies -e */ lxc_fill_elevated_privileges(NULL, &elevated_privileges); break; - case 500: /* clear-env */ - env_policy = LXC_ATTACH_CLEAR_ENV; - break; - case 501: /* keep-env */ - env_policy = LXC_ATTACH_KEEP_ENV; - break; + case 500: /* clear-env */ + env_policy = LXC_ATTACH_CLEAR_ENV; + break; + case 501: /* keep-env */ + env_policy = LXC_ATTACH_KEEP_ENV; + break; case 502: /* keep-var */ ret = add_to_simple_array(&extra_keep, &extra_keep_size, arg); if (ret < 0) { @@ -146,7 +146,7 @@ Execute the specified COMMAND - enter the container NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -e, --elevated-privileges=PRIVILEGES\n\ Use elevated privileges instead of those of the\n\ container. If you don't specify privileges to be\n\ diff -Nru lxc-1.0.7/src/lxc/lxc_autostart.c lxc-1.0.8/src/lxc/lxc_autostart.c --- lxc-1.0.7/src/lxc/lxc_autostart.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_autostart.c 2015-11-09 22:49:15.000000000 +0000 @@ -174,8 +174,10 @@ if ( list_contains_entry( workptr, workstr_list ) ) { if ( *workptr ) { fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr ); + fflush(stderr); } else { - fprintf(stderr, "Duilicate NULL group in list - ignoring\n" ); + fprintf(stderr, "Duplicate NULL group in list - ignoring\n" ); + fflush(stderr); } } else { worklist = malloc(sizeof(*worklist)); @@ -353,7 +355,8 @@ qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder); if (cmd_groups_list && my_args.all) { - fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides."); + fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides.\n"); + fflush(stderr); } if (!cmd_groups_list) { @@ -423,12 +426,15 @@ if (my_args.shutdown) { /* Shutdown the container */ if (c->is_running(c)) { - if (my_args.list) + if (my_args.list) { printf("%s\n", c->name); + fflush(stdout); + } else { if (!c->shutdown(c, my_args.timeout)) { if (!c->stop(c)) { fprintf(stderr, "Error shutting down container: %s\n", c->name); + fflush(stderr); } } } @@ -437,23 +443,31 @@ else if (my_args.hardstop) { /* Kill the container */ if (c->is_running(c)) { - if (my_args.list) + if (my_args.list) { printf("%s\n", c->name); + fflush(stdout); + } else { - if (!c->stop(c)) + if (!c->stop(c)) { fprintf(stderr, "Error killing container: %s\n", c->name); + fflush(stderr); + } } } } else if (my_args.reboot) { /* Reboot the container */ if (c->is_running(c)) { - if (my_args.list) + if (my_args.list) { printf("%s %d\n", c->name, get_config_integer(c, "lxc.start.delay")); + fflush(stdout); + } else { - if (!c->reboot(c)) + if (!c->reboot(c)) { fprintf(stderr, "Error rebooting container: %s\n", c->name); + fflush(stderr); + } else sleep(get_config_integer(c, "lxc.start.delay")); } @@ -462,12 +476,16 @@ else { /* Start the container */ if (!c->is_running(c)) { - if (my_args.list) + if (my_args.list) { printf("%s %d\n", c->name, get_config_integer(c, "lxc.start.delay")); + fflush(stdout); + } else { - if (!c->start(c, 0, default_start_args)) + if (!c->start(c, 0, default_start_args)) { fprintf(stderr, "Error starting container: %s\n", c->name); + fflush(stderr); + } else sleep(get_config_integer(c, "lxc.start.delay")); } @@ -482,7 +500,7 @@ if ( lxc_container_put(c) > 0 ) { containers[i] = NULL; } - if ( c_groups_lists && c_groups_lists[i] ) { + if ( c_groups_lists ) { toss_list(c_groups_lists[i]); c_groups_lists[i] = NULL; } @@ -499,13 +517,8 @@ } } - if ( c_groups_lists ) - free(c_groups_lists); - - if ( cmd_groups_list ) { - toss_list( cmd_groups_list ); - } - + free(c_groups_lists); + toss_list( cmd_groups_list ); free(containers); return 0; diff -Nru lxc-1.0.7/src/lxc/lxc_cgroup.c lxc-1.0.8/src/lxc/lxc_cgroup.c --- lxc-1.0.7/src/lxc/lxc_cgroup.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_cgroup.c 2015-11-09 22:49:15.000000000 +0000 @@ -56,7 +56,7 @@ in the container's cgroup for the corresponding subsystem.\n\ \n\ Options :\n\ - -n, --name=NAME container name", + -n, --name=NAME NAME of the container", .options = my_longopts, .parser = NULL, .checker = my_checker, diff -Nru lxc-1.0.7/src/lxc/lxc-checkconfig.in lxc-1.0.8/src/lxc/lxc-checkconfig.in --- lxc-1.0.7/src/lxc/lxc-checkconfig.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc-checkconfig.in 2015-11-09 22:49:15.000000000 +0000 @@ -24,7 +24,7 @@ if [ $RES -eq 0 ]; then $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL else - if [ ! -z "$mandatory" -a "$mandatory" = yes ]; then + if [ ! -z "$mandatory" ] && [ "$mandatory" = yes ]; then $SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL else $SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL @@ -100,7 +100,7 @@ echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT echo -n "Cgroup memory controller: " -if [ $KVER_MAJOR -ge 3 -a $KVER_MINOR -ge 6 ]; then +if ([ $KVER_MAJOR -ge 3 ] && [ $KVER_MINOR -ge 6 ]) || ([ $KVER_MAJOR -gt 3 ]); then is_enabled CONFIG_MEMCG else is_enabled CONFIG_CGROUP_MEM_RES_CTLR @@ -111,6 +111,25 @@ echo -n "Veth pair device: " && is_enabled CONFIG_VETH echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q +echo -n "Bridges: " && is_enabled CONFIG_BRIDGE +echo -n "Advanced netfilter: " && is_enabled CONFIG_NETFILTER_ADVANCED +echo -n "CONFIG_NF_NAT_IPV4: " && is_enabled CONFIG_NF_NAT_IPV4 +echo -n "CONFIG_NF_NAT_IPV6: " && is_enabled CONFIG_NF_NAT_IPV6 +echo -n "CONFIG_IP_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP_NF_TARGET_MASQUERADE +echo -n "CONFIG_IP6_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP6_NF_TARGET_MASQUERADE +echo -n "CONFIG_NETFILTER_XT_TARGET_CHECKSUM: " && is_enabled CONFIG_NETFILTER_XT_TARGET_CHECKSUM + +echo +echo "--- Checkpoint/Restore ---" +echo -n "checkpoint restore: " && is_enabled CONFIG_CHECKPOINT_RESTORE +echo -n "CONFIG_FHANDLE: " && is_enabled CONFIG_FHANDLE +echo -n "CONFIG_EVENTFD: " && is_enabled CONFIG_EVENTFD +echo -n "CONFIG_EPOLL: " && is_enabled CONFIG_EPOLL +echo -n "CONFIG_UNIX_DIAG: " && is_enabled CONFIG_UNIX_DIAG +echo -n "CONFIG_INET_DIAG: " && is_enabled CONFIG_INET_DIAG +echo -n "CONFIG_PACKET_DIAG: " && is_enabled CONFIG_PACKET_DIAG +echo -n "CONFIG_NETLINK_DIAG: " && is_enabled CONFIG_NETLINK_DIAG + echo -n "File capabilities: " && \ ( [ "${KVER_MAJOR}" = 2 ] && [ ${KVER_MINOR} -lt 33 ] && \ is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) || \ diff -Nru lxc-1.0.7/src/lxc/lxc_console.c lxc-1.0.8/src/lxc/lxc_console.c --- lxc-1.0.7/src/lxc/lxc_console.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_console.c 2015-11-09 22:49:15.000000000 +0000 @@ -78,7 +78,7 @@ lxc-console logs on the container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -t, --tty=NUMBER console tty number\n\ -e, --escape=PREFIX prefix for escape command\n", .options = my_longopts, diff -Nru lxc-1.0.7/src/lxc/lxccontainer.c lxc-1.0.8/src/lxc/lxccontainer.c --- lxc-1.0.7/src/lxc/lxccontainer.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxccontainer.c 2015-11-09 22:49:15.000000000 +0000 @@ -221,14 +221,10 @@ if (!c) return; - if (c->configfile) { - free(c->configfile); - c->configfile = NULL; - } - if (c->error_string) { - free(c->error_string); - c->error_string = NULL; - } + free(c->configfile); + c->configfile = NULL; + free(c->error_string); + c->error_string = NULL; if (c->slock) { lxc_putlock(c->slock); c->slock = NULL; @@ -237,18 +233,14 @@ lxc_putlock(c->privlock); c->privlock = NULL; } - if (c->name) { - free(c->name); - c->name = NULL; - } + free(c->name); + c->name = NULL; if (c->lxc_conf) { lxc_conf_free(c->lxc_conf); c->lxc_conf = NULL; } - if (c->config_path) { - free(c->config_path); - c->config_path = NULL; - } + free(c->config_path); + c->config_path = NULL; free(c); } @@ -561,6 +553,10 @@ /* container exists */ if (!c) return false; + + /* If anything fails before we set error_num, we want an error in there */ + c->error_num = 1; + /* container has been setup */ if (!c->lxc_conf) return false; @@ -621,22 +617,20 @@ pid = fork(); if (pid < 0) { SYSERROR("Error doing dual-fork"); - return false; + exit(1); } if (pid != 0) exit(0); /* like daemon(), chdir to / and redirect 0,1,2 to /dev/null */ if (chdir("/")) { SYSERROR("Error chdir()ing to /."); - return false; + exit(1); } lxc_check_inherited(conf, -1); - close(0); - close(1); - close(2); - open("/dev/zero", O_RDONLY); - open("/dev/null", O_RDWR); - open("/dev/null", O_RDWR); + if (null_stdfds() < 0) { + ERROR("failed to close fds"); + exit(1); + } setsid(); } else { if (!am_single_threaded()) { @@ -653,6 +647,8 @@ if (pid_fp == NULL) { SYSERROR("Failed to create pidfile '%s' for '%s'", c->pidfile, c->name); + if (daemonize) + exit(1); return false; } @@ -660,6 +656,8 @@ SYSERROR("Failed to write '%s'", c->pidfile); fclose(pid_fp); pid_fp = NULL; + if (daemonize) + exit(1); return false; } @@ -667,14 +665,15 @@ pid_fp = NULL; } -reboot: conf->reboot = 0; + +reboot: ret = lxc_start(c->name, argv, conf, c->config_path); c->error_num = ret; - if (conf->reboot) { + if (conf->reboot == 1) { INFO("container requested reboot"); - conf->reboot = 0; + conf->reboot = 2; goto reboot; } @@ -838,40 +837,6 @@ return bdev; } -/* - * Given the '-t' template option to lxc-create, figure out what to - * do. If the template is a full executable path, use that. If it - * is something like 'sshd', then return $templatepath/lxc-sshd. - * On success return the template, on error return NULL. - */ -static char *get_template_path(const char *t) -{ - int ret, len; - char *tpath; - - if (t[0] == '/' && access(t, X_OK) == 0) { - tpath = strdup(t); - return tpath; - } - - len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1; - tpath = malloc(len); - if (!tpath) - return NULL; - ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t); - if (ret < 0 || ret >= len) { - free(tpath); - return NULL; - } - if (access(tpath, X_OK) < 0) { - SYSERROR("bad template: %s", t); - free(tpath); - return NULL; - } - - return tpath; -} - static char *lxcbasename(char *path) { char *p = path + strlen(path) - 1; @@ -880,7 +845,7 @@ return p; } -static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet, +static bool create_run_template(struct lxc_container *c, char *tpath, bool need_null_stdfds, char *const argv[]) { pid_t pid; @@ -902,13 +867,8 @@ char **newargv; struct lxc_conf *conf = c->lxc_conf; - if (quiet) { - close(0); - close(1); - close(2); - open("/dev/zero", O_RDONLY); - open("/dev/null", O_RDWR); - open("/dev/null", O_RDWR); + if (need_null_stdfds && null_stdfds() < 0) { + exit(1); } src = c->lxc_conf->rootfs.path; @@ -950,8 +910,7 @@ exit(1); } } else { // TODO come up with a better way here! - if (bdev->dest) - free(bdev->dest); + free(bdev->dest); bdev->dest = strdup(bdev->src); } @@ -1289,19 +1248,26 @@ goto free_tpath; /* - * either template or rootfs.path should be set. * if both template and rootfs.path are set, template is setup as rootfs.path. * container is already created if we have a config and rootfs.path is accessible */ - if (!c->lxc_conf->rootfs.path && !tpath) - /* no template passed in and rootfs does not exist: error */ + if (!c->lxc_conf->rootfs.path && !tpath) { + /* no template passed in and rootfs does not exist */ + if (!c->save_config(c, NULL)) { + ERROR("failed to save starting configuration for %s\n", c->name); + goto out; + } + ret = true; goto out; + } if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) != 0) /* rootfs passed into configuration, but does not exist: error */ goto out; if (lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !tpath) { /* Rootfs already existed, user just wanted to save the * loaded configuration */ + if (!c->save_config(c, NULL)) + ERROR("failed to save starting configuration for %s\n", c->name); ret = true; goto out; } @@ -1372,11 +1338,10 @@ if (partial_fd >= 0) remove_partial(c, partial_fd); out: - if (!ret && c) + if (!ret) lxcapi_destroy(c); free_tpath: - if (tpath) - free(tpath); + free(tpath); return ret; } @@ -1974,8 +1939,8 @@ lxc_container_put(p); } out: - if (lxcpath) free(lxcpath); - if (lxcname) free(lxcname); + free(lxcpath); + free(lxcname); fclose(f); } @@ -2166,8 +2131,7 @@ return false; } - if (c->configfile) - free(c->configfile); + free(c->configfile); c->configfile = newpath; return true; @@ -2206,8 +2170,7 @@ oldpath = NULL; } err: - if (oldpath) - free(oldpath); + free(oldpath); container_mem_unlock(c); return b; } @@ -2564,26 +2527,25 @@ return -1; } } else { // TODO come up with a better way - if (bdev->dest) - free(bdev->dest); + free(bdev->dest); bdev->dest = strdup(bdev->src); } if (!lxc_list_empty(&conf->hooks[LXCHOOK_CLONE])) { /* Start of environment variable setup for hooks */ - if (setenv("LXC_SRC_NAME", c0->name, 1)) { + if (c0->name && setenv("LXC_SRC_NAME", c0->name, 1)) { SYSERROR("failed to set environment variable for source container name"); } - if (setenv("LXC_NAME", c->name, 1)) { + if (c->name && setenv("LXC_NAME", c->name, 1)) { SYSERROR("failed to set environment variable for container name"); } - if (setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) { + if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) { SYSERROR("failed to set environment variable for config path"); } - if (setenv("LXC_ROOTFS_MOUNT", bdev->dest, 1)) { + if (bdev->dest && setenv("LXC_ROOTFS_MOUNT", bdev->dest, 1)) { SYSERROR("failed to set environment variable for rootfs mount"); } - if (setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) { + if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) { SYSERROR("failed to set environment variable for rootfs mount"); } @@ -2645,7 +2607,7 @@ if (!p) return -1; *p = '\0'; - ret = do_create_container_dir(path, conf); + ret = do_create_container_dir(path, conf); *p = '/'; return ret; } @@ -2735,9 +2697,11 @@ goto out; // update utsname - if (!set_config_item_locked(c2, "lxc.utsname", newname)) { - ERROR("Error setting new hostname"); - goto out; + if (!(flags & LXC_CLONE_KEEPNAME)) { + if (!set_config_item_locked(c2, "lxc.utsname", newname)) { + ERROR("Error setting new hostname"); + goto out; + } } // copy hooks @@ -2968,14 +2932,10 @@ static void lxcsnap_free(struct lxc_snapshot *s) { - if (s->name) - free(s->name); - if (s->comment_pathname) - free(s->comment_pathname); - if (s->timestamp) - free(s->timestamp); - if (s->lxcpath) - free(s->lxcpath); + free(s->name); + free(s->comment_pathname); + free(s->timestamp); + free(s->lxcpath); } static char *get_snapcomment_path(char* snappath, char *name) @@ -3610,7 +3570,7 @@ p++; // Now p is the start of lxc_name - p2 = index(p, '/'); + p2 = strchr(p, '/'); if (!p2 || strncmp(p2, "/command", 8) != 0) continue; *p2 = '\0'; @@ -3676,8 +3636,7 @@ } out: - if (line) - free(line); + free(line); fclose(f); return ret; @@ -3749,16 +3708,13 @@ for (i = 0; i < ct_list_cnt; i++) { lxc_container_put(ct_list[i]); } - if (ct_list) - free(ct_list); + free(ct_list); free_active_name: for (i = 0; i < active_cnt; i++) { - if (active_name[i]) - free(active_name[i]); + free(active_name[i]); } - if (active_name) - free(active_name); + free(active_name); free_ct_name: for (i = 0; i < ct_cnt; i++) { diff -Nru lxc-1.0.7/src/lxc/lxccontainer.h lxc-1.0.8/src/lxc/lxccontainer.h --- lxc-1.0.7/src/lxc/lxccontainer.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxccontainer.h 2015-11-09 22:49:15.000000000 +0000 @@ -763,17 +763,17 @@ * \brief Specifications for how to create a new backing store */ struct bdev_specs { - char *fstype; /*!< Filesystem type */ - uint64_t fssize; /*!< Filesystem size in bytes */ - struct { - char *zfsroot; /*!< ZFS root path */ - } zfs; - struct { - char *vg; /*!< LVM Volume Group name */ - char *lv; /*!< LVM Logical Volume name */ - char *thinpool; /*!< LVM thin pool to use, if any */ - } lvm; - char *dir; /*!< Directory path */ + char *fstype; /*!< Filesystem type */ + uint64_t fssize; /*!< Filesystem size in bytes */ + struct { + char *zfsroot; /*!< ZFS root path */ + } zfs; + struct { + char *vg; /*!< LVM Volume Group name */ + char *lv; /*!< LVM Logical Volume name */ + char *thinpool; /*!< LVM thin pool to use, if any */ + } lvm; + char *dir; /*!< Directory path */ }; /*! diff -Nru lxc-1.0.7/src/lxc/lxc_create.c lxc-1.0.8/src/lxc/lxc_create.c --- lxc-1.0.7/src/lxc/lxc_create.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_create.c 2015-11-09 22:49:15.000000000 +0000 @@ -61,7 +61,7 @@ else if (*end == 't' || *end == 'T') ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL; else - { + { fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s); return 0; } @@ -101,8 +101,6 @@ static void create_helpfn(const struct lxc_arguments *args) { char *argv[3], *path; - size_t len; - int ret; pid_t pid; if (!args->template) @@ -114,11 +112,7 @@ return; } - len = strlen(LXCTEMPLATEDIR) + strlen(args->template) + strlen("/lxc-") + 1; - path = alloca(len); - ret = snprintf(path, len, "%s/lxc-%s", LXCTEMPLATEDIR, args->template); - if (ret < 0 || ret >= len) - return; + path = get_template_path(args->template); argv[0] = path; argv[1] = "-h"; @@ -132,12 +126,12 @@ .progname = "lxc-create", .helpfn = create_helpfn, .help = "\ ---name=NAME [-w] [-r] [-t template] [-P lxcpath]\n\ +--name=NAME -t template [-w] [-r] [-P lxcpath]\n\ \n\ lxc-create creates a container\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -f, --config=file Initial configuration file\n\ -t, --template=t Template to use to setup container\n\ -B, --bdev=BDEV Backing store type to use\n\ @@ -203,6 +197,15 @@ exit(1); lxc_log_options_no_override(); + if (!my_args.template) { + fprintf(stderr, "A template must be specified.\n"); + fprintf(stderr, "Use \"none\" if you really want a container without a rootfs.\n"); + exit(1); + } + + if (strcmp(my_args.template, "none") == 0) + my_args.template = NULL; + memset(&spec, 0, sizeof(spec)); if (!my_args.bdevtype) my_args.bdevtype = "_unset"; diff -Nru lxc-1.0.7/src/lxc/lxc_execute.c lxc-1.0.8/src/lxc/lxc_execute.c --- lxc-1.0.7/src/lxc/lxc_execute.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_execute.c 2015-11-09 22:49:15.000000000 +0000 @@ -79,7 +79,7 @@ and execs COMMAND into this container.\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -f, --rcfile=FILE Load configuration file FILE\n\ -s, --define KEY=VAL Assign VAL to configuration variable KEY\n", .options = my_longopts, diff -Nru lxc-1.0.7/src/lxc/lxc_freeze.c lxc-1.0.8/src/lxc/lxc_freeze.c --- lxc-1.0.7/src/lxc/lxc_freeze.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_freeze.c 2015-11-09 22:49:15.000000000 +0000 @@ -47,7 +47,7 @@ lxc-freeze freezes a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container", + -n, --name=NAME NAME of the container", .options = my_longopts, .parser = NULL, .checker = NULL, diff -Nru lxc-1.0.7/src/lxc/lxc.h lxc-1.0.8/src/lxc/lxc.h --- lxc-1.0.7/src/lxc/lxc.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc.h 2015-11-09 22:49:15.000000000 +0000 @@ -64,44 +64,6 @@ struct lxc_conf *conf, const char *lxcpath); /* - * Open the monitoring mechanism for a specific container - * The function will return an fd corresponding to the events - * Returns a file descriptor on success, < 0 otherwise - */ -extern int lxc_monitor_open(const char *lxcpath); - -/* - * Blocking read for the next container state change - * @fd : the file descriptor provided by lxc_monitor_open - * @msg : the variable which will be filled with the state - * Returns 0 if the monitored container has exited, > 0 if - * data was read, < 0 otherwise - */ -extern int lxc_monitor_read(int fd, struct lxc_msg *msg); - -/* - * Blocking read for the next container state change with timeout - * @fd : the file descriptor provided by lxc_monitor_open - * @msg : the variable which will be filled with the state - * @timeout : the timeout in seconds to wait for a state change - * Returns 0 if the monitored container has exited, > 0 if - * data was read, < 0 otherwise - */ -extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout); - -/* - * Blocking read from multiple monitors for the next container state - * change with timeout - * @rfds : an fd_set of file descriptors provided by lxc_monitor_open - * @nfds : the maximum fd number in rfds + 1 - * @msg : the variable which will be filled with the state - * @timeout : the timeout in seconds to wait for a state change - * Returns 0 if the monitored container has exited, > 0 if - * data was read, < 0 otherwise - */ -extern int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, int timeout); - -/* * Close the fd associated with the monitoring * @fd : the file descriptor provided by lxc_monitor_open * Returns 0 on success, < 0 otherwise diff -Nru lxc-1.0.7/src/lxc/lxc_info.c lxc-1.0.8/src/lxc/lxc_info.c --- lxc-1.0.7/src/lxc/lxc_info.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_info.c 2015-11-09 22:49:15.000000000 +0000 @@ -53,7 +53,7 @@ char **newk; switch (c) { case 'c': - newk = realloc(key, keys+1 * sizeof(key[0])); + newk = realloc(key, (keys + 1) * sizeof(key[0])); if (!newk) return -1; key = newk; @@ -87,7 +87,7 @@ lxc-info display some information about a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -c, --config=KEY show configuration variable KEY from running container\n\ -i, --ips shows the IP addresses\n\ -p, --pid shows the process id of the init container\n\ diff -Nru lxc-1.0.7/src/lxc/lxc_init.c lxc-1.0.8/src/lxc/lxc_init.c --- lxc-1.0.7/src/lxc/lxc_init.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_init.c 2015-11-09 22:49:15.000000000 +0000 @@ -36,7 +36,7 @@ #include "log.h" #include "caps.h" #include "error.h" -#include "utils.h" +#include "initutils.h" lxc_log_define(lxc_init, lxc); @@ -61,7 +61,7 @@ static void usage(void) { fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n" "Common options :\n" - " -n, --name=NAME NAME for name of the container\n" + " -n, --name=NAME NAME of the container\n" " -l, --logpriority=LEVEL Set log priority to LEVEL\n" " -q, --quiet Don't produce any output\n" " -P, --lxcpath=PATH Use specified container path\n" @@ -117,7 +117,7 @@ aargv = &argv[optind]; - /* + /* * mask all the signals so we are safe to install a * signal handler and to fork */ diff -Nru lxc-1.0.7/src/lxc/lxclock.c lxc-1.0.8/src/lxc/lxclock.c --- lxc-1.0.7/src/lxc/lxclock.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxclock.c 2015-11-09 22:49:15.000000000 +0000 @@ -103,13 +103,13 @@ char *rundir; /* lockfile will be: - * "/run" + "/lock/lxc/$lxcpath/$lxcname + '\0' if root + * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root * or - * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root + * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root */ - /* length of "/lock/lxc/" + $lxcpath + "/" + $lxcname + '\0' */ - len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 2; + /* length of "/lxc/lock/" + $lxcpath + "/" + $lxcname + '\0' */ + len = strlen("/lxc/lock/") + strlen(n) + strlen(p) + 2; rundir = get_rundir(); if (!rundir) return NULL; @@ -120,7 +120,7 @@ return NULL; } - ret = snprintf(dest, len, "%s/lock/lxc/%s", rundir, p); + ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p); if (ret < 0 || ret >= len) { free(dest); free(rundir); @@ -128,31 +128,13 @@ } ret = mkdir_p(dest, 0755); if (ret < 0) { - /* fall back to "/tmp/" $(id -u) "/lxc/" $lxcpath / $lxcname + '\0' */ - int l2 = 33 + strlen(n) + strlen(p); - if (l2 > len) { - char *d; - d = realloc(dest, l2); - if (!d) { - free(dest); - free(rundir); - return NULL; - } - len = l2; - dest = d; - } - ret = snprintf(dest, len, "/tmp/%d/lxc/%s", geteuid(), p); - if (ret < 0 || ret >= len) { - free(dest); - free(rundir); - return NULL; - } - ret = snprintf(dest, len, "/tmp/%d/lxc/%s/%s", geteuid(), p, n); - } else - ret = snprintf(dest, len, "%s/lock/lxc/%s/%s", rundir, p, n); + free(dest); + free(rundir); + return NULL; + } + ret = snprintf(dest, len, "%s/lxc/lock/%s/%s", rundir, p, n); free(rundir); - if (ret < 0 || ret >= len) { free(dest); return NULL; @@ -323,10 +305,8 @@ close(l->u.f.fd); l->u.f.fd = -1; } - if (l->u.f.fname) { - free(l->u.f.fname); - l->u.f.fname = NULL; - } + free(l->u.f.fname); + l->u.f.fname = NULL; break; } free(l); diff -Nru lxc-1.0.7/src/lxc/lxc_monitor.c lxc-1.0.8/src/lxc/lxc_monitor.c --- lxc-1.0.7/src/lxc/lxc_monitor.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_monitor.c 2015-11-09 22:49:15.000000000 +0000 @@ -29,6 +29,7 @@ #include #include #include +#include #include "lxc.h" #include "log.h" @@ -60,7 +61,7 @@ lxc-monitor monitors the state of the NAME container\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ NAME may be a regular expression\n\ -Q, --quit tell lxc-monitord to quit\n", .name = ".*", @@ -70,13 +71,28 @@ .lxcpath_additional = -1, }; +static void close_fds(struct pollfd *fds, nfds_t nfds) +{ + nfds_t i; + + if (nfds < 1) + return; + + for (i = 0; i < nfds; ++i) { + close(fds[i].fd); + } +} + int main(int argc, char *argv[]) { char *regexp; struct lxc_msg msg; regex_t preg; - fd_set rfds, rfds_save; - int len, rc, i, nfds = -1; + struct pollfd *fds; + nfds_t nfds; + int len, rc_main, rc_snp, i; + + rc_main = 0; if (lxc_arguments_parse(&my_args, argc, argv)) return 1; @@ -117,51 +133,49 @@ ERROR("failed to allocate memory"); return 1; } - rc = snprintf(regexp, len, "^%s$", my_args.name); - if (rc < 0 || rc >= len) { + rc_snp = snprintf(regexp, len, "^%s$", my_args.name); + if (rc_snp < 0 || rc_snp >= len) { ERROR("Name too long"); - free(regexp); - return 1; + rc_main = 1; + goto error; } if (regcomp(&preg, regexp, REG_NOSUB|REG_EXTENDED)) { ERROR("failed to compile the regex '%s'", my_args.name); - free(regexp); - return 1; + rc_main = 1; + goto error; } - free(regexp); - if (my_args.lxcpath_cnt > FD_SETSIZE) { - ERROR("too many paths requested, only the first %d will be monitored", FD_SETSIZE); - my_args.lxcpath_cnt = FD_SETSIZE; + fds = malloc(my_args.lxcpath_cnt * sizeof(struct pollfd)); + if (!fds) { + SYSERROR("out of memory"); + rc_main = -1; + goto cleanup; } - FD_ZERO(&rfds); - for (i = 0; i < my_args.lxcpath_cnt; i++) { + nfds = my_args.lxcpath_cnt; + for (i = 0; i < nfds; i++) { int fd; lxc_monitord_spawn(my_args.lxcpath[i]); fd = lxc_monitor_open(my_args.lxcpath[i]); if (fd < 0) { - regfree(&preg); - return 1; + close_fds(fds, i); + rc_main = 1; + goto cleanup; } - FD_SET(fd, &rfds); - if (fd > nfds) - nfds = fd; + fds[i].fd = fd; + fds[i].events = POLLIN; + fds[i].revents = 0; } - memcpy(&rfds_save, &rfds, sizeof(rfds_save)); - nfds++; setlinebuf(stdout); for (;;) { - memcpy(&rfds, &rfds_save, sizeof(rfds)); - - if (lxc_monitor_read_fdset(&rfds, nfds, &msg, -1) < 0) { - regfree(&preg); - return 1; + if (lxc_monitor_read_fdset(fds, nfds, &msg, -1) < 0) { + rc_main = 1; + goto close_and_clean; } msg.name[sizeof(msg.name)-1] = '\0'; @@ -183,7 +197,15 @@ } } +close_and_clean: + close_fds(fds, nfds); + +cleanup: regfree(&preg); + free(fds); - return 0; +error: + free(regexp); + + return rc_main; } diff -Nru lxc-1.0.7/src/lxc/lxc_snapshot.c lxc-1.0.8/src/lxc/lxc_snapshot.c --- lxc-1.0.7/src/lxc/lxc_snapshot.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_snapshot.c 2015-11-09 22:49:15.000000000 +0000 @@ -72,8 +72,7 @@ while (getline(&line, &sz, f) != -1) { printf("%s", line); } - if (line) - free(line); + free(line); fclose(f); } diff -Nru lxc-1.0.7/src/lxc/lxc_start.c lxc-1.0.8/src/lxc/lxc_start.c --- lxc-1.0.7/src/lxc/lxc_start.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_start.c 2015-11-09 22:49:15.000000000 +0000 @@ -89,8 +89,7 @@ err = 0; err: - if (fullpath) - free(fullpath); + free(fullpath); return err; } @@ -182,7 +181,7 @@ lxc-start start COMMAND in specified container NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -d, --daemon Daemonize the container\n\ -F, --foreground Start with the current tty attached to /dev/console (default)\n\ -p, --pidfile=FILE Create a file with the process id\n\ @@ -191,7 +190,7 @@ -L, --console-log=FILE Log container console output to FILE\n\ -C, --close-all-fds If any fds are inherited, close them\n\ If not specified, exit with failure instead\n\ - Note: --daemon implies --close-all-fds\n\ + Note: --daemon implies --close-all-fds\n\ -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\ --share-[net|ipc|uts]=NAME Share a namespace with another container or pid\n\ ", diff -Nru lxc-1.0.7/src/lxc/lxc-start-ephemeral.in lxc-1.0.8/src/lxc/lxc-start-ephemeral.in --- lxc-1.0.7/src/lxc/lxc-start-ephemeral.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc-start-ephemeral.in 2015-11-09 22:49:15.000000000 +0000 @@ -29,7 +29,6 @@ import gettext import lxc import os -import pwd import sys import subprocess import tempfile @@ -117,12 +116,6 @@ args = parser.parse_args() -# Basic requirements check -## We only support privileged containers for now -if os.geteuid() != 0 and args.union_type != "overlayfs": - parser.error(_("Unprivileged containers may only use " - "overlayfs at this time.")) - ## Check that -d and CMD aren't used at the same time if args.command and args.daemon: parser.error(_("You can't use -d and a command at the same time.")) @@ -162,6 +155,7 @@ dest.load_config(orig.config_file_name) dest.set_config_item("lxc.utsname", dest.name) dest.set_config_item("lxc.rootfs", os.path.join(dest_path, "rootfs")) +print("setting rootfs to .%s.", os.path.join(dest_path, "rootfs")) for nic in dest.network: if hasattr(nic, 'hwaddr'): nic.hwaddr = randomMAC() @@ -206,6 +200,14 @@ # Setup an overlay for anything remaining overlay_dirs += [(fields[0], dest_mount)] +# do we have the new overlay fs which requires workdir, or the older +# overlayfs which does not? +have_new_overlay = False +with open("/proc/filesystems", "r") as fd: + for line in fd: + if line == "nodev\toverlay\n": + have_new_overlay = True + # Generate pre-mount script with open(os.path.join(dest_path, "pre-mount"), "w+") as fd: os.fchmod(fd.fileno(), 0o755) @@ -217,26 +219,38 @@ count = 0 for entry in overlay_dirs: - target = "%s/delta%s" % (dest_path, count) - fd.write("mkdir -p %s %s\n" % (target, entry[1])) - + tmpdir = "%s/tmpfs" % dest_path + fd.write("mkdir -p %s\n" % (tmpdir)) if args.storage_type == "tmpfs": - fd.write("mount -n -t tmpfs -o mode=0755 none %s\n" % (target)) + fd.write("mount -n -t tmpfs -o mode=0755 none %s\n" % (tmpdir)) + deltdir = "%s/delta%s" % (tmpdir, count) + workdir = "%s/work%s" % (tmpdir, count) + fd.write("mkdir -p %s %s\n" % (deltdir, entry[1])) + if have_new_overlay: + fd.write("mkdir -p %s\n" % workdir) if args.union_type == "overlayfs": - fd.write("mount -n -t overlayfs" - " -oupperdir=%s,lowerdir=%s none %s\n" % ( - target, - entry[0], - entry[1])) + if have_new_overlay: + fd.write("mount -n -t overlay" + " -oupperdir=%s,lowerdir=%s,workdir=%s none %s\n" % ( + deltdir, + entry[0], + workdir, + entry[1])) + else: + fd.write("mount -n -t overlayfs" + " -oupperdir=%s,lowerdir=%s none %s\n" % ( + deltdir, + entry[0], + entry[1])) elif args.union_type == "aufs": - xino_path = "%s/lxc/aufs.xino" % get_rundir() + xino_path = "/dev/shm/aufs.xino" if not os.path.exists(os.path.basename(xino_path)): os.makedirs(os.path.basename(xino_path)) fd.write("mount -n -t aufs " "-o br=%s=rw:%s=ro,noplink,xino=%s none %s\n" % ( - target, + deltdir, entry[0], xino_path, entry[1])) @@ -323,12 +337,17 @@ if args.user: username = args.user - user = pwd.getpwnam(username) - os.setgid(user.pw_gid) - os.initgroups(user.pw_name, user.pw_gid) - os.setuid(user.pw_uid) - os.chdir(user.pw_dir) - os.environ['HOME'] = user.pw_dir + line = subprocess.check_output( + ["getent", "passwd", username], + universal_newlines=True).rstrip("\n") + _, _, pw_uid, pw_gid, _, pw_dir, _ = line.split(":", 6) + pw_uid = int(pw_uid) + pw_gid = int(pw_gid) + os.setgid(pw_gid) + os.initgroups(username, pw_gid) + os.setuid(pw_uid) + os.chdir(pw_dir) + os.environ['HOME'] = pw_dir except: print(_("Unable to switch to user: %s" % username)) sys.exit(1) diff -Nru lxc-1.0.7/src/lxc/lxc_stop.c lxc-1.0.8/src/lxc/lxc_stop.c --- lxc-1.0.7/src/lxc/lxc_stop.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_stop.c 2015-11-09 22:49:15.000000000 +0000 @@ -69,7 +69,7 @@ lxc-stop stops a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -r, --reboot reboot the container\n\ -W, --nowait don't wait for shutdown or reboot to complete\n\ -t, --timeout=T wait T seconds before hard-stopping\n\ diff -Nru lxc-1.0.7/src/lxc/lxc_unfreeze.c lxc-1.0.8/src/lxc/lxc_unfreeze.c --- lxc-1.0.7/src/lxc/lxc_unfreeze.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_unfreeze.c 2015-11-09 22:49:15.000000000 +0000 @@ -45,7 +45,7 @@ lxc-unfreeze unfreezes a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n", + -n, --name=NAME NAME of the container\n", .options = my_longopts, .parser = NULL, .checker = NULL, diff -Nru lxc-1.0.7/src/lxc/lxc_unshare.c lxc-1.0.8/src/lxc/lxc_unshare.c --- lxc-1.0.7/src/lxc/lxc_unshare.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_unshare.c 2015-11-09 22:49:15.000000000 +0000 @@ -115,8 +115,8 @@ int *flags; uid_t *uid; bool setuid; - int want_default_mounts; - const char *want_hostname; + int want_default_mounts; + const char *want_hostname; }; static int do_start(void *arg) diff -Nru lxc-1.0.7/src/lxc/lxc_user_nic.c lxc-1.0.8/src/lxc/lxc_user_nic.c --- lxc-1.0.7/src/lxc/lxc_user_nic.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_user_nic.c 2015-11-09 22:49:15.000000000 +0000 @@ -133,8 +133,7 @@ return n; } fclose(fin); - if (line) - free(line); + free(line); return -1; } diff -Nru lxc-1.0.7/src/lxc/lxc_usernsexec.c lxc-1.0.8/src/lxc/lxc_usernsexec.c --- lxc-1.0.7/src/lxc/lxc_usernsexec.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_usernsexec.c 2015-11-09 22:49:15.000000000 +0000 @@ -74,8 +74,11 @@ exit(1); } -static void opentty(const char * tty) { - int i, fd, flags; +static void opentty(const char * tty, int which) { + int fd, flags; + + if (tty[0] == '\0') + return; fd = open(tty, O_RDWR | O_NONBLOCK); if (fd == -1) { @@ -90,13 +93,11 @@ return; } - for (i = 0; i < fd; i++) - close(i); - for (i = 0; i < 3; i++) - if (fd != i) - dup2(fd, i); - if (fd >= 3) + close(which); + if (fd != which) { + dup2(fd, which); close(fd); + } } // Code copy end @@ -214,10 +215,10 @@ strncmp(line, username, strlen(username)) != 0 || line[strlen(username)] != ':') continue; - p1 = index(line, ':'); + p1 = strchr(line, ':'); if (!p1) continue; - p2 = index(p1+1, ':'); + p2 = strchr(p1+1, ':'); if (!p2) continue; newmap = malloc(sizeof(*newmap)); @@ -244,8 +245,7 @@ break; } - if (line) - free(line); + free(line); fclose(fin); return 0; } @@ -266,7 +266,7 @@ { int c; unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS; - char ttyname[256]; + char ttyname0[256], ttyname1[256], ttyname2[256]; int status; int ret; int pid; @@ -275,11 +275,25 @@ int pipe1[2], // child tells parent it has unshared pipe2[2]; // parent tells child it is mapped and may proceed - memset(ttyname, '\0', sizeof(ttyname)); - ret = readlink("/proc/self/fd/0", ttyname, sizeof(ttyname)); - if (ret < 0) { - perror("readlink on fd 0"); - exit(1); + memset(ttyname0, '\0', sizeof(ttyname0)); + memset(ttyname1, '\0', sizeof(ttyname1)); + memset(ttyname2, '\0', sizeof(ttyname2)); + if (isatty(0)) { + ret = readlink("/proc/self/fd/0", ttyname0, sizeof(ttyname0)); + if (ret < 0) { + perror("unable to open stdin."); + exit(1); + } + ret = readlink("/proc/self/fd/1", ttyname1, sizeof(ttyname1)); + if (ret < 0) { + printf("Warning: unable to open stdout, continuing."); + memset(ttyname1, '\0', sizeof(ttyname1)); + } + ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2)); + if (ret < 0) { + printf("Warning: unable to open stderr, continueing."); + memset(ttyname2, '\0', sizeof(ttyname2)); + } } lxc_list_init(&active_map); @@ -316,7 +330,9 @@ close(pipe1[0]); close(pipe2[1]); - opentty(ttyname); + opentty(ttyname0, 0); + opentty(ttyname1, 1); + opentty(ttyname2, 2); ret = unshare(flags); if (ret < 0) { diff -Nru lxc-1.0.7/src/lxc/lxc_wait.c lxc-1.0.8/src/lxc/lxc_wait.c --- lxc-1.0.7/src/lxc/lxc_wait.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/lxc_wait.c 2015-11-09 22:49:15.000000000 +0000 @@ -68,7 +68,7 @@ lxc-wait waits for NAME container state to reach STATE\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -s, --state=STATE ORed states to wait for\n\ STOPPED, STARTING, RUNNING, STOPPING,\n\ ABORTING, FREEZING, FROZEN, THAWED\n\ diff -Nru lxc-1.0.7/src/lxc/Makefile.am lxc-1.0.8/src/lxc/Makefile.am --- lxc-1.0.7/src/lxc/Makefile.am 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/Makefile.am 2015-11-09 22:49:15.000000000 +0000 @@ -12,6 +12,7 @@ conf.h \ console.h \ error.h \ + initutils.h \ list.h \ log.h \ lxc.h \ @@ -66,6 +67,7 @@ cgfs.c \ cgroup.c cgroup.h \ lxc.h \ + initutils.c initutils.h \ utils.c utils.h \ sync.c sync.h \ namespace.h namespace.c \ diff -Nru lxc-1.0.7/src/lxc/Makefile.in lxc-1.0.8/src/lxc/Makefile.in --- lxc-1.0.7/src/lxc/Makefile.in 2014-12-05 20:50:27.000000000 +0000 +++ lxc-1.0.8/src/lxc/Makefile.in 2015-11-09 22:49:20.000000000 +0000 @@ -146,18 +146,18 @@ am__liblxc_so_SOURCES_DIST = arguments.c arguments.h bdev.c bdev.h \ lxc-btrfs.h commands.c commands.h start.c start.h execute.c \ monitor.c monitor.h console.c freezer.c error.h error.c \ - parse.c parse.h cgfs.c cgroup.c cgroup.h lxc.h utils.c utils.h \ - sync.c sync.h namespace.h namespace.c conf.c conf.h confile.c \ - confile.h list.h state.c state.h log.c log.h attach.c attach.h \ - network.c network.h nl.c nl.h rtnl.c rtnl.h genl.c genl.h \ - caps.c caps.h lxcseccomp.h mainloop.c mainloop.h af_unix.c \ - af_unix.h lxcutmp.c lxcutmp.h lxclock.h lxclock.c \ - lxccontainer.c lxccontainer.h version.h lsm/nop.c lsm/lsm.h \ - lsm/lsm.c lsm/apparmor.c lsm/selinux.c cgmanager.c \ - ../include/ifaddrs.c ../include/ifaddrs.h ../include/openpty.c \ - ../include/openpty.h ../include/lxcmntent.c \ - ../include/lxcmntent.h ../include/getline.c \ - ../include/getline.h seccomp.c + parse.c parse.h cgfs.c cgroup.c cgroup.h lxc.h initutils.c \ + initutils.h utils.c utils.h sync.c sync.h namespace.h \ + namespace.c conf.c conf.h confile.c confile.h list.h state.c \ + state.h log.c log.h attach.c attach.h network.c network.h nl.c \ + nl.h rtnl.c rtnl.h genl.c genl.h caps.c caps.h lxcseccomp.h \ + mainloop.c mainloop.h af_unix.c af_unix.h lxcutmp.c lxcutmp.h \ + lxclock.h lxclock.c lxccontainer.c lxccontainer.h version.h \ + lsm/nop.c lsm/lsm.h lsm/lsm.c lsm/apparmor.c lsm/selinux.c \ + cgmanager.c ../include/ifaddrs.c ../include/ifaddrs.h \ + ../include/openpty.c ../include/openpty.h \ + ../include/lxcmntent.c ../include/lxcmntent.h \ + ../include/getline.c ../include/getline.h seccomp.c am__dirstamp = $(am__leading_dot)dirstamp @ENABLE_APPARMOR_TRUE@am__objects_1 = \ @ENABLE_APPARMOR_TRUE@ lsm/liblxc_so-apparmor.$(OBJEXT) @@ -177,18 +177,18 @@ liblxc_so-monitor.$(OBJEXT) liblxc_so-console.$(OBJEXT) \ liblxc_so-freezer.$(OBJEXT) liblxc_so-error.$(OBJEXT) \ liblxc_so-parse.$(OBJEXT) liblxc_so-cgfs.$(OBJEXT) \ - liblxc_so-cgroup.$(OBJEXT) liblxc_so-utils.$(OBJEXT) \ - liblxc_so-sync.$(OBJEXT) liblxc_so-namespace.$(OBJEXT) \ - liblxc_so-conf.$(OBJEXT) liblxc_so-confile.$(OBJEXT) \ - liblxc_so-state.$(OBJEXT) liblxc_so-log.$(OBJEXT) \ - liblxc_so-attach.$(OBJEXT) liblxc_so-network.$(OBJEXT) \ - liblxc_so-nl.$(OBJEXT) liblxc_so-rtnl.$(OBJEXT) \ - liblxc_so-genl.$(OBJEXT) liblxc_so-caps.$(OBJEXT) \ - liblxc_so-mainloop.$(OBJEXT) liblxc_so-af_unix.$(OBJEXT) \ - liblxc_so-lxcutmp.$(OBJEXT) liblxc_so-lxclock.$(OBJEXT) \ - liblxc_so-lxccontainer.$(OBJEXT) $(am__objects_3) \ - $(am__objects_4) $(am__objects_5) $(am__objects_6) \ - $(am__objects_7) + liblxc_so-cgroup.$(OBJEXT) liblxc_so-initutils.$(OBJEXT) \ + liblxc_so-utils.$(OBJEXT) liblxc_so-sync.$(OBJEXT) \ + liblxc_so-namespace.$(OBJEXT) liblxc_so-conf.$(OBJEXT) \ + liblxc_so-confile.$(OBJEXT) liblxc_so-state.$(OBJEXT) \ + liblxc_so-log.$(OBJEXT) liblxc_so-attach.$(OBJEXT) \ + liblxc_so-network.$(OBJEXT) liblxc_so-nl.$(OBJEXT) \ + liblxc_so-rtnl.$(OBJEXT) liblxc_so-genl.$(OBJEXT) \ + liblxc_so-caps.$(OBJEXT) liblxc_so-mainloop.$(OBJEXT) \ + liblxc_so-af_unix.$(OBJEXT) liblxc_so-lxcutmp.$(OBJEXT) \ + liblxc_so-lxclock.$(OBJEXT) liblxc_so-lxccontainer.$(OBJEXT) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + $(am__objects_6) $(am__objects_7) liblxc_so_OBJECTS = $(am_liblxc_so_OBJECTS) am__DEPENDENCIES_1 = @ENABLE_CGMANAGER_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ @@ -374,9 +374,9 @@ *) (install-info --version) >/dev/null 2>&1;; \ esac am__noinst_HEADERS_DIST = arguments.h attach.h bdev.h caps.h cgroup.h \ - conf.h console.h error.h list.h log.h lxc.h lxc-btrfs.h \ - lxclock.h monitor.h namespace.h start.h state.h utils.h \ - ../include/ifaddrs.h ../include/openpty.h \ + conf.h console.h error.h initutils.h list.h log.h lxc.h \ + lxc-btrfs.h lxclock.h monitor.h namespace.h start.h state.h \ + utils.h ../include/ifaddrs.h ../include/openpty.h \ ../include/lxcmntent.h ../include/getline.h HEADERS = $(noinst_HEADERS) $(pkginclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) @@ -566,23 +566,24 @@ version.h noinst_HEADERS = arguments.h attach.h bdev.h caps.h cgroup.h conf.h \ - console.h error.h list.h log.h lxc.h lxc-btrfs.h lxclock.h \ - monitor.h namespace.h start.h state.h utils.h $(am__append_1) \ - $(am__append_2) + console.h error.h initutils.h list.h log.h lxc.h lxc-btrfs.h \ + lxclock.h monitor.h namespace.h start.h state.h utils.h \ + $(am__append_1) $(am__append_2) sodir = $(libdir) LSM_SOURCES = lsm/nop.c lsm/lsm.h lsm/lsm.c $(am__append_3) \ $(am__append_4) liblxc_so_SOURCES = arguments.c arguments.h bdev.c bdev.h lxc-btrfs.h \ commands.c commands.h start.c start.h execute.c monitor.c \ monitor.h console.c freezer.c error.h error.c parse.c parse.h \ - cgfs.c cgroup.c cgroup.h lxc.h utils.c utils.h sync.c sync.h \ - namespace.h namespace.c conf.c conf.h confile.c confile.h \ - list.h state.c state.h log.c log.h attach.c attach.h network.c \ - network.h nl.c nl.h rtnl.c rtnl.h genl.c genl.h caps.c caps.h \ - lxcseccomp.h mainloop.c mainloop.h af_unix.c af_unix.h \ - lxcutmp.c lxcutmp.h lxclock.h lxclock.c lxccontainer.c \ - lxccontainer.h version.h $(LSM_SOURCES) $(am__append_5) \ - $(am__append_6) $(am__append_7) $(am__append_13) + cgfs.c cgroup.c cgroup.h lxc.h initutils.c initutils.h utils.c \ + utils.h sync.c sync.h namespace.h namespace.c conf.c conf.h \ + confile.c confile.h list.h state.c state.h log.c log.h \ + attach.c attach.h network.c network.h nl.c nl.h rtnl.c rtnl.h \ + genl.c genl.h caps.c caps.h lxcseccomp.h mainloop.c mainloop.h \ + af_unix.c af_unix.h lxcutmp.c lxcutmp.h lxclock.h lxclock.c \ + lxccontainer.c lxccontainer.h version.h $(LSM_SOURCES) \ + $(am__append_5) $(am__append_6) $(am__append_7) \ + $(am__append_13) AM_CFLAGS = -I$(top_srcdir)/src -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ -DLXCPATH=\"$(LXCPATH)\" \ -DLXC_GLOBAL_CONF=\"$(LXC_GLOBAL_CONF)\" \ @@ -1031,6 +1032,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-execute.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-freezer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-genl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-initutils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-lxccontainer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblxc_so-lxclock.Po@am__quote@ @@ -1259,6 +1261,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-cgroup.obj `if test -f 'cgroup.c'; then $(CYGPATH_W) 'cgroup.c'; else $(CYGPATH_W) '$(srcdir)/cgroup.c'; fi` +liblxc_so-initutils.o: initutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-initutils.o -MD -MP -MF $(DEPDIR)/liblxc_so-initutils.Tpo -c -o liblxc_so-initutils.o `test -f 'initutils.c' || echo '$(srcdir)/'`initutils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-initutils.Tpo $(DEPDIR)/liblxc_so-initutils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='initutils.c' object='liblxc_so-initutils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-initutils.o `test -f 'initutils.c' || echo '$(srcdir)/'`initutils.c + +liblxc_so-initutils.obj: initutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-initutils.obj -MD -MP -MF $(DEPDIR)/liblxc_so-initutils.Tpo -c -o liblxc_so-initutils.obj `if test -f 'initutils.c'; then $(CYGPATH_W) 'initutils.c'; else $(CYGPATH_W) '$(srcdir)/initutils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-initutils.Tpo $(DEPDIR)/liblxc_so-initutils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='initutils.c' object='liblxc_so-initutils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -c -o liblxc_so-initutils.obj `if test -f 'initutils.c'; then $(CYGPATH_W) 'initutils.c'; else $(CYGPATH_W) '$(srcdir)/initutils.c'; fi` + liblxc_so-utils.o: utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblxc_so_CFLAGS) $(CFLAGS) -MT liblxc_so-utils.o -MD -MP -MF $(DEPDIR)/liblxc_so-utils.Tpo -c -o liblxc_so-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblxc_so-utils.Tpo $(DEPDIR)/liblxc_so-utils.Po diff -Nru lxc-1.0.7/src/lxc/monitor.c lxc-1.0.8/src/lxc/monitor.c --- lxc-1.0.7/src/lxc/monitor.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/monitor.c 2015-11-09 22:49:15.000000000 +0000 @@ -38,6 +38,7 @@ #include #include #include +#include #include "error.h" #include "af_unix.h" @@ -181,7 +182,7 @@ int lxc_monitor_open(const char *lxcpath) { struct sockaddr_un addr; - int fd,ret; + int fd,ret = 0; int retry,backoff_ms[] = {10, 50, 100}; size_t len; @@ -219,19 +220,13 @@ return ret; } -int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, +int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg, int timeout) { - struct timeval tval,*tv = NULL; - int ret,i; - - if (timeout != -1) { - tv = &tval; - tv->tv_sec = timeout; - tv->tv_usec = 0; - } + long i; + int ret; - ret = select(nfds, rfds, NULL, NULL, tv); + ret = poll(fds, nfds, timeout * 1000); if (ret == -1) return -1; else if (ret == 0) @@ -241,8 +236,9 @@ * for when this routine is called again */ for (i = 0; i < nfds; i++) { - if (FD_ISSET(i, rfds)) { - ret = recv(i, msg, sizeof(*msg), 0); + if (fds[i].revents != 0) { + fds[i].revents = 0; + ret = recv(fds[i].fd, msg, sizeof(*msg), 0); if (ret <= 0) { SYSERROR("client failed to recv (monitord died?) %s", strerror(errno)); @@ -257,12 +253,13 @@ int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout) { - fd_set rfds; + struct pollfd fds; - FD_ZERO(&rfds); - FD_SET(fd, &rfds); + fds.fd = fd; + fds.events = POLLIN | POLLPRI; + fds.revents = 0; - return lxc_monitor_read_fdset(&rfds, fd+1, msg, timeout); + return lxc_monitor_read_fdset(&fds, 1, msg, timeout); } int lxc_monitor_read(int fd, struct lxc_msg *msg) @@ -332,12 +329,8 @@ exit(EXIT_FAILURE); } lxc_check_inherited(NULL, pipefd[1]); - close(0); - close(1); - close(2); - open("/dev/null", O_RDONLY); - open("/dev/null", O_RDWR); - open("/dev/null", O_RDWR); + if (null_stdfds() < 0) + exit(EXIT_FAILURE); close(pipefd[0]); sprintf(pipefd_str, "%d", pipefd[1]); execvp(args[0], args); diff -Nru lxc-1.0.7/src/lxc/monitor.h lxc-1.0.8/src/lxc/monitor.h --- lxc-1.0.7/src/lxc/monitor.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/monitor.h 2015-11-09 22:49:15.000000000 +0000 @@ -26,6 +26,7 @@ #include #include #include +#include #include "conf.h" @@ -41,7 +42,6 @@ int value; }; -extern int lxc_monitor_open(const char *lxcpath); extern int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr); extern int lxc_monitor_fifo_name(const char *lxcpath, char *fifo_path, size_t fifo_path_sz, int do_mkdirp); @@ -51,4 +51,44 @@ const char *lxcpath); extern int lxc_monitord_spawn(const char *lxcpath); +/* + * Open the monitoring mechanism for a specific container + * The function will return an fd corresponding to the events + * Returns a file descriptor on success, < 0 otherwise + */ +extern int lxc_monitor_open(const char *lxcpath); + +/* + * Blocking read for the next container state change + * @fd : the file descriptor provided by lxc_monitor_open + * @msg : the variable which will be filled with the state + * Returns 0 if the monitored container has exited, > 0 if + * data was read, < 0 otherwise + */ +extern int lxc_monitor_read(int fd, struct lxc_msg *msg); + +/* + * Blocking read for the next container state change with timeout + * @fd : the file descriptor provided by lxc_monitor_open + * @msg : the variable which will be filled with the state + * @timeout : the timeout in seconds to wait for a state change + * Returns 0 if the monitored container has exited, > 0 if + * data was read, < 0 otherwise + */ +extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout); + +/* + * Blocking read from multiple monitors for the next container state + * change with timeout + * @fds : struct pollfd descripting the fds to use + * @nfds : the number of entries in fds + * @msg : the variable which will be filled with the state + * @timeout : the timeout in seconds to wait for a state change + * Returns 0 if the monitored container has exited, > 0 if + * data was read, < 0 otherwise + */ +extern int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg, + int timeout); + + #endif diff -Nru lxc-1.0.7/src/lxc/nl.c lxc-1.0.8/src/lxc/nl.c --- lxc-1.0.7/src/lxc/nl.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/nl.c 2015-11-09 22:49:15.000000000 +0000 @@ -74,7 +74,7 @@ extern int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string) { - return nla_put(nlmsg, attr, string, strlen(string) + 1); + return nla_put(nlmsg, attr, string, strlen(string) + 1); } extern int nla_put_u32(struct nlmsg *nlmsg, int attr, int value) @@ -173,23 +173,23 @@ extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer) { int ret; - struct sockaddr_nl nladdr; - struct iovec iov = { - .iov_base = answer->nlmsghdr, - .iov_len = answer->nlmsghdr->nlmsg_len, - }; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = answer->nlmsghdr, + .iov_len = answer->nlmsghdr->nlmsg_len, + }; struct msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = 0; - nladdr.nl_groups = 0; + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; again: ret = recvmsg(handler->fd, &msg, 0); @@ -211,23 +211,23 @@ extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg) { - struct sockaddr_nl nladdr; - struct iovec iov = { - .iov_base = nlmsg->nlmsghdr, - .iov_len = nlmsg->nlmsghdr->nlmsg_len, - }; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = nlmsg->nlmsghdr, + .iov_len = nlmsg->nlmsghdr->nlmsg_len, + }; struct msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; int ret; - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = 0; - nladdr.nl_groups = 0; + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; ret = sendmsg(handler->fd, &msg, 0); if (ret < 0) @@ -263,45 +263,45 @@ extern int netlink_open(struct nl_handler *handler, int protocol) { socklen_t socklen; - int sndbuf = 32768; - int rcvbuf = 32768; + int sndbuf = 32768; + int rcvbuf = 32768; - memset(handler, 0, sizeof(*handler)); + memset(handler, 0, sizeof(*handler)); - handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol); - if (handler->fd < 0) - return -errno; + handler->fd = socket(AF_NETLINK, SOCK_RAW, protocol); + if (handler->fd < 0) + return -errno; - if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF, + if (setsockopt(handler->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) - return -errno; + return -errno; - if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF, + if (setsockopt(handler->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,sizeof(rcvbuf)) < 0) - return -errno; + return -errno; - memset(&handler->local, 0, sizeof(handler->local)); - handler->local.nl_family = AF_NETLINK; - handler->local.nl_groups = 0; + memset(&handler->local, 0, sizeof(handler->local)); + handler->local.nl_family = AF_NETLINK; + handler->local.nl_groups = 0; - if (bind(handler->fd, (struct sockaddr*)&handler->local, + if (bind(handler->fd, (struct sockaddr*)&handler->local, sizeof(handler->local)) < 0) - return -errno; + return -errno; - socklen = sizeof(handler->local); - if (getsockname(handler->fd, (struct sockaddr*)&handler->local, + socklen = sizeof(handler->local); + if (getsockname(handler->fd, (struct sockaddr*)&handler->local, &socklen) < 0) - return -errno; + return -errno; - if (socklen != sizeof(handler->local)) - return -EINVAL; + if (socklen != sizeof(handler->local)) + return -EINVAL; - if (handler->local.nl_family != AF_NETLINK) - return -EINVAL; + if (handler->local.nl_family != AF_NETLINK) + return -EINVAL; handler->seq = time(NULL); - return 0; + return 0; } extern int netlink_close(struct nl_handler *handler) diff -Nru lxc-1.0.7/src/lxc/nl.h lxc-1.0.8/src/lxc/nl.h --- lxc-1.0.7/src/lxc/nl.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/nl.h 2015-11-09 22:49:15.000000000 +0000 @@ -46,10 +46,10 @@ * @peer: the peer address */ struct nl_handler { - int fd; + int fd; int seq; - struct sockaddr_nl local; - struct sockaddr_nl peer; + struct sockaddr_nl local; + struct sockaddr_nl peer; }; /* diff -Nru lxc-1.0.7/src/lxc/parse.c lxc-1.0.8/src/lxc/parse.c --- lxc-1.0.7/src/lxc/parse.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/parse.c 2015-11-09 22:49:15.000000000 +0000 @@ -59,8 +59,7 @@ } } - if (line) - free(line); + free(line); fclose(f); return err; } diff -Nru lxc-1.0.7/src/lxc/seccomp.c lxc-1.0.8/src/lxc/seccomp.c --- lxc-1.0.7/src/lxc/seccomp.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/seccomp.c 2015-11-09 22:49:15.000000000 +0000 @@ -28,6 +28,7 @@ #include #include #include +#include #include "config.h" #include "lxcseccomp.h" @@ -120,6 +121,10 @@ lxc_seccomp_arch_i386, lxc_seccomp_arch_amd64, lxc_seccomp_arch_arm, + lxc_seccomp_arch_arm64, + lxc_seccomp_arch_ppc64, + lxc_seccomp_arch_ppc64le, + lxc_seccomp_arch_ppc, lxc_seccomp_arch_unknown = 999, }; @@ -136,6 +141,14 @@ return lxc_seccomp_arch_amd64; else if (strncmp(uts.machine, "armv7", 5) == 0) return lxc_seccomp_arch_arm; + else if (strncmp(uts.machine, "aarch64", 7) == 0) + return lxc_seccomp_arch_arm64; + else if (strncmp(uts.machine, "ppc64le", 7) == 0) + return lxc_seccomp_arch_ppc64le; + else if (strncmp(uts.machine, "ppc64", 5) == 0) + return lxc_seccomp_arch_ppc64; + else if (strncmp(uts.machine, "ppc", 3) == 0) + return lxc_seccomp_arch_ppc; return lxc_seccomp_arch_unknown; } @@ -149,6 +162,18 @@ case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; 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 + case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break; +#endif +#ifdef SCMP_ARCH_PPC64LE + case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break; +#endif +#ifdef SCMP_ARCH_PPC64 + case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break; +#endif +#ifdef SCMP_ARCH_PPC + case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break; +#endif default: return NULL; } @@ -186,6 +211,18 @@ ERROR("BUG: seccomp: rule and context arch do not match (arch %d)", arch); return false; } + + if (strncmp(line, "reject_force_umount", 19) == 0) { + INFO("Setting seccomp rule to reject force umounts\n"); + ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2), + 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE )); + if (ret < 0) { + ERROR("failed (%d) loading rule to reject force umount", ret); + return false; + } + return true; + } + nr = seccomp_syscall_resolve_name(line); if (nr == __NR_SCMP_ERROR) { WARN("Seccomp: failed to resolve syscall: %s", line); @@ -228,6 +265,7 @@ uint32_t default_policy_action = -1, default_rule_action = -1, action; enum lxc_hostarch_t native_arch = get_hostarch(), cur_rule_arch = native_arch; + uint32_t compat_arch = SCMP_ARCH_NATIVE; if (strncmp(line, "blacklist", 9) == 0) blacklist = true; @@ -257,6 +295,7 @@ if (native_arch == lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_all; + compat_arch = SCMP_ARCH_X86; compat_ctx = get_new_ctx(lxc_seccomp_arch_i386, default_policy_action); if (!compat_ctx) @@ -293,14 +332,6 @@ continue; } cur_rule_arch = lxc_seccomp_arch_i386; - if (native_arch == lxc_seccomp_arch_amd64) { - if (compat_ctx) - continue; - compat_ctx = get_new_ctx(lxc_seccomp_arch_i386, - default_policy_action); - if (!compat_ctx) - goto bad; - } } else if (strcmp(line, "[X86_64]") == 0 || strcmp(line, "[x86_64]") == 0) { if (native_arch != lxc_seccomp_arch_amd64) { @@ -311,14 +342,6 @@ } else if (strcmp(line, "[all]") == 0 || strcmp(line, "[ALL]") == 0) { cur_rule_arch = lxc_seccomp_arch_all; - if (native_arch == lxc_seccomp_arch_amd64 && !compat_ctx) { - if (compat_ctx) - continue; - compat_ctx = get_new_ctx(lxc_seccomp_arch_i386, - default_policy_action); - if (!compat_ctx) - goto bad; - } } #ifdef SCMP_ARCH_ARM else if (strcmp(line, "[arm]") == 0 || @@ -330,6 +353,46 @@ cur_rule_arch = lxc_seccomp_arch_arm; } #endif +#ifdef SCMP_ARCH_AARCH64 + else if (strcmp(line, "[arm64]") == 0 || + strcmp(line, "[ARM64]") == 0) { + if (native_arch != lxc_seccomp_arch_arm64) { + cur_rule_arch = lxc_seccomp_arch_unknown; + continue; + } + cur_rule_arch = lxc_seccomp_arch_arm64; + } +#endif +#ifdef SCMP_ARCH_PPC64LE + else if (strcmp(line, "[ppc64le]") == 0 || + strcmp(line, "[PPC64LE]") == 0) { + if (native_arch != lxc_seccomp_arch_ppc64le) { + cur_rule_arch = lxc_seccomp_arch_unknown; + continue; + } + cur_rule_arch = lxc_seccomp_arch_ppc64le; + } +#endif +#ifdef SCMP_ARCH_PPC64 + else if (strcmp(line, "[ppc64]") == 0 || + strcmp(line, "[PPC64]") == 0) { + if (native_arch != lxc_seccomp_arch_ppc64) { + cur_rule_arch = lxc_seccomp_arch_unknown; + continue; + } + cur_rule_arch = lxc_seccomp_arch_ppc64; + } +#endif +#ifdef SCMP_ARCH_PPC + else if (strcmp(line, "[ppc]") == 0 || + strcmp(line, "[PPC]") == 0) { + if (native_arch != lxc_seccomp_arch_ppc) { + cur_rule_arch = lxc_seccomp_arch_unknown; + continue; + } + cur_rule_arch = lxc_seccomp_arch_ppc; + } +#endif else goto bad_arch; @@ -347,41 +410,24 @@ goto bad_rule; } - /* - * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch) - * - * in other words, the rule is 32-bit only, on 64-bit host; don't run - * the rule against the native arch. - */ - if (!(cur_rule_arch == lxc_seccomp_arch_i386 && - native_arch == lxc_seccomp_arch_amd64)) { - INFO("Adding non-compat rule for %s action %d", line, action); + if (cur_rule_arch == native_arch || + cur_rule_arch == lxc_seccomp_arch_native || + compat_arch == SCMP_ARCH_NATIVE) { + INFO("Adding native rule for %s action %d", line, action); if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) goto bad_rule; } - - /* - * TODO generalize - if need_compat(native_arch, cur_rule_arch) - */ - if (native_arch == lxc_seccomp_arch_amd64 && - cur_rule_arch != lxc_seccomp_arch_amd64) { - int nr1, nr2; + else if (cur_rule_arch != lxc_seccomp_arch_all) { + INFO("Adding compat-only rule for %s action %d", line, action); + if (!do_resolve_add_rule(compat_arch, line, compat_ctx, action)) + goto bad_rule; + } + else { + INFO("Adding native rule for %s action %d", line, action); + if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) + goto bad_rule; INFO("Adding compat rule for %s action %d", line, action); - nr1 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86, line); - nr2 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, line); - if (nr1 == nr2) { - /* If the syscall # is the same for 32- and 64-bit, then we cannot - * apply it to the compat_ctx. So apply it to the noncompat ctx. - * We may already have done so, but that's ok - */ - INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2); - if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) - goto bad_rule; - continue; - } - INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2); - if (!do_resolve_add_rule(SCMP_ARCH_X86, line, - compat_ctx, action)) + if (!do_resolve_add_rule(compat_arch, line, compat_ctx, action)) goto bad_rule; } } @@ -393,6 +439,7 @@ goto bad; } } + return 0; bad_arch: @@ -550,10 +597,8 @@ } void lxc_seccomp_free(struct lxc_conf *conf) { - if (conf->seccomp) { - free(conf->seccomp); - conf->seccomp = NULL; - } + free(conf->seccomp); + conf->seccomp = NULL; #if HAVE_SCMP_FILTER_CTX if (conf->seccomp_ctx) { seccomp_release(conf->seccomp_ctx); diff -Nru lxc-1.0.7/src/lxc/start.c lxc-1.0.8/src/lxc/start.c --- lxc-1.0.7/src/lxc/start.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/start.c 2015-11-09 22:49:15.000000000 +0000 @@ -117,14 +117,15 @@ } } -static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags) { +static int preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid) { int i, saved_errno; char path[MAXPATHLEN]; for (i = 0; i < LXC_NS_MAX; i++) ns_fd[i] = -1; - if (access("/proc/self/ns", X_OK)) { + snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid); + if (access(path, X_OK)) { WARN("Kernel does not support attach; preserve_ns ignored"); return 0; } @@ -132,7 +133,8 @@ for (i = 0; i < LXC_NS_MAX; i++) { if ((clone_flags & ns_info[i].clone_flag) == 0) continue; - snprintf(path, MAXPATHLEN, "/proc/self/ns/%s", ns_info[i].proc_name); + snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, + ns_info[i].proc_name); ns_fd[i] = open(path, O_RDONLY | O_CLOEXEC); if (ns_fd[i] < 0) goto error; @@ -355,6 +357,7 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char *lxcpath) { + int i; struct lxc_handler *handler; handler = malloc(sizeof(*handler)); @@ -367,6 +370,9 @@ handler->lxcpath = lxcpath; handler->pinfd = -1; + for (i = 0; i < LXC_NS_MAX; i++) + handler->nsfd[i] = -1; + lsm_init(); handler->name = strdup(name); @@ -390,16 +396,16 @@ } /* Start of environment variable setup for hooks */ - if (setenv("LXC_NAME", name, 1)) { + if (name && setenv("LXC_NAME", name, 1)) { SYSERROR("failed to set environment variable for container name"); } - if (setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) { + if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) { SYSERROR("failed to set environment variable for config path"); } - if (setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) { + if (conf->rootfs.mount && setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) { SYSERROR("failed to set environment variable for rootfs mount"); } - if (setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) { + if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) { SYSERROR("failed to set environment variable for rootfs mount"); } if (conf->console.path && setenv("LXC_CONSOLE", conf->console.path, 1)) { @@ -462,10 +468,19 @@ static void lxc_fini(const char *name, struct lxc_handler *handler) { + int i; + /* The STOPPING state is there for future cleanup code * which can take awhile */ lxc_set_state(name, handler, STOPPING); + + for (i = 0; i < LXC_NS_MAX; i++) { + if (handler->nsfd[i] != -1) { + close(handler->nsfd[i]); + handler->nsfd[i] = -1; + } + } lxc_set_state(name, handler, STOPPED); if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL)) @@ -505,10 +520,10 @@ */ static int container_reboot_supported(void *arg) { - int *cmd = arg; + int *cmd = arg; int ret; - ret = reboot(*cmd); + ret = reboot(*cmd); if (ret == -1 && errno == EINVAL) return 1; return 0; @@ -518,10 +533,10 @@ { FILE *f; int ret, cmd, v, flags; - long stack_size = 4096; - void *stack = alloca(stack_size); - int status; - pid_t pid; + long stack_size = 4096; + void *stack = alloca(stack_size); + int status; + pid_t pid; f = fopen("/proc/sys/kernel/ctrl-alt-del", "r"); if (!f) { @@ -621,7 +636,7 @@ return -1; } - /* This prctl must be before the synchro, so if the parent + /* This prctl must be before the synchro, so if the parent * dies before we set the parent death signal, we will detect * its death with the synchro right after, otherwise we have * a window where the parent can exit before we set the pdeath @@ -874,7 +889,7 @@ INFO("failed to pin the container's rootfs"); } - if (preserve_ns(saved_ns_fd, preserve_mask) < 0) + if (preserve_ns(saved_ns_fd, preserve_mask, getpid()) < 0) goto out_delete_net; if (attach_ns(handler->conf->inherit_ns_fd) < 0) goto out_delete_net; @@ -895,6 +910,11 @@ goto out_delete_net; } + if (preserve_ns(handler->nsfd, handler->clone_flags, handler->pid) < 0) { + ERROR("failed to store namespace references"); + goto out_delete_net; + } + if (attach_ns(saved_ns_fd)) WARN("failed to restore saved namespaces"); @@ -1081,6 +1101,8 @@ goto out_fini_nonet; } + handler->conf->reboot = 0; + netnsfd = get_netns_fd(handler->pid); err = lxc_poll(name, handler); @@ -1100,7 +1122,7 @@ * lxc-execute which simply exited. In any case, treat * it as a 'halt' */ - if (WIFSIGNALED(status)) { + if (WIFSIGNALED(status)) { switch(WTERMSIG(status)) { case SIGINT: /* halt */ DEBUG("Container halting"); @@ -1116,9 +1138,14 @@ DEBUG("unknown exit status for init: %d", WTERMSIG(status)); break; } - } + } + DEBUG("Pushing physical nics back to host namespace"); lxc_rename_phys_nics_on_shutdown(netnsfd, handler->conf); + + DEBUG("Tearing down virtual network devices used by container"); + lxc_delete_network(handler); + if (netnsfd >= 0) close(netnsfd); diff -Nru lxc-1.0.7/src/lxc/start.h lxc-1.0.8/src/lxc/start.h --- lxc-1.0.7/src/lxc/start.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/start.h 2015-11-09 22:49:15.000000000 +0000 @@ -72,6 +72,7 @@ int pinfd; const char *lxcpath; void *cgroup_data; + int nsfd[LXC_NS_MAX]; }; extern struct lxc_handler *lxc_init(const char *name, struct lxc_conf *, const char *); diff -Nru lxc-1.0.7/src/lxc/utils.c lxc-1.0.8/src/lxc/utils.c --- lxc-1.0.7/src/lxc/utils.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/utils.c 2015-11-09 22:49:15.000000000 +0000 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -44,9 +45,22 @@ #include "log.h" #include "lxclock.h" +#ifndef O_PATH +#define O_PATH 010000000 +#endif + +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 00400000 +#endif + lxc_log_define(lxc_utils, lxc); -static int _recursive_rmdir_onedev(char *dirname, dev_t pdev) +/* + * if path is btrfs, tries to remove it and any subvolumes beneath it + */ +extern bool btrfs_try_remove_subvol(const char *path); + +static int _recursive_rmdir(char *dirname, dev_t pdev, bool onedev) { struct dirent dirent, *direntp; DIR *dir; @@ -76,26 +90,32 @@ failed=1; continue; } + ret = lstat(pathname, &mystat); if (ret) { ERROR("%s: failed to stat %s", __func__, pathname); - failed=1; + failed = 1; continue; } - if (mystat.st_dev != pdev) + if (onedev && mystat.st_dev != pdev) { + /* TODO should we be checking /proc/self/mountinfo for + * pathname and not doing this if found? */ + if (btrfs_try_remove_subvol(pathname)) + INFO("Removed btrfs subvolume at %s\n", pathname); continue; + } if (S_ISDIR(mystat.st_mode)) { - if (_recursive_rmdir_onedev(pathname, pdev) < 0) + if (_recursive_rmdir(pathname, pdev, onedev) < 0) failed=1; } else { if (unlink(pathname) < 0) { - ERROR("%s: failed to delete %s", __func__, pathname); + SYSERROR("%s: failed to delete %s", __func__, pathname); failed=1; } } } - if (rmdir(dirname) < 0) { + if (rmdir(dirname) < 0 && !btrfs_try_remove_subvol(dirname)) { ERROR("%s: failed to delete %s", __func__, dirname); failed=1; } @@ -109,54 +129,43 @@ return failed ? -1 : 0; } -/* returns 0 on success, -1 if there were any failures */ -extern int lxc_rmdir_onedev(char *path) +/* we have two different magic values for overlayfs, yay */ +#define OVERLAYFS_SUPER_MAGIC 0x794c764f +#define OVERLAY_SUPER_MAGIC 0x794c7630 +/* + * In overlayfs, st_dev is unreliable. so on overlayfs we don't do + * the lxc_rmdir_onedev() + */ +static bool is_native_overlayfs(const char *path) { - struct stat mystat; + struct statfs sb; - if (lstat(path, &mystat) < 0) { - ERROR("%s: failed to stat %s", __func__, path); - return -1; - } - - return _recursive_rmdir_onedev(path, mystat.st_dev); + if (statfs(path, &sb) < 0) + return false; + if (sb.f_type == OVERLAYFS_SUPER_MAGIC || + sb.f_type == OVERLAY_SUPER_MAGIC) + return true; + return false; } -static int mount_fs(const char *source, const char *target, const char *type) +/* returns 0 on success, -1 if there were any failures */ +extern int lxc_rmdir_onedev(char *path) { - /* the umount may fail */ - if (umount(target)) - WARN("failed to unmount %s : %s", target, strerror(errno)); + struct stat mystat; + bool onedev = true; - if (mount(source, target, type, 0, NULL)) { - ERROR("failed to mount %s : %s", target, strerror(errno)); - return -1; + if (is_native_overlayfs(path)) { + onedev = false; } - DEBUG("'%s' mounted on '%s'", source, target); - - return 0; -} - -extern void lxc_setup_fs(void) -{ - if (mount_fs("proc", "/proc", "proc")) - INFO("failed to remount proc"); - - /* if we can't mount /dev/shm, continue anyway */ - if (mount_fs("shmfs", "/dev/shm", "tmpfs")) - INFO("failed to mount /dev/shm"); - - /* If we were able to mount /dev/shm, then /dev exists */ - /* Sure, but it's read-only per config :) */ - if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) { - DEBUG("failed to create '/dev/mqueue'"); - return; + if (lstat(path, &mystat) < 0) { + if (errno == ENOENT) + return 0; + ERROR("%s: failed to stat %s", __func__, path); + return -1; } - /* continue even without posix message queue support */ - if (mount_fs("mqueue", "/dev/mqueue", "mqueue")) - INFO("failed to mount /dev/mqueue"); + return _recursive_rmdir(path, mystat.st_dev, onedev); } /* borrowed from iproute2 */ @@ -201,195 +210,6 @@ return 0; } -extern void remove_trailing_slashes(char *p) -{ - int l = strlen(p); - while (--l >= 0 && (p[l] == '/' || p[l] == '\n')) - p[l] = '\0'; -} - -static char *copy_global_config_value(char *p) -{ - int len = strlen(p); - char *retbuf; - - if (len < 1) - return NULL; - if (p[len-1] == '\n') { - p[len-1] = '\0'; - len--; - } - retbuf = malloc(len+1); - if (!retbuf) - return NULL; - strcpy(retbuf, p); - return retbuf; -} - -#define DEFAULT_VG "lxc" -#define DEFAULT_THIN_POOL "lxc" -#define DEFAULT_ZFSROOT "lxc" - -const char *lxc_global_config_value(const char *option_name) -{ - static const char * const options[][2] = { - { "lxc.bdev.lvm.vg", DEFAULT_VG }, - { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL }, - { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT }, - { "lxc.lxcpath", NULL }, - { "lxc.default_config", NULL }, - { "lxc.cgroup.pattern", NULL }, - { "lxc.cgroup.use", NULL }, - { NULL, NULL }, - }; - - /* placed in the thread local storage pool for non-bionic targets */ -#ifdef HAVE_TLS - static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; -#else - static const char *values[sizeof(options) / sizeof(options[0])] = { 0 }; -#endif - - /* user_config_path is freed as soon as it is used */ - char *user_config_path = NULL; - - /* - * The following variables are freed at bottom unconditionally. - * So NULL the value if it is to be returned to the caller - */ - char *user_default_config_path = NULL; - char *user_lxc_path = NULL; - char *user_cgroup_pattern = NULL; - - if (geteuid() > 0) { - const char *user_home = getenv("HOME"); - if (!user_home) - user_home = "/"; - - user_config_path = malloc(sizeof(char) * (22 + strlen(user_home))); - user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home))); - user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home))); - - sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home); - sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home); - sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home); - user_cgroup_pattern = strdup("%n"); - } - else { - user_config_path = strdup(LXC_GLOBAL_CONF); - user_default_config_path = strdup(LXC_DEFAULT_CONFIG); - user_lxc_path = strdup(LXCPATH); - user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN); - } - - const char * const (*ptr)[2]; - size_t i; - char buf[1024], *p, *p2; - FILE *fin = NULL; - - for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) { - if (!strcmp(option_name, (*ptr)[0])) - break; - } - if (!(*ptr)[0]) { - free(user_config_path); - free(user_default_config_path); - free(user_lxc_path); - free(user_cgroup_pattern); - errno = EINVAL; - return NULL; - } - - if (values[i]) { - free(user_config_path); - free(user_default_config_path); - free(user_lxc_path); - free(user_cgroup_pattern); - return values[i]; - } - - fin = fopen_cloexec(user_config_path, "r"); - free(user_config_path); - if (fin) { - while (fgets(buf, 1024, fin)) { - if (buf[0] == '#') - continue; - p = strstr(buf, option_name); - if (!p) - continue; - /* see if there was just white space in front - * of the option name - */ - for (p2 = buf; p2 < p; p2++) { - if (*p2 != ' ' && *p2 != '\t') - break; - } - if (p2 < p) - continue; - p = strchr(p, '='); - if (!p) - continue; - /* see if there was just white space after - * the option name - */ - for (p2 += strlen(option_name); p2 < p; p2++) { - if (*p2 != ' ' && *p2 != '\t') - break; - } - if (p2 < p) - continue; - p++; - while (*p && (*p == ' ' || *p == '\t')) p++; - if (!*p) - continue; - - if (strcmp(option_name, "lxc.lxcpath") == 0) { - free(user_lxc_path); - user_lxc_path = copy_global_config_value(p); - remove_trailing_slashes(user_lxc_path); - values[i] = user_lxc_path; - user_lxc_path = NULL; - goto out; - } - - values[i] = copy_global_config_value(p); - goto out; - } - } - /* could not find value, use default */ - if (strcmp(option_name, "lxc.lxcpath") == 0) { - remove_trailing_slashes(user_lxc_path); - values[i] = user_lxc_path; - user_lxc_path = NULL; - } - else if (strcmp(option_name, "lxc.default_config") == 0) { - values[i] = user_default_config_path; - user_default_config_path = NULL; - } - else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) { - values[i] = user_cgroup_pattern; - user_cgroup_pattern = NULL; - } - else - values[i] = (*ptr)[1]; - - /* special case: if default value is NULL, - * and there is no config, don't view that - * as an error... */ - if (!values[i]) - errno = 0; - -out: - if (fin) - fclose(fin); - - free(user_cgroup_pattern); - free(user_default_config_path); - free(user_lxc_path); - - return values[i]; -} - char *get_rundir() { char *rundir; @@ -595,50 +415,6 @@ return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0); } -FILE *fopen_cloexec(const char *path, const char *mode) -{ - int open_mode = 0; - int step = 0; - int fd; - int saved_errno = 0; - FILE *ret; - - if (!strncmp(mode, "r+", 2)) { - open_mode = O_RDWR; - step = 2; - } else if (!strncmp(mode, "r", 1)) { - open_mode = O_RDONLY; - step = 1; - } else if (!strncmp(mode, "w+", 2)) { - open_mode = O_RDWR | O_TRUNC | O_CREAT; - step = 2; - } else if (!strncmp(mode, "w", 1)) { - open_mode = O_WRONLY | O_TRUNC | O_CREAT; - step = 1; - } else if (!strncmp(mode, "a+", 2)) { - open_mode = O_RDWR | O_CREAT | O_APPEND; - step = 2; - } else if (!strncmp(mode, "a", 1)) { - open_mode = O_WRONLY | O_CREAT | O_APPEND; - step = 1; - } - for (; mode[step]; step++) - if (mode[step] == 'x') - open_mode |= O_EXCL; - open_mode |= O_CLOEXEC; - - fd = open(path, open_mode, 0666); - if (fd < 0) - return NULL; - - ret = fdopen(fd, mode); - saved_errno = errno; - if (!ret) - close(fd); - errno = saved_errno; - return ret; -} - extern struct lxc_popen_FILE *lxc_popen(const char *command) { struct lxc_popen_FILE *fp = NULL; @@ -1322,3 +1098,291 @@ free(path); return NULL; } + +/* + * Given the '-t' template option to lxc-create, figure out what to + * do. If the template is a full executable path, use that. If it + * is something like 'sshd', then return $templatepath/lxc-sshd. + * On success return the template, on error return NULL. + */ +char *get_template_path(const char *t) +{ + int ret, len; + char *tpath; + + if (t[0] == '/' && access(t, X_OK) == 0) { + tpath = strdup(t); + return tpath; + } + + len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1; + tpath = malloc(len); + if (!tpath) + return NULL; + ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t); + if (ret < 0 || ret >= len) { + free(tpath); + return NULL; + } + if (access(tpath, X_OK) < 0) { + SYSERROR("bad template: %s", t); + free(tpath); + return NULL; + } + + return tpath; +} + +int null_stdfds(void) +{ + int fd, ret = -1; + + fd = open("/dev/null", O_RDWR); + if (fd < 0) + return -1; + + if (dup2(fd, 0) < 0) + goto err; + if (dup2(fd, 1) < 0) + goto err; + if (dup2(fd, 2) < 0) + goto err; + + ret = 0; +err: + close(fd); + return ret; +} + +/* + * @path: a pathname where / replaced with '\0'. + * @offsetp: pointer to int showing which path segment was last seen. + * Updated on return to reflect the next segment. + * @fulllen: full original path length. + * Returns a pointer to the next path segment, or NULL if done. + */ +static char *get_nextpath(char *path, int *offsetp, int fulllen) +{ + int offset = *offsetp; + + if (offset >= fulllen) + return NULL; + + while (path[offset] != '\0' && offset < fulllen) + offset++; + while (path[offset] == '\0' && offset < fulllen) + offset++; + + *offsetp = offset; + return (offset < fulllen) ? &path[offset] : NULL; +} + +/* + * Check that @subdir is a subdir of @dir. @len is the length of + * @dir (to avoid having to recalculate it). + */ +static bool is_subdir(const char *subdir, const char *dir, size_t len) +{ + size_t subdirlen = strlen(subdir); + + if (subdirlen < len) + return false; + if (strncmp(subdir, dir, len) != 0) + return false; + if (dir[len-1] == '/') + return true; + if (subdir[len] == '/' || subdirlen == len) + return true; + return false; +} + +/* + * Check if the open fd is a symlink. Return -ELOOP if it is. Return + * -ENOENT if we couldn't fstat. Return 0 if the fd is ok. + */ +static int check_symlink(int fd) +{ + struct stat sb; + int ret = fstat(fd, &sb); + if (ret < 0) + return -ENOENT; + if (S_ISLNK(sb.st_mode)) + return -ELOOP; + return 0; +} + +/* + * Open a file or directory, provided that it contains no symlinks. + * + * CAVEAT: This function must not be used for other purposes than container + * setup before executing the container's init + */ +static int open_if_safe(int dirfd, const char *nextpath) +{ + int newfd = openat(dirfd, nextpath, O_RDONLY | O_NOFOLLOW); + if (newfd >= 0) // was not a symlink, all good + return newfd; + + if (errno == ELOOP) + return newfd; + + if (errno == EPERM || errno == EACCES) { + /* we're not root (cause we got EPERM) so + try opening with O_PATH */ + newfd = openat(dirfd, nextpath, O_PATH | O_NOFOLLOW); + if (newfd >= 0) { + /* O_PATH will return an fd for symlinks. We know + * nextpath wasn't a symlink at last openat, so if fd + * is now a link, then something * fishy is going on + */ + int ret = check_symlink(newfd); + if (ret < 0) { + close(newfd); + newfd = ret; + } + } + } + + return newfd; +} + +/* + * Open a path intending for mounting, ensuring that the final path + * is inside the container's rootfs. + * + * CAVEAT: This function must not be used for other purposes than container + * setup before executing the container's init + * + * @target: path to be opened + * @prefix_skip: a part of @target in which to ignore symbolic links. This + * would be the container's rootfs. + * + * Return an open fd for the path, or <0 on error. + */ +static int open_without_symlink(const char *target, const char *prefix_skip) +{ + int curlen = 0, dirfd, fulllen, i; + char *dup = NULL; + + fulllen = strlen(target); + + /* make sure prefix-skip makes sense */ + if (prefix_skip) { + curlen = strlen(prefix_skip); + if (!is_subdir(target, prefix_skip, curlen)) { + ERROR("WHOA there - target '%s' didn't start with prefix '%s'", + target, prefix_skip); + return -EINVAL; + } + /* + * get_nextpath() expects the curlen argument to be + * on a (turned into \0) / or before it, so decrement + * curlen to make sure that happens + */ + if (curlen) + curlen--; + } else { + prefix_skip = "/"; + curlen = 0; + } + + /* Make a copy of target which we can hack up, and tokenize it */ + if ((dup = strdup(target)) == NULL) { + SYSERROR("Out of memory checking for symbolic link"); + return -ENOMEM; + } + for (i = 0; i < fulllen; i++) { + if (dup[i] == '/') + dup[i] = '\0'; + } + + dirfd = open(prefix_skip, O_RDONLY); + if (dirfd < 0) + goto out; + while (1) { + int newfd, saved_errno; + char *nextpath; + + if ((nextpath = get_nextpath(dup, &curlen, fulllen)) == NULL) + goto out; + newfd = open_if_safe(dirfd, nextpath); + saved_errno = errno; + close(dirfd); + dirfd = newfd; + if (newfd < 0) { + errno = saved_errno; + if (errno == ELOOP) + SYSERROR("%s in %s was a symbolic link!", nextpath, target); + else + SYSERROR("Error examining %s in %s", nextpath, target); + goto out; + } + } + +out: + free(dup); + return dirfd; +} + +/* + * Safely mount a path into a container, ensuring that the mount target + * is under the container's @rootfs. (If @rootfs is NULL, then the container + * uses the host's /) + * + * CAVEAT: This function must not be used for other purposes than container + * setup before executing the container's init + */ +int safe_mount(const char *src, const char *dest, const char *fstype, + unsigned long flags, const void *data, const char *rootfs) +{ + int srcfd = -1, destfd, ret, saved_errno; + char srcbuf[50], destbuf[50]; // only needs enough for /proc/self/fd/ + const char *mntsrc = src; + + if (!rootfs) + rootfs = ""; + + /* todo - allow symlinks for relative paths if 'allowsymlinks' option is passed */ + if (flags & MS_BIND && src && src[0] != '/') { + INFO("this is a relative bind mount"); + srcfd = open_without_symlink(src, NULL); + if (srcfd < 0) + return srcfd; + ret = snprintf(srcbuf, 50, "/proc/self/fd/%d", srcfd); + if (ret < 0 || ret > 50) { + close(srcfd); + ERROR("Out of memory"); + return -EINVAL; + } + mntsrc = srcbuf; + } + + destfd = open_without_symlink(dest, rootfs); + if (destfd < 0) { + if (srcfd != -1) + close(srcfd); + return destfd; + } + + ret = snprintf(destbuf, 50, "/proc/self/fd/%d", destfd); + if (ret < 0 || ret > 50) { + if (srcfd != -1) + close(srcfd); + close(destfd); + ERROR("Out of memory"); + return -EINVAL; + } + + ret = mount(mntsrc, destbuf, fstype, flags, data); + saved_errno = errno; + if (srcfd != -1) + close(srcfd); + close(destfd); + if (ret < 0) { + errno = saved_errno; + SYSERROR("Failed to mount %s onto %s", src, dest); + return ret; + } + + return 0; +} diff -Nru lxc-1.0.7/src/lxc/utils.h lxc-1.0.8/src/lxc/utils.h --- lxc-1.0.7/src/lxc/utils.h 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/lxc/utils.h 2015-11-09 22:49:15.000000000 +0000 @@ -32,17 +32,14 @@ #include #include "config.h" +#include "initutils.h" /* returns 1 on success, 0 if there were any failures */ extern int lxc_rmdir_onedev(char *path); -extern void lxc_setup_fs(void); extern int get_u16(unsigned short *val, const char *arg, int base); extern int mkdir_p(const char *dir, mode_t mode); -extern void remove_trailing_slashes(char *p); extern char *get_rundir(void); -extern const char *lxc_global_config_value(const char *option_name); - /* Define getline() if missing from the C library */ #ifndef HAVE_GETLINE #ifdef HAVE_FGETLN @@ -148,10 +145,6 @@ } #endif -/* open a file with O_CLOEXEC */ -FILE *fopen_cloexec(const char *path, const char *mode); - - /* 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)) @@ -275,8 +268,13 @@ #define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval); -#endif int detect_shared_rootfs(void); int detect_ramfs_rootfs(void); char *on_path(char *cmd); +char *get_template_path(const char *t); +int null_stdfds(void); + +int safe_mount(const char *src, const char *dest, const char *fstype, + unsigned long flags, const void *data, const char *rootfs); +#endif /* __LXC_UTILS_H */ diff -Nru lxc-1.0.7/src/lxc/version.h lxc-1.0.8/src/lxc/version.h --- lxc-1.0.7/src/lxc/version.h 2014-12-05 20:50:40.000000000 +0000 +++ lxc-1.0.8/src/lxc/version.h 2015-11-09 22:49:31.000000000 +0000 @@ -25,7 +25,7 @@ #define LXC_VERSION_MAJOR 1 #define LXC_VERSION_MINOR 0 -#define LXC_VERSION_MICRO 7 -#define LXC_VERSION "1.0.7" +#define LXC_VERSION_MICRO 8 +#define LXC_VERSION "1.0.8" #endif diff -Nru lxc-1.0.7/src/python-lxc/lxc.c lxc-1.0.8/src/python-lxc/lxc.c --- lxc-1.0.7/src/python-lxc/lxc.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/python-lxc/lxc.c 2015-11-09 22:49:15.000000000 +0000 @@ -237,8 +237,7 @@ int i; if (!options) return; - if (options->initial_cwd) - free(options->initial_cwd); + free(options->initial_cwd); if (options->extra_env_vars) { for (i = 0; options->extra_env_vars[i]; i++) free(options->extra_env_vars[i]); diff -Nru lxc-1.0.7/src/tests/aa.c lxc-1.0.8/src/tests/aa.c --- lxc-1.0.7/src/tests/aa.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/tests/aa.c 2015-11-09 22:49:15.000000000 +0000 @@ -47,9 +47,11 @@ if (f) { printf("yes\n"); fclose(f); + fflush(NULL); return 1; } printf("no\n"); + fflush(NULL); return 0; } diff -Nru lxc-1.0.7/src/tests/attach.c lxc-1.0.8/src/tests/attach.c --- lxc-1.0.7/src/tests/attach.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/tests/attach.c 2015-11-09 22:49:15.000000000 +0000 @@ -149,10 +149,10 @@ goto err2; } result[ret] = '\0'; - space = index(result, '\n'); + space = strchr(result, '\n'); if (space) *space = '\0'; - space = index(result, ' '); + space = strchr(result, ' '); if (space) *space = '\0'; diff -Nru lxc-1.0.7/src/tests/concurrent.c lxc-1.0.8/src/tests/concurrent.c --- lxc-1.0.7/src/tests/concurrent.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/tests/concurrent.c 2015-11-09 22:49:15.000000000 +0000 @@ -85,8 +85,8 @@ } if (debug) { - c->set_config_item(c, "lxc.loglevel", "DEBUG"); - c->set_config_item(c, "lxc.logfile", name); + c->set_config_item(c, "lxc.loglevel", "DEBUG"); + c->set_config_item(c, "lxc.logfile", name); } if (strcmp(args->mode, "create") == 0) { @@ -132,7 +132,7 @@ out: lxc_container_put(c); if (debug) - lxc_log_close(); + lxc_log_close(); } static void *concurrent(void *arguments) @@ -171,9 +171,9 @@ case 'q': quiet = 1; break; - case 'D': - debug = 1; - break; + case 'D': + debug = 1; + break; case 'm': { char *mode_tok, *tok, *saveptr = NULL; @@ -182,11 +182,15 @@ (tok = strtok_r(mode_tok, ",", &saveptr)); i++, mode_tok = NULL) { modes = realloc(modes, sizeof(*modes) * (i+2)); + if (!modes) { + perror("realloc"); + exit(EXIT_FAILURE); + } modes[i] = tok; - } + } modes[i] = NULL; break; - } + } default: /* '?' */ usage(); exit(EXIT_FAILURE); diff -Nru lxc-1.0.7/src/tests/locktests.c lxc-1.0.8/src/tests/locktests.c --- lxc-1.0.7/src/tests/locktests.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/tests/locktests.c 2015-11-09 22:49:15.000000000 +0000 @@ -122,7 +122,7 @@ exit(1); } struct stat sb; - char *pathname = RUNTIME_PATH "/lock/lxc/var/lib/lxc/"; + char *pathname = RUNTIME_PATH "/lxc/lock/var/lib/lxc/"; ret = stat(pathname, &sb); if (ret != 0) { fprintf(stderr, "%d: filename %s not created\n", __LINE__, diff -Nru lxc-1.0.7/src/tests/lxc-test-symlink lxc-1.0.8/src/tests/lxc-test-symlink --- lxc-1.0.7/src/tests/lxc-test-symlink 1970-01-01 00:00:00.000000000 +0000 +++ lxc-1.0.8/src/tests/lxc-test-symlink 2015-11-09 22:49:15.000000000 +0000 @@ -0,0 +1,89 @@ +#!/bin/bash + +set -ex + +# lxc: linux Container library + +# Authors: +# Serge Hallyn +# +# This is a regression test for symbolic links + +dirname=`mktemp -d` +fname=`mktemp` +fname2=`mktemp` + +lxcpath=/var/lib/lxcsym1 + +cleanup() { + lxc-destroy -P $lxcpath -f -n symtest1 || true + rm -f $lxcpath + rmdir $dirname || true + rm -f $fname || true + rm -f $fname2 || true +} + +trap cleanup EXIT SIGHUP SIGINT SIGTERM + +testrun() { + expected=$1 + run=$2 + pass="pass" + lxc-start -d -P $lxcpath -n symtest1 -l trace -o $lxcpath/log || pass="fail" + [ $pass = "pass" ] && lxc-wait -P $lxcpath -n symtest1 -t 10 -s RUNNING || pass="fail" + if [ "$pass" != "$expected" ]; then + echo "Test $run: expected $expected but container did not. Start log:" + cat $lxcpath/log + echo "FAIL: Test $run: expected $expected but container did not." + false + fi + lxc-stop -P $lxcpath -n symtest1 -k || true +} + +# make lxcpath a symlink - this should NOT cause failure +ln -s /var/lib/lxc $lxcpath + +lxc-destroy -P $lxcpath -f -n symtest1 || true +lxc-create -P $lxcpath -t busybox -n symtest1 + +cat >> /var/lib/lxc/symtest1/config << EOF +lxc.mount.entry = $dirname opt/xxx/dir none bind,create=dir +lxc.mount.entry = $fname opt/xxx/file none bind,create=file +lxc.mount.entry = $fname2 opt/xxx/file2 none bind +lxc.mount.entry = $dirname /var/lib/lxc/symtest1/rootfs/opt/xxx/dir2 none bind,create=dir +EOF + +# Regular - should succeed +mkdir -p /var/lib/lxc/symtest1/rootfs/opt/xxx +touch /var/lib/lxc/symtest1/rootfs/opt/xxx/file2 +testrun pass 1 + +# symlink - should fail +rm -rf /var/lib/lxc/symtest1/rootfs/opt/xxx +mkdir -p /var/lib/lxc/symtest1/rootfs/opt/xxx2 +ln -s /var/lib/lxc/symtest1/rootfs/opt/xxx2 /var/lib/lxc/symtest1/rootfs/opt/xxx +touch /var/lib/lxc/symtest1/rootfs/opt/xxx/file2 +testrun fail 2 + +# final final symlink - should fail +rm -rf $lxcpath/symtest1/rootfs/opt/xxx +mkdir -p $lxcpath/symtest1/rootfs/opt/xxx +mkdir -p $lxcpath/symtest1/rootfs/opt/xxx/dir +touch $lxcpath/symtest1/rootfs/opt/xxx/file +touch $lxcpath/symtest1/rootfs/opt/xxx/file2src +ln -s $lxcpath/symtest1/rootfs/opt/xxx/file2src $lxcpath/symtest1/rootfs/opt/xxx/file2 +testrun fail 3 + +# Ideally we'd also try a loop device, but that won't work in nested containers +# anyway - TODO + +# what about /proc itself + +rm -rf $lxcpath/symtest1/rootfs/opt/xxx +mkdir -p $lxcpath/symtest1/rootfs/opt/xxx +touch $lxcpath/symtest1/rootfs/opt/xxx/file2 +mv $lxcpath/symtest1/rootfs/proc $lxcpath/symtest1/rootfs/proc1 +ln -s $lxcpath/symtest1/rootfs/proc1 $lxcpath/symtest1/rootfs/proc +testrun fail 4 + +echo "all tests passed" diff -Nru lxc-1.0.7/src/tests/Makefile.am lxc-1.0.8/src/tests/Makefile.am --- lxc-1.0.7/src/tests/Makefile.am 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/tests/Makefile.am 2015-11-09 22:49:15.000000000 +0000 @@ -48,7 +48,7 @@ lxc-test-reboot lxc-test-list lxc-test-attach lxc-test-device-add-remove \ lxc-test-apparmor -bin_SCRIPTS = lxc-test-autostart +bin_SCRIPTS = lxc-test-autostart lxc-test-symlink if DISTRO_UBUNTU bin_SCRIPTS += lxc-test-usernic lxc-test-ubuntu lxc-test-unpriv @@ -71,6 +71,7 @@ locktests.c \ lxcpath.c \ lxc-test-autostart \ + lxc-test-symlink \ lxc-test-ubuntu \ lxc-test-unpriv \ may_control.c \ diff -Nru lxc-1.0.7/src/tests/Makefile.in lxc-1.0.8/src/tests/Makefile.in --- lxc-1.0.7/src/tests/Makefile.in 2014-12-05 20:50:27.000000000 +0000 +++ lxc-1.0.8/src/tests/Makefile.in 2015-11-09 22:49:20.000000000 +0000 @@ -547,7 +547,8 @@ @ENABLE_TESTS_TRUE@ -DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" \ @ENABLE_TESTS_TRUE@ -DRUNTIME_PATH=\"$(RUNTIME_PATH)\" \ @ENABLE_TESTS_TRUE@ $(am__append_1) $(am__append_2) -@ENABLE_TESTS_TRUE@bin_SCRIPTS = lxc-test-autostart $(am__append_3) +@ENABLE_TESTS_TRUE@bin_SCRIPTS = lxc-test-autostart lxc-test-symlink \ +@ENABLE_TESTS_TRUE@ $(am__append_3) EXTRA_DIST = \ cgpath.c \ clonetest.c \ @@ -563,6 +564,7 @@ locktests.c \ lxcpath.c \ lxc-test-autostart \ + lxc-test-symlink \ lxc-test-ubuntu \ lxc-test-unpriv \ may_control.c \ diff -Nru lxc-1.0.7/src/tests/reboot.c lxc-1.0.8/src/tests/reboot.c --- lxc-1.0.7/src/tests/reboot.c 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/src/tests/reboot.c 2015-11-09 22:49:15.000000000 +0000 @@ -35,43 +35,43 @@ static int do_reboot(void *arg) { - int *cmd = arg; + int *cmd = arg; - if (reboot(*cmd)) - printf("failed to reboot(%d): %m\n", *cmd); + if (reboot(*cmd)) + printf("failed to reboot(%d): %m\n", *cmd); return 0; } static int test_reboot(int cmd, int sig) { - long stack_size = 4096; - void *stack = alloca(stack_size) + stack_size; - int status; - pid_t ret; - - ret = clone(do_reboot, stack, CLONE_NEWPID | SIGCHLD, &cmd); - if (ret < 0) { - printf("failed to clone: %m\n"); - return -1; - } - - if (wait(&status) < 0) { - printf("unexpected wait error: %m\n"); - return -1; - } + long stack_size = 4096; + void *stack = alloca(stack_size) + stack_size; + int status; + pid_t ret; + + ret = clone(do_reboot, stack, CLONE_NEWPID | SIGCHLD, &cmd); + if (ret < 0) { + printf("failed to clone: %m\n"); + return -1; + } + + if (wait(&status) < 0) { + printf("unexpected wait error: %m\n"); + return -1; + } - if (!WIFSIGNALED(status)) { + if (!WIFSIGNALED(status)) { if (sig != -1) printf("child process exited but was not signaled\n"); - return -1; - } + return -1; + } - if (WTERMSIG(status) != sig) { - printf("signal termination is not the one expected\n"); - return -1; - } + if (WTERMSIG(status) != sig) { + printf("signal termination is not the one expected\n"); + return -1; + } - return 0; + return 0; } static int have_reboot_patch(void) @@ -95,46 +95,46 @@ int main(int argc, char *argv[]) { - int status; + int status; if (getuid() != 0) { - printf("Must run as root.\n"); - return 1; + printf("Must run as root.\n"); + return 1; } status = have_reboot_patch(); if (status != 0) { - printf("Your kernel does not have the container reboot patch\n"); - return 1; + printf("Your kernel does not have the container reboot patch\n"); + return 1; + } + + status = test_reboot(LINUX_REBOOT_CMD_CAD_ON, -1); + if (status >= 0) { + printf("reboot(LINUX_REBOOT_CMD_CAD_ON) should have failed\n"); + return 1; } + printf("reboot(LINUX_REBOOT_CMD_CAD_ON) has failed as expected\n"); - status = test_reboot(LINUX_REBOOT_CMD_CAD_ON, -1); - if (status >= 0) { - printf("reboot(LINUX_REBOOT_CMD_CAD_ON) should have failed\n"); - return 1; - } - printf("reboot(LINUX_REBOOT_CMD_CAD_ON) has failed as expected\n"); - - status = test_reboot(LINUX_REBOOT_CMD_RESTART, SIGHUP); - if (status < 0) - return 1; - printf("reboot(LINUX_REBOOT_CMD_RESTART) succeed\n"); - - status = test_reboot(LINUX_REBOOT_CMD_RESTART2, SIGHUP); - if (status < 0) - return 1; - printf("reboot(LINUX_REBOOT_CMD_RESTART2) succeed\n"); - - status = test_reboot(LINUX_REBOOT_CMD_HALT, SIGINT); - if (status < 0) - return 1; - printf("reboot(LINUX_REBOOT_CMD_HALT) succeed\n"); - - status = test_reboot(LINUX_REBOOT_CMD_POWER_OFF, SIGINT); - if (status < 0) - return 1; - printf("reboot(LINUX_REBOOT_CMD_POWERR_OFF) succeed\n"); + status = test_reboot(LINUX_REBOOT_CMD_RESTART, SIGHUP); + if (status < 0) + return 1; + printf("reboot(LINUX_REBOOT_CMD_RESTART) succeed\n"); + + status = test_reboot(LINUX_REBOOT_CMD_RESTART2, SIGHUP); + if (status < 0) + return 1; + printf("reboot(LINUX_REBOOT_CMD_RESTART2) succeed\n"); + + status = test_reboot(LINUX_REBOOT_CMD_HALT, SIGINT); + if (status < 0) + return 1; + printf("reboot(LINUX_REBOOT_CMD_HALT) succeed\n"); + + status = test_reboot(LINUX_REBOOT_CMD_POWER_OFF, SIGINT); + if (status < 0) + return 1; + printf("reboot(LINUX_REBOOT_CMD_POWERR_OFF) succeed\n"); - printf("All tests passed\n"); - return 0; + printf("All tests passed\n"); + return 0; } diff -Nru lxc-1.0.7/templates/lxc-alpine.in lxc-1.0.8/templates/lxc-alpine.in --- lxc-1.0.7/templates/lxc-alpine.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-alpine.in 2015-11-09 22:49:15.000000000 +0000 @@ -28,10 +28,15 @@ if [ -z "$repository" ]; then url=http://wiki.alpinelinux.org/cgi-bin/dl.cgi + yaml_path="latest-stable/releases/$apk_arch/latest-releases.yaml" if [ -z "$release" ]; then echo -n "Determining the latest release... " - release=$($wget $url/.latest.$apk_arch.txt | \ - cut -d " " -f 3 | cut -d / -f 1 | uniq) + release=$($wget $url/$yaml_path | \ + awk '$1 == "branch:" {print $2; exit 0}') + if [ -z "$release" ]; then + release=$($wget $url/.latest.$apk_arch.txt | \ + cut -d " " -f 3 | cut -d / -f 1 | uniq) + fi if [ -z "$release" ]; then echo failed return 1 @@ -78,7 +83,7 @@ # verify the static apk binary signature APK=$rootfs/sbin/apk.static - openssl dgst -verify $rootfs/etc/apk/keys/$keyname \ + openssl dgst -sha1 -verify $rootfs/etc/apk/keys/$keyname \ -signature "$APK.SIGN.RSA.$keyname" "$APK" || return 1 if [ "$auto_repo_dir" ]; then @@ -104,7 +109,7 @@ else cp /etc/apk/repositories "$rootfs"/etc/apk/repositories || return 1 if [ -n "$release" ]; then - sed -i -e "s:/[^/]\+/\([^/]\+\)$:/$release/\1:" \ + sed -E -i "s:/[^/]+/([^/]+)$:/$release/\\1:" \ "$rootfs"/etc/apk/repositories fi fi @@ -247,7 +252,7 @@ lxc.mount.entry=proc proc proc nodev,noexec,nosuid 0 0 lxc.mount.entry=run run tmpfs nodev,noexec,nosuid,relatime,size=1m,mode=0755 0 0 lxc.mount.entry=none dev/pts devpts gid=5,mode=620 0 0 -lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777 0 0 +lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777,create=dir 0 0 EOF @@ -273,12 +278,6 @@ exit 1 } -optarg_check() { - if [ -z "$2" ]; then - usage_err "option '$1' requires an argument" - fi -} - default_path=@LXCPATH@ release= arch=$(uname -m) @@ -289,58 +288,39 @@ exit 1 fi +options=$(getopt -o hn:p:r:R:a: -l help,name:,rootfs:,path:,repository:,release:,arch: -- "$@") +[ $? -eq 0 ] || usage_err +eval set -- "$options" + while [ $# -gt 0 ]; do - opt="$1" - shift - case "$opt" in + case "$1" in -h|--help) usage exit 0 ;; -n|--name) - optarg_check $opt "$1" - name=$1 - shift + name=$2 ;; --rootfs) - optarg_check $opt "$1" - rootfs=$1 - shift + rootfs=$2 ;; -p|--path) - optarg_check $opt "$1" - path=$1 - shift + path=$2 ;; -r|--repository) - optarg_check $opt "$1" - repository=$1 - shift + repository=$2 ;; -R|--release) - optarg_check $opt "$1" - release=$1 - shift + release=$2 ;; -a|--arch) - optarg_check $opt "$1" - arch=$1 - shift + arch=$2 ;; --) + shift break;; - --*=*) - # split --myopt=foo=bar into --myopt foo=bar - set -- ${opt%=*} ${opt#*=} "$@" - ;; - -?) - usage_err "unknown option '$opt'" - ;; - -*) - # split opts -abc into -a -b -c - set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@" - ;; esac + shift 2 done diff -Nru lxc-1.0.7/templates/lxc-altlinux.in lxc-1.0.8/templates/lxc-altlinux.in --- lxc-1.0.7/templates/lxc-altlinux.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-altlinux.in 2015-11-09 22:49:15.000000000 +0000 @@ -393,7 +393,7 @@ --rootfs) rootfs_path=$2; shift 2;; -n|--name) name=$2; shift 2;; -P|--profile) profile=$2; shift 2;; - -c|--clean) clean=$2; shift 2;; + -c|--clean) clean=1; shift 1;; -R|--release) release=$2; shift 2;; -4|--ipv4) ipv4=$2; shift 2;; -6|--ipv6) ipv6=$2; shift 2;; @@ -478,7 +478,7 @@ exit 1 fi -if [ ! -z $clean ]; then +if [ ! -z "$clean" ]; then clean || exit 1 exit 0 fi diff -Nru lxc-1.0.7/templates/lxc-archlinux.in lxc-1.0.8/templates/lxc-archlinux.in --- lxc-1.0.7/templates/lxc-archlinux.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-archlinux.in 2015-11-09 22:49:15.000000000 +0000 @@ -113,6 +113,10 @@ ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target # enable sigpwr signal handling in systemd as otherwise lxc-stop won't work ln -s /usr/lib/systemd/system/poweroff.target /etc/systemd/system/sigpwr.target +# fix systemd-sysctl service +sed -e 's/^ConditionPathIsReadWrite=\/proc\/sys\/$/ConditionPathIsReadWrite=\/proc\/sys\/net\//' \ + -e 's/^ExecStart=\/usr\/lib\/systemd\/systemd-sysctl$/ExecStart=\/usr\/lib\/systemd\/systemd-sysctl --prefix net/' \ + -i /usr/lib/systemd/system/systemd-sysctl.service # initialize pacman keyring pacman-key --init pacman-key --populate archlinux diff -Nru lxc-1.0.7/templates/lxc-busybox.in lxc-1.0.8/templates/lxc-busybox.in --- lxc-1.0.7/templates/lxc-busybox.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-busybox.in 2015-11-09 22:49:15.000000000 +0000 @@ -73,9 +73,8 @@ # minimal devices needed for busybox if [ $in_userns -eq 1 ]; then - for dev in tty console tty0 tty1 tty5 ram0 null urandom; do - touch $rootfs/dev/$dev - echo "/dev/$dev dev/$dev none bind 0 0" >> $path/fstab + for dev in tty console tty0 tty1 ram0 null urandom; do + echo "/dev/$dev dev/$dev none bind,optional,create=file 0 0" >> $path/fstab done else mknod -m 666 tty c 5 0 || res=1 diff -Nru lxc-1.0.7/templates/lxc-centos.in lxc-1.0.8/templates/lxc-centos.in --- lxc-1.0.7/templates/lxc-centos.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-centos.in 2015-11-09 22:49:15.000000000 +0000 @@ -247,7 +247,7 @@ NM_CONTROLLED=no TYPE=Ethernet MTU=${MTU} -DHCP_HOSTNAME=$name +DHCP_HOSTNAME=\`hostname\` EOF # set the hostname @@ -264,7 +264,6 @@ # set minimal fstab cat < $rootfs_path/etc/fstab /dev/root / rootfs defaults 0 0 -none /dev/shm tmpfs nosuid,nodev 0 0 EOF # create lxc compatibility init script @@ -274,14 +273,19 @@ env container pre-start script - if [ "x$container" != "xlxc" -a "x$container" != "xlibvirt" ]; then + if [ "x\$container" != "xlxc" -a "x\$container" != "xlibvirt" ]; then stop; fi - initctl start tty TTY=console + rm -f /var/lock/subsys/* rm -f /var/run/*.pid + [ -e /etc/mtab ] || ln -s /proc/mounts /etc/mtab + mkdir -p /dev/shm + mount -t tmpfs -o nosuid,nodev tmpfs /dev/shm + + initctl start tty TTY=console telinit 3 - exit 0; + exit 0 end script EOF elif [ "$release" = "5" ]; then @@ -340,7 +344,7 @@ # prevent mingetty from calling vhangup(2) since it fails with userns. # Same issue as oracle template: prevent mingetty from calling vhangup(2) # commit 2e83f7201c5d402478b9849f0a85c62d5b9f1589. - sed -i 's|mingetty|mingetty --nohangup|' $container_rootfs/etc/init/tty.conf + sed -i 's|mingetty|mingetty --nohangup|' $rootfs_path/etc/init/tty.conf if [ ${root_display_password} = "yes" ] then @@ -399,7 +403,13 @@ # download a mini centos into a cache echo "Downloading centos minimal ..." - YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck" + YUM0="yum --installroot $INSTALL_ROOT -y --nogpgcheck" + + if yum -h | grep -q 'releasever=RELEASEVER'; then + YUM="$YUM0 --releasever=$release" + else + YUM="$YUM0" + fi PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils" # use temporary repository definition @@ -465,7 +475,7 @@ mknod -m 666 $INSTALL_ROOT/$INSTALL_ROOT/dev/urandom c 1 9 mkdir -p $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum cp -al $INSTALL_ROOT/var/cache/yum/* $INSTALL_ROOT/$INSTALL_ROOT/var/cache/yum/ - chroot $INSTALL_ROOT $YUM install $PKG_LIST + chroot $INSTALL_ROOT $YUM0 install $PKG_LIST if [ $? -ne 0 ]; then echo "Failed to download the rootfs, aborting." return 1 @@ -685,11 +695,11 @@ case "$1" in -h|--help) usage $0 && exit 0;; -p|--path) path=$2; shift 2;; - --rootfs) rootfs=$2; shift 2;; + --rootfs) rootfs_path=$2; shift 2;; -n|--name) name=$2; shift 2;; - -c|--clean) clean=$2; shift 2;; + -c|--clean) clean=1; shift 1;; -R|--release) release=$2; shift 2;; - --repo) repo="$2"; shift 2;; + --repo) repo="$2"; shift 2;; -a|--arch) newarch=$2; shift 2;; --fqdn) utsname=$2; shift 2;; --) shift 1; break ;; @@ -833,7 +843,6 @@ exit 1 fi - if [ -z "$rootfs_path" ]; then rootfs_path=$path/rootfs # check for 'lxc.rootfs' passed in through default config by lxc-create @@ -877,7 +886,7 @@ configure_centos_init -if [ ! -z $clean ]; then +if [ ! -z "$clean" ]; then clean || exit 1 exit 0 fi diff -Nru lxc-1.0.7/templates/lxc-debian.in lxc-1.0.8/templates/lxc-debian.in --- lxc-1.0.7/templates/lxc-debian.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-debian.in 2015-11-09 22:49:15.000000000 +0000 @@ -32,6 +32,7 @@ # Make sure the usual locations are in PATH export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin +export GREP_OPTIONS="" MIRROR=${MIRROR:-http://http.debian.net/debian} SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.debian.org/} @@ -96,16 +97,6 @@ EOF # reconfigure some services - if [ -z "$LANG" ]; then - chroot $rootfs locale-gen en_US.UTF-8 UTF-8 - chroot $rootfs update-locale LANG=en_US.UTF-8 - else - encoding=$(echo $LANG | cut -d. -f2) - chroot $rootfs sed -e "s/^# \(${LANG} ${encoding}\)/\1/" \ - -i /etc/locale.gen 2> /dev/null - chroot $rootfs locale-gen $LANG $encoding - chroot $rootfs update-locale LANG=$LANG - fi # remove pointless services in a container chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh disable @@ -168,8 +159,13 @@ cat >> "${rootfs}/etc/apt/sources.list" << EOF ${prefix} $MIRROR ${release} main contrib non-free +EOF + + if [ "$release" != "unstable" -a "$release" != "sid" ]; then + cat >> "${rootfs}/etc/apt/sources.list" << EOF ${prefix} $SECURITY_MIRROR ${release}/updates main contrib non-free EOF + fi } configure_debian_systemd() @@ -196,6 +192,11 @@ mkdir -p ${rootfs}/{lib,etc}/systemd/system mkdir -p ${rootfs}/etc/systemd/system/getty.target.wants + # Fix getty-static-service as debootstrap does not install dbus + if [ -e $rootfs//lib/systemd/system/getty-static.service ] ; then + sed 's/ getty@tty[5-9].service//g' $rootfs/lib/systemd/system/getty-static.service | sed 's/\(tty2-tty\)[5-9]/\14/g' > $rootfs/etc/systemd/system/getty-static.service + fi + # This function has been copied and adapted from lxc-fedora rm -f ${rootfs}/etc/systemd/system/default.target touch ${rootfs}/etc/fstab @@ -376,8 +377,10 @@ # If the container isn't running a native architecture, setup multiarch if [ "${arch}" != "${hostarch}" ]; then - mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d - echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch + # Test if dpkg supports multiarch + if ! chroot $rootfs dpkg --print-foreign-architecture 2>&1; then + chroot $rootfs dpkg --add-architecture ${hostarch} + fi fi # Write a new sources.list containing both native and multiarch entries @@ -390,6 +393,25 @@ # Re-enable service startup rm ${rootfs}/usr/sbin/policy-rc.d + + # reconfigure locales + if [ -z "$LANG" ]; then + cat >> $rootfs/etc/locale.gen << EOF +en_US.UTF-8 UTF-8 +EOF + chroot $rootfs locale-gen en_US.UTF-8 UTF-8 + chroot $rootfs update-locale LANG=en_US.UTF-8 + else + encoding=$(echo $LANG | cut -d. -f2) + chroot $rootfs sed -e "s/^# \(${LANG} ${encoding}\)/\1/" \ + -i /etc/locale.gen 2> /dev/null + cat >> $rootfs/etc/locale.gen << EOF +$LANG $encoding +EOF + chroot $rootfs locale-gen $LANG $encoding + chroot $rootfs update-locale LANG=$LANG + fi + # end } clean() @@ -418,11 +440,35 @@ usage() { cat < [-a|--arch] [-c|--clean] [--mirror=] [-r|--release=] [--security-mirror=] -arch: the container architecture (e.g. amd64): defaults to host arch -release: the debian release (e.g. wheezy): defaults to current stable -mirror: debain mirror to use during installation -security mirror: debain mirror to use for security updates +Template specific options can be passed to lxc-create after a '--' like this: + + lxc-create --name=NAME [-lxc-create-options] -- [-template-options] + +Usage: $1 -h|--help -p|--path= [-c|--clean] [-a|--arch=] [-r|--release=] + [--mirror=] [--security-mirror=] + +Options : + + -h, --help print this help text + -p, --path=PATH directory where config and rootfs of this VM will be kept + -a, --arch=ARCH The container architecture. Can be one of: i686, x86_64, + amd64, armhf, armel, powerpc. Defaults to host arch. + -r, --release=RELEASE Debian release. Can be one of: squeeze, wheezy, jessie, sid. + Defaults to current stable. + --mirror=MIRROR Debian mirror to use during installation. Overrides the MIRROR + environment variable (see below). + --security-mirror=SECURITY_MIRROR + Debian mirror to use for security updates. Overrides the + SECURITY_MIRROR environment variable (see below). + -c, --clean only clean up the cache and terminate + +Environment variables: + + MIRROR The Debian package mirror to use. See also the --mirror switch above. + Defaults to '$MIRROR' + SECURITY_MIRROR The Debian package security mirror to use. See also the --security-mirror switch above. + Defaults to '$SECURITY_MIRROR' + EOF return 0 } @@ -434,17 +480,13 @@ fi eval set -- "$options" -if which dpkg > /dev/null 2>&1 ; then - arch=$(dpkg --print-architecture) -else - arch=$(uname -m) - if [ "$arch" = "i686" ]; then - arch="i386" - elif [ "$arch" = "x86_64" ]; then - arch="amd64" - elif [ "$arch" = "armv7l" ]; then - arch="armhf" - fi +arch=$(uname -m) +if [ "$arch" = "i686" ]; then + arch="i386" +elif [ "$arch" = "x86_64" ]; then + arch="amd64" +elif [ "$arch" = "armv7l" ]; then + arch="armhf" fi hostarch=$arch @@ -455,7 +497,7 @@ --) shift 1; break ;; -a|--arch) arch=$2; shift 2;; - -c|--clean) clean=$2; shift 1;; + -c|--clean) clean=1; shift 1;; --mirror) MIRROR=$2; shift 2;; -n|--name) name=$2; shift 2;; -p|--path) path=$2; shift 2;; @@ -513,7 +555,7 @@ current_release=`wget ${MIRROR}/dists/stable/Release -O - 2> /dev/null | head |awk '/^Codename: (.*)$/ { print $2; }'` release=${release:-${current_release}} -valid_releases=('squeeze' 'wheezy' 'jessie' 'sid') +valid_releases=('squeeze' 'wheezy' 'jessie' 'stretch' 'sid') if [[ ! "${valid_releases[*]}" =~ (^|[^[:alpha:]])$release([^[:alpha:]]|$) ]]; then echo "Invalid release ${release}, valid ones are: ${valid_releases[*]}" exit 1 @@ -551,7 +593,7 @@ post_process ${rootfs} ${release} ${arch} ${hostarch} -if [ ! -z $clean ]; then +if [ ! -z "$clean" ]; then clean || exit 1 exit 0 fi diff -Nru lxc-1.0.7/templates/lxc-download.in lxc-1.0.8/templates/lxc-download.in --- lxc-1.0.7/templates/lxc-download.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-download.in 2015-11-09 22:49:15.000000000 +0000 @@ -188,21 +188,23 @@ cat < ]: The name of the distribution [ -r | --release ]: Release name/version [ -a | --arch ]: Architecture of the container Optional arguments: -[ -h | --help ]: This help message -[ -l | --list ]: List all available images [ --variant ]: Variant of the image (default: "default") [ --server ]: Image server (default: "images.linuxcontainers.org") [ --keyid ]: GPG keyid (default: 0x...) [ --keyserver ]: GPG keyserver to use [ --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 +[ --force-cache ]: Force the use of the local copy even if expired LXC internal arguments (do not pass manually!): [ --name ]: The container name @@ -266,8 +268,10 @@ # Check that we have all variables we need if [ -z "$LXC_NAME" ] || [ -z "$LXC_PATH" ] || [ -z "$LXC_ROOTFS" ]; then - echo "ERROR: Not running through LXC." 1>&2 - exit 1 + if [ "$DOWNLOAD_LIST_IMAGES" != "true" ]; then + echo "ERROR: Not running through LXC." 1>&2 + exit 1 + fi fi USERNS=$(in_userns) @@ -571,6 +575,11 @@ sed -i "s#LXC_HOOK_DIR#$LXC_HOOK_DIR#g" $file done +# prevent mingetty from calling vhangup(2) since it fails with userns on Centos / Oracle +if [ -f ${LXC_ROOTFS}/etc/init/tty.conf ]; then + sed -i 's|mingetty|mingetty --nohangup|' ${LXC_ROOTFS}/etc/init/tty.conf +fi + if [ -n "$LXC_MAPPED_UID" ] && [ "$LXC_MAPPED_UID" != "-1" ]; then chown $LXC_MAPPED_UID $LXC_PATH/config $LXC_PATH/fstab >/dev/null 2>&1 || true fi diff -Nru lxc-1.0.7/templates/lxc-fedora.in lxc-1.0.8/templates/lxc-fedora.in --- lxc-1.0.7/templates/lxc-fedora.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-fedora.in 2015-11-09 22:49:15.000000000 +0000 @@ -220,6 +220,7 @@ BOOTPROTO=dhcp ONBOOT=yes HOSTNAME=${utsname} +DHCP_HOSTNAME=\`hostname\` NM_CONTROLLED=no TYPE=Ethernet MTU=${MTU} @@ -362,6 +363,12 @@ chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target # Make systemd honor SIGPWR chroot ${rootfs_path} ln -s /usr/lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target + + # if desired, prevent systemd from over-mounting /tmp with tmpfs + if [ $masktmp -eq 1 ]; then + chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/tmp.mount + fi + #dependency on a device unit fails it specially that we disabled udev # sed -i 's/After=dev-%i.device/After=/' ${rootfs_path}/lib/systemd/system/getty\@.service # @@ -570,7 +577,7 @@ # Right now, we are using Fedora 20 for the inial bootstrap. # We could make this the "current" Fedora rev (F > 15). - rsync -av mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/LiveOS . + rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/LiveOS . if [[ 0 == $? ]] then @@ -647,8 +654,8 @@ # of this LiveOS image we're camped out on. This is the beginning # of the butt ugly hack. Look close or you may missing it... - rsync -av mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/Packages/r/rpm-[0-9]* \ - mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/Packages/y/yum-[0-9]* . + rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/r/rpm-[0-9]* \ + ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/y/yum-[0-9]* . # And here it is... # The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?! @@ -680,7 +687,7 @@ echo "Stage 1 creation complete. Building stage 2 Installation Bootstrap" mount -o bind ../bootstrap run/install - rsync -av mirrors.kernel.org::fedora/releases/20/Fedora/$basearch/os/Packages/f/fedora-release-20* . + rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/f/fedora-release-20* . # The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?! chroot . rpm --root /run/install --nodeps -ivh fedora-release-* @@ -813,6 +820,13 @@ PKG_LIST="${PKG_LIST} db4-utils" fi + if [[ ${release} -ge 21 ]] + then + # Since Fedora 21, a separate fedora-repos package is needed. + # Before, the information was conained in fedora-release. + PKG_LIST="${PKG_LIST} fedora-repos" + fi + DOWNLOAD_OK=no # We're splitting the old loop into two loops plus a directory retrival. @@ -841,7 +855,7 @@ RELEASE_URL="$MIRROR_URL/Packages/" fi - echo "Fetching rpm name from $RELEASE_URL..." + echo "Fetching release rpm name from $RELEASE_URL..." # This code is mildly "brittle" in that it assumes a certain directory # page format and parsing HTML. I've done worse. :-P RELEASE_RPM=$(curl -L -f "$RELEASE_URL" | sed -e "/fedora-release-${release}-/!d" -e 's/.*.*//' ) @@ -857,6 +871,24 @@ continue fi + # F21 and newer need fedora-repos in addition to fedora-release. + if [ "$release" -ge "21" ]; then + echo "Fetching repos rpm name from $RELEASE_URL..." + REPOS_RPM=$(curl -L -f "$RELEASE_URL" | sed -e "/fedora-repos-${release}-/!d" -e 's/.*.*//' ) + if [ $? -ne 0 -o "${REPOS_RPM}" = "" ]; then + echo "Failed to identify fedora repos rpm." + continue + fi + + echo "Fetching fedora repos rpm from ${RELEASE_URL}/${REPOS_RPM}..." + curl -L -f "${RELEASE_URL}/${REPOS_RPM}" > ${INSTALL_ROOT}/${REPOS_RPM} + if [ $? -ne 0 ]; then + echo "Failed to download fedora repos rpm ${RELEASE_RPM}." + continue + fi + fi + + DOWNLOAD_OK=yes break done @@ -877,9 +909,18 @@ fedora_bootstrap_mounts ${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} --initdb + # The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?! ${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} --nodeps -ivh ${BOOTSTRAP_INSTALL_ROOT}/${RELEASE_RPM} + # F21 and newer need fedora-repos in addition to fedora-release... + # Note that fedora-release and fedora-system have a mutual dependency. + # So installing the reops package after the release package we can + # spare one --nodeps. + if [ "$release" -ge "21" ]; then + ${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} -ivh ${BOOTSTRAP_INSTALL_ROOT}/${REPOS_RPM} + fi + # yum will take $basearch from host, so force the arch we want sed -i "s|\$basearch|$basearch|" ${BOOTSTRAP_DIR}/${BOOTSTRAP_INSTALL_ROOT}/etc/yum.repos.d/* @@ -1073,13 +1114,22 @@ " >> $config_path/config fi + if [ "x$have_systemd" = "x1" ]; then + cat <> $config_path/config +lxc.autodev = 1 +lxc.kmsg = 0 +EOF + else + cat <> $config_path/config +lxc.autodev = 0 +EOF + fi + # Append things which require expansion here... cat <> $config_path/config lxc.arch = $arch lxc.utsname = $utsname -lxc.autodev = $auto_dev - # When using LXC with apparmor, uncomment the next line to run unconfined: #lxc.aa_profile = unconfined @@ -1131,41 +1181,49 @@ cat < - [-p|--path=] [-c|--clean] [-R|--release=] [--fqdn=] [-a|--arch=] + [-p|--path=] [-c|--clean] [-R|--release=] + [--fqdn=] [-a|--arch=] + [--mask-tmp] [-h|--help] Mandatory args: - -n,--name container name, used to as an identifier for that container from now on + -n,--name container name, used to as an identifier for that container Optional args: - -p,--path path to where the container will be created, defaults to @LXCPATH@. The container config will go under @LXCPATH@ in that case + -p,--path path to where the container will be created, + defaults to @LXCPATH@. --rootfs path for actual rootfs. -c,--clean clean the cache - -R,--release Fedora release for the new container. if the host is Fedora, then it will default to the host's release. + -R,--release Fedora release for the new container. + Defaults to host's release if the host is Fedora. --fqdn fully qualified domain name (FQDN) for DNS and system naming -a,--arch Define what arch the container will be [i686,x86_64] + --mask-tmp Prevent systemd from over-mounting /tmp with tmpfs. -h,--help print this help EOF return 0 } -options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,arch:,fqdn: -- "$@") +options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,arch:,fqdn:,mask-tmp -- "$@") if [ $? -ne 0 ]; then usage $(basename $0) exit 1 fi arch=$(uname -m) +masktmp=0 + eval set -- "$options" while true do case "$1" in -h|--help) usage $0 && exit 0;; -p|--path) path=$2; shift 2;; - --rootfs) rootfs=$2; shift 2;; + --rootfs) rootfs_path=$2; shift 2;; -n|--name) name=$2; shift 2;; - -c|--clean) clean=$2; shift 2;; + -c|--clean) clean=1; shift 1;; -R|--release) release=$2; shift 2;; -a|--arch) newarch=$2; shift 2;; --fqdn) utsname=$2; shift 2;; + --mask-tmp) masktmp=1; shift 1;; --) shift 1; break ;; *) break ;; esac @@ -1176,7 +1234,6 @@ exit 0 fi - basearch=${arch} # Map a few architectures to their generic Fedora repository archs. # The two ARM archs are a bit of a guesstimate for the v5 and v6 @@ -1191,6 +1248,12 @@ *) ;; esac +mirrorurl="archives.fedoraproject.org::fedora-archive" +case "$basearch" in +ppc64|s390x) mirrorurl="archives.fedoraproject.org::fedora-secondary" ;; +*) ;; +esac + # Somebody wants to specify an arch. This is very limited case. # i386/i586/i686 on i386/x86_64 # - or - @@ -1288,17 +1351,17 @@ if [ "$is_fedora" -a "$fedora_host_ver" ]; then release=$fedora_host_ver else - echo "This is not a fedora host and release missing, defaulting to 20 use -R|--release to specify release" - release=20 + echo "This is not a fedora host and release missing, defaulting to 22 use -R|--release to specify release" + release=22 fi fi -# Fedora 15 and above run systemd. We need autodev enabled to keep +# Fedora 15 and above run systemd.We need autodev enabled to keep # systemd from causing problems. +# Also, kmsg must not be mapped to prevent a 100% cpu loop +# in systemd-journald. if [ $release -gt 14 ]; then - auto_dev="1" -else - auto_dev="0" + have_systemd="1" fi if [ "$(id -u)" != "0" ]; then @@ -1306,7 +1369,6 @@ exit 1 fi - if [ -z "$rootfs_path" ]; then rootfs_path=$path/rootfs # check for 'lxc.rootfs' passed in through default config by lxc-create @@ -1362,7 +1424,7 @@ configure_fedora_init fi -if [ ! -z $clean ]; then +if [ ! -z "$clean" ]; then clean || exit 1 exit 0 fi diff -Nru lxc-1.0.7/templates/lxc-gentoo.in lxc-1.0.8/templates/lxc-gentoo.in --- lxc-1.0.7/templates/lxc-gentoo.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-gentoo.in 2015-11-09 22:49:15.000000000 +0000 @@ -160,7 +160,7 @@ printf "Determining path to latest Gentoo %s (%s) stage3 archive...\n" "${arch}" "${variant}" printf " => downloading and processing %s\n" "${stage3_pointer}" - local stage3_latest_tarball=$(wget -q -O - "${stage3_pointer}" | tail -n1 ) \ + local stage3_latest_tarball=$(wget -q -O - "${stage3_pointer}" | tail -n1 | cut -d' ' -f1) \ || die 6 "Error: unable to fetch\n" printf " => Got: %s\n" "${stage3_latest_tarball}" @@ -641,11 +641,11 @@ if [[ -r "${auth_key}" ]]; then printf " deploying auth_key %s for user %s ...\n" "${auth_key}" "${user}" mkdir -p "${rootfs}/${auth_home}/.ssh" - cat >> "${rootfs}/${auth_home}/.ssh/authorized_keys" + cat "${auth_key}" >> "${rootfs}/${auth_home}/.ssh/authorized_keys" chroot "${rootfs}" chown "${user}:" "${auth_home}/.ssh/authorized_keys" printf " => inserted public key in %s/.ssh/authorized_keys\n" "${auth_home}" [[ -z "${forced_password}" ]] && unset password - store_user_message "${user} has the ssh key you gived us" + store_user_message "${user} has the ssh key you gave us" fi if [[ -n "${password}" ]]; then @@ -681,6 +681,13 @@ #at this point if there conf_file="${path}/config" + # if there is exactly one veth network entry, make sure it has an + # associated hwaddr. + nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' ${conf_file} | wc -l` + if [ $nics -eq 1 ]; then + grep -q "^lxc.network.hwaddr" ${conf_file} || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" ${conf_file} + fi + if grep -q "^lxc.rootfs" "${conf_file}" ; then #lxc-create already provided one conf_rootfs_line="" @@ -775,7 +782,7 @@ 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: -- "$@") +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: -- "$@") eval set -- "$options" diff -Nru lxc-1.0.7/templates/lxc-openmandriva.in lxc-1.0.8/templates/lxc-openmandriva.in --- lxc-1.0.7/templates/lxc-openmandriva.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-openmandriva.in 2015-11-09 22:49:15.000000000 +0000 @@ -377,7 +377,7 @@ --rootfs) rootfs_path=$2; shift 2;; -n|--name) name=$2; shift 2;; -P|--profile) profile=$2; shift 2;; - -c|--clean) clean=$2; shift 2;; + -c|--clean) clean=1; shift 1;; -R|--release) release=$2; shift 2;; -A|--arch) arch=$2; shift 2;; -4|--ipv4) ipv4=$2; shift 2;; @@ -483,7 +483,7 @@ exit 1 fi -if [ ! -z $clean ]; then +if [ ! -z "$clean" ]; then clean || exit 1 exit 0 fi diff -Nru lxc-1.0.7/templates/lxc-opensuse.in lxc-1.0.8/templates/lxc-opensuse.in --- lxc-1.0.7/templates/lxc-opensuse.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-opensuse.in 2015-11-09 22:49:15.000000000 +0000 @@ -38,7 +38,7 @@ # Make sure the usual locations are in PATH export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin -DISTRO=12.3 +DISTRO=13.1 configure_opensuse() { @@ -372,7 +372,7 @@ -p|--path) path=$2; shift 2;; --rootfs) rootfs=$2; shift 2;; -n|--name) name=$2; shift 2;; - -c|--clean) clean=$2; shift 2;; + -c|--clean) clean=1; shift 1;; --) shift 1; break ;; *) break ;; esac @@ -395,8 +395,11 @@ fi if grep -q Harlequin /etc/os-release || grep -q Tumbleweed /etc/os-release ; then - echo "Building containers on openSUSE 13.2 or Tumbleweed is broken at the moment. We are working on this problem." - exit 1 + BVER=`rpm -q --qf '%{version}\n' build` + if [ $? -ne 0 -o "$BVER" -lt "20141120" ]; then + echo "Building openSUSE containers with your version of the build package is broken. Please install the update to version 20141120 or newer." + exit 1 + fi fi if [ "$(id -u)" != "0" ]; then @@ -432,7 +435,7 @@ exit 1 fi -if [ ! -z $clean ]; then +if [ ! -z "$clean" ]; then clean || exit 1 exit 0 fi diff -Nru lxc-1.0.7/templates/lxc-oracle.in lxc-1.0.8/templates/lxc-oracle.in --- lxc-1.0.7/templates/lxc-oracle.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-oracle.in 2015-11-09 22:49:15.000000000 +0000 @@ -290,7 +290,7 @@ BOOTPROTO=dhcp ONBOOT=yes HOSTNAME=$name -DHCP_HOSTNAME=$name +DHCP_HOSTNAME=\`hostname\` NM_CONTROLLED=no TYPE=Ethernet EOF @@ -314,13 +314,13 @@ # sem_open(3) checks that /dev/shm is SHMFS_SUPER_MAGIC, so make sure to mount /dev/shm (normally done by dracut initrd) as tmpfs if [ $container_release_major = "4" -o $container_release_major = "5" ]; then - echo "mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.sysinit - echo "mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.d/rc.sysinit + echo "mkdir -p /dev/shm && mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.sysinit + echo "mkdir -p /dev/shm && mount -t tmpfs tmpfs /dev/shm" >>$container_rootfs/etc/rc.d/rc.sysinit fi if [ $container_release_major = "6" ]; then - sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.sysinit - sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.d/rc.sysinit + sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm \&\& mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.sysinit + sed -i 's|mount -n -o remount /dev/shm >/dev/null 2>&1$|mkdir -p /dev/shm \&\& mount -t tmpfs tmpfs /dev/shm # LXC|' $container_rootfs/etc/rc.d/rc.sysinit fi # setup console and tty[1-4] for login. note that /dev/console and diff -Nru lxc-1.0.7/templates/lxc-ubuntu-cloud.in lxc-1.0.8/templates/lxc-ubuntu-cloud.in --- lxc-1.0.7/templates/lxc-ubuntu-cloud.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-ubuntu-cloud.in 2015-11-09 22:49:15.000000000 +0000 @@ -25,7 +25,7 @@ HOOK_DIR="@LXCHOOKDIR@" CLONE_HOOK_FN="$HOOK_DIR/ubuntu-cloud-prep" LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@" -KNOWN_RELEASES="lucid precise quantal saucy trusty" +KNOWN_RELEASES="precise trusty utopic vivid" skip_arch_check=${UCTEMPLATE_SKIP_ARCH_CHECK:-0} # Make sure the usual locations are in PATH @@ -204,7 +204,7 @@ while true do case "$1" in - -h|--help) usage $0 && exit 0;; + -h|--help) usage $0 && exit 1;; -p|--path) path=$2; shift 2;; -n|--name) name=$2; shift 2;; -F|--flush-cache) flushcache=1; shift 1;; @@ -297,9 +297,9 @@ if ! url1=`ubuntu-cloudimg-query $release $stream $arch --format "%{url}\n"`; then echo "There is no download available for release=$release, stream=$stream, arch=$arch" [ "$stream" = "daily" ] || echo "You may try with '--stream=daily'" - exit + exit 1 fi - url2=`echo $url1 | sed -e 's/.tar.gz/-root\0/'` + url2=`echo $url1 | sed -e 's/.tar.gz/-root\0/' -e 's/.tar.gz/.tar.xz/'` fi filename=`basename $url2` @@ -309,44 +309,6 @@ rm -f $filename } -buildcleanup() -{ - cd $rootfs - umount -l $cache/$xdir || true - rm -rf $cache -} - -# if the release doesn't have a *-rootfs.tar.gz, then create one from the -# cloudimg.tar.gz by extracting the .img, mounting it loopback, and creating -# a tarball from the mounted image. -build_root_tgz() -{ - url=$1 - filename=$2 - - xdir=`mktemp -d -p .` - tarname=`basename $url` - imgname="$release-*-cloudimg-$arch.img" - trap buildcleanup EXIT SIGHUP SIGINT SIGTERM - if [ $flushcache -eq 1 -o ! -f $cache/$tarname ]; then - rm -f $tarname - echo "Downloading cloud image from $url" - wget $url || { echo "Couldn't find cloud image $url."; exit 1; } - fi - echo "Creating new cached cloud image rootfs" - tar --wildcards -zxf "$tarname" "$imgname" - mount -o loop $imgname $xdir - (cd $xdir; tar --numeric-owner -cpzf "../$filename" .) - umount $xdir - rm -f $tarname $imgname - rmdir $xdir - echo "New cloud image cache created" - trap EXIT - trap SIGHUP - trap SIGINT - trap SIGTERM -} - do_extract_rootfs() { cd $cache @@ -357,7 +319,7 @@ trap wgetcleanup EXIT SIGHUP SIGINT SIGTERM if [ ! -f $filename ]; then - wget $url2 || build_root_tgz $url1 $filename + wget $url2 fi trap EXIT trap SIGHUP @@ -368,10 +330,10 @@ mkdir -p $rootfs cd $rootfs if [ $in_userns -eq 1 ]; then - tar --anchored --exclude="dev/*" --numeric-owner -xpzf "$cache/$filename" + tar --anchored --exclude="dev/*" --numeric-owner -xpJf "$cache/$filename" mkdir -p $rootfs/dev/pts/ else - tar --numeric-owner -xpzf "$cache/$filename" + tar --numeric-owner -xpJf "$cache/$filename" fi } diff -Nru lxc-1.0.7/templates/lxc-ubuntu.in lxc-1.0.8/templates/lxc-ubuntu.in --- lxc-1.0.7/templates/lxc-ubuntu.in 2014-12-05 20:50:20.000000000 +0000 +++ lxc-1.0.8/templates/lxc-ubuntu.in 2015-11-09 22:49:15.000000000 +0000 @@ -497,28 +497,6 @@ EOF chmod +x $rootfs/usr/sbin/policy-rc.d - if [ ! -f $rootfs/etc/init/container-detect.conf ]; then - # Make sure we have a working resolv.conf - cresolvonf="${rootfs}/etc/resolv.conf" - mv $cresolvonf ${cresolvonf}.lxcbak - cat /etc/resolv.conf > ${cresolvonf} - - # for lucid, if not trimming, then add the ubuntu-virt - # ppa and install lxcguest - if [ $release = "lucid" ]; then - chroot $rootfs apt-get update - install_packages $rootfs "python-software-properties" - chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa - fi - - chroot $rootfs apt-get update - chroot $rootfs apt-get install --force-yes -y lxcguest - - # Restore old resolv.conf - rm -f ${cresolvonf} - mv ${cresolvonf}.lxcbak ${cresolvonf} - fi - # If the container isn't running a native architecture, setup multiarch if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then dpkg_version=$(chroot $rootfs dpkg-query -W -f='${Version}' dpkg)