From 3dbf4735ddc4f4fc9c5c9ecc0be86c03dd84002f Mon Sep 17 00:00:00 2001 From: Radovan Sroka Date: Fri, 28 Mar 2025 08:43:45 +0100 Subject: [PATCH] RHEL 9.7.0 ERRATUM - RPMDB crashes with SIGBUS when updating the RPMDB repeatedly Resolves: RHEL-63090 - File /run/fapolicyd differs from RPM expectations Resolves: RHEL-59626 - fapolicyd.service badly instructs how to start after nss-user-lookup.target Resolves: RHEL-21871 - fapolicy rule containing 'pattern=normal' produces error Resolves: RHEL-30020 Signed-off-by: Radovan Sroka --- fapolicyd-normal-pattern.patch | 27 +++ fapolicyd-nss-lookup.patch | 26 +++ fapolicyd-rpm-loader.patch | 309 +++++++++++++++++++++++++++++ fapolicyd-rpm-v.patch | 34 ++++ fapolicyd-sync-update-thread.patch | 81 ++++++++ fapolicyd.spec | 25 ++- 6 files changed, 501 insertions(+), 1 deletion(-) create mode 100644 fapolicyd-normal-pattern.patch create mode 100644 fapolicyd-nss-lookup.patch create mode 100644 fapolicyd-rpm-loader.patch create mode 100644 fapolicyd-rpm-v.patch create mode 100644 fapolicyd-sync-update-thread.patch diff --git a/fapolicyd-normal-pattern.patch b/fapolicyd-normal-pattern.patch new file mode 100644 index 0000000..59b4723 --- /dev/null +++ b/fapolicyd-normal-pattern.patch @@ -0,0 +1,27 @@ +From 0b42573e129c8c095536e15b326fe76b87da2601 Mon Sep 17 00:00:00 2001 +From: Radovan Sroka +Date: Fri, 28 Feb 2025 18:02:16 +0100 +Subject: [PATCH] Fix normal pattern handling + +Signed-off-by: Radovan Sroka +--- + src/library/rules.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/library/rules.c b/src/library/rules.c +index 849a6c39..7f8fc7f5 100644 +--- a/src/library/rules.c ++++ b/src/library/rules.c +@@ -406,9 +406,10 @@ static int assign_subject(lnode *n, int type, const char *ptr2, int lineno) + goto free_and_error; + } + +- if (strcmp(tmp, +- PATTERN_LD_SO_STR) == 0) { ++ if (strcmp(tmp, PATTERN_LD_SO_STR) == 0) { + n->s[i].val = PATTERN_LD_SO_VAL; ++ } else if (strcmp(tmp, PATTERN_NORMAL_STR) == 0) { ++ n->s[i].val = PATTERN_NORMAL_VAL; + } else if (strcmp(tmp, PATTERN_STATIC_STR) == 0) { + n->s[i].val = PATTERN_STATIC_VAL; + } else if (strcmp(tmp, PATTERN_LD_PRELOAD_STR) == 0) { diff --git a/fapolicyd-nss-lookup.patch b/fapolicyd-nss-lookup.patch new file mode 100644 index 0000000..1e4ed5b --- /dev/null +++ b/fapolicyd-nss-lookup.patch @@ -0,0 +1,26 @@ +diff --git a/init/fapolicyd.service b/init/fapolicyd.service +index 7eb2841a..a1b7da90 100644 +--- a/init/fapolicyd.service ++++ b/init/fapolicyd.service +@@ -1,6 +1,12 @@ ++# You should manage this file with systemctl edit utility and not manually ++ + [Unit] + Description=File Access Policy Daemon + DefaultDependencies=no ++# If rules need user/group lookup, create a drop-in to delay the startup after NSS lookup is available: ++# # mkdir -p /etc/systemd/system/fapolicyd.service.d ++# # echo -e "[Unit]\nAfter=nss-user-lookup.target local-fs.target systemd-tmpfiles-setup.service" > /etc/systemd/system/fapolicyd.service.d/nss-lookup.conf ++# # systemctl daemon-reload + After=local-fs.target systemd-tmpfiles-setup.service + Documentation=man:fapolicyd(8) + +@@ -12,8 +18,6 @@ PIDFile=/run/fapolicyd.pid + ExecStartPre=/usr/sbin/fagenrules + ExecStart=/usr/sbin/fapolicyd + Restart=on-abnormal +-# Uncomment the following line if rules need user/group name lookup +-#After=nss-user-lookup.target + + [Install] + WantedBy=multi-user.target diff --git a/fapolicyd-rpm-loader.patch b/fapolicyd-rpm-loader.patch new file mode 100644 index 0000000..d55397d --- /dev/null +++ b/fapolicyd-rpm-loader.patch @@ -0,0 +1,309 @@ +diff -up ./fapolicyd.spec.rpm-loader ./fapolicyd.spec +--- ./fapolicyd.spec.rpm-loader 2024-04-29 17:59:11.000000000 +0200 ++++ ./fapolicyd.spec 2025-05-18 20:11:39.722717947 +0200 +@@ -268,6 +268,7 @@ fi + %attr(644,root,root) %{_tmpfilesdir}/%{name}.conf + %attr(755,root,root) %{_sbindir}/%{name} + %attr(755,root,root) %{_sbindir}/%{name}-cli ++%attr(755,root,root) %{_sbindir}/%{name}-rpm-loader + %attr(755,root,root) %{_sbindir}/fagenrules + %attr(644,root,root) %{_mandir}/man8/* + %attr(644,root,root) %{_mandir}/man5/* +diff -up ./src/daemon/fapolicyd.c.rpm-loader ./src/daemon/fapolicyd.c +--- ./src/daemon/fapolicyd.c.rpm-loader 2025-05-18 20:11:39.721683468 +0200 ++++ ./src/daemon/fapolicyd.c 2025-05-18 20:11:39.722858226 +0200 +@@ -105,17 +105,19 @@ static void install_syscall_filter(void) + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + goto err_out; +- ++#ifndef USE_RPM + rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), + SCMP_SYS(execve), 0); + if (rc < 0) + goto err_out; +-#ifdef HAVE_FEXECVE +-# ifdef __NR_fexecve ++ ++# ifdef HAVE_FEXECVE ++# ifdef __NR_fexecve + rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), + SCMP_SYS(fexecve), 0); + if (rc < 0) + goto err_out; ++# endif + # endif + #endif + rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EIO), +diff -up ./src/handler/fapolicyd-rpm-loader.c.rpm-loader ./src/handler/fapolicyd-rpm-loader.c +--- ./src/handler/fapolicyd-rpm-loader.c.rpm-loader 2025-05-18 20:11:39.722986504 +0200 ++++ ./src/handler/fapolicyd-rpm-loader.c 2025-05-18 20:13:48.417481732 +0200 +@@ -0,0 +1,85 @@ ++/* ++ * fapolicy-rpm-loader.c - loader tool for fapolicyd ++ * Copyright (c) 2025-2025 Red Hat Inc. ++ * All Rights Reserved. ++ * ++ * This software may be freely redistributed and/or modified under the ++ * terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2, or (at your option) any ++ * later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; see the file COPYING. If not, write to the ++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor ++ * Boston, MA 02110-1335, USA. ++ * ++ * Authors: ++ * Radovan Sroka ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "backend-manager.h" ++#include "daemon-config.h" ++#include "message.h" ++#include "llist.h" ++#include "fd-fgets.h" ++#include "paths.h" ++ ++volatile atomic_bool stop = 0; // Library needs this ++unsigned int debug_mode = 0; // Library needs this ++unsigned int permissive = 0; // Library needs this ++ ++ ++int do_rpm_init_backend(void); ++int do_rpm_load_list(conf_t * conf); ++int do_rpm_destroy_backend(void); ++ ++extern backend rpm_backend; ++ ++int main(int argc, char * const argv[]) ++{ ++ ++ set_message_mode(MSG_STDERR, DBG_YES); ++ ++ conf_t config; ++ ++ load_daemon_config(&config); ++ ++ do_rpm_init_backend(); ++ do_rpm_load_list(&config); ++ ++ msg(LOG_INFO, "Loaded files %ld", rpm_backend.list.count); ++ ++ list_item_t *item = list_get_first(&rpm_backend.list); ++ for (; item != NULL; item = item->next) { ++ printf("%s %s\n", (const char*)item->index, (const char*)item->data); ++ } ++ ++ do_rpm_destroy_backend(); ++ ++ free_daemon_config(&config); ++ return 0; ++} ++ +diff -up ./src/library/rpm-backend.c.rpm-loader ./src/library/rpm-backend.c +--- ./src/library/rpm-backend.c.rpm-loader 2025-05-18 20:11:39.718862697 +0200 ++++ ./src/library/rpm-backend.c 2025-05-18 20:11:39.723077584 +0200 +@@ -23,8 +23,11 @@ + */ + + #include "config.h" ++#include + #include + #include ++#include ++#include + #include + #include + #include +@@ -37,11 +40,16 @@ + + #include "message.h" + #include "gcc-attributes.h" ++#include "fd-fgets.h" + #include "fapolicyd-backend.h" + #include "llist.h" + + #include "filter.h" + ++int do_rpm_init_backend(void); ++int do_rpm_load_list(const conf_t *); ++int do_rpm_destroy_backend(void); ++ + static int rpm_init_backend(void); + static int rpm_load_list(const conf_t *); + static int rpm_destroy_backend(void); +@@ -183,9 +191,104 @@ struct _hash_record { + UT_hash_handle hh; + }; + +-extern unsigned int debug_mode; ++#define BUFFER_SIZE 4096 ++#define MAX_DELIMS 3 + static int rpm_load_list(const conf_t *conf) + { ++ int pipefd[2]; ++ if (pipe(pipefd) == -1) { ++ perror("pipe failed"); ++ return 1; ++ } ++ // we well read stdout later ++ // there will be data from rpmdb ++ posix_spawn_file_actions_t actions; ++ posix_spawn_file_actions_init(&actions); ++ posix_spawn_file_actions_addclose(&actions, pipefd[0]); ++ posix_spawn_file_actions_adddup2(&actions, pipefd[1], STDOUT_FILENO); ++ posix_spawn_file_actions_addclose(&actions, pipefd[1]); ++ ++ char *argv[] = { NULL }; ++ char *custom_env[] = { NULL }; ++ ++ pid_t pid = -1; ++ // int status = posix_spawn(&pid, "/home/rsroka/Work/fapolicyd-upstream-fork2/src/fapolicyd-rpm-loader", &actions, NULL, argv, custom_env); ++ int status = posix_spawn(&pid, "/usr/sbin/fapolicyd-rpm-loader", &actions, NULL, argv, custom_env); ++ ++ ++ close(pipefd[1]); // Parent doesn't write ++ ++ if (status == 0) { ++ msg(LOG_DEBUG, "fapolicyd-rpm-loader spawned with pid: %d", pid); ++ ++ char buff[BUFFER_SIZE]; ++ fd_fgets_context_t * fd_fgets_context = fd_fgets_init(); ++ do { ++ fd_fgets_rewind(fd_fgets_context); ++ int res = fd_fgets(fd_fgets_context, buff, sizeof(buff), pipefd[0]); ++ if (res == -1) ++ break; ++ else if (res > 0) { ++ char* end = strchr(buff, '\n'); ++ ++ if (end == NULL) { ++ msg(LOG_ERR, "Too long line?"); ++ continue; ++ } ++ ++ int size = end - buff; ++ *end = '\0'; ++ ++ // it's better to parse it from the end because there can be space in file name ++ int delims = 0; ++ char * delim = NULL; ++ for (int i = size-1 ; i >= 0 ; i--) { ++ if (isspace(buff[i])) { ++ delim = &buff[i]; ++ delims++; ++ } ++ ++ if (delims >= MAX_DELIMS) { ++ buff[i] = '\0'; ++ break; ++ } ++ } ++ ++ char * index = strdup(buff); ++ char * data = strdup(delim + 1); ++ if (!index || !data) { ++ free(index); ++ free(data); ++ continue; ++ } ++ ++ list_append(&rpm_backend.list, index, data); ++ } ++ } while(!fd_fgets_eof(fd_fgets_context)); ++ ++ fd_fgets_destroy(fd_fgets_context); ++ ++ close(pipefd[0]); ++ waitpid(pid, NULL, 0); ++ ++ } else { ++ msg(LOG_ERR, "posix_spawn failed: %s\n", strerror(status)); ++ } ++ ++ posix_spawn_file_actions_destroy(&actions); ++ ++ if (rpm_backend.list.count == 0) { ++ msg(LOG_DEBUG, "Recieved 0 files from rpmdb loader"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++// this function is used in fapolicyd-rpm-loader ++extern unsigned int debug_mode; ++int do_rpm_load_list(const conf_t *conf) ++{ + int rc; + unsigned int msg_count = 0; + +@@ -298,6 +401,14 @@ static int rpm_load_list(const conf_t *c + + static int rpm_init_backend(void) + { ++ list_init(&rpm_backend.list); ++ ++ return 0; ++} ++ ++// this function is used in fapolicyd-rpm-loader ++int do_rpm_init_backend(void) ++{ + if (filter_init()) + return 1; + +@@ -318,3 +429,10 @@ static int rpm_destroy_backend(void) + list_empty(&rpm_backend.list); + return 0; + } ++ ++// this function is used in fapolicyd-rpm-loader ++int do_rpm_destroy_backend(void) ++{ ++ list_empty(&rpm_backend.list); ++ return 0; ++} +diff -up ./src/Makefile.am.rpm-loader ./src/Makefile.am +--- ./src/Makefile.am.rpm-loader 2025-05-18 20:11:39.718965116 +0200 ++++ ./src/Makefile.am 2025-05-18 20:11:39.723185202 +0200 +@@ -75,6 +75,15 @@ libfapolicyd_la_SOURCES += \ + library/filter.c \ + library/filter.h + ++sbin_PROGRAMS += fapolicyd-rpm-loader ++ ++fapolicyd_rpm_loader_SOURCES = \ ++ handler/fapolicyd-rpm-loader.c ++ ++fapolicyd_rpm_loader_CFLAGS = $(fapolicyd_CFLAGS) ++fapolicyd_rpm_loader_LDFLAGS = $(fapolicyd_LDFLAGS) ++ ++fapolicyd_rpm_loader_LDADD = libfapolicyd.la + endif + + if WITH_DEB diff --git a/fapolicyd-rpm-v.patch b/fapolicyd-rpm-v.patch new file mode 100644 index 0000000..78fb1d7 --- /dev/null +++ b/fapolicyd-rpm-v.patch @@ -0,0 +1,34 @@ +From 686096c400587d5f28e041c4ebb58e07e4d7b3fc Mon Sep 17 00:00:00 2001 +From: Radovan Sroka +Date: Wed, 20 Nov 2024 14:30:14 +0100 +Subject: [PATCH] Fix creation of RUN_DIR because it breaks rpm verify + +Signed-off-by: Radovan Sroka +--- + src/library/database.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/src/library/database.c b/src/library/database.c +index 44dd0b2b..d89b16c1 100644 +--- a/src/library/database.c ++++ b/src/library/database.c +@@ -122,6 +122,19 @@ int preconstruct_fifo(const conf_t *config) + strerror_r(errno, err_buff, BUFFER_SIZE)); + return 1; + } else { ++ ++ if ((chmod(RUN_DIR, 0770))) { ++ msg(LOG_ERR, "Failed to fix mode of dir %s (%s)", ++ RUN_DIR, strerror_r(errno, err_buff, BUFFER_SIZE)); ++ return 1; ++ } ++ ++ if ((chown(RUN_DIR, 0, config->gid))) { ++ msg(LOG_ERR, "Failed to fix ownership of dir %s (%s)", ++ RUN_DIR, strerror_r(errno, err_buff, BUFFER_SIZE)); ++ return 1; ++ } ++ + /* Make sure that there is no such file/fifo */ + unlink_fifo(); + } diff --git a/fapolicyd-sync-update-thread.patch b/fapolicyd-sync-update-thread.patch new file mode 100644 index 0000000..47b9b72 --- /dev/null +++ b/fapolicyd-sync-update-thread.patch @@ -0,0 +1,81 @@ +diff -up ./src/daemon/fapolicyd.c.sync-update ./src/daemon/fapolicyd.c +--- ./src/daemon/fapolicyd.c.sync-update 2024-04-29 17:27:41.000000000 +0200 ++++ ./src/daemon/fapolicyd.c 2025-04-21 13:35:21.751343832 +0200 +@@ -66,7 +66,11 @@ + unsigned int debug_mode = 0, permissive = 0; + + // Signal handler notifications +-volatile atomic_bool stop = false, hup = false, run_stats = false; ++volatile atomic_bool try_to_stop = false, stop = false; ++volatile atomic_bool hup = false, run_stats = false; ++ ++extern volatile atomic_bool update_thread_loop; ++extern volatile atomic_bool update_thread_stop; + + // Local variables + static conf_t config; +@@ -214,7 +218,7 @@ static void init_fs_list(const char *wat + + static void term_handler(int sig __attribute__((unused))) + { +- stop = true; ++ try_to_stop = true; + } + + +@@ -667,7 +672,7 @@ int main(int argc, const char *argv[]) + msg(LOG_DEBUG, "Got SIGHUP"); + reconfigure(); + } +- rc = poll(pfd, 2, -1); ++ rc = poll(pfd, 2, 1000); + + #ifdef DEBUG + msg(LOG_DEBUG, "Main poll interrupted"); +@@ -699,7 +704,15 @@ int main(int argc, const char *argv[]) + sigaction(SIGINT, &sa, NULL); + #endif + } ++ ++ if (try_to_stop) ++ update_thread_stop = true; ++ ++ if (try_to_stop && !update_thread_loop) ++ stop = true; ++ + } ++ + msg(LOG_INFO, "shutting down..."); + shutdown_fanotify(m); + close(pfd[0].fd); +diff -up ./src/library/database.c.sync-update ./src/library/database.c +--- ./src/library/database.c.sync-update 2025-04-21 13:34:57.479790359 +0200 ++++ ./src/library/database.c 2025-04-21 13:34:57.480928947 +0200 +@@ -70,6 +70,9 @@ static struct pollfd ffd[1] = { {0, 0, + static integrity_t integrity; + static atomic_int reload_db = 0; + ++volatile atomic_bool update_thread_loop = false; ++volatile atomic_bool update_thread_stop = false; ++ + static pthread_t update_thread; + static pthread_mutex_t update_lock; + static pthread_mutex_t rule_lock; +@@ -1283,7 +1286,8 @@ static void *update_thread_main(void *ar + fcntl(ffd[0].fd, F_SETFL, O_NONBLOCK); + ffd[0].events = POLLIN; + +- while (!stop) { ++ update_thread_loop = true; ++ while (!update_thread_stop) { + + rc = poll(ffd, 1, 1000); + +@@ -1407,6 +1411,7 @@ static void *update_thread_main(void *ar + } + + finalize: ++ update_thread_loop = false; + close(ffd[0].fd); + unlink_fifo(); + diff --git a/fapolicyd.spec b/fapolicyd.spec index 40ec347..28d19ee 100644 --- a/fapolicyd.spec +++ b/fapolicyd.spec @@ -5,7 +5,7 @@ Summary: Application Whitelisting Daemon Name: fapolicyd Version: 1.3.3 -Release: 100%{?dist} +Release: 102%{?dist} License: GPLv3+ URL: http://people.redhat.com/sgrubb/fapolicyd Source0: https://people.redhat.com/sgrubb/fapolicyd/%{name}-%{version}.tar.gz @@ -33,6 +33,11 @@ Requires(postun): systemd-units Patch1: fapolicyd-uthash-bundle.patch Patch2: selinux.patch Patch3: var-run-selinux.patch +Patch4: fapolicyd-rpm-v.patch +Patch5: fapolicyd-nss-lookup.patch +Patch6: fapolicyd-normal-pattern.patch +Patch7: fapolicyd-sync-update-thread.patch +Patch8: fapolicyd-rpm-loader.patch %description Fapolicyd (File Access Policy Daemon) implements application whitelisting @@ -68,6 +73,12 @@ The %{name}-selinux package contains selinux policy for the %{name} daemon. %patch -P 2 -p1 -b .selinux %patch -P 3 -p1 -R -b .var-run-selinux +%patch -P 4 -p1 -b .rpm-v +%patch -P 5 -p1 -b .nss-lookup +%patch -P 6 -p1 -b .normal-pattern + +%patch -P 7 -p1 -b .sync-update +%patch -P 8 -p1 -b .rpm-loader # generate rules for python sed -i "s|%python2_path%|`readlink -f %{__python2}`|g" rules.d/*.rules @@ -223,6 +234,7 @@ fi %ghost %attr(644,root,%{name}) %{_sysconfdir}/%{name}/compiled.rules %attr(644,root,root) %{_unitdir}/%{name}.service %attr(644,root,root) %{_tmpfilesdir}/%{name}.conf +%attr(755,root,root) %{_sbindir}/%{name}-rpm-loader %attr(755,root,root) %{_sbindir}/%{name} %attr(755,root,root) %{_sbindir}/%{name}-cli %attr(755,root,root) %{_sbindir}/fagenrules @@ -254,6 +266,17 @@ fi %selinux_relabel_post -s %{selinuxtype} %changelog +* Wed May 28 2025 Radovan Sroka - 1.3.3-102 +RHEL 9.7.0 ERRATUM +- RPMDB crashes with SIGBUS when updating the RPMDB repeatedly +Resolves: RHEL-63090 +- File /run/fapolicyd differs from RPM expectations +Resolves: RHEL-59626 +- fapolicyd.service badly instructs how to start after nss-user-lookup.target +Resolves: RHEL-21871 +- fapolicy rule containing 'pattern=normal' produces error +Resolves: RHEL-30020 + * Wed Jul 19 2023 Radovan Sroka - 1.3.3-100 RHEL 9.5.0 ERRATUM - rebase to fapolicyd-1.3.3 and fapolicyd-selinux-0.7