Bug 1386233
| Summary: | haproxy requires fowner capability when non-root user is used for a socket file | ||
|---|---|---|---|
| Product: | Red Hat Enterprise Linux 7 | Reporter: | Zdenek Pytela <zpytela> |
| Component: | selinux-policy | Assignee: | Lukas Vrabec <lvrabec> |
| Status: | CLOSED ERRATA | QA Contact: | Milos Malik <mmalik> |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | 7.4 | CC: | bperkins, dborek, lvrabec, mgrepl, mmalik, nils, plautrba, pvrabec, ssekidde, tbowling |
| Target Milestone: | rc | ||
| Target Release: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | selinux-policy-3.13.1-133.el7 | Doc Type: | If docs needed, set a value |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2017-08-01 15:15:11 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: | 1420851 | ||
This strace output shows what haproxy is up to when it fails:
464 00:52:09.832823 chown("/var/run/haproxy.sock.464.tmp", 188, 4294967295) = 0 <0.000081>
464 00:52:09.833261 chmod("/var/run/haproxy.sock.464.tmp", 0755) = -1 EPERM (Operation not permitted) <0.000466> <----- here
464 00:52:09.833829 unlink("/var/run/haproxy.sock.464.tmp") = 0 <0.000041>
464 00:52:09.833950 close(4) = 0 <0.000105>
464 00:52:09.834119 unlink("/var/run/haproxy.sock.464.bak") = -1 ENOENT (No such file or directory) <0.000040>
464 00:52:09.834293 write(2, "[ALERT] 291/005149 (464) : ", 27) = 27 <0.000589>
464 00:52:09.835018 write(2, "Starting frontend GLOBAL: cannot change UNIX socket ownership [/var/run/haproxy.sock]\n", 86) = 86 <0.001536>
And this is where it happens in src/proto_uxst.c:
if (!ext && path[0] &&
(((listener->bind_conf->ux.uid != -1 || listener->bind_conf->ux.gid != -1) &&
(chown(tempname, listener->bind_conf->ux.uid, listener->bind_conf->ux.gid) == -1)) ||
(listener->bind_conf->ux.mode != 0 && chmod(tempname, listener->bind_conf->ux.mode) == -1))) {
err |= ERR_FATAL | ERR_ALERT;
msg = "cannot change UNIX socket ownership";
goto err_unlink_temp;
}
Accidentally, I found out that file context pattern for the /var/run/haproxy.sock socket is incorrect: # semanage fcontext -l | grep '/var/run/haproxy.*sock' /var/run/haproxy\.sock.* regular file system_u:object_r:haproxy_var_run_t:s0 # ls -l /var/run/haproxy.sock srwxr-xr-x. 1 haproxy root 0 Oct 18 16:40 /var/run/haproxy.sock # matchpathcon /var/run/haproxy.sock /var/run/haproxy.sock system_u:object_r:var_run_t:s0 # rm -f /var/run/haproxy.sock # matchpathcon /var/run/haproxy.sock /var/run/haproxy.sock system_u:object_r:haproxy_var_run_t:s0 # The file context pattern matches only regular files, but it should match sockets: # semanage fcontext -l | grep '/var/run/haproxy.*sock' /var/run/haproxy\.sock.* socket system_u:object_r:haproxy_var_run_t:s0 # Milosi, Once the daemon manages to start, the socket file context looks like the correct one, either it is in /var/run or /var/lib/haproxy directory: $ ls -lZ /var/run/haproxy.sock /var/lib/haproxy/haproxy2.sock srwxr-xr-x. root root system_u:object_r:haproxy_var_lib_t:s0 /var/lib/haproxy/haproxy2.sock srwxr-xr-x. root root system_u:object_r:haproxy_var_run_t:s0 /var/run/haproxy.sock Not quite sure if it is related, but the files are actually created in the /run directory which is a tmpfs linked to from /var/run. The policy does not seem to contain any reference to ^/run. RHEL-6 and RHEL-7 support a feature called file context equivalences which define that /run will be treated the same way as /var/run: # semanage fcontext -l | grep -A 100 -i equivalence SELinux Distribution fcontext Equivalence /usr/local/lib64 = /usr/lib /etc/systemd/system = /usr/lib/systemd/system /run/systemd/system = /usr/lib/systemd/system /run/systemd/generator = /usr/lib/systemd/system /var/home = /home /var/roothome = /root /usr/lib64 = /usr/lib /var/lib/xguest/home = /home /var/named/chroot/lib64 = /usr/lib /var/named/chroot/usr/lib64 = /usr/lib /run = /var/run /usr/local/lib32 = /usr/lib /lib64 = /usr/lib /lib = /usr/lib /run/lock = /var/lock # This feature is heavily used by RHSCL components. Could we confirm if this is a simple selinux policy that needs corrected? Or does it need updated to use the file context equivalence as noted in cmt6? (In reply to Terry Bowling from comment #7) > Could we confirm if this is a simple selinux policy that needs corrected? > Or does it need updated to use the file context equivalence as noted in cmt6? According to comment#4 we should update haproxy context file policy. Thanks guys for investigation. I set a non-root group on the haproxy socket file and are also affected by this. This prevents HAProxy from being reloaded and can also prevent haproxy from starting. I sometimes have to manually remove the socket file before I can start HAProxy.
This is in my audit.log.
---
type=AVC msg=audit(1485174334.322:170648): avc: denied { link } for pid=62485 comm="haproxy" name="haproxy.sock" dev="tmpfs" ino=57340817 scontext=system_u:system_r:haproxy_t:s0 tcontext=system_u:object_r:var_run_t:s0 tclass=sock_file
type=AVC msg=audit(1485175066.360:171290): avc: denied { fsetid } for pid=65435 comm="haproxy" capability=4 scontext=system_u:system_r:haproxy_t:s0 tcontext=system_u:system_r:haproxy_t:s0 tclass=capability
---
The first denial is caused by having the wrong file context (var_run_t in stead of haproxy_var_run_t), but the second I am not sure.
Perhaps the second one is a missing permission for the HAProxy process?
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://access.redhat.com/errata/RHBA-2017:1861 |
Description of problem: The haproxy daemon can be configured with a socket file owned by a non-root user and permissions of 0600 to give another process exclusive access to this socket in order to configure and monitor the haproxy service. With such a configuration, the service fails to start. Version-Release number of selected component (if applicable): haproxy-1.5.14-3.el7.x86_64 selinux-policy-3.13.1-60.el7_2.9.noarch How reproducible: always Steps to Reproduce: 1. Add a line like this to default haproxy configuration: stats socket /var/run/haproxy.sock level admin user lb-admin mode 755 2. systemctl start haproxy; sleep 2; systemctl status haproxy -l Actual results: Oct 18 14:38:53 rhel7 haproxy-systemd-wrapper[11465]: haproxy-systemd-wrapper: exit, haproxy RC=15 Oct 18 14:38:53 rhel7 systemd[1]: haproxy.service: main process exited, code=exited, status=15/n/a Oct 18 14:38:53 rhel7 systemd[1]: Stopped HAProxy Load Balancer. Oct 18 14:38:53 rhel7 systemd[1]: Unit haproxy.service entered failed state. Oct 18 14:38:53 rhel7 systemd[1]: haproxy.service failed. Oct 18 14:38:57 rhel7 systemd[1]: Started HAProxy Load Balancer. Oct 18 14:38:57 rhel7 systemd[1]: Starting HAProxy Load Balancer... Oct 18 14:38:57 rhel7 haproxy-systemd-wrapper[11541]: haproxy-systemd-wrapper: executing /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds Oct 18 14:38:57 rhel7 haproxy-systemd-wrapper[11541]: [ALERT] 291/145544 (13356) : Starting frontend GLOBAL: cannot change UNIX socket ownership [/var/run/haproxy.sock] Oct 18 14:38:57 rhel7 haproxy-systemd-wrapper[11541]: haproxy-systemd-wrapper: exit, haproxy RC=256 alternatively, if the socket file exists: Oct 18 14:38:57 rhel7 haproxy-systemd-wrapper[11541]: [ALERT] 291/143857 (11543) : Starting frontend GLOBAL: error when trying to preserve previous UNIX socket [/var/run/haproxy.sock] Expected results: * haproxy.service - HAProxy Load Balancer Loaded: loaded (/usr/lib/systemd/system/haproxy.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2016-10-18 14:40:44 CEST; 2s ago Main PID: 11608 (haproxy-systemd) CGroup: /system.slice/haproxy.service |-11608 /usr/sbin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid |-11609 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds `-11611 /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds Oct 18 14:40:44 rhel7 systemd[1]: Started HAProxy Load Balancer. Oct 18 14:40:44 rhel7 systemd[1]: Starting HAProxy Load Balancer... Oct 18 14:40:44 rhel7 haproxy-systemd-wrapper[11608]: haproxy-systemd-wrapper: executing /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds Additional info: ausearch -i -m avc,user_avc,selinux_err,user_selinux_err -ts today ---- type=SYSCALL msg=audit(10/14/16 11:01:25.317:838) : arch=x86_64 syscall=chmod success=yes exit=0 a0=0x7ffd0f227450 a1=0755 a2=0xffffffff a3=0x0 items=0 ppid=4038 pid=4039 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=haproxy exe=/usr/sbin/haproxy subj=system_u:system_r:haproxy_t:s0 key=(null) type=AVC msg=audit(10/14/16 11:01:25.317:838) : avc: denied { fowner } for pid=4039 comm=haproxy capability=fowner scontext=system_u:system_r:haproxy_t:s0 tcontext=system_u:system_r:haproxy_t:s0 tclass=capability ---- sesearch -s haproxy_t -t haproxy_t -c capability --allow ---- Found 2 semantic av rules: allow haproxy_t haproxy_t : capability { chown dac_override kill setgid setuid net_bind_service net_admin net_raw sys_chroot sys_nice sys_resource } ; allow haproxy_t haproxy_t : capability net_bind_service ; ---- ^^ fowner cap is missing Making haproxy_t a permissive domain helps to start the service.