813822
commit 39595ccee321497dc3b08c7cab8a10304345429c
813822
Author: Radovan Sroka <rsroka@redhat.com>
813822
Date:   Tue Oct 27 16:18:04 2020 +0100
813822
813822
    Added fapolicyd rpm plugin
813822
    
813822
    Fapolicyd (File Access Policy Daemon) implements application whitelisting
813822
    to decide file access rights. Applications that are known via a reputation
813822
    source are allowed access while unknown applications are not.
813822
    
813822
    The rpm plugin allows us to use rpm database as a source of trust.
813822
    We used dnf plugin since the beggining but it only provides notification
813822
    when transaction ends. With "integrity checking" requirement we need
813822
    a continual addition of files which are installed during the system
813822
    update. With fapolicyd rpm plugin we can allow using of recently
813822
    added/updated files in scriptlets during rpm transaction.
813822
    
813822
    The fapolicyd plugin gathers metadata of currently installed files.
813822
    It sends the information about files and about ongoing rpm transaction
813822
    to the fapolicyd daemon. The information is written to Linux pipe which
813822
    is placed in /var/run/fapolicyd/fapolicyd.fifo.
813822
    
813822
    The data format is "%s %lu %64s\n". [path, size, sha256]
813822
    
813822
    The fapolicyd rpm plugin can be enabled with "--with-fapolicyd"
813822
    configure option.
813822
    
813822
    Related PRs:
813822
    https://github.com/linux-application-whitelisting/fapolicyd/pull/105
813822
    https://github.com/linux-application-whitelisting/fapolicyd/pull/106
813822
    
813822
    Signed-off-by: Radovan Sroka <rsroka@redhat.com>
813822
813822
    Backported into 4.16.1.3, together with commit
813822
    6d61b7118adcc14631b7ee5163a481472af940b8 (covscan fix)
813822
813822
diff -up rpm-4.16.1.3/configure.ac.orig rpm-4.16.1.3/configure.ac
813822
--- rpm-4.16.1.3/configure.ac.orig	2021-03-22 11:05:07.311635968 +0100
813822
+++ rpm-4.16.1.3/configure.ac	2021-07-22 16:18:29.352006782 +0200
813822
@@ -891,6 +891,14 @@ AS_IF([test "$enable_plugins" != no],[
813822
 AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])
813822
 
813822
 #=================
813822
+# Check for fapolicyd support
813822
+AC_ARG_WITH(fapolicyd,
813822
+AS_HELP_STRING([--with-fapolicyd],[build with File Access Policy Daemon support]),
813822
+with_fapolicyd=$withval,
813822
+with_fapolicyd=auto)
813822
+AM_CONDITIONAL(FAPOLICYD,[test "$with_fapolicyd" = yes])
813822
+
813822
+#=================
813822
 # Check for audit library.
813822
 AC_ARG_WITH(audit,
813822
 AS_HELP_STRING([--with-audit],[Linux audit plugin]),
813822
diff -up rpm-4.16.1.3/doc/Makefile.am.orig rpm-4.16.1.3/doc/Makefile.am
813822
--- rpm-4.16.1.3/doc/Makefile.am.orig	2020-06-23 14:13:01.895628382 +0200
813822
+++ rpm-4.16.1.3/doc/Makefile.am	2021-07-22 16:18:29.352006782 +0200
813822
@@ -25,6 +25,9 @@ endif
813822
 if IMA
813822
 man_man8_DATA += rpm-plugin-ima.8
813822
 endif
813822
+if FAPOLICYD
813822
+man_man8_DATA += rpm-plugin-fapolicyd.8
813822
+endif
813822
 if SELINUX
813822
 man_man8_DATA += rpm-plugin-selinux.8
813822
 endif
813822
@@ -37,6 +40,8 @@ endif
813822
 EXTRA_DIST += rpm-plugins.8 rpm-plugin-prioreset.8 rpm-plugin-syslog.8 
813822
 EXTRA_DIST += rpm-plugin-audit.8 rpm-plugin-systemd-inhibit.8 
813822
 EXTRA_DIST += rpm-plugin-ima.8 rpm-plugin-selinux.8 rpm2archive.8
813822
+EXTRA_DIST += rpm-plugin-fapolicyd.8
813822
+
813822
 
813822
 man_fr_man8dir = $(mandir)/fr/man8
813822
 man_fr_man8_DATA = fr/rpm.8
813822
diff -up rpm-4.16.1.3/doc/rpm-plugin-fapolicyd.8.orig rpm-4.16.1.3/doc/rpm-plugin-fapolicyd.8
813822
--- rpm-4.16.1.3/doc/rpm-plugin-fapolicyd.8.orig	2021-07-22 16:18:29.353006800 +0200
813822
+++ rpm-4.16.1.3/doc/rpm-plugin-fapolicyd.8	2021-07-22 16:18:29.353006800 +0200
813822
@@ -0,0 +1,21 @@
813822
+'\" t
813822
+.TH "RPM-FAPOLICYD" "8" "28 Jan 2021" "Red Hat, Inc."
813822
+.SH NAME
813822
+rpm-plugin-fapolicyd \- Fapolicyd plugin for the RPM Package Manager
813822
+
813822
+.SH Description
813822
+
813822
+The plugin gathers metadata of currently installed files. It sends the
813822
+information about files and about ongoing rpm transaction to the fapolicyd daemon.
813822
+The information is written to Linux pipe which is placed in
813822
+/var/run/fapolicyd/fapolicyd.fifo.
813822
+
813822
+.SH Configuration
813822
+
813822
+There are currently no options for this plugin in particular. See
813822
+.BR rpm-plugins (8)
813822
+on how to control plugins in general.
813822
+
813822
+.SH SEE ALSO
813822
+.IR fapolicyd (8)
813822
+.IR rpm-plugins (8)
813822
diff -up rpm-4.16.1.3/macros.in.orig rpm-4.16.1.3/macros.in
813822
--- rpm-4.16.1.3/macros.in.orig	2021-07-22 16:18:20.525844141 +0200
813822
+++ rpm-4.16.1.3/macros.in	2021-07-22 16:19:36.196238525 +0200
813822
@@ -1208,6 +1208,7 @@ package or when debugging this package.\
813822
 %__transaction_selinux		%{__plugindir}/selinux.so
813822
 %__transaction_syslog		%{__plugindir}/syslog.so
813822
 %__transaction_ima		%{__plugindir}/ima.so
813822
+%__transaction_fapolicyd	%{__plugindir}/fapolicyd.so
813822
 %__transaction_prioreset	%{__plugindir}/prioreset.so
813822
 %__transaction_audit		%{__plugindir}/audit.so
813822
 
813822
diff -up rpm-4.16.1.3/Makefile.am.orig rpm-4.16.1.3/Makefile.am
813822
--- rpm-4.16.1.3/Makefile.am.orig	2021-07-22 16:18:29.350006745 +0200
813822
+++ rpm-4.16.1.3/Makefile.am	2021-07-22 16:19:18.223907346 +0200
813822
@@ -14,6 +14,7 @@ DISTCHECK_CONFIGURE_FLAGS = \
813822
 	--with-audit \
813822
 	--with-selinux \
813822
 	--with-imaevm \
813822
+	--with-fapolicyd \
813822
 	--disable-dependency-tracking
813822
 
813822
 include $(top_srcdir)/rpm.am
813822
diff -up rpm-4.16.1.3/plugins/fapolicyd.c.orig rpm-4.16.1.3/plugins/fapolicyd.c
813822
--- rpm-4.16.1.3/plugins/fapolicyd.c.orig	2021-07-22 16:18:29.356006855 +0200
813822
+++ rpm-4.16.1.3/plugins/fapolicyd.c	2021-07-22 16:18:35.380117862 +0200
813822
@@ -0,0 +1,191 @@
813822
+#include "system.h"
813822
+
813822
+#include <rpm/rpmts.h>
813822
+#include <rpm/rpmlog.h>
813822
+#include "lib/rpmplugin.h"
813822
+
813822
+#include <fcntl.h>
813822
+#include <errno.h>
813822
+#include <unistd.h>
813822
+#include <sys/stat.h>
813822
+
813822
+struct fapolicyd_data {
813822
+    int fd;
813822
+    long changed_files;
813822
+    const char * fifo_path;
813822
+};
813822
+
813822
+static struct fapolicyd_data fapolicyd_state = {
813822
+    .fd = -1,
813822
+    .changed_files = 0,
813822
+    .fifo_path = "/run/fapolicyd/fapolicyd.fifo",
813822
+};
813822
+
813822
+static rpmRC open_fifo(struct fapolicyd_data* state)
813822
+{
813822
+    int fd = -1;
813822
+    struct stat s;
813822
+
813822
+    fd = open(state->fifo_path, O_RDWR);
813822
+    if (fd == -1) {
813822
+        rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno));
813822
+        goto bad;
813822
+    }
813822
+
813822
+    if (stat(state->fifo_path, &s) == -1) {
813822
+        rpmlog(RPMLOG_DEBUG, "Stat: %s -> %s\n", state->fifo_path, strerror(errno));
813822
+        goto bad;
813822
+    }
813822
+
813822
+    if (!S_ISFIFO(s.st_mode)) {
813822
+        rpmlog(RPMLOG_DEBUG, "File: %s exists but it is not a pipe!\n", state->fifo_path);
813822
+        goto bad;
813822
+    }
813822
+
813822
+    /* keep only file's permition bits */
813822
+    mode_t mode = s.st_mode & ~S_IFMT;
813822
+
813822
+    /* we require pipe to have 0660 permission */
813822
+    if (mode != 0660) {
813822
+        rpmlog(RPMLOG_ERR, "File: %s has %o instead of 0660 \n",
813822
+               state->fifo_path,
813822
+               mode );
813822
+        goto bad;
813822
+    }
813822
+
813822
+    state->fd = fd;
813822
+    /* considering success */
813822
+    return RPMRC_OK;
813822
+
813822
+ bad:
813822
+    if (fd >= 0)
813822
+        close(fd);
813822
+    return RPMRC_FAIL;
813822
+}
813822
+
813822
+static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
813822
+{
813822
+    ssize_t len = strlen(str);
813822
+    ssize_t written = 0;
813822
+    ssize_t n = 0;
813822
+
813822
+    while (written < len) {
813822
+        if ((n = write(state->fd, str + written, len - written)) < 0) {
813822
+            if (errno == EINTR || errno == EAGAIN)
813822
+                continue;
813822
+            rpmlog(RPMLOG_DEBUG, "Write: %s -> %s\n", state->fifo_path, strerror(errno));
813822
+            goto bad;
813822
+        }
813822
+        written += n;
813822
+    }
813822
+
813822
+    return RPMRC_OK;
813822
+
813822
+ bad:
813822
+    return RPMRC_FAIL;
813822
+}
813822
+
813822
+static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
813822
+{
813822
+    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
813822
+        goto end;
813822
+
813822
+    if (!rstreq(rpmtsRootDir(ts), "/"))
813822
+        goto end;
813822
+
813822
+    (void) open_fifo(&fapolicyd_state);
813822
+
813822
+ end:
813822
+    return RPMRC_OK;
813822
+}
813822
+
813822
+static void fapolicyd_cleanup(rpmPlugin plugin)
813822
+{
813822
+    if (fapolicyd_state.fd > 0)
813822
+        (void) close(fapolicyd_state.fd);
813822
+
813822
+    fapolicyd_state.fd = -1;
813822
+}
813822
+
813822
+static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
813822
+{
813822
+    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
813822
+        goto end;
813822
+
813822
+    /* we are ready */
813822
+    if (fapolicyd_state.fd > 0) {
813822
+        /* send a signal that transaction is over */
813822
+        (void) write_fifo(&fapolicyd_state, "1\n");
813822
+        /* flush cache */
813822
+        (void) write_fifo(&fapolicyd_state, "2\n");
813822
+    }
813822
+
813822
+ end:
813822
+    return RPMRC_OK;
813822
+}
813822
+
813822
+static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
813822
+                                     int type)
813822
+{
813822
+    if (fapolicyd_state.fd == -1)
813822
+        goto end;
813822
+
813822
+    if (fapolicyd_state.changed_files > 0) {
813822
+        /* send signal to flush cache */
813822
+        (void) write_fifo(&fapolicyd_state, "2\n");
813822
+
813822
+        /* optimize flushing */
813822
+        /* flush only when there was an actual change */
813822
+        fapolicyd_state.changed_files = 0;
813822
+    }
813822
+
813822
+ end:
813822
+    return RPMRC_OK;
813822
+}
813822
+
813822
+static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
813822
+                                        const char *path, const char *dest,
813822
+                                        mode_t file_mode, rpmFsmOp op)
813822
+{
813822
+    /* not ready  */
813822
+    if (fapolicyd_state.fd == -1)
813822
+        goto end;
813822
+
813822
+    rpmFileAction action = XFO_ACTION(op);
813822
+
813822
+    /* Ignore skipped files and unowned directories */
813822
+    if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) {
813822
+        rpmlog(RPMLOG_DEBUG, "fapolicyd skipping early: path %s dest %s\n",
813822
+               path, dest);
813822
+        goto end;
813822
+    }
813822
+
813822
+    if (!S_ISREG(rpmfiFMode(fi))) {
813822
+        rpmlog(RPMLOG_DEBUG, "fapolicyd skipping non regular: path %s dest %s\n",
813822
+               path, dest);
813822
+        goto end;
813822
+    }
813822
+
813822
+    fapolicyd_state.changed_files++;
813822
+
813822
+    char buffer[4096];
813822
+
813822
+    rpm_loff_t size = rpmfiFSize(fi);
813822
+    char * sha = rpmfiFDigestHex(fi, NULL);
813822
+
813822
+    snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
813822
+    (void) write_fifo(&fapolicyd_state, buffer);
813822
+
813822
+    free(sha);
813822
+
813822
+ end:
813822
+    return RPMRC_OK;
813822
+}
813822
+
813822
+struct rpmPluginHooks_s fapolicyd_hooks = {
813822
+    .init = fapolicyd_init,
813822
+    .cleanup = fapolicyd_cleanup,
813822
+    .scriptlet_pre = fapolicyd_scriptlet_pre,
813822
+    .tsm_post = fapolicyd_tsm_post,
813822
+    .fsm_file_prepare = fapolicyd_fsm_file_prepare,
813822
+};
813822
diff -up rpm-4.16.1.3/plugins/Makefile.am.orig rpm-4.16.1.3/plugins/Makefile.am
813822
--- rpm-4.16.1.3/plugins/Makefile.am.orig	2021-07-22 16:18:23.022890155 +0200
813822
+++ rpm-4.16.1.3/plugins/Makefile.am	2021-07-22 16:18:55.797494098 +0200
813822
@@ -43,6 +43,12 @@ ima_la_LIBADD = $(top_builddir)/lib/libr
813822
 plugins_LTLIBRARIES += ima.la
813822
 endif
813822
 
813822
+if FAPOLICYD
813822
+fapolicyd_la_sources = fapolicyd.c
813822
+fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
813822
+plugins_LTLIBRARIES += fapolicyd.la
813822
+endif
813822
+
813822
 if AUDIT
813822
 audit_la_sources = audit.c
813822
 audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@