Hide Forgot
Description of problem: Public debian bug #732394 points out a vulnerability where a malicious guest can use symlinks to cause the LXC driver to manipulate unintended files in the host during the virDomainShutdown, virDomainReboot, virDomainDeviceAttach, and virDomainDeviceDettach APIs. The libvirt-security list has been notified (private archives: https://www.redhat.com/mailman/private/libvirt-security/2013-December/msg00018.html), and we are now awaiting assignment of a CVE to cover this issue. Public patches are underway for the virDomainShutdown/virDomainReboot issues (v4 is incomplete, v5 not posted yet: https://www.redhat.com/archives/libvir-list/2013-December/msg01182.html), at the time of this BZ, the virDomainDevice{Attach,Dettach} issue still needs work. Version-Release number of selected component (if applicable): libvirt-1.1.1-16.el7 How reproducible: 100% Steps to Reproduce: 1. 2. 3. Actual results: Expected results: Additional info: Description ----------- The LXC driver will open paths under /proc/$PID/root for some operations it performs on running guests. For the virDomainShutdown and virDomainReboot APIs it will use this to access the /dev/initctl path in the container. For the virDomainDeviceAttach / virDomainDeviceDettach APIs it will use this to create device nodes in the container's /dev filesystem. If any of the path components under control of the container are symlinks the container can cause the libvirtd daemon to access the incorrect files. Impact ------ A container can cause the administrator to shutdown or reboot the host OS if /dev/initctl in the container is made to be an absolute symlink back to itself or /run/initctl. A container can cause the host administrator to mknod in an arbitrary host directory when invoking the virDomainDeviceAttach API by replacing '/dev' with an absolute symlink. A container can cause the host administrator to delete host device when invoking the virDomainDeviceDettach API by replacing '/dev' with an absolute symlink. Workaround ---------- Do not use the virDomainShutdown or virDomainReboot APIs without also passing the VIR_DOMAIN_SHUTDOWN_SIGNAL or VIR_DOMAIN_REBOOT_SIGNAL flags respectively. These will cause the LXC driver to send a SIGTERM or SIGHUP signal respectively, to the init process instead of using /dev/initct.. Do not use the virDomainDeviceAttach or virDomainDeviceDetach APIs at all unless the guest OS is trusted.
Reported on: 20131217 Published on: 20131217 Reported by: Reco <recoverym4n>
This issue was assigned CVE-2013-6456 (CVE bug not yet filed, sorry about that!)
In POST: http://post-office.corp.redhat.com/archives/rhvirt-patches/2014-February/msg00647.html
Follow Eric's advice , verified this one via strace with libvirt-1.1.1-27.el7.x86_64 on RHEL7 platform. There are something need to be noted here first , 1.Since rhel7 use systemd to control , which not sysinit or upstart that used on other distributions , like debian , it's hard to reproduce the "host reboot" issue here. 2.Due to /run/initctl is no longer recommanded for using through systemd's document , i just create a fake /run/initctl in container and ln it to /dev/initctl to watch if libvirtd try to open it when call related virDomainShutdown , virDomainReboot APIs. 3.I use two libvirt versions which pre-patch and post-patch to contrast A.if libvirtd will continue share a same namespace with container B.if libvirtd will try to open the /dev/initctl C.if libvirtd will fork a child process to execute the action about open /dev/initctl in container D.if can destroy the container successfully once the child process has broken , and there is no affect in host after do that Below is the steps. 1.Prepare a default /bin/bash container #virsh -c lxc:/// dumpxml test <domain type='lxc' id='8631'> <name>test</name> <uuid>4c669f82-cb0d-4bf4-98aa-eb0933075efa</uuid> <memory unit='KiB'>1048576</memory> <currentMemory unit='KiB'>1048576</currentMemory> <vcpu placement='static'>1</vcpu> <resource> <partition>/machine</partition> </resource> <os> <type arch='x86_64'>exe</type> <init>/bin/sh</init> </os> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> <emulator>/usr/libexec/libvirt_lxc</emulator> <filesystem type='mount' accessmode='passthrough'> <source dir='/'/> <target dir='/'/> </filesystem> <interface type='network'> <mac address='00:16:3e:e5:02:c5'/> <source network='default'/> <target dev='vnet0'/> </interface> <console type='pty' tty='/dev/pts/3'> <source path='/dev/pts/3'/> <target type='lxc' port='0'/> <alias name='console0'/> </console> </devices> <seclabel type='none' model='selinux'/> </domain> 2.start the container opening another terminal to use strace #virsh -c lxc:/// start test On another terminal # strace -o output.txt -f -F -p $(pidof libvirtd) 3.Run the command inside the container sh-4.2# touch /run/initctl sh-4.2# ln -s /run/initctl /dev/initctl 4.Remains the container start first, then try to reboot/shutdown it on host #virsh -c lxc:/// reboot test 5.Grep the strace output file to check whether libvirtd try to open /proc/$pid/root/dev/initctl On libvirt-1.1.1-23.el7.x86_64 , which is a pre-patch version #cat output.txt | grep -i initctl 8353 open("/proc/8635/root//dev/initctl", O_WRONLY|O_NOCTTY|O_NONBLOCK|O_CLOEXEC <unfinished ...> That means first the container and the host shared a same namespace and then libvirtd try to open it on host. On libvirt-1.1.1-27.el7.x86_64 cat output.txt | grep -i initctl 1458 open("/dev/initctl", O_WRONLY|O_NOCTTY|O_NONBLOCK|O_CLOEXEC) = -1 ELOOP (Too many levels of symbolic links) Apparently , with the post-patch version , the container already have an individual namespace. Use fake file and then ln it to initctl may lead some error but will not harm the host itself 6.Make up error message for step 4 libvirt-1.1.1-23.el7.x86_64: virsh # reboot test error: Failed to reboot domain test error: Cannot open init control /proc/8635/root//dev/initctl: Too many levels of symbolic links libvirt-1.1.1-27.el7.x86_64: virsh # reboot test error: Failed to reboot domain test error: internal error: Child process (1458) unexpected exit status 1 libvirtd will fork a child process to execute the behaviour 7.Destroy the container #virsh -c lxc:/// destroy test #systemctl status libvirtd libvirtd.service - Virtualization daemon Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; enabled) Active: active (running) since Fri 2014-03-14 13:06:59 CST; 1min 17s ago Main PID: 6997 (libvirtd) CGroup: /system.slice/libvirtd.service ├─3011 /sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf └─6997 /usr/sbin/libvirtd Have no affect on systemd and host. So set this one VERIFIED
Fixed in 7.0 GA, closing.