Skip to content

Commit

Permalink
Fix for rpmdb with SQLite3 backend
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
radosroka committed Oct 27, 2024
1 parent 9df179e commit 23fef4c
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 1 deletion.
4 changes: 4 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions m4/rpm_path.m4
Original file line number Diff line number Diff line change
@@ -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])
])
25 changes: 24 additions & 1 deletion src/library/policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}


Expand Down
95 changes: 95 additions & 0 deletions src/library/rpm-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
*/

#include "config.h"
#include <stdatomic.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <unistd.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>
#include <rpm/rpmmacro.h>
Expand All @@ -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",
Expand All @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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;

Expand All @@ -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;
}

0 comments on commit 23fef4c

Please sign in to comment.