Bug 478734

Summary: selinux blocks kvm network configuration script (e.g. /etc/qemu-ifup)
Product: [Community] Virtualization Tools Reporter: Pierre Ossman <pierre-bugzilla>
Component: libvirtAssignee: Daniel Veillard <veillard>
Status: CLOSED CURRENTRELEASE QA Contact:
Severity: medium Docs Contact:
Priority: low    
Version: unspecifiedCC: berrange, clalance, crobinso, dwmw2, markmc, mgrepl, veillard, virt-maint, xen-maint
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2010-07-12 17:25:09 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Pierre Ossman 2009-01-04 12:15:06 UTC
I upgraded from F8 to F10 and SELinux no longer plays nice with KVM. It is prevented from setting up a tun device and configuring it.

I get the following in dmesg:

type=1400 audit(1230302457.484:33): avc:  denied  { net_admin } for  pid=7459 comm="qemu-kvm" capability=12 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=unconfined_u:system_r:qemu_t:s0 tclass=capability
type=1400 audit(1230302457.601:34): avc:  denied  { execute } for  pid=7480 comm="qemu-kvm" name="qemu-ifup" dev=dm-0 ino=1311793 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:etc_t:s0 tclass=file
type=1400 audit(1230302457.601:35): avc:  denied  { execute_no_trans } for  pid=7480 comm="qemu-kvm" path="/etc/qemu-ifup" dev=dm-0 ino=1311793 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:etc_t:s0 tclass=file
type=1400 audit(1230302457.602:36): avc:  denied  { execute } for  pid=7480 comm="qemu-kvm" name="bash" dev=dm-0 ino=1245277 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:shell_exec_t:s0 tclass=file
type=1400 audit(1230302457.602:37): avc:  denied  { read } for  pid=7480 comm="qemu-kvm" name="bash" dev=dm-0 ino=1245277 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:shell_exec_t:s0 tclass=file
type=1400 audit(1230302457.608:38): avc:  denied  { getattr } for  pid=7482 comm="qemu-ifup" path="/bin/grep" dev=dm-0 ino=1245191 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file
type=1400 audit(1230302457.608:39): avc:  denied  { execute } for  pid=7482 comm="qemu-ifup" name="grep" dev=dm-0 ino=1245191 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file
type=1400 audit(1230302457.608:40): avc:  denied  { read } for  pid=7482 comm="qemu-ifup" name="grep" dev=dm-0 ino=1245191 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file
type=1400 audit(1230302457.609:41): avc:  denied  { execute_no_trans } for  pid=7482 comm="qemu-ifup" path="/bin/grep" dev=dm-0 ino=1245191 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=file
type=1400 audit(1230302457.637:42): avc:  denied  { getattr } for  pid=7480 comm="qemu-ifup" path="/sbin/ifconfig" dev=dm-0 ino=884801 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.636:5): avc:  denied  { execute } for  pid=6484 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.637:6): avc:  denied  { read } for  pid=6484 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.637:7): avc:  denied  { execute } for  pid=6484 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.638:8): avc:  denied  { read } for  pid=6484 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.638:9): avc:  denied  { execute } for  pid=6499 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.640:10): avc:  denied  { execute } for  pid=6499 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.640:11): avc:  denied  { read } for  pid=6499 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.715:12): avc:  denied  { execute } for  pid=6511 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230302990.715:13): avc:  denied  { read } for  pid=6511 comm="qemu-ifup" name="ifconfig" dev=dm-0 ino=884801 scontext=system_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230303496.435:11): avc:  denied  { execute_no_trans } for  pid=6912 comm="qemu-ifup" path="/sbin/ifconfig" dev=dm-0 ino=884801 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:ifconfig_exec_t:s0 tclass=file
type=1400 audit(1230303496.438:12): avc:  denied  { read } for  pid=6912 comm="ifconfig" name="net" dev=proc ino=4026531869 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:proc_net_t:s0 tclass=lnk_file
type=1400 audit(1230303496.438:13): avc:  denied  { read } for  pid=6912 comm="ifconfig" name="unix" dev=proc ino=4026531984 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:proc_net_t:s0 tclass=file
type=1400 audit(1230303496.438:14): avc:  denied  { create } for  pid=6912 comm="ifconfig" scontext=unconfined_u:system_r:qemu_t:s0 tcontext=unconfined_u:system_r:qemu_t:s0 tclass=unix_dgram_socket
type=1400 audit(1230303496.439:15): avc:  denied  { search } for  pid=6912 comm="ifconfig" scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:sysctl_net_t:s0 tclass=dir
type=1400 audit(1230303496.503:16): avc:  denied  { getattr } for  pid=6898 comm="qemu-kvm" path="/dev/mapper/system-fiat" dev=tmpfs ino=590 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:fixed_disk_device_t:s0 tclass=blk_file
type=1400 audit(1230303496.503:17): avc:  denied  { read write } for  pid=6898 comm="qemu-kvm" name="system-fiat" dev=tmpfs ino=590 scontext=unconfined_u:system_r:qemu_t:s0 tcontext=system_u:object_r:fixed_disk_device_t:s0 tclass=blk_file

This translates to the following rules:

module local 1.0;

require {
        type proc_net_t;
        type ifconfig_exec_t;
        type etc_t;
        type qemu_t;
        type port_t;
        type bin_t;
        type fixed_disk_device_t;
        type shell_exec_t;
        type sysctl_net_t;
        class lnk_file read;
        class capability net_admin;
        class file { getattr read execute execute_no_trans };
        class blk_file { read write getattr };
        class unix_dgram_socket create;
        class dir search;
}

#============= qemu_t ==============
allow qemu_t bin_t:file { read getattr execute execute_no_trans };
allow qemu_t etc_t:file { execute execute_no_trans };
allow qemu_t fixed_disk_device_t:blk_file { read write getattr };
allow qemu_t ifconfig_exec_t:file { read getattr execute execute_no_trans };
allow qemu_t proc_net_t:file read;
allow qemu_t proc_net_t:lnk_file read;
allow qemu_t self:capability net_admin;
allow qemu_t self:unix_dgram_socket create;
allow qemu_t shell_exec_t:file { read execute };
allow qemu_t sysctl_net_t:dir search;


Also, previously KVM hardcoded the script "/etc/qemu-ifup" to set up the network. This path now has to be explicitly configured. This might mean it need some special SELinux context.

Comment 2 Daniel Walsh 2009-01-13 15:51:05 UTC
/dev/mapper/system-fiat needs to be labeled virt_image_t

# semanage fcontext -a -t virt_image_t /dev/mapper/system-fiat
# restorecon /dev/mapper/system-fiat

Should fix this.

Daniel, this is what I was talking about using the qemu both for setup and the actual running of the qemu leads to excessive privs required for qemu.

Comment 3 Daniel Walsh 2009-01-13 16:07:09 UTC
If we ever hope to confine what a qemu process is doing, we need to separate out the setup from the running of the guest OS.  So we need to processes run.

libvirt_t->qemu_setup_t->qemu_t

Running one process that sets up the guest os and then running the guest os, will force us to allow the guest os process the ability to manipulate the hosts networking.  So if someone breaks out of the guest os, he will be able to change the network on the host machine.

Comment 4 Daniel Berrangé 2009-01-13 16:33:43 UTC
Ahhhh, I understand what you mean now. So 'qemu' would start with 'qemu_setup_t' domain, and then 'drop privileges' by transitioning to the 'qemu_t'.

The hard thing here is that you can hot-plug lots of virtual hardware, adding/removing NICs and Disks on the fly. Many deployment scenarios won't care about hotplug though, so we could certainly restrict them.

NB for networking the normal case libvirtd will do the networking setup, passing QEMU a pre-opened & configured TAP device FD. Running shell scripts for setting up networking is only for when QEMU is launched outside context of libvirt.

Comment 5 Pierre Ossman 2009-01-13 18:25:50 UTC
(In reply to comment #2)
> /dev/mapper/system-fiat needs to be labeled virt_image_t
> 
> # semanage fcontext -a -t virt_image_t /dev/mapper/system-fiat
> # restorecon /dev/mapper/system-fiat
> 
> Should fix this.

I'll give that a try. Oddly enough though, there were three other guests started after this with the same context for the storage, yet only this first one generated avc messages. Is there some filtering going on in the audit output?

(In reply to comment #4)
> NB for networking the normal case libvirtd will do the networking setup,
> passing QEMU a pre-opened & configured TAP device FD. Running shell scripts for
> setting up networking is only for when QEMU is launched outside context of
> libvirt.

No, not only. In my case I use libvirt and a <script/> addition in the <interface/>. I do this to get a routed guest, something that libvirt isn't supporting directly.

Comment 6 David Woodhouse 2009-01-14 21:45:13 UTC
There's a lot to be said for having qemu/kvm/etc networking set up in _advance_ by the standard network scripts, using persistent tun devices. Then all qemu would have to do would be to open it and send packets; no actual configuration (even in libvirtd).

Comment 7 Pierre Ossman 2009-03-29 09:55:01 UTC
Any news here?

Comment 8 Mark McLoughlin 2009-03-30 09:42:16 UTC
dwalsh: the problem here appears to be the use of a script to configure the tap interface e.g.

    <interface type='ethernet'>
       <target dev='vnet7'/>
       <script path='/etc/qemu-ifup-mynet'/>
    </interface>

pierre: could you attach your domain's XML configuration and the network script?

Comment 9 Daniel Berrangé 2009-03-30 09:53:42 UTC
IMHO, it is simply not practical to support SELinux enforcing mode when using type='ethernet'. The config will be executing arbitrary shell scripts and as such we have no way of knowing what the user will want to be able todo in these scripts. In addition allowing the running of arbitrary network commands from these scripts will compromise the security of all other QEMU configs, by allowing QEMU to execute ifcfg / ip commands that it should not ordinarily be allowed todo. 

The most practical option here is to determine how to support the desired network config directly in libvirtd, avoiding the need to run a guest with type='ethernet' config, and avoiding need for QEMU to be given ability to run arbitrary networking commands.

Comment 10 Mark McLoughlin 2009-03-30 10:08:20 UTC
Fair enough - moving to upstream libvirt

pierre: given danpb's comment, we need information on your configuration so that we can try and support this in libvirt without the need for a qemu-ifup script

Comment 11 Pierre Ossman 2009-03-30 11:26:30 UTC
My desires are fairly simple. I want my machines to be routed via the host, not bridged or any libvirt specific magic.

My script is nothing special, only that it computes the IP configuration based on the if name (to keep things simple). It is acceptable to have to enter the host side configuration for each guest in a generic solution though.

Example of one network configuration:

    <interface type='ethernet'>
      <mac address='00:16:3e:00:00:02'/>
      <script path='/etc/libvirt/qemu/ifup'/>
      <target dev='virt11'/>
      <model type='virtio'/>
    </interface>

The "ifup" script:

#!/bin/bash

if ! echo $1 | grep "^virt[0-9]\+$" > /dev/null; then
        exit
fi

NUM=`echo $1 | sed 's%virt\([0-9]\+\)%\1%'`

IPADDR=10.8.3.$[ $NUM * 8 + 1 ]
NETMASK=255.255.255.248

ifconfig $1 $IPADDR netmask $NETMASK

Comment 12 Pierre Ossman 2009-10-07 08:32:27 UTC
Has anyone had a chance to look at this?

Comment 13 Daniel Berrangé 2009-11-13 11:08:52 UTC
It is now worse than before - QEMU now runs unprivileged, so network scripts have non of the capabilities required to configure networking

http://www.redhat.com/archives/libvir-list/2009-November/msg00336.html

Comment 14 Pierre Ossman 2009-11-13 19:08:51 UTC
Well thanks for that. Is anyone working on a solution that will support routed guests?

Comment 15 Pierre Ossman 2009-12-01 07:59:40 UTC
Ping! Any comments? You can't really go and remove a common use case like that without providing any alternatives.

Comment 16 Daniel Berrangé 2010-07-12 17:25:09 UTC
In 0.8.2, /etc/libvirt/qemu.conf allows you to run with VMs with full capabilities

 clear_emulator_capabilities = 0
 user = "root"
 group = "root"

This is of course horribly insecure, but that's only option for direct use of qemu's ifup scripts.