Matchcon and restorecon do not agree after setting a equivalency fcontext. Reproducible: Always Steps to Reproduce: # semanage fcontext -a -e /etc /var/run/foo/bar # mkdir -p /var/run/foo/bar # ls -lZd /var/run/foo/bar drwxr-xr-x. 2 root root unconfined_u:object_r:var_run_t:s0 40 Sep 29 10:01 /var/run/foo/bar # matchpathcon /var/run/foo/bar /var/run/foo/bar system_u:object_r:etc_t:s0 Everything looks correct except # restorecon -v /var/run/foo/bar The restorecon command does not fix the label. # ls -lZd /var/run/foo/bar drwxr-xr-x. 2 root root unconfined_u:object_r:var_run_t:s0 40 Sep 29 10:01 /var/run/foo/bar # chcon -t etc_t /var/run/foo/bar # ls -lZd /var/run/foo/bar drwxr-xr-x. 2 root root unconfined_u:object_r:etc_t:s0 40 Sep 29 10:01 /var/run/foo/bar # restorecon -v /var/run/foo/bar Relabeled /run/foo/bar from unconfined_u:object_r:etc_t:s0 to unconfined_u:object_r:var_run_t:s0 Why is matchpathcon and restorecon different ideas on what the label should be?
# semanage fcontext -l | grep '^/run =' /run = /var/run # semanage fcontext -a -e /etc /var/run/foo/bar # semanage fcontext -l -C SELinux Local fcontext Equivalence /var/run/foo/bar = /etc # matchpathcon /etc/ /etc system_u:object_r:etc_t:s0 # matchpathcon /var/run/foo/bar /var/run/foo/bar system_u:object_r:etc_t:s0 # matchpathcon /run/foo/bar /run/foo/bar system_u:object_r:var_run_t:s0 # As you can see above, the SELinux context changed by removing the "/var" prefix. # ls -ild /run 1 drwxr-xr-x. 33 root root 980 Oct 2 02:41 /run # ls -ild /var/run 402 lrwxrwxrwx. 1 root root 6 Sep 26 07:43 /var/run -> ../run #
I can't make /etc equivalent to /run/foo/bar though. # semanage fcontext -a -e /etc /run/foo/bar ValueError: File spec /run/foo/bar conflicts with equivalency rule '/run /var/run'; Try adding '/var/run/foo/bar' instead So, the only way this could work is as per the example. I was hoping it would resolve the equivalences in multiple steps though. Like /run/foo/bar => /var/run/foo/bar => /etc
`restorecon` uses `realpath` before it evaluates a context. In this case: # realpath /var/run/foo/bar/ /run/foo/bar But it's not possible to add a new equivalency rule for "/run/foo/bar" as it's in conflict with already existing rule: # semanage fcontext -a -e /etc /run/foo/bar ValueError: File spec /run/foo/bar conflicts with equivalency rule '/run /var/run'; Try adding '/var/run/foo/bar' instead # semanage fcontext -l | sed '1,/SELinux Distribution fcontext Equivalence/d' | grep '/var/run' /run = /var/run At this moment, I think it's time to change selinux policy equivalence rules so that they follows the fact that `/var/run` is a symlink to `/run`, i.e. change equivalence rules so that "/var/run" => "/run" instead of current "/run" => "/var/run"
There's another tool - `setfiles` which can be used for setting SELinux file contexts and which does not expand paths via `realpath`, e.g. # matchpathcon /var/run/foo/bar /run/foo/bar /var/run/foo/bar system_u:object_r:etc_t:s0 /run/foo/bar system_u:object_r:var_run_t:s0 # setfiles -v /etc/selinux/targeted/contexts/files/file_contexts /var/run/foo/bar Relabeled /var/run/foo/bar from system_u:object_r:var_run_t:s0 to system_u:object_r:etc_t:s0 # setfiles -v /etc/selinux/targeted/contexts/files/file_contexts /run/foo/bar Relabeled /run/foo/bar from system_u:object_r:etc_t:s0 to system_u:object_r:var_run_t:s0 See https://github.com/SELinuxProject/selinux/blob/main/policycoreutils/setfiles/setfiles.c#L180 and https://github.com/SELinuxProject/selinux/blob/main/policycoreutils/setfiles/setfiles.c#L198
I'm not in control of how the relabeling is happening, because its systemd that triggers the relabeling of /run (from the initrd) after it has loaded the policy.
Could you please share more details about your problem? From the reproducer in the description it's not clear when and why the relabeling happens
Well, the reproducer just showed what went wrong in a minimal way. The actual usecase was that I wanted to use a directory in /run as an upperdir in an overlayfs mount for /etc. This is problematic, because /run is mounted in the initrd, so it has no initial labeling. Immediately after loading the selinux policy systemd then triggers a relabel, which makes my directory of type var_run_t. This is not right, as the upper directory label will be the label of the overlayfs /etc mount, which needs to be etc_t, otherwise I get all sorts of errors. In practice, I'm currently looking at other ways to handle /etc, so this isn't strictly a problem for me anymore. Still, it seems like a bug to me.
If the only file needed to be labeled etc_t is the top level file, you could force it, and then tell restorecon to not relabel it, by adding a file context: semanage fcontext -a -t <<none>> /var/run/foo/bar
I believe this issue is gone in F40+ with https://github.com/fedora-selinux/selinux-policy/pull/2017