From aa0f3efd6c13c912e57b94c1649b0dc0afb7d694 Mon Sep 17 00:00:00 2001 From: Radovan Sroka Date: Wed, 23 Oct 2024 17:50:09 +0200 Subject: [PATCH] Fix for rpmdb with SQLite3 backend When the daemon is reloading the trustdb, and the rpmdb file is concurrently processed as an object, the file descriptor is closed at the end of evaluation. A close() on the SQLite database file causes the locks to be dropped. As a result, subsequent RPM installations can corrupt the RPM database when fapolicyd is running. Signed-off-by: Radovan Sroka --- configure.ac | 4 ++ m4/rpm_path.m4 | 6 +++ src/library/policy.c | 25 ++++++++++- src/library/rpm-backend.c | 95 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 m4/rpm_path.m4 diff --git a/configure.ac b/configure.ac index 7279dc78..d0b99f19 100644 --- a/configure.ac +++ b/configure.ac @@ -177,6 +177,10 @@ AC_CHECK_LIB(lmdb, mdb_env_create, , [AC_MSG_ERROR([liblmdb not found])], -llmdb LD_SO_PATH +if test x$use_rpm = xyes ; then +RPMDB_PATH +fi + AC_CONFIG_FILES([Makefile src/Makefile src/tests/Makefile init/Makefile doc/Makefile rules.d/Makefile]) AC_OUTPUT diff --git a/m4/rpm_path.m4 b/m4/rpm_path.m4 new file mode 100644 index 00000000..3ff46625 --- /dev/null +++ b/m4/rpm_path.m4 @@ -0,0 +1,6 @@ +AC_DEFUN([RPMDB_PATH], +[ + xpath=`rpm --eval '%_dbpath'` + echo "rpmdb path is.....$xpath" + AC_DEFINE_UNQUOTED(RPM_DB_PATH, ["$xpath"], [rpmdb path]) +]) diff --git a/src/library/policy.c b/src/library/policy.c index 09433c26..a3515611 100644 --- a/src/library/policy.c +++ b/src/library/policy.c @@ -562,10 +562,15 @@ static int test_info_api(int fd) } #endif +#ifdef USE_RPM +int push_fd_to_buffer(int); +extern volatile atomic_bool ongoing_rpm_operation; +extern const char *rpm_dir_path; +extern ssize_t rpm_dir_path_len; +#endif void reply_event(int fd, const struct fanotify_event_metadata *metadata, unsigned reply, event_t *e) { - close(metadata->fd); #ifdef FAN_AUDIT_RULE_NUM static int use_new = 2; if (use_new == 2) @@ -604,6 +609,24 @@ void reply_event(int fd, const struct fanotify_event_metadata *metadata, response.fd = metadata->fd; response.response = reply; write(fd, &response, sizeof(struct fanotify_response)); + +#ifdef USE_RPM + if (ongoing_rpm_operation) { + + object_attr_t *obj; + char *path = NULL; + if (e && (obj = get_obj_attr(e, PATH))) { + path = obj->o; + } + + if (path && !strncmp(path, rpm_dir_path, rpm_dir_path_len)) { + if(push_fd_to_buffer(metadata->fd)) + close(metadata->fd); + return; // no close for now + } + } +#endif + close(metadata->fd); } diff --git a/src/library/rpm-backend.c b/src/library/rpm-backend.c index 86e6da5d..be2584f9 100644 --- a/src/library/rpm-backend.c +++ b/src/library/rpm-backend.c @@ -23,8 +23,12 @@ */ #include "config.h" +#include #include +#include #include +#include +#include #include #include #include @@ -46,6 +50,8 @@ static int rpm_init_backend(void); static int rpm_load_list(const conf_t *); static int rpm_destroy_backend(void); +volatile atomic_bool ongoing_rpm_operation = 0; + backend rpm_backend = { "rpmdb", @@ -56,6 +62,75 @@ backend rpm_backend = { 0, 0, NULL }, }; +#ifdef RPM_DB_PATH +const char *rpm_dir_path = RPM_DB_PATH; +#else +const char *rpm_dir_path = "/usr/lib/sysimage/rpm"; +#endif +ssize_t rpm_dir_path_len = -1; + + +static size_t fd_buffer_size = 0; +static size_t fd_buffer_pos = 0; +static int *fd_buffer = NULL; + +#define MIN_BUFFER_SIZE 512 +static int init_fd_buffer(void) { + struct rlimit limit; + getrlimit(RLIMIT_NOFILE, &limit); + + fd_buffer_size = limit.rlim_cur / 4; + if (fd_buffer_size < MIN_BUFFER_SIZE) + fd_buffer_size = MIN_BUFFER_SIZE; + + fd_buffer = malloc(fd_buffer_size * sizeof(int)); + if (!fd_buffer) + return 1; + + for(size_t i = 0 ; i < fd_buffer_size; i++) + fd_buffer[i] = -1; + + msg(LOG_DEBUG, "FD buffer size set to: %ld", fd_buffer_size); + return 0; +} + +int push_fd_to_buffer(int fd) { + + if (!fd_buffer) { + msg(LOG_ERR, "FD buffer already freed!"); + return 1; + } + if (fd_buffer_pos < fd_buffer_size) { + msg(LOG_DEBUG, "Pushing to FD buffer(%ld), ocupancy: %ld", fd_buffer_size, fd_buffer_pos); + fd_buffer[fd_buffer_pos++] = fd; + return 0; + } + + msg(LOG_ERR, "FD buffer full"); + return 1; +} + +static void close_fds_in_buffer(void) { + if (fd_buffer_pos) + msg(LOG_DEBUG, "Closing FDs from buffer, size: %ld", fd_buffer_pos); + for (size_t i = 0 ; i < fd_buffer_pos ; i++) { + close(fd_buffer[i]); + fd_buffer[i] = -1; + } + + fd_buffer_pos = 0; +} + +static void destroy_fd_buffer(void) { + + if (!fd_buffer) + return; + + free(fd_buffer); + fd_buffer = NULL; + fd_buffer_size = -1; +} + static rpmts ts = NULL; static rpmdbMatchIterator mi = NULL; @@ -196,6 +271,8 @@ static int rpm_load_list(const conf_t *conf) // hash table struct _hash_record *hashtable = NULL; + ongoing_rpm_operation = 1; + msg(LOG_INFO, "Loading rpmdb backend"); if ((rc = init_rpm())) { msg(LOG_ERR, "init_rpm() failed (%d)", rc); @@ -285,6 +362,9 @@ static int rpm_load_list(const conf_t *conf) close_rpm(); + ongoing_rpm_operation = 0; + close_fds_in_buffer(); + // cleaning up struct _hash_record *item, *tmp; HASH_ITER( hh, hashtable, item, tmp) { @@ -298,6 +378,15 @@ static int rpm_load_list(const conf_t *conf) static int rpm_init_backend(void) { + if (rpm_dir_path_len == -1) { + rpm_dir_path_len = strlen(rpm_dir_path); + + if(init_fd_buffer()) { + + return 1; + } + } + if (filter_init()) return 1; @@ -312,9 +401,15 @@ static int rpm_init_backend(void) return 0; } + +extern volatile atomic_bool stop; static int rpm_destroy_backend(void) { filter_destroy(); list_empty(&rpm_backend.list); + // for sure + close_fds_in_buffer(); + if (stop) + destroy_fd_buffer(); return 0; }