Bug 999926
Summary: | Policy denies libvirtd the permission to relabel unix domain sockets | |||
---|---|---|---|---|
Product: | Red Hat Enterprise Linux 7 | Reporter: | Daniel Berrangé <berrange> | |
Component: | libvirt | Assignee: | Ján Tomko <jtomko> | |
Status: | CLOSED ERRATA | QA Contact: | Virtualization Bugs <virt-bugs> | |
Severity: | unspecified | Docs Contact: | ||
Priority: | unspecified | |||
Version: | 7.0 | CC: | berrange, dwalsh, dyuan, eparis, jtomko, mgrepl, mmalik, mzhan, pmoore, rbalakri, sdsmall, vivianzhang, ydu, zhwang | |
Target Milestone: | rc | |||
Target Release: | --- | |||
Hardware: | All | |||
OS: | Linux | |||
Whiteboard: | ||||
Fixed In Version: | libvirt-1.2.8-1.el7 | Doc Type: | Bug Fix | |
Doc Text: | Story Points: | --- | ||
Clone Of: | 999922 | |||
: | 1141228 (view as bug list) | Environment: | ||
Last Closed: | 2015-03-05 07:24:34 UTC | Type: | Bug | |
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: | 999291, 999925, 1141228 |
Description
Daniel Berrangé
2013-08-22 11:28:25 UTC
Fixed in selinux-policy-3.12.1-73 Yes, has been added. Should be a part of the latest build. When testing bug 999925(comment 5), i can still get AVC deny: type=AVC msg=audit(1378113990.127:30518): avc: denied { relabelto } for pid=25210 comm="libvirtd" name="UNIX" dev="sockfs" ino=496106 scontext=system_u:system_r:virtd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:svirt_image_t:s0:c43,c631 tclass=unix_stream_socket # rpm -q selinux-policy selinux-policy-3.12.1-73.el7.noarch Added additional fix. I think the problem here is libvirt is relabeling the unix_stream_socket to a file label rather then a process label. It should be labeling it svirt_t:s0:c43,c631 I believe. Hi, I'm testing bug 999925 with latest selinux-policy, but get many selinux deny and virt-viewer can not connect the the qemu guest. Can you please help to confirm this problem, thanks! # rpm -q selinux-policy selinux-policy-3.12.1-95.el7.noarch # virt-viewer -c qemu:///session --debug --attach virt-tests-vm ... audit.log: type=AVC msg=audit(1384245413.908:8554): avc: denied { setopt } for pid=27469 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c111,c220 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=SYSCALL msg=audit(1384245413.908:8554): arch=c000003e syscall=54 success=no exit=-13 a0=1e a1=6 a2=1 a3=7fffb213047c items=0 ppid=1 pid=27469 auid=4294967295 uid=107 gid=107 euid=107 suid=107 fsuid=107 egid=107 sgid=107 fsgid=107 tty=(none) ses=4294967295 comm="qemu-kvm" exe="/usr/libexec/qemu-kvm" subj=system_u:system_r:svirt_t:s0:c111,c220 key=(null) type=AVC msg=audit(1384245413.908:8555): avc: denied { getattr } for pid=27469 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c111,c220 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=SYSCALL msg=audit(1384245413.908:8555): arch=c000003e syscall=51 success=no exit=-13 a0=1e a1=7f5363c647a0 a2=7f5363c647c0 a3=0 items=0 ppid=1 pid=27469 auid=4294967295 uid=107 gid=107 euid=107 suid=107 fsuid=107 egid=107 sgid=107 fsgid=107 tty=(none) ses=4294967295 comm="qemu-kvm" exe="/usr/libexec/qemu-kvm" subj=system_u:system_r:svirt_t:s0:c111,c220 key=(null) type=AVC msg=audit(1384245413.908:8556): avc: denied { getattr } for pid=27469 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c111,c220 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=SYSCALL msg=audit(1384245413.908:8556): arch=c000003e syscall=52 success=no exit=-13 a0=1e a1=7f5363c647b0 a2=7f5363c647c4 a3=0 items=0 ppid=1 pid=27469 auid=4294967295 uid=107 gid=107 euid=107 suid=107 fsuid=107 egid=107 sgid=107 fsgid=107 tty=(none) ses=4294967295 comm="qemu-kvm" exe="/usr/libexec/qemu-kvm" subj=system_u:system_r:svirt_t:s0:c111,c220 key=(null) type=AVC msg=audit(1384245413.908:8557): avc: denied { getattr } for pid=27469 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c111,c220 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=SYSCALL msg=audit(1384245413.908:8557): arch=c000003e syscall=51 success=no exit=-13 a0=1e a1=7f5363c647c8 a2=7f5363c648c8 a3=0 items=0 ppid=1 pid=27469 auid=4294967295 uid=107 gid=107 euid=107 suid=107 fsuid=107 egid=107 sgid=107 fsgid=107 tty=(none) ses=4294967295 comm="qemu-kvm" exe="/usr/libexec/qemu-kvm" subj=system_u:system_r:svirt_t:s0:c111,c220 key=(null) type=AVC msg=audit(1384245413.908:8558): avc: denied { getattr } for pid=27469 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c111,c220 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=SYSCALL msg=audit(1384245413.908:8558): arch=c000003e syscall=52 success=no exit=-13 a0=1e a1=7f5363c64848 a2=7f5363c648cc a3=0 items=0 ppid=1 pid=27469 auid=4294967295 uid=107 gid=107 euid=107 suid=107 fsuid=107 egid=107 sgid=107 fsgid=107 tty=(none) ses=4294967295 comm="qemu-kvm" exe="/usr/libexec/qemu-kvm" subj=system_u:system_r:svirt_t:s0:c111,c220 key=(null) These AVC's indicate that svirt_t needs to talk to the unconfined_t stream socket. allow svirt_t unconfined_t:unix_stream_socket { getattr setopt }; Which is the remote end of virt-viewer. Dan B, does this make sense to you? (In reply to Daniel Walsh from comment #9) > These AVC's indicate that svirt_t needs to talk to the unconfined_t stream > socket. > > allow svirt_t unconfined_t:unix_stream_socket { getattr setopt }; > > > Which is the remote end of virt-viewer. > > Dan B, does this make sense to you? No, libvirt was supposed to be relabelling the socket, so that it was not unconfined_t. Ok so this is still a bug with libvirtd. For privileged libvirtd, we seem to be relabeling the socket: info : virSecuritySELinuxFSetFilecon:952 : Setting SELinux context on fd 25 to 'system_u:object_r:svirt_image_t:s0:c427,c497' But I'm getting AVCs like in comment 8. Perhaps we need to use a different type allowing getpeername and {g,s}etsockopt? (svirt_t suggested in comment 6 is rejected 'since it is not a valid file type') For session libvirtd (running as unconfined_t, not virtd_t), the relabeling fails: Raw Audit Messages type=AVC msg=audit(1386841203.408:2139): avc: denied { relabelto } for pid=17490 comm="libvirtd" name="UNIX" dev="sockfs" ino=561969 scontext=unconfined_u:system_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:svirt_image_t:s0:c168,c1021 tclass=unix_stream_socket type=SYSCALL msg=audit(1386841203.408:2139): arch=x86_64 syscall=fsetxattr success=no exit=EACCES a0=15 a1=7fc7895fab5e a2=7fc7741c5090 a3=32 items=0 ppid=1 pid=17490 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=(none) ses=183 comm=libvirtd exe=/usr/sbin/libvirtd subj=unconfined_u:system_r:unconfined_t:s0-s0:c0.c1023 key=(null) Hash: libvirtd,unconfined_t,svirt_image_t,unix_stream_socket,relabelto The problem here is that we have a socket labeled with a file type not a process type. I think libvirt should be changing the label to svirt_t, rather then svirt_image_t. Then unconfined_t would be allowed to relabel it. sesearch -A -s unconfined_t -t svirt_t -c unix_stream_socket Found 1 semantic av rules: allow unconfined_domain_type domain : unix_stream_socket { ioctl read write create getattr setattr lock relabelfrom relabelto append bind connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg name_bind connectto newconn acceptfrom } ; fsetfilecon_raw gives me EACCESS when I try to label it as svirt_t: error : virSecuritySELinuxFSetFilecon:975 : unable to set security context 'system_u:system_r:svirt_t:s0:c563,c804' on fd 32: Permission denied sealert: SELinux is preventing /usr/sbin/libvirtd from associate access on the filesystem UNIX. ***** Plugin associate (99.5 confidence) suggests ************************* If you want to change the label of UNIX to svirt_t, you are not allowed to since it is not a valid file type. Then you must pick a valid file label. Do select a valid file type. List valid file labels by executing: # seinfo -afile_type -x ***** Plugin catchall (1.49 confidence) suggests ************************** If you believe that libvirtd should be allowed associate access on the UNIX filesystem by default. Then you should report this as a bug. You can generate a local policy module to allow this access. Do allow this access for now by executing: # grep libvirtd /var/log/audit/audit.log | audit2allow -M mypol # semodule -i mypol.pp Additional Information: Source Context system_u:system_r:svirt_t:s0:c563,c804 Target Context system_u:object_r:fs_t:s0 Target Objects UNIX [ filesystem ] Source libvirtd Source Path /usr/sbin/libvirtd Port <Unknown> Host masina Source RPM Packages libvirt-daemon-1.1.1-14.el7jtomko.x86_64 Target RPM Packages Policy RPM selinux-policy-3.12.1-108.el7.noarch Selinux Enabled True Policy Type targeted Enforcing Mode Enforcing Host Name masina Platform Linux masina 3.10.0-60.el7.x86_64 #1 SMP Fri Dec 6 09:54:57 EST 2013 x86_64 x86_64 Alert Count 5 First Seen 2013-12-18 12:06:07 CET Last Seen 2013-12-18 12:21:22 CET Local ID 4cc70231-ce79-4095-b508-f282e912983d Raw Audit Messages type=AVC msg=audit(1387365682.727:3294): avc: denied { associate } for pid=11657 comm="libvirtd" name="UNIX" dev="sockfs" ino=22452 scontext=system_u:system_r:svirt_t:s0:c563,c804 tcontext=system_u:object_r:fs_t:s0 tclass=filesystem type=SYSCALL msg=audit(1387365682.727:3294): arch=x86_64 syscall=fsetxattr success=no exit=EACCES a0=20 a1=7fb6fe6cdb5e a2=7fb6b800659 a3=27 items=0 ppid=1 pid=11657 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 commlibvirtd exe=/usr/sbin/libvirtd subj=system_u:system_r:virtd_t:s0-s0:c0.c1023 key=(null) Hash: libvirtd,svirt_t,fs_t,filesystem,associate If you are labeling a file, sock_file, fifo_file it should be svirt_image_t, if you are labeling a process socket or fd it should be svirt_t. Is it possible to relabel an existing process socket given its fd? 'fsetfilecon_raw' fails with svirt_t (comment 14). We use 'setsockcreatecon_raw' in other places in libvirt, but it only affects newly created sockets. I haven't found any other relevant selinux call. Labelling the socket as 'svirt_image_t' gets it past SCM_RIGHTS, but calling getsockname (for VNC. With SPICE, setsockopt is the first failed call) fails saying it's unconfined (comment 8), even though calling fgetxattr via gdb right before it fails says it's "system_u:object_r:svirt_image_t:s0:c74,c99". Can't yo ucall setsockcreatecon_raw before the socket gets created? No, as the socket is created by virt-viewer - the virDomainOpenGraphics API requires a file descriptor of a socket opened by socketpair as an argument: http://libvirt.org/html/libvirt-libvirt.html#virDomainOpenGraphics If the file label being taken into account when passing the fd, but not for getsockname/setsockopt is expected SELinux behavior, I don't see other way to make this API work with SELinux than allow getattr, setopt for qemu as proposed in comment 9. Can we possibly do that? If not, libvirt should at least print an error instead of passing the fd and letting qemu fail. Yes, we really do need to be able to re-label the existing socket based on FD. Libvirt isn't in control of the creation of the socket so setsockcreatecon is useless here. Do you have to use socketpair() to create the sockets? Could you create the sockets individually, using setsockcreatecon() as needed, and then connect the two sockets before passing one of the sockets to libvirt? We do all the labeling in libvirt. If we wanted to label it in virt-viewer (and other apps using virDomainOpenGraphics), it would have to learn what label libvirt generated and have the permission to change the socket label to that. Pushing this out to applications like virt-viewer isn't really an option. The entire goal of sVirt is that applications do not need to know about Libvirt's use of SELinux - libvirt just "does the right thing" to make it work for them. The issue is that you really can't relabel a socket once it has been created, especially if that socket is a connected stream socket. If you need that socket to be labeled a certain way you need to make sure it is labeled correctly at the time of creation. If labeling the socket is out of the question in virt-viewer, I think the only option is to adjust the SELinux policy for libvirt. Regrettable, but I can't think of any other option off the top of my head at this moment. Also, as an aside, using fsetfilecon() on a socket probably isn't the best idea. It's disallowed in every domain except for unconfined_t and we probably should restrict that as well as it can be confusing for the reasons we are seeing here. If we allow a svirt_t to use a unconfined_t unix_stream_socket, what is the risk? Somehow a unconfined_t:unix_stream_socket was leaked or given to the svirt_t process. Either through transition or in this case passing the argument? Correct? There is no way for the svirt_t to got into /proc and get a hold of this socket. (In reply to Daniel Walsh from comment #24) > If we allow a svirt_t to use a unconfined_t unix_stream_socket, what is the > risk? I don't like this either, it seems dangerous to me, but if the libvirt folks are unwilling to label the socket in the client when it is created, it would appear to be the only option. > Somehow a unconfined_t:unix_stream_socket was leaked or given to the svirt_t > process. Either through transition or in this case passing the argument? > Correct? There is no way for the svirt_t to got into /proc and get a hold > of this socket. My understanding based on the spec posted in comment #18 is that the UNIX socket is passed to the daemon/svirt_t from the client/unconfined_t. Would it be possible to change the libvirt API, or introduce a new API, that would allow the client to request a fd/socket from the daemon? (In reply to Paul Moore from comment #25) > > Somehow a unconfined_t:unix_stream_socket was leaked or given to the svirt_t > > process. Either through transition or in this case passing the argument? > > Correct? There is no way for the svirt_t to got into /proc and get a hold > > of this socket. > > My understanding based on the spec posted in comment #18 is that the UNIX > socket is passed to the daemon/svirt_t from the client/unconfined_t. Perhaps instead of having the client app running unconfined_t, a better solution would be to create a new 'virt_viewer_t' domain for virt-viewer to run under. Then presumably the socket would be virt_viewer_t instead of unconfined_t too, and thus the policy wouldn't have to blanket allow unconfined_t I'm not sure why we can't just allow the original requested permissions, without any relabeling involved. Allowing a domain to use a socket created by unconfined_t just means that it can use that socket if it is passed one. Just don't allow it create or relabelfrom/relabelto. /proc/pid/fd should be restricted via ptrace checks. I guess one possible concern would be that if a unconfined process passes a socket that is not connected yet or a dgram socket to a confined process and the confined process can send/connect with that socket to a different peer, then getpeercon() will make that peer think it is talking to the unconfined process. Stephen I am also worried about unconfined_t leaking into svirt_t, since unconfined_t users can run libvirt in userspace and transition to svirt_t. (In reply to Paul Moore from comment #26) > Would it be possible to change the libvirt API, or introduce a new API, that > would allow the client to request a fd/socket from the daemon? We could add an API 'virDomainCreateSocketPair' which would open a socket pair and send it back to the client, which would then pass it back to libvirtd in the virDomainOpenGraphics API call. A little strange to go back & forth like that though The second option would be to have a new virDomainOpenGraphics API which returned a socket pair to the client, rather than having the client pass on in. Since these options involve new APIs, we'd be looking at 7.1 for that. (In reply to Daniel Walsh from comment #30) > Stephen I am also worried about unconfined_t leaking into svirt_t, since > unconfined_t users can run libvirt in userspace and transition to svirt_t. Ok, then run virt-viewer in its own domain and only allow access to that domain's sockets. Do we need virDomainOpenGraphics to work badly enough to change virt-viewer's context/allow QEMU to access unconfined sockets? Per comment 23, I don't think there's any other option to fix this particular call. If we do, libvirt should possibly stop trying to label the socket as 'svirt_image_t'. If not, it should fail before passing the fd to QEMU and we'd need to wait for the new APIs (comment 31). A new API 'virDomainOpenGraphicsFD' which returns a fd of a cocket created by the daemon that should be properly labeled has been pushed upstream: http://libvirt.org/html/libvirt-libvirt.html#virDomainOpenGraphicsFD commit 3ddc85440eab66d2467c5046a600087763722e03 Author: Ján Tomko <jtomko> CommitDate: 2014-08-26 18:55:30 +0200 Introduce virDomainOpenGraphicsFD API Define the public API implementation and declare internal driver prototype. commit 408aae3849418c391db0fabadd7ae92951db0183 Author: Ján Tomko <jtomko> CommitDate: 2014-08-26 19:26:28 +0200 Add RPC implementation for virDomainOpenGraphicsFd commit 27a20b6c1a78c43f9706989c7efe1d3acb853868 Author: Ján Tomko <jtomko> CommitDate: 2014-08-26 19:26:35 +0200 Wire up virDomainOpenGraphicsFD in QEMU driver Should fix https://bugzilla.redhat.com/show_bug.cgi?id=999926 commit b259e459b9d424fb9e176642e42c0a531fe3d7ee Author: Eric Blake <eblake> CommitDate: 2014-08-26 16:36:32 -0600 API: Tweak virDomainOpenGraphics to return fd directly Let's fix this before we bake in a painful API. Since we know that we have exactly one non-negative fd on success, we might as well return the fd directly instead of forcing the user to pass in a pointer. Furthermore, I found some memory and fd leaks while reviewing the code - the idea is that on success, libvirtd will have handed two fds in two different directions: one to qemu, and one to the RPC client. * include/libvirt/libvirt.h.in (virDomainOpenGraphicsFD): Drop unneeded parameter. * src/driver.h (virDrvDomainOpenGraphicsFD): Likewise. * src/libvirt.c (virDomainOpenGraphicsFD): Adjust interface to return fd directly. * daemon/remote.c (remoteDispatchDomainOpenGraphicsFd): Adjust semantics. * src/qemu/qemu_driver.c (qemuDomainOpenGraphicsFD): Likewise, and plug fd leak. * src/remote/remote_driver.c (remoteDomainOpenGraphicsFD): Likewise, and plug memory and fd leak. Signed-off-by: Eric Blake <eblake> git describe: v1.2.7-240-gb259e45 contains: v1.2.8-rc1~6 Still got the issue with build: libvirt-1.2.8-1.el7.x86_64 selinux-policy-3.13.1-1.el7.noarch selinux-policy-targeted-3.13.1-1.el7.noarch steps: # virt-viewer -c qemu:///session --debug --attach guest ... audit.log: type=AVC msg=audit(1410243904.460:610): avc: denied { getattr } for pid=10088 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c218,c665 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=AVC msg=audit(1410244024.072:611): avc: denied { getattr } for pid=10088 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c218,c665 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=AVC msg=audit(1410244834.970:640): avc: denied { getattr } for pid=10088 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c218,c665 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=AVC msg=audit(1410244996.622:642): avc: denied { getattr } for pid=10088 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c218,c665 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket type=AVC msg=audit(1410245191.007:643): avc: denied { getattr } for pid=10088 comm="qemu-kvm" scontext=system_u:system_r:svirt_t:s0:c218,c665 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=unix_stream_socket Could you help to check or confirm above? If above is not right, could you provide additional verify steps for this issue? The old API could not have been fixed, so new API was introduced. A client using the new API is required for this to work. Using virt-viewer with the patch from bug 1141228 is probably the easiest way to verify this. *** Bug 999925 has been marked as a duplicate of this bug. *** I re-test this issue with build libvirt-1.2.8-2.el7.x86_64 + x86_64 scratch build of virt-viewer-0.6.0-4.el7 + the patch (https://www.redhat.com/archives/virt-tools-list/2014-September/msg00096.html) steps: # virt-viewer -c qemu:///session --debug --attach guest ... check audit.log: cat /var/log/audit/audit.log | grep -i AVC There is not AVC info in audit.log, so this issue does not occur on above build. I can produce this issue with build libvirt-1.2.8-10.el7.x86_64 + virt-viewer-0.6.0-12.el7.x86_64 verify it on build libvirt-1.2.8-10.el7.x86_64 + virt-viewer-0.6.0-12.el7.x86_64 + patch (https://www.redhat.com/archives/virt-tools-list/2014-September/msg00096.html) verify steps: # virt-viewer -c qemu:///session --debug --attach rhel7 ... check audit.log # cat /var/log/audit/audit.log | grep -i AVC no AVC info shown in audit.log, so move to verified Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://rhn.redhat.com/errata/RHSA-2015-0323.html |