Re: [PATCH v2 3/3] policycoreutils/setfiles: honor RESTORECON_THREADS
Stephen Smalley <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <CAEjxPJ4vzaopfLB87QHvPBsFB6BrinGhX6-Xn5MnatLhkaxf+A@mail.gmail.com> |
On Wed, Aug 19, 2026 at 10:30 AM jboero <[email protected]> wrote: > > From: Johnny Boero <[email protected]> > > Relabeling is invoked from places that cannot reasonably be given a -T > option. On a Fedora 44 system, 10 installed packages run restorecon > from their scriptlets -- filesystem, kernel-core, container-selinux and > selinux-policy-targeted among them -- and not one of them passes -T: > > restorecon -R /usr/bin /usr/sbin > restorecon -e /run/media -R /root /var/log /var/run /etc/passwd* ... > restorecon -R /var/lib/containers > > Influencing those means patching every spec file in the distribution, > one merge request at a time, and only covers the packages one happens to > have installed. The environment is the only knob that reaches them all > at once. > > Add RESTORECON_THREADS, with the same meaning as -T, which takes > precedence when both are given: > > RESTORECON_THREADS=1 dnf update # keep relabeling on a single core > RESTORECON_THREADS=8 dnf update # cap parallelism during application load > > An invalid value is reported and ignored rather than being fatal, since > the variable is inherited by every child process and should not be able > to break an unrelated caller. parse_nthreads() does not touch nthreads > on error, so whichever default is compiled in stays in effect. > > Link: https://github.com/SELinuxProject/selinux/issues/489 > Signed-off-by: Johnny Boero <[email protected]> Acked-by: Stephen Smalley <[email protected]> > --- > > This replaces 3/3 of the v1 series; 1/3 and 2/3 are unchanged and still > apply as sent. > > v2: drop the "nthreads = 0" reset on an invalid value, as Stephen > Smalley pointed out. parse_nthreads() does not write nthreads on error, so the > reset was a no-op with 2/3 applied and turned an invalid value into > all-cores without it. Verified by building 1/3 + 3/3 without 2/3: > before the fix an invalid value ran at ~1000% CPU, after it stays > single threaded at 99%. Commit message reworded accordingly. > > policycoreutils/setfiles/restorecon.8 | 17 ++++++++++++++++- > policycoreutils/setfiles/setfiles.8 | 18 +++++++++++++++++- > policycoreutils/setfiles/setfiles.c | 18 ++++++++++++++++-- > 3 files changed, 49 insertions(+), 4 deletions(-) > > diff --git a/policycoreutils/setfiles/restorecon.8 b/policycoreutils/setfiles/restorecon.8 > index 8d7b46f0..001039b7 100644 > --- a/policycoreutils/setfiles/restorecon.8 > +++ b/policycoreutils/setfiles/restorecon.8 > @@ -187,8 +187,23 @@ use up to > .I nthreads > threads. Specify 0 to create as many threads as there are available > CPU cores (default); 1 to use only a single thread; or any positive > -number to use the given number of threads (if possible). > +number to use the given number of threads (if possible). This option > +overrides the > +.B RESTORECON_THREADS > +environment variable. > +.SH "ENVIRONMENT" > .TP > +.B RESTORECON_THREADS > +Sets the default number of threads to use, with the same meaning as the > +.B \-T > +option. This allows the amount of parallelism to be controlled for > +callers that do not pass > +.B \-T > +themselves, such as package installation scripts. Setting it to 1 > +restores the historic single threaded behaviour. An invalid value is > +ignored with a warning. The > +.B \-T > +option takes precedence. > .SH "ARGUMENTS" > .IR pathname \ ... > The pathname for the file(s) to be relabeled. > diff --git a/policycoreutils/setfiles/setfiles.8 b/policycoreutils/setfiles/setfiles.8 > index 53cb97cc..101556a9 100644 > --- a/policycoreutils/setfiles/setfiles.8 > +++ b/policycoreutils/setfiles/setfiles.8 > @@ -192,12 +192,28 @@ use up to > .I nthreads > threads. Specify 0 to create as many threads as there are available > CPU cores (default); 1 to use only a single thread; or any positive > -number to use the given number of threads (if possible). > +number to use the given number of threads (if possible). This option > +overrides the > +.B RESTORECON_THREADS > +environment variable. > .TP > .B \-A > do not track inodes with multiple hard links or bind mounts that would > match different contexts (saves memory) > > +.SH "ENVIRONMENT" > +.TP > +.B RESTORECON_THREADS > +Sets the default number of threads to use, with the same meaning as the > +.B \-T > +option. This allows the amount of parallelism to be controlled for > +callers that do not pass > +.B \-T > +themselves, such as package installation scripts. Setting it to 1 > +restores the historic single threaded behaviour. An invalid value is > +ignored with a warning. The > +.B \-T > +option takes precedence. > .SH "ARGUMENTS" > .TP > .I spec_file > diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c > index 4c860755..7f1c0a31 100644 > --- a/policycoreutils/setfiles/setfiles.c > +++ b/policycoreutils/setfiles/setfiles.c > @@ -65,8 +65,8 @@ static void set_rootpath(const char *arg) > } > > /* > - * Parse a thread count, as given by the -T option. Returns -1 on invalid > - * input. > + * Parse a thread count, as given by the -T option or the > + * RESTORECON_THREADS environment variable. Returns -1 on invalid input. > */ > static int parse_nthreads(const char *str, size_t *nthreads) > { > @@ -166,6 +166,7 @@ int main(int argc, char **argv) > struct stat sb; > int opt, i = 0; > const char *input_filename = NULL; > + const char *env_nthreads; > int use_input_file = 0; > char *buf = NULL; > size_t buf_len = 0, nthreads = 0; > @@ -246,6 +247,19 @@ int main(int argc, char **argv) > exit(0); > } > > + /* > + * An explicit -T option takes precedence over the environment. An > + * invalid value is not fatal, so that a bogus setting inherited by > + * every child process does not break unrelated callers; > + * parse_nthreads() leaves nthreads alone in that case. > + */ > + env_nthreads = getenv("RESTORECON_THREADS"); > + if (env_nthreads && env_nthreads[0] != '\0' && > + parse_nthreads(env_nthreads, &nthreads) < 0) > + fprintf(stderr, > + "%s: invalid RESTORECON_THREADS value \"%s\", ignoring\n", > + r_opts.progname, env_nthreads); > + > /* Process any options. */ > while ((opt = getopt(argc, argv, opts)) > 0) { > switch (opt) { > -- > 2.55.0 >