Bug 732417

Summary: SELinux doesn't allow libvirtd to relabel TCP sockets
Product: Red Hat Enterprise Linux 6 Reporter: Jiri Denemark <jdenemar>
Component: selinux-policyAssignee: Miroslav Grepl <mgrepl>
Status: CLOSED NOTABUG QA Contact: BaseOS QE Security Team <qe-baseos-security>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 6.1CC: dallan, dwalsh, dyuan, eparis, gsun, mmalik, mzhan, pmoore, rwu, sdsmall, veillard, whuang
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2011-08-26 08:25:16 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:
Bug Depends On:    
Bug Blocks: 731243    

Description Jiri Denemark 2011-08-22 12:01:30 UTC
Description of problem:

Recently we added support for fd: protocol migration to libvirt, which means we create a TCP socket, connect it to destination qemu, and pass it using SCM_RIGHTS to source qemu (previously source qemu was opening the socket itself). To be able to send the socket to qemu, we need to label it but we are not allowed to. The attempt results in

type=AVC msg=audit(1314013212.316:93716): avc:  denied  { relabelto } for pid=19499 comm="libvirtd" name="" dev=sockfs ino=636054 scontext=unconfined_u:system_r:virtd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:svirt_image_t:s0:c54,c853 tclass=tcp_socket

type=SYSCALL msg=audit(1314013212.316:93716): arch=c000003e syscall=190 success=no exit=-13 a0=16 a1=3ea2216239 a2=7f64441a43f0 a3=2c items=0 ppid=1 pid=19499 auid=500 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="libvirtd" exe="/usr/sbin/libvirtd" subj=unconfined_u:system_r:virtd_t:s0-s0:c0.c1023 key=(null)

Version-Release number of selected component (if applicable):

selinux-policy-3.7.19-107.el6.noarch
libvirt-0.9.4-?.el6

The patch that does correct labeling of the socket is not in libvirt yet (see bug 731243). As soon as it's there, I'll update this BZ with the right libvirt release to test with.

How reproducible:

100%

Steps to Reproduce:
1. create a domain
2. try to migrate it using non-peer2peer migration
   # virsh migrate DOM qemu+ssh://target/system
  
Actual results:

error: unable to set security context 'system_u:object_r:svirt_image_t:s0:c54,c853' on fd 22: Permission denied

Expected results:

Successfully labeled socket so that migration can proceed.

Additional info:

Comment 1 Miroslav Grepl 2011-08-23 07:30:34 UTC
We allow this for

Comment 2 Miroslav Grepl 2011-08-23 07:31:20 UTC
(In reply to comment #1)
> We allow this for

I apologize. Bad window.

Comment 3 Jiri Denemark 2011-08-23 12:11:01 UTC
The following AVCs were reported when I tried running migration with selinux in permissive mode:

type=AVC msg=audit(1314098069.651:94776): avc:  denied  { relabelto } for  pid=19499 comm="libvirtd" name="" dev=sockfs ino=678882 scontext=unconfined_u:system_r:virtd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:svirt_image_t:s0:c54,c853 tclass=tcp_socket
type=AVC msg=audit(1314098069.653:94777): avc:  denied  { read write } for  pid=10369 comm="qemu-kvm" path="socket:[678882]" dev=sockfs ino=678882 scontext=system_u:system_r:svirt_t:s0:c54,c853 tcontext=system_u:object_r:svirt_image_t:s0:c54,c853 tclass=tcp_socket
type=AVC msg=audit(1314098069.755:94778): avc:  denied  { write } for  pid=10369 comm="qemu-kvm" path="socket:[678882]" dev=sockfs ino=678882 scontext=system_u:system_r:svirt_t:s0:c54,c853 tcontext=system_u:object_r:svirt_image_t:s0:c54,c853 tclass=tcp_socket

Comment 4 Miroslav Grepl 2011-08-23 13:34:42 UTC
And does it work with rules from these AVC msgs in enforcing mode?

allow svirt_t svirt_image_t:tcp_socket { read write }
allow virtd_t virt_image_type:tcp_socket relabel_file_perms;

Comment 5 Dave Allan 2011-08-23 20:09:32 UTC
Running audit2allow on my system produced the following local.te which made the problem go away.  (Disclaimer, my use of selinux is pretty mechanical.)

module local 1.0;

require {
	type virtd_t;
	type svirt_t;
	class fifo_file write;
}

#============= svirt_t ==============
allow svirt_t virtd_t:fifo_file write;

Comment 6 Dave Allan 2011-08-23 20:16:39 UTC
2d disclaimer: this is an F15 system with upstream libvirt, not RHEL.

Comment 7 Daniel Walsh 2011-08-24 02:48:42 UTC
This is the wrong label it should not be setting virt tcp_socket to svirt_image_t?

Sockets should be labeled svirt_t not svirt_image_t.

Similarly the virtd_t should have been relabeled svirt_t.

Comment 8 Jiri Denemark 2011-08-25 16:36:06 UTC
OK, I changed the code to label TCP sockets as svirt_t but still some tweak to selinux-policy is needed:

avc:  denied  { associate } for  pid=5616 comm="libvirtd" name="" dev=sockfs ino=932613 scontext=system_u:system_r:svirt_t:s0:c355,c490 tcontext=system_u:object_r:fs_t:s0 tclass=filesystem

which run through audit2allow suggests the following policy:

module tcp_socket 1.0;

require {
        type fs_t;
        type svirt_t;
        class filesystem associate;
}

#============= svirt_t ==============
allow svirt_t fs_t:filesystem associate;


With this policy in, I get no AVCs even in enforcing mode.

Comment 9 Daniel Walsh 2011-08-25 17:24:00 UTC
Stephen and Eric is this a bug?  

fd = socket(TCP),  connect(fd, SOMEREMOTEHOST).     setffilecon($fd, "svirt_t:MCS") 

Shouldn't this be allowed. Without having to allow process types to be assigned to filesystems?  Looks like a pseudo file system is causing the problem?

Comment 10 Eric Paris 2011-08-25 17:28:25 UTC
It is a pseudo filesystem, sockfs, which you chose to call fs_t:

fs_use_task sockfs system_u:object_r:fs_t:s0;

Everything is on a filesystem   :)

It's no different than creating a file on ext3.  You need associate permissions...

Comment 11 Daniel Walsh 2011-08-25 18:40:28 UTC
Well I don't want to do that. I am testing out doing it another way where I label the sockfs file system as sockfs_t and then allow domain sockfs_t:filesystem associate;

Testing it in F17 now.

Comment 12 Paul Moore 2011-08-25 18:55:14 UTC
You can't change the label of a connected TCP socket as there are several access control points involved in establishing a connection and changing the label on the socket changes the label on the connection which could cause an already established connection to fail.

In addition, changing the label on an established connection could cause unknown problems with the other end of the connection if labeled networking is in use.

The correct solution would be to set the correct label on socket using setsockcreatecon() before the connection is established.

Comment 13 Jiri Denemark 2011-08-25 19:20:20 UTC
(In reply to comment #12)
> You can't change the label of a connected TCP socket as there are several
> access control points involved in establishing a connection and changing the
> label on the socket changes the label on the connection which could cause an
> already established connection to fail.

OK, this is a very convincing explanation, I'll go the setsockcreatecon() way and see if that works as expected. If so, I'll close this BZ as NOTABUG.

Comment 14 Jiri Denemark 2011-08-26 08:25:16 UTC
Great, when setsockcreatecon() is used for labeling the TCP socket, everything works without any change to selinux-policy. I'm closing this BZ...