Re: [PATCH] libselinux: selinux_restorecon: avoid triggering auto-mounts unnecessarily
Félix-Antoine Fortin <[email protected]> Wed, 29 Jul 2026 09:37:52 -0400
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <CALAjPzH8EVi_f27kpONesg=KP7VqmShxJByXmg5-7j_+8zH-LA@mail.gmail.com> |
Sorry for failing to provide an update earlier. While implementing patch, I found out my initial analysis was wrong. autofs entries do not have the seclabel attribute. This was not the right cause for the automount. What I found out was, there was a second mount on XFS with the same path, and the seclabel attribute. restorecon was therefore triggering automount while reading info on another mount with the same path. In summary: restorecon called statvfs() on the pathname of a hidden seclabel bind mount listed in /proc/mounts. Because that pathname is covered by a systemd autofs mount, the pathname-based statvfs() resolves to the topmost autofs mount and unexpectedly activates the corresponding NFS filesystem. If we would like to avoid restorecon triggering automount, the patch solution I initially proposed has no effect. On Wed, Jul 29, 2026 at 9:12 AM Stephen Smalley <[email protected]> wrote: > > Félix-Antoine Fortin <[email protected]> reported > the following bug report, quoted verbatim: > ---<snip>--- > I encountered an unexpected side effect in restorecon: processing a > single local file triggers unrelated automounts. > > Command (called during ipa-client-install): > > $ restorecon /etc/krb5.conf.d/freeipa > > Although the target is under /etc, this causes all of the following > NFS automounts to activate: > > nfs-home.automount > nfs-project.automount > nfs-scratch.automount > > The journal identifies restorecon as the process that triggered each automount: > > systemd[1]: nfs-home.automount: Got automount request for /nfs/home, > triggered by 10521 (restorecon) > systemd[1]: Mounting /nfs/home... > nfsrahead[10530]: setting /nfs/home readahead to 128 > systemd[1]: Mounted /nfs/home. > systemd[1]: nfs-project.automount: Got automount request for > /nfs/project, triggered by 10521 (restorecon) > systemd[1]: Mounting /nfs/project... > nfsrahead[10533]: setting /nfs/project readahead to 128 > systemd[1]: Mounted /nfs/project. > systemd[1]: nfs-scratch.automount: Got automount request for > /nfs/scratch, triggered by 10521 (restorecon) > systemd[1]: Mounting /nfs/scratch... > nfsrahead[10536]: setting /nfs/scratch readahead to 128 > systemd[1]: Mounted /nfs/scratch. > > The fstab entries are: > > nfs_server:/home /nfs/home nfs4 > proto=tcp,nosuid,nolock,noatime,actimeo=3,nfsvers=4.2,seclabel,_netdev,x-systemd.automount,x-systemd.mount-timeout=30 > 0 0 > nfs_server:/project /nfs/project nfs4 > proto=tcp,nosuid,nolock,noatime,actimeo=3,nfsvers=4.2,seclabel,_netdev,x-systemd.automount,x-systemd.mount-timeout=30 > 0 0 > nfs_server:/scratch /nfs/scratch nfs4 > proto=tcp,nosuid,nolock,noatime,actimeo=3,nfsvers=4.2,seclabel,_netdev,x-systemd.automount,x-systemd.mount-timeout=30 > 0 0 > > An strace shows restorecon probing these mountpoints: > > $ strace -f restorecon /etc/krb5.conf/freeipa 2>&1 | grep /nfs > > statfs("/nfs/home", {f_type=NFS_SUPER_MAGIC, f_bsize=1048576, > f_blocks=10172, f_bfree=10069, f_bavail=10069, f_files=5240832, > f_ffree=5240755, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=1048576, > f_flags=ST_VALID|ST_NOSUID|ST_NOATIME}) = 0 > statfs("/nfs/project", {f_type=NFS_SUPER_MAGIC, f_bsize=1048576, > f_blocks=10172, f_bfree=10069, f_bavail=10069, f_files=5240832, > f_ffree=5240816, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=1048576, > f_flags=ST_VALID|ST_NOSUID|ST_NOATIME}) = 0 > statfs("/nfs/scratch", {f_type=NFS_SUPER_MAGIC, f_bsize=1048576, > f_blocks=10172, f_bfree=10069, f_bavail=10069, f_files=5240832, > f_ffree=5240818, f_fsid={val=[0, 0]}, f_namelen=255, f_frsize=1048576, > f_flags=ST_VALID|ST_NOSUID|ST_NOATIME}) = 0 > > My understanding is: > > 1. When restorecon is called without ignore mount (-m) flag, it reads > the mount table to construct the exclusion list for filesystems > without SELinux labeling support. > https://github.com/SELinuxProject/selinux/blob/main/libselinux/src/selinux_restorecon.c#L146C14-L146C28 > 2. exclude_non_seclabel_mounts() calls file_system_count() for mounts that > advertise the seclabel option. file_system_count() calls statvfs() on > the mountpoint. > https://github.com/SELinuxProject/selinux/blob/main/libselinux/src/selinux_restorecon.c#L343 > https://github.com/SELinuxProject/selinux/blob/main/libselinux/src/selinux_restorecon.c#L282 > 3. Calling statvfs() on a autofs mountpoint activates the underlying mount. > 4. The resulting file count appears to be used only for progress reporting, but > it is calculated even when neither progress nor mass-relabel reporting > was requested. > > So a non-recursive restorecon operation on one local file can mount > unrelated remote filesystems. > > I would expect restorecon to not activate unrelated systemd automount > filesystems when progress reporting is not requested and the target > does not traverse those filesystems. > > I think the best minimal patch would to skip calling file_system_count on > mounts which type is autofs (mount_info[2]). > > ---<snip>--- > > Fix this issue as the original reporter suggested. > > Reported-by: Félix-Antoine Fortin <[email protected]> > Suggested-by: Félix-Antoine Fortin <[email protected]> > Signed-off-by: Stephen Smalley <[email protected]> > --- > libselinux/src/selinux_restorecon.c | 10 +++++++++- > 1 file changed, 9 insertions(+), 1 deletion(-) > > diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c > index 30f1b836..8bae1464 100644 > --- a/libselinux/src/selinux_restorecon.c > +++ b/libselinux/src/selinux_restorecon.c > @@ -301,6 +301,7 @@ static uint64_t exclude_non_seclabel_mounts(void) > uint64_t nfile = 0; > char *mount_info[4]; > char *buf = NULL, *item, *saveptr; > + bool autofs = false; > > /* Check to see if the kernel supports seclabel */ > if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0) > @@ -335,12 +336,19 @@ static uint64_t exclude_non_seclabel_mounts(void) > /* Remove pre-existing entry */ > remove_exclude(mount_info[1]); > > + autofs = !strcmp(mount_info[2], "autofs"); > saveptr = NULL; > item = strtok_r(mount_info[3], ",", &saveptr); > while (item != NULL) { > if (strcmp(item, "seclabel") == 0) { > found = 1; > - nfile += file_system_count(mount_info[1]); > + /* > + * Avoid triggering an auto-mount just to > + * count files for progress tracking. > + */ > + if (!autofs) > + nfile += file_system_count( > + mount_info[1]); > break; > } > item = strtok_r(NULL, ",", &saveptr); > -- > 2.55.0 >