Bug 2241366

Summary: Restorecon not working correctly
Product: [Fedora] Fedora Reporter: Daniel Walsh <dwalsh>
Component: selinux-policyAssignee: Zdenek Pytela <zpytela>
Status: CLOSED CURRENTRELEASE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: high Docs Contact:
Priority: high    
Version: 38CC: alexl, dwalsh, lvrabec, mmalik, nknazeko, omosnacek, pkoncity, plautrba, vmojzis, zpytela
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2024-04-22 15:51:05 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:

Description Daniel Walsh 2023-09-29 14:31:26 UTC
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?

Comment 1 Milos Malik 2023-10-02 06:50:30 UTC
# 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
#

Comment 2 Alexander Larsson 2023-10-02 10:45:22 UTC
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

Comment 3 Petr Lautrbach 2023-10-02 11:36:46 UTC
`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"

Comment 4 Petr Lautrbach 2023-10-02 13:16:06 UTC
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

Comment 5 Alexander Larsson 2023-10-02 13:18:51 UTC
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.

Comment 6 Petr Lautrbach 2023-10-02 13:45:26 UTC
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

Comment 7 Alexander Larsson 2023-10-04 15:30:13 UTC
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.

Comment 8 Daniel Walsh 2023-10-05 10:22:07 UTC
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

Comment 9 Zdenek Pytela 2024-04-22 15:51:05 UTC
I believe this issue is gone in F40+ with
https://github.com/fedora-selinux/selinux-policy/pull/2017