July 7th, 2011

Fun with sVirt.

I have been in Washington DC for the last few days talking about SELinux and sVirt, Secure Virtualization. 

sVirt is the combining of SELinux with kvm/qemu virtualization.  The libvirt daemon launches virtual guests in Red Hat operating systems.  Before an virtual machine  is started libvirt picks a random MCS label with two categories, like s0:c1,c2 and then labels all of the virtual machines content as svirt_image_t:s0:c1,c2.  Then it executes qemu with the label svirt_t:c0:c1,c2.   

One of the questions on sVirt I have been asked is how can I test out the sVirt policy, to make sure it works?

I thought about it and I came up with an easy way that someone can play with it. 

One of the major goals of a hacker is to get a root shell on the host, lets see what you can do with the root shell running as svirt_t.

Note: the unconfined_t user type is allowed to transition to svirt_t in Fedora 14-16 and RHEL6 I believe. 

In order to test the svirt_t, we need a program to run, I copied /bin/sh to /bin/svirt.  

# cp /bin/sh /bin/svirt

The policy requires that the entry point for svirt_t must be labeled qemu_exec_t.

# chcon -t qemu_exec_t /bin/svirt

Now I use the runcon command to force a transition from unconfined_t to svirt and pick out an MCS label s0:c1,c2 to run with the svirt shell.

# runcon -t svirt_t -l s0:c1,c2 /bin/svirt
svirt: /root/.bashrc: Permission denied
# id
svirt: child setpgid (6962 to 6962): Permission denied
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=unconfined_u:unconfined_r:svirt_t:s0:c1,c2

First the shell tried to read /root/.bashrc and was denied. because svirt_t is not allowed to read the admin_home_t label.  The shell attempts to setpgid for every command that is executed which SELinux denies svirt_t and prints an error to the screen.  I have removed these errors from the blog just for clarity.
# ping
svirt: ping: command not found
# cat /etc/shadow
cat: /etc/shadow: Permission denied

# touch /tmp/svirt
# ls -lZ /tmp/svirt
-rw-r--r--. root root unconfined_u:object_r:svirt_tmp_t:s0:c1,c2 /tmp/svirt

Note Notice the touch succeeded, allowing me to create a file in the /tmp directory labeled svirt_tmp_t:s0:c0,c2
# ^D

Now I exit this shell and start another svirt shell with a slightly different MCS label s0:c1,c3

# runcon -t svirt_t -l s0:c1,c3 /bin/svirt
svirt: /root/.bashrc: Permission denied
# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=unconfined_u:unconfined_r:svirt_t:s0:c1,c3
# touch /tmp/svirt
touch: cannot touch `/tmp/svirt': Permission denied

Note: This svirt shell is denied the ability to use the previously created /tmp/svirt file since this file has a label s0:c1,c2 but this svirt shell is running as s0:c1,c3. This would simulate one svirt guest process attacking another svirt_t process.

Have fun with this and see what svirt can do.  If you find what you believe to be a vulnerability please report it in bugzilla.  If you build a test script with this, we would love to use it.

You will fill your /var/log/audit/audit.log file with audit messages and setroubleshoot will not be happy, but it is pretty good test.