setfiles: introduce the -C option for distinguishing file tree walk errors

setfiles(8) exits with status 255 if it encounters any error. Introduce
the "-C" option: if the only errors that setfiles(8) encounters are
labeling errors seen during the file tree walk(s), then let setfiles(8)
exit with status 1.

Cc: "Richard W.M. Jones" <rjones@redhat.com>
Cc: Petr Lautrbach <plautrba@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1794518
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
Laszlo Ersek 2022-05-03 10:23:26 +02:00 committed by Petr Lautrbach
parent 0b691d1afe
commit 2b6f7e969c
4 changed files with 44 additions and 9 deletions

View File

@ -41,7 +41,8 @@ void restore_init(struct restore_opts *opts)
opts->xdev | opts->abort_on_error |
opts->syslog_changes | opts->log_matches |
opts->ignore_noent | opts->ignore_mounts |
opts->mass_relabel | opts->conflict_error;
opts->mass_relabel | opts->conflict_error |
opts->count_errors;
/* Use setfiles, restorecon and restorecond own handles */
selinux_restorecon_set_sehandle(opts->hnd);
@ -72,7 +73,8 @@ void restore_finish(void)
}
}
int process_glob(char *name, struct restore_opts *opts, size_t nthreads)
int process_glob(char *name, struct restore_opts *opts, size_t nthreads,
long unsigned *skipped_errors)
{
glob_t globbuf;
size_t i = 0;
@ -96,6 +98,8 @@ int process_glob(char *name, struct restore_opts *opts, size_t nthreads)
nthreads);
if (rc < 0)
errors = rc;
else if (opts->restorecon_flags & SELINUX_RESTORECON_COUNT_ERRORS)
*skipped_errors += selinux_restorecon_get_skipped_errors();
}
globfree(&globbuf);

View File

@ -35,6 +35,7 @@ struct restore_opts {
unsigned int ignore_noent;
unsigned int ignore_mounts;
unsigned int conflict_error;
unsigned int count_errors;
/* restorecon_flags holds | of above for restore_init() */
unsigned int restorecon_flags;
char *rootpath;
@ -49,7 +50,8 @@ struct restore_opts {
void restore_init(struct restore_opts *opts);
void restore_finish(void);
void add_exclude(const char *directory);
int process_glob(char *name, struct restore_opts *opts, size_t nthreads);
int process_glob(char *name, struct restore_opts *opts, size_t nthreads,
long unsigned *skipped_errors);
extern char **exclude_list;
#endif

View File

@ -6,6 +6,7 @@ setfiles \- set SELinux file security contexts.
.B setfiles
.RB [ \-c
.IR policy ]
.RB [ \-C ]
.RB [ \-d ]
.RB [ \-l ]
.RB [ \-m ]
@ -58,6 +59,13 @@ option will force a replacement of the entire context.
.B \-c
check the validity of the contexts against the specified binary policy.
.TP
.B \-C
If only relabeling errors are encountered during the file tree walks,
exit with status
.B 1
rather than
.BR 255 .
.TP
.B \-d
show what specification matched each file.
.TP
@ -219,6 +227,20 @@ or the
.B \-s
option is used.
.SH "EXIT STATUS"
.B setfiles
exits with status
.B 0
if it encounters no errors. Fatal errors result in status
.BR 255 .
Labeling errors encountered during file tree walk(s) result in status
.B 1
if the
.B -C
option is specified and no other kind of error is encountered, and in status
.B 255
otherwise.
.SH "NOTES"
.IP "1." 4
.B setfiles

View File

@ -40,8 +40,8 @@ static __attribute__((__noreturn__)) void usage(const char *const name)
name, name);
} else {
fprintf(stderr,
"usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n"
"usage: %s [-diIDlmnpqvEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n"
"usage: %s [-diIDlmnpqvCEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file pathname...\n"
"usage: %s [-diIDlmnpqvCEFWT] [-e excludedir] [-r alt_root_path] [-c policyfile] spec_file -f filename\n"
"usage: %s -s [-diIDlmnpqvFWT] spec_file\n",
name, name, name);
}
@ -150,9 +150,10 @@ int main(int argc, char **argv)
const char *base;
int errors = 0;
const char *ropts = "e:f:hiIDlmno:pqrsvFRW0xT:";
const char *sopts = "c:de:f:hiIDlmno:pqr:svEFR:W0T:";
const char *sopts = "c:de:f:hiIDlmno:pqr:svCEFR:W0T:";
const char *opts;
union selinux_callback cb;
long unsigned skipped_errors;
/* Initialize variables */
memset(&r_opts, 0, sizeof(r_opts));
@ -161,6 +162,7 @@ int main(int argc, char **argv)
warn_no_match = 0;
request_digest = 0;
policyfile = NULL;
skipped_errors = 0;
if (!argv[0]) {
fprintf(stderr, "Called without required program name!\n");
@ -288,6 +290,9 @@ int main(int argc, char **argv)
r_opts.syslog_changes =
SELINUX_RESTORECON_SYSLOG_CHANGES;
break;
case 'C':
r_opts.count_errors = SELINUX_RESTORECON_COUNT_ERRORS;
break;
case 'E':
r_opts.conflict_error =
SELINUX_RESTORECON_CONFLICT_ERROR;
@ -447,13 +452,15 @@ int main(int argc, char **argv)
buf[len - 1] = 0;
if (!strcmp(buf, "/"))
r_opts.mass_relabel = SELINUX_RESTORECON_MASS_RELABEL;
errors |= process_glob(buf, &r_opts, nthreads) < 0;
errors |= process_glob(buf, &r_opts, nthreads,
&skipped_errors) < 0;
}
if (strcmp(input_filename, "-") != 0)
fclose(f);
} else {
for (i = optind; i < argc; i++)
errors |= process_glob(argv[i], &r_opts, nthreads) < 0;
errors |= process_glob(argv[i], &r_opts, nthreads,
&skipped_errors) < 0;
}
maybe_audit_mass_relabel(r_opts.mass_relabel, errors);
@ -467,5 +474,5 @@ int main(int argc, char **argv)
if (r_opts.progress)
fprintf(stdout, "\n");
exit(errors ? -1 : 0);
exit(errors ? -1 : skipped_errors ? 1 : 0);
}