From: Vit Mojzis <vmojzis@redhat.com>
To: selinux@vger.kernel.org
Subject: [PATCH] restorecon: Add option to count number of relabeled files
Date: Mon, 10 Nov 2025 19:05:50 +0100 [thread overview]
Message-ID: <20251110180935.202229-1-vmojzis@redhat.com> (raw)
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 where relabeled).
Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
---
libselinux/include/selinux/restorecon.h | 9 +++++++++
libselinux/src/libselinux.map | 1 +
libselinux/src/selinux_restorecon.c | 14 ++++++++++++++
policycoreutils/setfiles/restore.h | 1 +
policycoreutils/setfiles/restorecon.8 | 3 +++
policycoreutils/setfiles/setfiles.c | 24 ++++++++++++++++++++----
6 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h
index 0ccf73a6..736481bb 100644
--- a/libselinux/include/selinux/restorecon.h
+++ b/libselinux/include/selinux/restorecon.h
@@ -228,6 +228,15 @@ 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(3) or selinux_restorecon_parallel(3) was called,
+ * 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..f21e089e 100644
--- a/libselinux/src/libselinux.map
+++ b/libselinux/src/libselinux.map
@@ -244,6 +244,7 @@ LIBSELINUX_1.0 {
LIBSELINUX_3.4 {
global:
selinux_restorecon_get_skipped_errors;
+ selinux_restorecon_get_relabeled_files;
selinux_restorecon_parallel;
} LIBSELINUX_1.0;
diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index 681c69db..6e9a159e 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;
@@ -796,6 +799,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
syslog(LOG_INFO, "labeling %s to %s\n",
pathname, newcon);
}
+
+ /* Count relabeled files (or would be relabeled if "nochange" was not set) */
+ relabeled_files++;
+
}
out:
@@ -1096,6 +1103,8 @@ static int selinux_restorecon_common(const char *pathname_orig,
state.skipped_errors = 0;
state.saved_errno = 0;
+ relabeled_files = 0;
+
struct stat sb;
char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
char *paths[2] = { NULL, NULL };
@@ -1618,3 +1627,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.h b/policycoreutils/setfiles/restore.h
index 95afb960..7c949c1c 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;
diff --git a/policycoreutils/setfiles/restorecon.8 b/policycoreutils/setfiles/restorecon.8
index 1134420e..e9bd16b6 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 the number of relabeled files (capped at 254).
+.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..6323f56c 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,7 +146,7 @@ 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;
@@ -223,7 +223,10 @@ int main(int argc, char **argv)
while ((opt = getopt(argc, argv, opts)) > 0) {
switch (opt) {
case 'c':
- {
+ if (iamrestorecon) {
+ r_opts.count_relabeled = 1;
+ break;
+ } else {
FILE *policystream;
policyfile = optarg;
@@ -479,5 +482,18 @@ 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 number of relabeled files (capped at 254) */
+ if (errors) {
+ exit(-1);
+ } else {
+ exit(relabeled_count > 254 ? 254 : (int)relabeled_count);
+ }
+ }
+
exit(errors ? -1 : skipped_errors ? 1 : 0);
}
--
2.51.0
next reply other threads:[~2025-11-10 18:09 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-10 18:05 Vit Mojzis [this message]
2025-11-10 20:21 ` [PATCH] restorecon: Add option to count number of relabeled files Stephen Smalley
2025-11-10 20:23 ` William Roberts
2025-11-10 20:37 ` William Roberts
2025-11-11 14:44 ` Daniel Burgener
[not found] ` <CAFftDdoTR5ae1qORSjPuOj5ea1O15qtgrRiadhTp2HMh926swg@mail.gmail.com>
2025-11-13 0:43 ` William Roberts
2025-11-13 17:11 ` [PATCH v2] restorecon: Add option to count " Vit Mojzis
2025-11-13 20:17 ` William Roberts
2025-11-18 8:59 ` Petr Lautrbach
2025-11-18 20:11 ` [PATCH v3] " Vit Mojzis
2025-11-13 17:35 ` [PATCH] restorecon: Add option to count number of " Daniel Burgener
2025-11-13 19:29 ` William Roberts
2025-11-13 19:32 ` Daniel Burgener
2025-11-13 19:39 ` William Roberts
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251110180935.202229-1-vmojzis@redhat.com \
--to=vmojzis@redhat.com \
--cc=selinux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).