policycoreutils-3.9-3
- restorecon: Add option to count relabeled files Note: Patch0009 needs to also contain diff for libselinux because of updated header files (Makefile uses -I../../libselinux/include) Resolves: RHEL-94827
This commit is contained in:
parent
f46b044e34
commit
f70418328b
356
0009-restorecon-Add-option-to-count-relabeled-files.patch
Normal file
356
0009-restorecon-Add-option-to-count-relabeled-files.patch
Normal file
@ -0,0 +1,356 @@
|
||||
From 54cbd31a219790932364d8b79f9a459ea3276bcf Mon Sep 17 00:00:00 2001
|
||||
From: Vit Mojzis <vmojzis@redhat.com>
|
||||
Date: Fri, 7 Nov 2025 18:41:36 +0100
|
||||
Subject: [PATCH] restorecon: Add option to count relabeled files
|
||||
|
||||
This is useful in case we want to check that a remediation using
|
||||
restorecon was successful (otherwise 0 is always returned, even if no
|
||||
files were relabeled).
|
||||
|
||||
Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
|
||||
---
|
||||
libselinux/include/selinux/restorecon.h | 15 +++++++++++
|
||||
libselinux/src/libselinux.map | 5 ++++
|
||||
libselinux/src/selinux_restorecon.c | 34 ++++++++++++++++++++++---
|
||||
policycoreutils/setfiles/restore.c | 12 ++++++---
|
||||
policycoreutils/setfiles/restore.h | 3 ++-
|
||||
policycoreutils/setfiles/restorecon.8 | 3 +++
|
||||
policycoreutils/setfiles/setfiles.c | 26 ++++++++++++++-----
|
||||
7 files changed, 83 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h
|
||||
index 8dcc831b..aca218dc 100644
|
||||
--- a/libselinux/include/selinux/restorecon.h
|
||||
+++ b/libselinux/include/selinux/restorecon.h
|
||||
@@ -134,6 +134,11 @@ extern int selinux_restorecon_parallel(const char *pathname,
|
||||
*/
|
||||
#define SELINUX_RESTORECON_SET_USER_ROLE 0x40000
|
||||
|
||||
+/*
|
||||
+ * Count the number of relabeled files (or would be relabeled if "nochange" was not set).
|
||||
+ */
|
||||
+#define SELINUX_RESTORECON_COUNT_RELABELED 0x80000
|
||||
+
|
||||
/**
|
||||
* selinux_restorecon_set_sehandle - Set the global fc handle.
|
||||
* @hndl: specifies handle to set as the global fc handle.
|
||||
@@ -228,6 +233,16 @@ extern int selinux_restorecon_xattr(const char *pathname,
|
||||
*/
|
||||
extern long unsigned selinux_restorecon_get_skipped_errors(void);
|
||||
|
||||
+/* selinux_restorecon_get_relabeled_files - Get the number of relabeled files
|
||||
+ *
|
||||
+ * If SELINUX_RESTORECON_COUNT_RELABELED was passed to selinux_restorecon(3) or
|
||||
+ * selinux_restorecon_parallel(3), this function returns the number of files
|
||||
+ * that were successfully relabeled.
|
||||
+ * If the SELINUX_RESTORECON_NOCHANGE flag was set, this function returns
|
||||
+ * the number of files that would be relabeled.
|
||||
+ */
|
||||
+extern long unsigned selinux_restorecon_get_relabeled_files(void);
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff --git a/libselinux/src/libselinux.map b/libselinux/src/libselinux.map
|
||||
index ab002f01..95cd53b0 100644
|
||||
--- a/libselinux/src/libselinux.map
|
||||
+++ b/libselinux/src/libselinux.map
|
||||
@@ -262,3 +262,8 @@ LIBSELINUX_3.9 {
|
||||
global:
|
||||
context_to_str;
|
||||
} LIBSELINUX_3.8;
|
||||
+
|
||||
+LIBSELINUX_3.10 {
|
||||
+ global:
|
||||
+ selinux_restorecon_get_relabeled_files;
|
||||
+} LIBSELINUX_3.9;
|
||||
diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
|
||||
index 23546cb0..28749ee2 100644
|
||||
--- a/libselinux/src/selinux_restorecon.c
|
||||
+++ b/libselinux/src/selinux_restorecon.c
|
||||
@@ -69,6 +69,9 @@ static struct dir_xattr *dir_xattr_last;
|
||||
/* Number of errors ignored during the file tree walk. */
|
||||
static long unsigned skipped_errors;
|
||||
|
||||
+/* Number of successfully relabeled files or files that would be relabeled */
|
||||
+static long unsigned relabeled_files;
|
||||
+
|
||||
/* restorecon_flags for passing to restorecon_sb() */
|
||||
struct rest_flags {
|
||||
bool nochange;
|
||||
@@ -88,6 +91,7 @@ struct rest_flags {
|
||||
bool warnonnomatch;
|
||||
bool conflicterror;
|
||||
bool count_errors;
|
||||
+ bool count_relabeled;
|
||||
};
|
||||
|
||||
static void restorecon_init(void)
|
||||
@@ -650,11 +654,12 @@ out:
|
||||
}
|
||||
|
||||
static int restorecon_sb(const char *pathname, const struct stat *sb,
|
||||
- const struct rest_flags *flags, bool first)
|
||||
+ const struct rest_flags *flags, bool first, bool *updated_out)
|
||||
{
|
||||
char *newcon = NULL;
|
||||
char *curcon = NULL;
|
||||
int rc;
|
||||
+ bool updated = false;
|
||||
const char *lookup_path = pathname;
|
||||
|
||||
if (rootpath) {
|
||||
@@ -736,7 +741,6 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
|
||||
}
|
||||
|
||||
if (curcon == NULL || strcmp(curcon, newcon) != 0) {
|
||||
- bool updated = false;
|
||||
|
||||
if (!flags->set_specctx && curcon &&
|
||||
(is_context_customizable(curcon) > 0)) {
|
||||
@@ -796,9 +800,14 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
|
||||
syslog(LOG_INFO, "labeling %s to %s\n",
|
||||
pathname, newcon);
|
||||
}
|
||||
+
|
||||
+ /* Note: relabel counting handled by caller */
|
||||
+
|
||||
}
|
||||
|
||||
out:
|
||||
+ if (updated_out)
|
||||
+ *updated_out = updated;
|
||||
rc = 0;
|
||||
out1:
|
||||
freecon(curcon);
|
||||
@@ -887,6 +896,7 @@ struct rest_state {
|
||||
bool abort;
|
||||
int error;
|
||||
long unsigned skipped_errors;
|
||||
+ long unsigned relabeled_files;
|
||||
int saved_errno;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
@@ -1010,8 +1020,9 @@ loop_body:
|
||||
if (state->parallel)
|
||||
pthread_mutex_unlock(&state->mutex);
|
||||
|
||||
+ bool updated = false;
|
||||
error = restorecon_sb(ent_path, &ent_st, &state->flags,
|
||||
- first);
|
||||
+ first, &updated);
|
||||
|
||||
if (state->parallel) {
|
||||
pthread_mutex_lock(&state->mutex);
|
||||
@@ -1030,6 +1041,8 @@ loop_body:
|
||||
state->skipped_errors++;
|
||||
else
|
||||
state->error = error;
|
||||
+ } else if (updated && state->flags.count_relabeled) {
|
||||
+ state->relabeled_files++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1087,6 +1100,8 @@ static int selinux_restorecon_common(const char *pathname_orig,
|
||||
SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false;
|
||||
state.flags.count_errors = (restorecon_flags &
|
||||
SELINUX_RESTORECON_COUNT_ERRORS) ? true : false;
|
||||
+ state.flags.count_relabeled = (restorecon_flags &
|
||||
+ SELINUX_RESTORECON_COUNT_RELABELED) ? true : false;
|
||||
state.setrestorecondigest = true;
|
||||
|
||||
state.head = NULL;
|
||||
@@ -1094,6 +1109,7 @@ static int selinux_restorecon_common(const char *pathname_orig,
|
||||
state.abort = false;
|
||||
state.error = 0;
|
||||
state.skipped_errors = 0;
|
||||
+ state.relabeled_files = 0;
|
||||
state.saved_errno = 0;
|
||||
|
||||
struct stat sb;
|
||||
@@ -1215,7 +1231,11 @@ static int selinux_restorecon_common(const char *pathname_orig,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- error = restorecon_sb(pathname, &sb, &state.flags, true);
|
||||
+ bool updated = false;
|
||||
+ error = restorecon_sb(pathname, &sb, &state.flags, true, &updated);
|
||||
+ if (updated && state.flags.count_relabeled) {
|
||||
+ state.relabeled_files++;
|
||||
+ }
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1341,6 +1361,7 @@ out:
|
||||
(void) fts_close(state.fts);
|
||||
errno = state.saved_errno;
|
||||
cleanup:
|
||||
+ relabeled_files = state.relabeled_files;
|
||||
if (state.flags.add_assoc) {
|
||||
if (state.flags.verbose)
|
||||
filespec_eval();
|
||||
@@ -1618,3 +1639,8 @@ long unsigned selinux_restorecon_get_skipped_errors(void)
|
||||
{
|
||||
return skipped_errors;
|
||||
}
|
||||
+
|
||||
+long unsigned selinux_restorecon_get_relabeled_files(void)
|
||||
+{
|
||||
+ return relabeled_files;
|
||||
+}
|
||||
diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c
|
||||
index 2c031ccc..07582e7c 100644
|
||||
--- a/policycoreutils/setfiles/restore.c
|
||||
+++ b/policycoreutils/setfiles/restore.c
|
||||
@@ -43,7 +43,7 @@ void restore_init(struct restore_opts *opts)
|
||||
opts->syslog_changes | opts->log_matches |
|
||||
opts->ignore_noent | opts->ignore_mounts |
|
||||
opts->mass_relabel | opts->conflict_error |
|
||||
- opts->count_errors;
|
||||
+ opts->count_errors | opts->count_relabeled;
|
||||
|
||||
/* Use setfiles, restorecon and restorecond own handles */
|
||||
selinux_restorecon_set_sehandle(opts->hnd);
|
||||
@@ -75,7 +75,7 @@ void restore_finish(void)
|
||||
}
|
||||
|
||||
int process_glob(char *name, struct restore_opts *opts, size_t nthreads,
|
||||
- long unsigned *skipped_errors)
|
||||
+ long unsigned *skipped_errors, long unsigned *relabeled_files)
|
||||
{
|
||||
glob_t globbuf;
|
||||
size_t i, len;
|
||||
@@ -99,8 +99,12 @@ 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();
|
||||
+ else {
|
||||
+ if (opts->restorecon_flags & SELINUX_RESTORECON_COUNT_ERRORS)
|
||||
+ *skipped_errors += selinux_restorecon_get_skipped_errors();
|
||||
+ if (opts->restorecon_flags & SELINUX_RESTORECON_COUNT_RELABELED)
|
||||
+ *relabeled_files += selinux_restorecon_get_relabeled_files();
|
||||
+ }
|
||||
}
|
||||
|
||||
globfree(&globbuf);
|
||||
diff --git a/policycoreutils/setfiles/restore.h b/policycoreutils/setfiles/restore.h
|
||||
index 95afb960..36f73059 100644
|
||||
--- a/policycoreutils/setfiles/restore.h
|
||||
+++ b/policycoreutils/setfiles/restore.h
|
||||
@@ -37,6 +37,7 @@ struct restore_opts {
|
||||
unsigned int ignore_mounts;
|
||||
unsigned int conflict_error;
|
||||
unsigned int count_errors;
|
||||
+ unsigned int count_relabeled;
|
||||
/* restorecon_flags holds | of above for restore_init() */
|
||||
unsigned int restorecon_flags;
|
||||
char *rootpath;
|
||||
@@ -52,7 +53,7 @@ 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,
|
||||
- long unsigned *skipped_errors);
|
||||
+ long unsigned *skipped_errors, long unsigned *relabeled_files);
|
||||
extern char **exclude_list;
|
||||
|
||||
#endif
|
||||
diff --git a/policycoreutils/setfiles/restorecon.8 b/policycoreutils/setfiles/restorecon.8
|
||||
index 77dd0542..66b9c800 100644
|
||||
--- a/policycoreutils/setfiles/restorecon.8
|
||||
+++ b/policycoreutils/setfiles/restorecon.8
|
||||
@@ -153,6 +153,9 @@ display warnings about entries that had no matching files by outputting the
|
||||
.BR selabel_stats (3)
|
||||
results.
|
||||
.TP
|
||||
+.B \-c
|
||||
+count and display the number of (would be) relabeled files. The exit code will be set to 0 only if at least one file is relabeled.
|
||||
+.TP
|
||||
.B \-0
|
||||
the separator for the input items is assumed to be the null character
|
||||
(instead of the white space). The quotes and the backslash characters are
|
||||
diff --git a/policycoreutils/setfiles/setfiles.c b/policycoreutils/setfiles/setfiles.c
|
||||
index 31034316..351940f3 100644
|
||||
--- a/policycoreutils/setfiles/setfiles.c
|
||||
+++ b/policycoreutils/setfiles/setfiles.c
|
||||
@@ -35,8 +35,8 @@ static __attribute__((__noreturn__)) void usage(const char *const name)
|
||||
{
|
||||
if (iamrestorecon) {
|
||||
fprintf(stderr,
|
||||
- "usage: %s [-iIDFUmnprRv0xT] [-e excludedir] pathname...\n"
|
||||
- "usage: %s [-iIDFUmnprRv0xT] [-e excludedir] -f filename\n",
|
||||
+ "usage: %s [-ciIDFUmnprRv0xT] [-e excludedir] pathname...\n"
|
||||
+ "usage: %s [-ciIDFUmnprRv0xT] [-e excludedir] -f filename\n",
|
||||
name, name);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
@@ -146,11 +146,12 @@ int main(int argc, char **argv)
|
||||
size_t buf_len, nthreads = 1;
|
||||
const char *base;
|
||||
int errors = 0;
|
||||
- const char *ropts = "e:f:hiIDlmno:pqrsvFURW0xT:";
|
||||
+ const char *ropts = "ce:f:hiIDlmno:pqrsvFURW0xT:";
|
||||
const char *sopts = "c:de:f:hiIDlmno:pqr:svACEFUR:W0T:";
|
||||
const char *opts;
|
||||
union selinux_callback cb;
|
||||
long unsigned skipped_errors;
|
||||
+ long unsigned relabeled_files;
|
||||
|
||||
/* Initialize variables */
|
||||
memset(&r_opts, 0, sizeof(r_opts));
|
||||
@@ -160,6 +161,7 @@ int main(int argc, char **argv)
|
||||
request_digest = 0;
|
||||
policyfile = NULL;
|
||||
skipped_errors = 0;
|
||||
+ relabeled_files = 0;
|
||||
|
||||
if (!argv[0]) {
|
||||
fprintf(stderr, "Called without required program name!\n");
|
||||
@@ -223,7 +225,10 @@ int main(int argc, char **argv)
|
||||
while ((opt = getopt(argc, argv, opts)) > 0) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
- {
|
||||
+ if (iamrestorecon) {
|
||||
+ r_opts.count_relabeled = SELINUX_RESTORECON_COUNT_RELABELED;
|
||||
+ break;
|
||||
+ } else {
|
||||
FILE *policystream;
|
||||
|
||||
policyfile = optarg;
|
||||
@@ -457,14 +462,14 @@ int main(int argc, char **argv)
|
||||
if (!strcmp(buf, "/"))
|
||||
r_opts.mass_relabel = SELINUX_RESTORECON_MASS_RELABEL;
|
||||
errors |= process_glob(buf, &r_opts, nthreads,
|
||||
- &skipped_errors) < 0;
|
||||
+ &skipped_errors, &relabeled_files) < 0;
|
||||
}
|
||||
if (strcmp(input_filename, "-") != 0)
|
||||
fclose(f);
|
||||
} else {
|
||||
for (i = optind; i < argc; i++)
|
||||
errors |= process_glob(argv[i], &r_opts, nthreads,
|
||||
- &skipped_errors) < 0;
|
||||
+ &skipped_errors, &relabeled_files) < 0;
|
||||
}
|
||||
|
||||
if (r_opts.mass_relabel && !r_opts.nochange)
|
||||
@@ -479,5 +484,14 @@ int main(int argc, char **argv)
|
||||
if (r_opts.progress)
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
+ /* Output relabeled file count if requested */
|
||||
+ if (r_opts.count_relabeled) {
|
||||
+ long unsigned relabeled_count = selinux_restorecon_get_relabeled_files();
|
||||
+ printf("Relabeled %lu files\n", relabeled_count);
|
||||
+
|
||||
+ /* Set exit code to 0 if at least one file was relabeled */
|
||||
+ exit(errors ? -1 : relabeled_count ? 0 : 1);
|
||||
+ }
|
||||
+
|
||||
exit(errors ? -1 : skipped_errors ? 1 : 0);
|
||||
}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
* Mon Jan 26 2026 Vit Mojzis <vmojzis@redhat.com> - 3.9-3
|
||||
- restorecon: Add option to count relabeled files (RHEL-94827)
|
||||
|
||||
* Tue Oct 07 2025 Vit Mojzis <vmojzis@redhat.com> - 3.9-2
|
||||
- semanage: Reset active value when deleting boolean customizations (RHEL-111421)
|
||||
- setfiles: Add -A option to disable SELINUX_RESTORECON_ADD_ASSOC (RHEL-111505)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
%global libauditver 3.0
|
||||
%global libsepolver 3.9-1
|
||||
%global libsemanagever 3.9-1
|
||||
%global libselinuxver 3.9-1
|
||||
%global libselinuxver 3.9-4
|
||||
|
||||
%global generatorsdir %{_prefix}/lib/systemd/system-generators
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
Summary: SELinux policy core utilities
|
||||
Name: policycoreutils
|
||||
Version: 3.9
|
||||
Release: 2%{?dist}
|
||||
Release: 3%{?dist}
|
||||
License: GPL-2.0-or-later
|
||||
# https://github.com/SELinuxProject/selinux/wiki/Releases
|
||||
Source0: https://github.com/SELinuxProject/selinux/releases/download/%{version}/selinux-%{version}.tar.gz
|
||||
@ -46,6 +46,8 @@ Patch0005: 0005-python-sepolicy-Fix-spec-file-dependencies.patch
|
||||
Patch0006: 0006-sepolicy-Fix-detection-of-writeable-locations.patch
|
||||
Patch0007: 0007-setfiles-Add-A-option-to-disable-SELINUX_RESTORECON_.patch
|
||||
Patch0008: 0008-semanage-Reset-active-value-when-deleting-boolean-cu.patch
|
||||
Patch0009: 0009-restorecon-Add-option-to-count-relabeled-files.patch
|
||||
# Patch0009 ^^^ needs to also contain diff for libselinux because of updated header files
|
||||
# Patch list end
|
||||
|
||||
Obsoletes: policycoreutils < 2.0.61-2
|
||||
|
||||
Loading…
Reference in New Issue
Block a user