+++ This bug was initially created as a clone of Bug #2177254 +++ When in selinux enforcing mode, SIGPIPE masking is not inherited by services started by systemd without an selinux policy defined. This can cause systemd services to behave unexpectedly on receipt of SIGPIPE. This behaviour contradicts systemd documentation and the intention of the code: 1. In https://www.freedesktop.org/software/systemd/man/systemd.exec.html the definition of IgnoreSIGPIPE is "causes SIGPIPE to be ignored in the executed process" and states that the default is true. 2. In systemd's src/core/execute.c, the function exec_child does the following if (context->ignore_sigpipe) (void) ignore_signals(SIGPIPE); before the execve(). How reproducible: always. Steps to Reproduce: cat > show-signals.c <<EOF #include <stdio.h> #include <string.h> int main(void) { FILE *fd = fopen("/proc/self/status", "r"); char buf[256]; while (fgets(buf, sizeof(buf), fd) != NULL) { if (strstr(buf, "SigIgn:")) printf(buf); } return 0; } EOF gcc -o /usr/libexec/show-signals show-signals.c cat > /etc/systemd/system/show-signals.service <<EOF [Service] Type=oneshot ExecStart=/usr/libexec/show-signals EOF systemctl daemon-reload systemctl start show-signals.service journalctl -u show-signals.service | fgrep SigIgn | tail -n 1 Actual results: Feb 22 10:00:38 test-host show-signals[30527]: SigIgn: 0000000000000000 Expected results: Feb 22 10:00:38 test-host show-signals[30527]: SigIgn: 0000000000001000 Note that bit 13 corresponds to SIGPIPE. Additional info: The problem is with RHEL 8's selinux-policy-targeted restricting signal inheritance when systemd spawns processes. (I was using selinux-policy-targeted-3.14.3-108.el8_7.1.noarch.) Because show-signals does not have an associated selinux-policy it is started by systemd in the "unconfined_service_t" context. systemd runs in context init_t which is now allowed to transition to target "unconfined_service_t" with the "process" class's "siginh" permission: # sesearch -s init_t -t unconfined_service_t -c process -p siginh -A # On RHEL 7, that permission existed because init_t had the typeattribute unconfined_domain_type. On RHEL 8, unconfined_domain_type does have the siginh permission: # sesearch -s unconfined_domain_type -t unconfined_service_t -c process -p siginh -A allow unconfined_domain_type domain:process { fork getattr getcap getpgid getrlimit getsched getsession noatsecure rlimitinh setcap setcurrent setexec setfscreate setkeycreate setpgid setrlimit setsched setsockcreate share sigchld siginh sigkill signal signull sigstop }; init_t lost the unconfined_domain_type typeattribute as a consequence of the following patch: https://github.com/fedora-selinux/selinux-policy/commit/015047e1d962173e3789af3fad86198a3b5e3ac2 The RHEL 7 behaviour is restored if the systemd service is given an selinux-policy using the init_daemon_domain interface or equivalent. Since this change in selinux-policy behaviour on RHEL 8 was not documented (to the best of my knowledge), my guess is that a lot of systemd services are assuming that SIGPIPE is ignored on RHEL 8, as it was on RHEL 7 and as the systemd docs state, leading to unexpected behaviour. --- Additional comment from Milos Malik on 2023-03-20 14:36:54 UTC --- After removing the dontaudit rules (semodule -DB) from active policy, a SELinux denial appears with each "systemctl start show-signals.service" command. Caught in enforcing mode: ---- type=PROCTITLE msg=audit(03/20/2023 10:31:32.593:313) : proctitle=/usr/libexec/show-signals type=PATH msg=audit(03/20/2023 10:31:32.593:313) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=12666 dev=fd:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 type=PATH msg=audit(03/20/2023 10:31:32.593:313) : item=0 name=/usr/libexec/show-signals inode=1251250 dev=fd:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=unconfined_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 type=CWD msg=audit(03/20/2023 10:31:32.593:313) : cwd=/ type=EXECVE msg=audit(03/20/2023 10:31:32.593:313) : argc=1 a0=/usr/libexec/show-signals type=SYSCALL msg=audit(03/20/2023 10:31:32.593:313) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x5627ac432240 a1=0x5627ac537e20 a2=0x5627ac60b220 a3=0x7 items=2 ppid=1 pid=5529 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=show-signals exe=/usr/libexec/show-signals subj=system_u:system_r:unconfined_service_t:s0 key=(null) type=AVC msg=audit(03/20/2023 10:31:32.593:313) : avc: denied { siginh } for pid=5529 comm=show-signals scontext=system_u:system_r:init_t:s0 tcontext=system_u:system_r:unconfined_service_t:s0 tclass=process permissive=0 ---- Caught in permissive mode: ---- type=PROCTITLE msg=audit(03/20/2023 10:32:24.349:318) : proctitle=/usr/libexec/show-signals type=PATH msg=audit(03/20/2023 10:32:24.349:318) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=12666 dev=fd:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=system_u:object_r:ld_so_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 type=PATH msg=audit(03/20/2023 10:32:24.349:318) : item=0 name=/usr/libexec/show-signals inode=1251250 dev=fd:01 mode=file,755 ouid=root ogid=root rdev=00:00 obj=unconfined_u:object_r:bin_t:s0 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0 type=CWD msg=audit(03/20/2023 10:32:24.349:318) : cwd=/ type=EXECVE msg=audit(03/20/2023 10:32:24.349:318) : argc=1 a0=/usr/libexec/show-signals type=SYSCALL msg=audit(03/20/2023 10:32:24.349:318) : arch=x86_64 syscall=execve success=yes exit=0 a0=0x5627ac410720 a1=0x5627ac43bc50 a2=0x5627ac5871f0 a3=0x7 items=2 ppid=1 pid=5537 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=show-signals exe=/usr/libexec/show-signals subj=system_u:system_r:unconfined_service_t:s0 key=(null) type=AVC msg=audit(03/20/2023 10:32:24.349:318) : avc: denied { siginh } for pid=5537 comm=show-signals scontext=system_u:system_r:init_t:s0 tcontext=system_u:system_r:unconfined_service_t:s0 tclass=process permissive=1 ---- --- Additional comment from Milos Malik on 2023-03-20 14:46:52 UTC --- # sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: actual (secure) Max kernel policy version: 33 # cat testpolicy.cil ( allow init_t unconfined_service_t ( process ( siginh ))) # semodule -i testpolicy.cil # semodule -lfull | grep test 400 testpolicy cil # systemctl start show-signals.service # systemctl status show-signals.service ● show-signals.service Loaded: loaded (/etc/systemd/system/show-signals.service; static; vendor preset: disabled) Active: inactive (dead) Mar 20 10:43:35 removed systemd[1]: Starting show-signals.service... Mar 20 10:43:35 removed show-signals[5599]: SigIgn: 0000000000001000 Mar 20 10:43:35 removed systemd[1]: show-signals.service: Succeeded. Mar 20 10:43:35 removed systemd[1]: Started show-signals.service. # I believe that the testpolicy module fixes the issue described in comment#0. --- Additional comment from Milos Malik on 2023-03-20 14:56:44 UTC --- The same issue is reproducible on RHEL-9.2. --- Additional comment from Zdenek Pytela on 2023-03-24 09:44:19 UTC --- The permissions is allowed for 2 attributes, but unconfined_service_t is not a part of any of them: # sesearch -A -s init_t -c process -p siginh allow init_t daemon:process siginh; allow init_t systemprocess:process { dyntransition siginh };
Commit to backport: a4f0d7c3f Allow unconfined service inherit signal state from init