fapolicyd-1.5

Resolves: RHEL-178765
This commit is contained in:
Petr Lautrbach 2026-05-20 21:37:27 +02:00
parent 668fb1b9d4
commit 75bf4a4e40
9 changed files with 15 additions and 420 deletions

4
.gitignore vendored
View File

@ -43,3 +43,7 @@
/fapolicyd-1.4.4.tar.gz.asc
/fapolicyd-1.4.5.tar.gz
/fapolicyd-1.4.5.tar.gz.asc
/fapolicyd-1.5.tar.gz
/fapolicyd-1.5.tar.gz.asc
/fapolicyd-selinux-1.2.tar.gz
/fapolicyd-selinux-1.2.tar.gz.asc

View File

@ -1,28 +0,0 @@
From 58d40adf7e2a9ce3323250b72c1ec96e431ce77a Mon Sep 17 00:00:00 2001
From: Steve Grubb <ausearch.1@gmail.com>
Date: Tue, 31 Mar 2026 15:04:18 -0400
Subject: [PATCH] Add a comment
Content-type: text/plain
---
src/daemon/notify.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/daemon/notify.c b/src/daemon/notify.c
index 195efd331821..c7bb4f82adc0 100644
--- a/src/daemon/notify.c
+++ b/src/daemon/notify.c
@@ -295,7 +295,9 @@ void fanotify_update(mlist *m)
}
}
- // Now remove the deleted mount point
+ // Now remove the deleted mount point - NOTE: the kernel
+ // cleans up the mark itself when umount ran. All we do
+ // here is update the bookkeeping.
if (cur->status == MNT_DELETE) {
msg(LOG_DEBUG, "Deleted %s mount point", safe_path);
temp = cur->next;
--
2.53.0

View File

@ -1,33 +0,0 @@
From 936b9cb962b4c84ebc5375c5acbd149c5a1155f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Fri, 20 Mar 2026 15:22:35 +0100
Subject: [PATCH] Bump maximum length of a configuration file line
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-type: text/plain
This is required for 'ignore_mounts' which can be quite long, depending
on the deployment.
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
---
src/library/daemon-config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/library/daemon-config.c b/src/library/daemon-config.c
index 3d3f50749e04..225ba917fee2 100644
--- a/src/library/daemon-config.c
+++ b/src/library/daemon-config.c
@@ -158,7 +158,7 @@ int load_daemon_config(conf_t *config)
{
int fd, lineno = 1;
FILE *f;
- char buf[160];
+ char buf[8192];
clear_daemon_config(config);
--
2.53.0

View File

@ -1,44 +0,0 @@
From 52a806bac550feae8d6bcbf55d402efb2d73b316 Mon Sep 17 00:00:00 2001
From: Petr Lautrbach <lautrbach@redhat.com>
Date: Fri, 17 Apr 2026 14:17:54 +0200
Subject: [PATCH] Announce sha256hash deprecation only when it's used
Content-type: text/plain
Signed-off-by: Petr Lautrbach <lautrbach@redhat.com>
---
src/library/object-attr.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/library/object-attr.c b/src/library/object-attr.c
index 2b0a69487184..04dc3b03ccb6 100644
--- a/src/library/object-attr.c
+++ b/src/library/object-attr.c
@@ -48,16 +48,17 @@ int obj_name_to_val(const char *name)
{
static bool warned;
- /* Announce deprecation once per start while keeping the alias usable. */
- if (!warned) {
- msg(LOG_NOTICE,
- "SHA256HASH object name is deprecated; use FILE_HASH instead");
- warned = true;
- }
-
// Accept the legacy name for compatibility with older rule sets.
- if (strcmp(name, "sha256hash") == 0)
+ if (strcmp(name, "sha256hash") == 0) {
+ /* Announce deprecation once per start while keeping the alias usable. */
+ if (!warned) {
+ msg(LOG_NOTICE,
+ "sha256hash object name is deprecated; use filehash instead");
+ warned = true;
+ }
+
return FILE_HASH;
+ }
unsigned int i = 0;
while (i < MAX_OBJECTS) {
--
2.53.0

View File

@ -1,53 +0,0 @@
From 2e5487e7f8c257364977b30567120baee5471801 Mon Sep 17 00:00:00 2001
From: Petr Lautrbach <lautrbach@redhat.com>
Date: Mon, 20 Apr 2026 15:34:40 +0200
Subject: [PATCH] Drop unused lineno parameter/variable
Content-type: text/plain
Signed-off-by: Petr Lautrbach <lautrbach@redhat.com>
---
src/cli/fapolicyd-cli.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/src/cli/fapolicyd-cli.c b/src/cli/fapolicyd-cli.c
index a12797729a45..c6251518fcc8 100644
--- a/src/cli/fapolicyd-cli.c
+++ b/src/cli/fapolicyd-cli.c
@@ -128,12 +128,12 @@ struct mount_scan_state {
static struct mount_scan_state scan_state;
-static char *get_line(FILE *f, unsigned *lineno)
+static char *get_line(FILE *f)
{
char *line = NULL;
size_t len = 0;
- while (getline(&line, &len, f) != -1) {
+ if (getline(&line, &len, f) != -1) {
/* remove newline */
char *ptr = strchr(line, 0x0a);
if (ptr)
@@ -442,7 +442,7 @@ static int do_ftype(const char *path)
static int do_list(void)
{
- unsigned count = 1, lineno = 0;
+ unsigned count = 1;
FILE *f = fopen(OLD_RULES_FILE, "rm");
char *buf;
@@ -465,9 +465,8 @@ static int do_list(void)
}
}
- while ((buf = get_line(f, &lineno))) {
+ while ((buf = get_line(f))) {
char *str = buf;
- lineno++;
while (*str) {
if (!isblank(*str))
break;
--
2.53.0

View File

@ -1,194 +0,0 @@
From 45eeeb36b765d5d872154ed1303d851a1b4a8637 Mon Sep 17 00:00:00 2001
From: Petr Lautrbach <lautrbach@redhat.com>
Date: Fri, 17 Apr 2026 12:38:06 +0200
Subject: [PATCH] Add fapolicyd-cli --check-rules option
Content-type: text/plain
`fapolicyd-cli --check-rules path` validates rules file syntax. The new
command parses a rules file and validates its syntax without loading it
into the daemon. Useful for verifying rule files before deployment.
Usage:
$ sudo fapolicyd-cli --check-rules /etc/fapolicyd/compiled.rules
Rules file is valid (12 rules)
$ fapolicyd-cli --check-rules invalid.rules
04/17/26 13:00:09 [ ERROR ]: '=' is missing for field all1, in line 6
04/17/26 13:00:09 [ ERROR ]: Object is missing in line 6
Rule validation failed at line 6
04/17/26 13:00:09 [ ERROR ]: Access permission (open1) is unknown in line 9
Rule validation failed at line 9
04/17/26 13:00:09 [ ERROR ]: Access permission (any2) is unknown in line 12
Rule validation failed at line 12
Signed-off-by: Petr Lautrbach <lautrbach@redhat.com>
---
doc/fapolicyd-cli.8 | 3 ++
init/fapolicyd.bash_completion | 11 ++++-
src/cli/fapolicyd-cli.c | 79 ++++++++++++++++++++++++++++++++++
3 files changed, 92 insertions(+), 1 deletion(-)
diff --git a/doc/fapolicyd-cli.8 b/doc/fapolicyd-cli.8
index c64aa41eb0e5..1cf232f1c6c8 100644
--- a/doc/fapolicyd-cli.8
+++ b/doc/fapolicyd-cli.8
@@ -33,6 +33,9 @@ matching the \fB%languages\fP macro. Any matches are reported and a summary per
mount is displayed. A non-zero status is returned when suspicious files are
found so automated workflows can gate changes.
.TP
+.B \-\-check-rules path
+Parse the rules file and validate its syntax without loading it into the daemon. A zero exit status means the file is valid.
+.TP
.B \-d, \-\-delete-db
Deletes the trust database. Normally this never needs to be done. But if for some reason the trust database becomes corrupted, then the only method of recovery is to run this command.
.TP
diff --git a/init/fapolicyd.bash_completion b/init/fapolicyd.bash_completion
index 43bb7d8efbbf..cbac4e501cdb 100644
--- a/init/fapolicyd.bash_completion
+++ b/init/fapolicyd.bash_completion
@@ -7,7 +7,7 @@ _fapolicydcli()
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
- opts="--check-config --check-path --check-status --check-trustdb \
+ opts="--check-config --check-path --check-rules --check-status --check-trustdb \
--check-watch_fs --check-ignore_mounts --delete-db --dump-db \
--file --filter --ftype --help --list --update --reload-rules \
--test-filter --trust-file --verbose -h -d -D -f -t -l -u -r"
@@ -116,6 +116,15 @@ _fapolicydcli()
fi
return 0
;;
+ --check-rules)
+ if [ -e /usr/share/bash-completion/bash_completion ] ; then
+ _filedir
+ else
+ compopt -o filenames 2>/dev/null
+ COMPREPLY=( $(compgen -f -- ${cur}) )
+ fi
+ return 0
+ ;;
--trust-file)
if [ -e /usr/share/bash-completion/bash_completion ] ; then
_filedir
diff --git a/src/cli/fapolicyd-cli.c b/src/cli/fapolicyd-cli.c
index c6251518fcc8..96c03816b241 100644
--- a/src/cli/fapolicyd-cli.c
+++ b/src/cli/fapolicyd-cli.c
@@ -45,6 +45,7 @@
#include <mntent.h>
#include <libgen.h> // basename
#include "policy.h"
+#include "rules.h"
#include "database.h"
#include "file-cli.h"
#include "file.h"
@@ -69,6 +70,7 @@ static const char *usage =
"--check-trustdb Check the trustdb against files on disk for problems\n"
"--check-watch_fs Check watch_fs against currently mounted file systems\n"
"--check-ignore_mounts [path] Scan ignored mounts for executable content\n"
+"--check-rules path Validate rules file syntax without loading\n"
"--verbose Enable verbose output for select commands\n"
"-d, --delete-db Delete the trust database\n"
"-D, --dump-db Dump the trust database contents\n"
@@ -94,6 +96,7 @@ static struct option long_opts[] =
{"check-trustdb",0, NULL, 3 },
{"check-status",0, NULL, 4 },
{"check-path", 0, NULL, 5 },
+ {"check-rules", 1, NULL, 9 },
{"delete-db", 0, NULL, 'd'},
{"dump-db", 0, NULL, 'D'},
{"file", 1, NULL, 'f'},
@@ -1194,6 +1197,75 @@ finish:
return rc;
}
+static int check_rules_file(const char *path)
+{
+ FILE *f;
+ int rc, lineno = 1, invalid = 0;
+ char *line = NULL;
+ llist temp_rules;
+
+ // Set message mode to stderr so error messages are visible
+ set_message_mode(MSG_STDERR, DBG_NO);
+
+ // Initialize attribute sets (needed for %set parsing)
+ if (init_attr_sets()) {
+ fprintf(stderr, "Failed to initialize attribute sets\n");
+ return CLI_EXIT_INTERNAL;
+ }
+
+ // Open the specified rules file
+ f = fopen(path, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Cannot open rules file %s (%s)\n",
+ path, strerror(errno));
+ destroy_attr_sets();
+ return CLI_EXIT_IO;
+ }
+
+ // Create temporary rules list for validation
+ if (rules_create(&temp_rules)) {
+ fprintf(stderr, "Failed to create rules list\n");
+ fclose(f);
+ destroy_attr_sets();
+ return CLI_EXIT_INTERNAL;
+ }
+
+ // Parse each line (same pattern as _load_rules in policy.c)
+ while ((line = get_line(f))) {
+ rc = rules_append(&temp_rules, line, lineno);
+ if (rc) {
+ fprintf(stderr, "Rule validation failed at line %d\n",
+ lineno);
+ invalid = 1;
+ }
+ free(line);
+ lineno++;
+ }
+
+ if (invalid) {
+ rules_clear(&temp_rules);
+ fclose(f);
+ destroy_attr_sets();
+ return CLI_EXIT_RULE_FILTER;
+ }
+
+ // Check for empty rules file
+ if (temp_rules.cnt == 0) {
+ fprintf(stderr, "No rules found in file\n");
+ rules_clear(&temp_rules);
+ fclose(f);
+ destroy_attr_sets();
+ return CLI_EXIT_RULE_FILTER;
+ }
+
+ printf("Rules file is valid (%u rules)\n", temp_rules.cnt);
+ rules_clear(&temp_rules);
+ fclose(f);
+ destroy_attr_sets();
+
+ return CLI_EXIT_SUCCESS;
+}
+
// Returns 0 = everything is OK, 1 = there is a problem
static int verify_file(const char *path, off_t size, const char *sha,
unsigned int tsource)
@@ -1606,6 +1678,13 @@ int main(int argc, char * const argv[])
}
break;
+ case 9: { // --check-rules
+ if (arg_count > 3)
+ goto args_err;
+ return check_rules_file(optarg);
+ }
+ break;
+
#ifdef HAVE_LIBRPM
case 6: { // --test-filter
if (arg_count > 3)
--
2.53.0

View File

@ -1,55 +0,0 @@
From 796fb575283648e5dea1bafadcba9e19ab5c3ae7 Mon Sep 17 00:00:00 2001
From: Petr Lautrbach <lautrbach@redhat.com>
Date: Fri, 17 Apr 2026 13:48:33 +0200
Subject: [PATCH] fagenrules: Validate new compiled rules
Content-type: text/plain
When `fagenrules` was run with invalid rules it broke `fapolicyd`
startup, see below.
# fapolicyd
04/17/2026 13:52:30 [ INFO ]: Can handle 524288 file descriptors
04/17/2026 13:52:30 [ INFO ]: Ruleset identity: 8b5126cc76e5372274fdf0024d2d13c274a52cda6611f15a577742bbace2dc99
04/17/2026 13:52:30 [ NOTICE ]: SHA256HASH object name is deprecated; use FILE_HASH instead
# killall fapolicyd
# echo 'a b c' > /etc/fapolicyd/rules.d/99.rules
# fagenrules
# fapolicyd
04/17/2026 13:53:35 [ INFO ]: Can handle 524288 file descriptors
04/17/2026 13:53:35 [ INFO ]: Ruleset identity: 308521d067909a4e66a429c5fafaf864cfe4071b00ba40ac24d63f2deb7ef36f
04/17/2026 13:53:35 [ NOTICE ]: SHA256HASH object name is deprecated; use FILE_HASH instead
04/17/2026 13:53:35 [ ERROR ]: Invalid decision (a) in line 15
With this change, `fapolicyd-cli --check-rules` is used before $TmpRules
are renamed to /etc/fapolicyd/compiled.rules in order to prevent this
behaviour.
Signed-off-by: Petr Lautrbach <lautrbach@redhat.com>
---
init/fagenrules | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/init/fagenrules b/init/fagenrules
index 6e5ae180d64b..e1e9270544a3 100644
--- a/init/fagenrules
+++ b/init/fagenrules
@@ -97,6 +97,15 @@ END {
for (i = 0; i < rest; i++) { printf "%s\n", rules[i]; }
}' >> "${TmpRules}"
+fapolicyd-cli --check-rules "${TmpRules}"
+err=$?
+if [ $err -ne 0 ]; then
+ echo "Rules file content:"
+ cat -n "${TmpRules}"
+ rm -f "${TmpRules}"
+ exit $err
+fi
+
# If the same then quit
cmp -s "${TmpRules}" ${DestinationFile} > /dev/null 2>&1
if [ $? -eq 0 ]; then
--
2.53.0

View File

@ -1,11 +1,11 @@
%global selinuxtype targeted
%global moduletype distributed
%define semodule_version 1.1
%define semodule_version 1.2
Summary: Application Whitelisting Daemon
Name: fapolicyd
Version: 1.4.5
Release: 2%{?dist}
Version: 1.5
Release: 1%{?dist}
License: GPL-3.0-or-later
URL: https://github.com/linux-application-whitelisting/fapolicyd
Source0: https://github.com/linux-application-whitelisting/fapolicyd/releases/download/v%{version}/fapolicyd-%{version}.tar.gz
@ -23,12 +23,6 @@ Source20: https://github.com/troydhanson/uthash/archive/refs/tags/v2.3.0.tar.gz#
# $ git format-patch -N --start-number 100 --src-prefix=a/fapolicyd-selinux-1.1/ --dst-prefix=b/fapolicyd-selinux-1.1/ v1.1
# $ for j in [0-9]*.patch; do printf "Patch: %s\n" $j; done
# Patch list start
Patch: 0002-Add-a-comment.patch
Patch: 0003-Bump-maximum-length-of-a-configuration-file-line.patch
Patch: 0004-Announce-sha256hash-deprecation-only-when-it-s-used.patch
Patch: 0005-Drop-unused-lineno-parameter-variable.patch
Patch: 0006-Add-fapolicyd-cli-check-rules-option.patch
Patch: 0007-fagenrules-Validate-new-compiled-rules.patch
# Patch list end
BuildRequires: gcc
@ -283,6 +277,10 @@ fi
%selinux_relabel_post -s %{selinuxtype}
%changelog
* Wed May 20 2026 Petr Lautrbach <lautrbach@redhat.com> - 1.5-1
- fapolicyd-1.5
https://github.com/linux-application-whitelisting/fapolicyd/releases/tag/v1.5
* Wed Apr 22 2026 Petr Lautrbach <lautrbach@redhat.com> - 1.4.5-2
- fagenrules: Validate new compiled rules
- Add fapolicyd-cli --check-rules option

View File

@ -1,5 +1,5 @@
SHA512 (fapolicyd-1.4.5.tar.gz) = 8211ff92947f378aba2882b0fe6b20d72973295f9d10d0d83e18edf6aafa504ac51f49e84506951d0df228524383ca339a1e861bfd00315a3469d6d7d825f109
SHA512 (fapolicyd-1.4.5.tar.gz.asc) = faebf3c23992d72e1a4028e0a14a313e9a3dbfb0932a51206c5223b2949b072cfa7b2cb7ca010ccdf6030a51c595a2dfb346df3390ae846795826b9174a22e13
SHA512 (fapolicyd-selinux-1.1.tar.gz) = 64a7068f8f0a730363e546921ac2eec66a8195d027bacd53f9bf837f55c82d3a667563eb553c6111bc7dfbd90693029577ccefc99dca3d7fe9b7ae5bb61d19bd
SHA512 (fapolicyd-selinux-1.1.tar.gz.asc) = e881e57d07b00143fce97349060b206f9f1706a914206c0cc4fc700318f4497ff362de1faea463f769594a6f6e5e30cfd18667e25146be7f138ff4cb13dbc7b8
SHA512 (fapolicyd-1.5.tar.gz) = d067137369299db080393224fa09249ecd02b2969884bf415f24d3ec4fae8ec05f3a395ec2df23dec25abc4cecd2527d4216f3fc7530fb44f6caa86e0cd9a59e
SHA512 (fapolicyd-1.5.tar.gz.asc) = be981a4f36dd816e9abd955431e0b9aebb78d4fb34e5c94d8a3cad53cd316fac74abd0429aad20ee5c3e7177886aed926b3a70c4045db96ccc76895f4b29e2e4
SHA512 (fapolicyd-selinux-1.2.tar.gz) = 7ec54e0c45328e280a1f56aad5987abd6dc40906c715bfdb2c4860bf65061b1206a97064d2f37c5e16d9913e2a529c915c48d5137c24cff85c133372fe363a2c
SHA512 (fapolicyd-selinux-1.2.tar.gz.asc) = c539ddcf7dda61a3ae1f845e431042cdb7bbd6e9295e0b745eff51f2451a7a2abbd66ccf1794fb699fdf6498161be33da5303b01330fb992d09d48b8ae9e5a60
SHA512 (uthash-2.3.0.tar.gz) = 3b01f1074790fb242900411cb16eb82c1a9afcf58e3196a0f4611d9d7ef94690ad38c0a500e7783d3efa20328aa8d6ab14f246be63b3b3d385502ba2b6b2a294