Re: [PATCH v4 2/2] man: Document directory cycle handling of selinux_restorecon

Stephen Smalley <[email protected]> Tue, 28 Jul 2026 10:50:55 -0400
Newsgroups org.kernel.vger.selinux
Message-ID <CAEjxPJ529Be7_1Pw1LRFsUtABDa3yVo_-wD=mT0QxiuA0sKfsA@mail.gmail.com>
On Tue, Jul 28, 2026 at 3:09 AM Johannes Segitz <[email protected]> wrote:
>
> Skipping directory cycles instead of aborting the file tree walk is a
> user visible behavior change: restorecon -R over a tree containing e.g.
> a bind mount of an ancestor directory now logs a warning, skips the
> cycle and completes successfully, instead of failing with ELOOP.
>
> Document the new behavior for the flag SELINUX_RESTORECON_RECURSE,
> including that a cycle is not an error and therefore is neither
> affected by SELINUX_RESTORECON_ABORT_ON_ERROR nor counted by
> SELINUX_RESTORECON_COUNT_ERRORS, and note the previous behavior in the
> selinux_restorecon(3), restorecon(8) and setfiles(8) man pages.
>
> Signed-off-by: Johannes Segitz <[email protected]>

Thank you for doing this!

Acked-by: Stephen Smalley <[email protected]>

> ---
>  libselinux/man/man3/selinux_restorecon.3 | 28 ++++++++++++++++++++++++
>  policycoreutils/setfiles/restorecon.8    | 20 +++++++++++++++++
>  policycoreutils/setfiles/setfiles.8      | 14 ++++++++++++
>  3 files changed, 62 insertions(+)
>
> diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3
> index 9bcd3d42..bafa86a2 100644
> --- a/libselinux/man/man3/selinux_restorecon.3
> +++ b/libselinux/man/man3/selinux_restorecon.3
> @@ -99,6 +99,21 @@ and if successful write an SHA1 digest of the specfile entries to an
>  extended attribute as described in the
>  .B NOTES
>  section.
> +.RS
> +Note that directory cycles encountered while descending, for example a bind
> +mount of an ancestor directory or nested BTRFS subvolumes, are not followed.
> +A warning is logged, the offending directory is not descended into and the
> +file tree walk continues with the remaining entries. Such cycles are not
> +treated as errors, therefore they neither abort the file tree walk when
> +.B SELINUX_RESTORECON_ABORT_ON_ERROR
> +is set, nor are they included in the count returned by
> +.BR selinux_restorecon_get_skipped_errors (3)
> +when
> +.B SELINUX_RESTORECON_COUNT_ERRORS
> +is set. See the
> +.B NOTES
> +section for details of the previous behavior.
> +.RE
>  .sp
>  .B SELINUX_RESTORECON_VERBOSE
>  log file label changes.
> @@ -302,6 +317,19 @@ with the
>  .B SELINUX_CB_LOG
>  .I type
>  option.
> +.IP "6." 4
> +Up to and including libselinux 3.11 a directory cycle was fatal:
> +.BR selinux_restorecon ()
> +logged an error, stopped the file tree walk and returned \-1 with
> +.I errno
> +set to
> +.BR ELOOP ,
> +regardless of the
> +.B SELINUX_RESTORECON_ABORT_ON_ERROR
> +and
> +.B SELINUX_RESTORECON_COUNT_ERRORS
> +flags. Since then the cycle is skipped as described above, so a file tree
> +walk over a directory tree containing a cycle can complete successfully.
>  .
>  .SH "SEE ALSO"
>  .BR selabel_get_digests_all_partial_matches (3),
> diff --git a/policycoreutils/setfiles/restorecon.8 b/policycoreutils/setfiles/restorecon.8
> index 982701c2..443f29ab 100644
> --- a/policycoreutils/setfiles/restorecon.8
> +++ b/policycoreutils/setfiles/restorecon.8
> @@ -145,6 +145,9 @@ options are mutually exclusive.
>  .TP
>  .B \-R, \-r
>  change files and directories file labels recursively (descend directories).
> +Directory cycles are skipped, see the
> +.B NOTES
> +section for details.
>  .br
>  .TP
>  .B \-v
> @@ -240,6 +243,23 @@ and provided the
>  .B \-n
>  option is NOT set and recursive mode is set, files will be relabeled as
>  required with the digests then being updated provided there are no errors.
> +.IP "4." 4
> +When descending directories (i.e. the
> +.B \-R
> +or
> +.B \-r
> +option is set)
> +.B restorecon
> +detects directory cycles, for example a bind mount of an ancestor directory or
> +nested BTRFS subvolumes. A cycle is reported as a warning and the offending
> +directory is not descended into, the remaining entries are still relabeled.
> +A directory cycle is not counted as a relabeling error, so it does not affect
> +the exit status and does not stop the file tree walk. Up to and including
> +version 3.11 a directory cycle was instead treated as a fatal
> +.B ELOOP
> +error, terminating
> +.B restorecon
> +with a non-zero exit status.
>
>  .SH EXAMPLE
>  .nf
> diff --git a/policycoreutils/setfiles/setfiles.8 b/policycoreutils/setfiles/setfiles.8
> index d55b42db..17cabe37 100644
> --- a/policycoreutils/setfiles/setfiles.8
> +++ b/policycoreutils/setfiles/setfiles.8
> @@ -307,6 +307,20 @@ and provided the
>  .B \-n
>  option is NOT set, files will be relabeled as required with the digests then
>  being updated provided there are no errors.
> +.IP "4." 4
> +.B setfiles
> +detects directory cycles while descending directories, for example a bind
> +mount of an ancestor directory or nested BTRFS subvolumes. A cycle is reported
> +as a warning and the offending directory is not descended into, the remaining
> +entries are still relabeled. A directory cycle is not counted as a relabeling
> +error, so it does not affect the exit status and does not stop the file tree
> +walk. Up to and including version 3.11 a directory cycle was instead treated
> +as a fatal
> +.B ELOOP
> +error, terminating
> +.B setfiles
> +with exit status
> +.BR 255 .
>
>  .SH EXAMPLE
>  .nf
> --
> 2.55.0
>
>