Testing answers to questions about sVirt SELinux policy

Posted: September 27th, 2011 | Filed under: Fedora, libvirt, Virt Tools | 1 Comment »

Yesterday on the #virt@irc.oftc.net IRC channel there was a question asked about whether sVirt+SELinux would prevent two virtual machines running under the same user ID, from ptrace()ing each other. If no SELinux is involved, there is no DAC restriction ptrace() between two PIDs with the same UID. So this is clearly the kind of thing you would expect/want sVirt to block, and indeed it does. But how can you easily prove the policy blocks ptrace ? Enter the ‘runcon’ command, which lets you impersonate VMs.

NB, when trying out the following, you want SELinux to be in “permissive” mode, not “enforcing”, since the way we do some parts of the tests will trigger other AVCs which get in the way.

Under sVirt each QEMU process is given a dedicate security label, formed by combining the base label “system_u:system_r:svirt_t:s0” with a unique MCS level. So to test our belief about ptrace(), we need to have two security labels. Lets use these two


Now we want a process to act as the target VM to be ptrace()d. With the first SELinux label above, and “runcon” we can launch a confined QEMU process in the same way libvirtd would have done:

$ runcon system_u:system_r:svirt_t:s0:c12,c34 /usr/bin/qemu -vnc :1

‘ps’ can be used to verify that ‘qemu’ really is under the confined domain

$ ps -axuwZ | grep qemu
system_u:system_r:svirt_t:s0:c12,c34 berrange 29542 0.0  0.0 106680 460 pts/12 S+   14:32   0:00 qemu

Now we have the victim running, we can try launching an attacker. Since we’re looking to see if ptrace() is blocked, ‘strace‘ is a natural command to try out. For testing other attack vectors you might want to create a tiny dedicated program. Using the second security label, and ‘runcon‘ again, we can do

$ runcon system_u:system_r:svirt_t:s0:c56,c78 strace -p $PID-OF-VICTIM

Finally, we can look at the audit log for any AVC messages about the ‘ptrace’ access vector:

# grep AVC /var/log/audit/audit.log | grep ptrace
type=AVC msg=audit(1317130603.887:33048): avc: denied { ptrace } for pid=29644 comm="strace" scontext=system_u:system_r:svirt_t:s0:c56,c78 tcontext=system_u:system_r:svirt_t:s0:c12,c34 tclass=process

What this AVC is saying is that a process under the label “scontext=system_u:system_r:svirt_t:s0:c56,c78” tried to execute ptrace() against a process under the label “system_u:system_r:svirt_t:s0:c12,c34” and it was blocked.

This exactly what we wanted to see happen. We have now proved that 2 VMs as the same user ID can not ptrace() each other.

When I outlined this on IRC, there was a follow up question. Can the attacking VM just use ‘runcon’ to change its security label ? The answer is again no. Transitions between security labels must be explicitly allowed by the policy, and sVirt policy does not allow any such transitions for the svirt_t type. Again this can be demonstrated by using ‘runcon‘ by chaining together two invocations:

runcon system_u:system_r:svirt_t:s0:c56,c78 runcon system_u:system_r:svirt_t:s0:c12,c34 strace -p $PID-OF-VICTIM

And then looking for any AVC log message about the ‘transition’ access vector

# grep AVC /var/log/audit/audit.log | grep transition
type=AVC msg=audit(1317131267.839:33153): avc:  denied  { transition } for  pid=29811 comm="runcon" path="/usr/bin/strace" dev=dm-1 ino=662333 scontext=system_u:system_r:svirt_t:s0:c56,c78 tcontext=system_u:system_r:svirt_t:s0:c12,c34 tclass=process

One Response to “Testing answers to questions about sVirt SELinux policy”

  1. Excellent post Dan. Great live example of svirt.

    Request: When you sometime, do you mind writing about the 9pfs work you’re prototyping ?

Leave a Reply

Spam protection: Sum of tw0 plus f0ur ?: