Hide Forgot
Description of problem: sVirt now allows mprotect(..., PROT_EXEC) and mmap(..., PROT_EXEC, ..., -1, ...) (that is, executable anonymous memory). This allows a vulnerable qemu to be compromised by stuffing the stack with a call to mprotect(), making some guest-controlled memory executable, and then returning to that memory. Version-Release number of selected component (if applicable): libvirt-0.9.4-20.el6 How reproducible: always (if you're incredibly clever) Steps to Reproduce: 1. Find a vulnerability within qemu 2. Fill some guest memory with stage 2 exploit code 3. Exploit the vulnerability 4. Circumvent PIE/PIC and cause the qemu to return to mprotect(), marking your stage 2 exploit code executable 5. Return to stage 2 exploit code 6. Find another vulnerability in the kernel 7. Get your stage 2 exploit code to exploit this vulnerability 8. Responsible disclosure 9. Submit a paper to Black Hat Actual results: p0wned Expected results: segfault Additional info: Please also verify that no file mappings can be made executable, either at mmap() time or via mprotect(); especially for guest controlled files like images, or qcow2 snapshot files.
Avi, I don't claim to completely understand this issue, but it seems like there's anything that libvirt could do except for running qemu process with the right SELinux context, which libvirt already does. So IMHO this needs to be handled in SELinux policy. Am I right or did I miss anything?
Maybe it can be handled fully in the policy; I'm not familiar with it. But note at least one snag - if you run qemu without kvm, then qemu needs to be able to PROT_EXEC some memory for its translated code. So libvirt does need to make some differentiation between the two cases.
Hmm, this is getting complicated. Daniel, any idea how to solve this without the need to have two SELinux types, one that allows PROT_EXEC and one that denies it? Which would be quite a mess. Something like a per-process boolean (which I doubt it exists) would be great :-)
No the way to fix this is to have two different types. svirt_t and svirt_prot_exec_t or something like that. They can have the exact same policy except one gets prot_exec and the other does not. The only problem is how to we tell libvirt which to launch.
When I originally designed the policy we had planned on there being multiple types BTW, I had thought at one time we might want to design a type that had no network access or limited network ports. For example. But a lot of that responsibility can be better handled by iptables.
OK, so it seems it won't be such a big mess then :-) Libvirt will need to decide which of the contexts to use according to domain type qemu/kvm. Anyway, I'm cloning this BZ to selinux-policy so that an appropriate svirt_* type is created.
Avi, did you actually try to reproduce the reported issue? According to Daniel's comment https://bugzilla.redhat.com/show_bug.cgi?id=760473#c6 this seems to be already blocked by current policy for svirt_t.
And Fedora bug 785635 confirms that this is indeed blocked (at least in Fedora) since qemu doesn't work because of that. So it seems we should be fine in RHEL as long as we have that policy as we have no qemu. We may need the extra virt type for Fedora/upstream though.
(In reply to comment #12) > Avi, did you actually try to reproduce the reported issue? According to > Daniel's comment https://bugzilla.redhat.com/show_bug.cgi?id=760473#c6 this > seems to be already blocked by current policy for svirt_t. I did not, and agree we appear to be protected now.
Great, I think we can just close this bug then. More work still needs to be done, but that only affects upstream and it is already tracked by bug 785635.
WORKSFORME I think, but agreed.