dcavalca / rpms / rpm

Forked from rpms/rpm a year ago
Clone
James Antill ee2eaf
From c33faabc2d09b9ad8c80b941b6114c1e4c2be80f Mon Sep 17 00:00:00 2001
James Antill ee2eaf
Message-Id: <c33faabc2d09b9ad8c80b941b6114c1e4c2be80f.1612252390.git.pmatilai@redhat.com>
James Antill ee2eaf
From: Radovan Sroka <rsroka@redhat.com>
James Antill ee2eaf
Date: Tue, 27 Oct 2020 16:18:04 +0100
James Antill ee2eaf
Subject: [PATCH] Added fapolicyd rpm plugin
James Antill ee2eaf
James Antill ee2eaf
Fapolicyd (File Access Policy Daemon) implements application whitelisting
James Antill ee2eaf
to decide file access rights. Applications that are known via a reputation
James Antill ee2eaf
source are allowed access while unknown applications are not.
James Antill ee2eaf
James Antill ee2eaf
The rpm plugin allows us to use rpm database as a source of trust.
James Antill ee2eaf
We used dnf plugin since the beggining but it only provides notification
James Antill ee2eaf
when transaction ends. With "integrity checking" requirement we need
James Antill ee2eaf
a continual addition of files which are installed during the system
James Antill ee2eaf
update. With fapolicyd rpm plugin we can allow using of recently
James Antill ee2eaf
added/updated files in scriptlets during rpm transaction.
James Antill ee2eaf
James Antill ee2eaf
The fapolicyd plugin gathers metadata of currently installed files.
James Antill ee2eaf
It sends the information about files and about ongoing rpm transaction
James Antill ee2eaf
to the fapolicyd daemon. The information is written to Linux pipe which
James Antill ee2eaf
is placed in /var/run/fapolicyd/fapolicyd.fifo.
James Antill ee2eaf
James Antill ee2eaf
The data format is "%s %lu %64s\n". [path, size, sha256]
James Antill ee2eaf
James Antill ee2eaf
The fapolicyd rpm plugin can be enabled with "--with-fapolicyd"
James Antill ee2eaf
configure option.
James Antill ee2eaf
James Antill ee2eaf
Related PRs:
James Antill ee2eaf
https://github.com/linux-application-whitelisting/fapolicyd/pull/105
James Antill ee2eaf
https://github.com/linux-application-whitelisting/fapolicyd/pull/106
James Antill ee2eaf
James Antill ee2eaf
Signed-off-by: Radovan Sroka <rsroka@redhat.com>
James Antill ee2eaf
(cherry picked from commit 39595ccee321497dc3b08c7cab8a10304345429c)
James Antill ee2eaf
James Antill ee2eaf
Backported from commit 39595ccee321497dc3b08c7cab8a10304345429c
James Antill ee2eaf
---
James Antill ee2eaf
 Makefile.am                |   1 +
James Antill ee2eaf
 configure.ac               |   8 ++
James Antill ee2eaf
 doc/Makefile.am            |   2 +-
James Antill ee2eaf
 doc/rpm-plugin-fapolicyd.8 |  21 +++++
James Antill ee2eaf
 macros.in                  |   1 +
James Antill ee2eaf
 plugins/Makefile.am        |   6 ++
James Antill ee2eaf
 plugins/fapolicyd.c        | 189 +++++++++++++++++++++++++++++++++++++
James Antill ee2eaf
 7 files changed, 227 insertions(+), 1 deletion(-)
James Antill ee2eaf
 create mode 100644 doc/rpm-plugin-fapolicyd.8
James Antill ee2eaf
 create mode 100644 plugins/fapolicyd.c
James Antill ee2eaf
James Antill ee2eaf
diff --git a/Makefile.am b/Makefile.am
James Antill ee2eaf
index 1f20f05b7..8e92f0cde 100644
James Antill ee2eaf
--- a/Makefile.am
James Antill ee2eaf
+++ b/Makefile.am
James Antill ee2eaf
@@ -16,6 +16,7 @@ DISTCHECK_CONFIGURE_FLAGS = \
James Antill ee2eaf
 	--with-selinux \
James Antill ee2eaf
 	--with-imaevm \
James Antill ee2eaf
 	--with-crypto=openssl \
James Antill ee2eaf
+	--with-fapolicyd \
James Antill ee2eaf
 	--disable-dependency-tracking
James Antill ee2eaf
 
James Antill ee2eaf
 include $(top_srcdir)/rpm.am
James Antill ee2eaf
diff --git a/configure.ac b/configure.ac
James Antill ee2eaf
index 3fcb3ff20..3d0e9ef91 100644
James Antill ee2eaf
--- a/configure.ac
James Antill ee2eaf
+++ b/configure.ac
James Antill ee2eaf
@@ -983,6 +983,14 @@ AS_IF([test "$enable_inhibit_plugin" = yes],[
James Antill ee2eaf
 ])
James Antill ee2eaf
 AM_CONDITIONAL(ENABLE_INHIBIT_PLUGIN,[test "$enable_inhibit_plugin" = yes])
James Antill ee2eaf
 
James Antill ee2eaf
+#=================
James Antill ee2eaf
+# Check for fapolicyd support
James Antill ee2eaf
+AC_ARG_WITH(fapolicyd,
James Antill ee2eaf
+AS_HELP_STRING([--with-fapolicyd],[build with File Access Policy Daemon support]),
James Antill ee2eaf
+with_fapolicyd=$withval,
James Antill ee2eaf
+with_fapolicyd=auto)
James Antill ee2eaf
+AM_CONDITIONAL(FAPOLICYD,[test "$with_fapolicyd" = yes])
James Antill ee2eaf
+
James Antill ee2eaf
 with_dbus=no
James Antill ee2eaf
 AS_IF([test "$enable_plugins" != no],[
James Antill ee2eaf
  AS_IF([test "$enable_inhibit_plugin" != no],[
James Antill ee2eaf
diff --git a/doc/Makefile.am b/doc/Makefile.am
James Antill ee2eaf
index d2f520d64..535ad3ec3 100644
James Antill ee2eaf
--- a/doc/Makefile.am
James Antill ee2eaf
+++ b/doc/Makefile.am
James Antill ee2eaf
@@ -9,7 +9,7 @@ EXTRA_DIST += $(man_man1_DATA)
James Antill ee2eaf
 man_man8dir = $(mandir)/man8
James Antill ee2eaf
 man_man8_DATA = rpm.8 rpm-misc.8 rpmbuild.8 rpmdeps.8 rpmgraph.8 rpm2cpio.8
James Antill ee2eaf
 man_man8_DATA += rpmdb.8 rpmkeys.8 rpmsign.8 rpmspec.8
James Antill ee2eaf
-man_man8_DATA += rpm-plugin-systemd-inhibit.8
James Antill ee2eaf
+man_man8_DATA += rpm-plugin-systemd-inhibit.8 rpm-plugin-fapolicyd.8
James Antill ee2eaf
 EXTRA_DIST += $(man_man8_DATA)
James Antill ee2eaf
 
James Antill ee2eaf
 man_fr_man8dir = $(mandir)/fr/man8
James Antill ee2eaf
diff --git a/doc/rpm-plugin-fapolicyd.8 b/doc/rpm-plugin-fapolicyd.8
James Antill ee2eaf
new file mode 100644
James Antill ee2eaf
index 000000000..fe7a8c78e
James Antill ee2eaf
--- /dev/null
James Antill ee2eaf
+++ b/doc/rpm-plugin-fapolicyd.8
James Antill ee2eaf
@@ -0,0 +1,21 @@
James Antill ee2eaf
+'\" t
James Antill ee2eaf
+.TH "RPM-FAPOLICYD" "8" "28 Jan 2021" "Red Hat, Inc."
James Antill ee2eaf
+.SH NAME
James Antill ee2eaf
+rpm-plugin-fapolicyd \- Fapolicyd plugin for the RPM Package Manager
James Antill ee2eaf
+
James Antill ee2eaf
+.SH Description
James Antill ee2eaf
+
James Antill ee2eaf
+The plugin gathers metadata of currently installed files. It sends the
James Antill ee2eaf
+information about files and about ongoing rpm transaction to the fapolicyd daemon.
James Antill ee2eaf
+The information is written to Linux pipe which is placed in
James Antill ee2eaf
+/var/run/fapolicyd/fapolicyd.fifo.
James Antill ee2eaf
+
James Antill ee2eaf
+.SH Configuration
James Antill ee2eaf
+
James Antill ee2eaf
+There are currently no options for this plugin in particular. See
James Antill ee2eaf
+.BR rpm-plugins (8)
James Antill ee2eaf
+on how to control plugins in general.
James Antill ee2eaf
+
James Antill ee2eaf
+.SH SEE ALSO
James Antill ee2eaf
+.IR fapolicyd (8)
James Antill ee2eaf
+.IR rpm-plugins (8)
James Antill ee2eaf
diff --git a/macros.in b/macros.in
James Antill ee2eaf
index a6069ee4d..2fbda64cc 100644
James Antill ee2eaf
--- a/macros.in
James Antill ee2eaf
+++ b/macros.in
James Antill ee2eaf
@@ -1173,6 +1173,7 @@ package or when debugging this package.\
James Antill ee2eaf
 %__transaction_selinux		%{__plugindir}/selinux.so
James Antill ee2eaf
 %__transaction_syslog		%{__plugindir}/syslog.so
James Antill ee2eaf
 %__transaction_ima		%{__plugindir}/ima.so
James Antill ee2eaf
+%__transaction_fapolicyd	%{__plugindir}/fapolicyd.so
James Antill ee2eaf
 %__transaction_prioreset	%{__plugindir}/prioreset.so
James Antill ee2eaf
 
James Antill ee2eaf
 #------------------------------------------------------------------------------
James Antill ee2eaf
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
James Antill ee2eaf
index ab4eee34f..cbfb81e19 100644
James Antill ee2eaf
--- a/plugins/Makefile.am
James Antill ee2eaf
+++ b/plugins/Makefile.am
James Antill ee2eaf
@@ -42,3 +42,9 @@ ima_la_sources = ima.c
James Antill ee2eaf
 ima_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
James Antill ee2eaf
 plugins_LTLIBRARIES += ima.la
James Antill ee2eaf
 endif
James Antill ee2eaf
+
James Antill ee2eaf
+if FAPOLICYD
James Antill ee2eaf
+fapolicyd_la_sources = fapolicyd.c
James Antill ee2eaf
+fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
James Antill ee2eaf
+plugins_LTLIBRARIES += fapolicyd.la
James Antill ee2eaf
+endif
James Antill ee2eaf
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
James Antill ee2eaf
new file mode 100644
James Antill ee2eaf
index 000000000..50f50155c
James Antill ee2eaf
--- /dev/null
James Antill ee2eaf
+++ b/plugins/fapolicyd.c
James Antill ee2eaf
@@ -0,0 +1,189 @@
James Antill ee2eaf
+#include "system.h"
James Antill ee2eaf
+
James Antill ee2eaf
+#include <rpm/rpmts.h>
James Antill ee2eaf
+#include <rpm/rpmlog.h>
James Antill ee2eaf
+#include "lib/rpmplugin.h"
James Antill ee2eaf
+
James Antill ee2eaf
+#include <fcntl.h>
James Antill ee2eaf
+#include <errno.h>
James Antill ee2eaf
+#include <unistd.h>
James Antill ee2eaf
+#include <sys/stat.h>
James Antill ee2eaf
+
James Antill ee2eaf
+struct fapolicyd_data {
James Antill ee2eaf
+    int fd;
James Antill ee2eaf
+    long changed_files;
James Antill ee2eaf
+    const char * fifo_path;
James Antill ee2eaf
+};
James Antill ee2eaf
+
James Antill ee2eaf
+static struct fapolicyd_data fapolicyd_state = {
James Antill ee2eaf
+    .fd = -1,
James Antill ee2eaf
+    .changed_files = 0,
James Antill ee2eaf
+    .fifo_path = "/run/fapolicyd/fapolicyd.fifo",
James Antill ee2eaf
+};
James Antill ee2eaf
+
James Antill ee2eaf
+static rpmRC open_fifo(struct fapolicyd_data* state)
James Antill ee2eaf
+{
James Antill ee2eaf
+    int fd = -1;
James Antill ee2eaf
+    struct stat s;
James Antill ee2eaf
+
James Antill ee2eaf
+    fd = open(state->fifo_path, O_RDWR);
James Antill ee2eaf
+    if (fd == -1) {
James Antill ee2eaf
+        rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno));
James Antill ee2eaf
+        goto bad;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    if (stat(state->fifo_path, &s) == -1) {
James Antill ee2eaf
+        rpmlog(RPMLOG_DEBUG, "Stat: %s -> %s\n", state->fifo_path, strerror(errno));
James Antill ee2eaf
+        goto bad;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    if (!S_ISFIFO(s.st_mode)) {
James Antill ee2eaf
+        rpmlog(RPMLOG_DEBUG, "File: %s exists but it is not a pipe!\n", state->fifo_path);
James Antill ee2eaf
+        goto bad;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    /* keep only file's permition bits */
James Antill ee2eaf
+    mode_t mode = s.st_mode & ~S_IFMT;
James Antill ee2eaf
+
James Antill ee2eaf
+    /* we require pipe to have 0660 permission */
James Antill ee2eaf
+    if (mode != 0660) {
James Antill ee2eaf
+        rpmlog(RPMLOG_ERR, "File: %s has %o instead of 0660 \n",
James Antill ee2eaf
+               state->fifo_path,
James Antill ee2eaf
+               mode );
James Antill ee2eaf
+        goto bad;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    state->fd = fd;
James Antill ee2eaf
+    /* considering success */
James Antill ee2eaf
+    return RPMRC_OK;
James Antill ee2eaf
+
James Antill ee2eaf
+ bad:
James Antill ee2eaf
+    if (fd > 0)
James Antill ee2eaf
+        close(fd);
James Antill ee2eaf
+    return RPMRC_FAIL;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
James Antill ee2eaf
+{
James Antill ee2eaf
+    ssize_t len = strlen(str);
James Antill ee2eaf
+    ssize_t written = 0;
James Antill ee2eaf
+    ssize_t n = 0;
James Antill ee2eaf
+
James Antill ee2eaf
+    while (written < len) {
James Antill ee2eaf
+        if ((n = write(state->fd, str + written, len - written)) < 0) {
James Antill ee2eaf
+            if (errno == EINTR || errno == EAGAIN)
James Antill ee2eaf
+                continue;
James Antill ee2eaf
+            rpmlog(RPMLOG_DEBUG, "Write: %s -> %s\n", state->fifo_path, strerror(errno));
James Antill ee2eaf
+            goto bad;
James Antill ee2eaf
+        }
James Antill ee2eaf
+        written += n;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    return RPMRC_OK;
James Antill ee2eaf
+
James Antill ee2eaf
+ bad:
James Antill ee2eaf
+    return RPMRC_FAIL;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
James Antill ee2eaf
+{
James Antill ee2eaf
+    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
James Antill ee2eaf
+        goto end;
James Antill ee2eaf
+
James Antill ee2eaf
+    if (!rstreq(rpmtsRootDir(ts), "/"))
James Antill ee2eaf
+        goto end;
James Antill ee2eaf
+
James Antill ee2eaf
+    (void) open_fifo(&fapolicyd_state);
James Antill ee2eaf
+
James Antill ee2eaf
+ end:
James Antill ee2eaf
+    return RPMRC_OK;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+static void fapolicyd_cleanup(rpmPlugin plugin)
James Antill ee2eaf
+{
James Antill ee2eaf
+    if (fapolicyd_state.fd > 0)
James Antill ee2eaf
+        (void) close(fapolicyd_state.fd);
James Antill ee2eaf
+
James Antill ee2eaf
+    fapolicyd_state.fd = -1;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
James Antill ee2eaf
+{
James Antill ee2eaf
+    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
James Antill ee2eaf
+        goto end;
James Antill ee2eaf
+
James Antill ee2eaf
+    /* we are ready */
James Antill ee2eaf
+    if (fapolicyd_state.fd > 0) {
James Antill ee2eaf
+        /* send a signal that transaction is over */
James Antill ee2eaf
+        (void) write_fifo(&fapolicyd_state, "1\n");
James Antill ee2eaf
+        /* flush cache */
James Antill ee2eaf
+        (void) write_fifo(&fapolicyd_state, "2\n");
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+ end:
James Antill ee2eaf
+    return RPMRC_OK;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
James Antill ee2eaf
+                                     int type)
James Antill ee2eaf
+{
James Antill ee2eaf
+    if (fapolicyd_state.fd == -1)
James Antill ee2eaf
+        goto end;
James Antill ee2eaf
+
James Antill ee2eaf
+    if (fapolicyd_state.changed_files > 0) {
James Antill ee2eaf
+        /* send signal to flush cache */
James Antill ee2eaf
+        (void) write_fifo(&fapolicyd_state, "2\n");
James Antill ee2eaf
+
James Antill ee2eaf
+        /* optimize flushing */
James Antill ee2eaf
+        /* flush only when there was an actual change */
James Antill ee2eaf
+        fapolicyd_state.changed_files = 0;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+ end:
James Antill ee2eaf
+    return RPMRC_OK;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
James Antill ee2eaf
+                                        const char *path, const char *dest,
James Antill ee2eaf
+                                        mode_t file_mode, rpmFsmOp op)
James Antill ee2eaf
+{
James Antill ee2eaf
+    /* not ready  */
James Antill ee2eaf
+    if (fapolicyd_state.fd == -1)
James Antill ee2eaf
+        goto end;
James Antill ee2eaf
+
James Antill ee2eaf
+    rpmFileAction action = XFO_ACTION(op);
James Antill ee2eaf
+
James Antill ee2eaf
+    /* Ignore skipped files and unowned directories */
James Antill ee2eaf
+    if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) {
James Antill ee2eaf
+        rpmlog(RPMLOG_DEBUG, "fapolicyd skipping early: path %s dest %s\n",
James Antill ee2eaf
+               path, dest);
James Antill ee2eaf
+        goto end;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    if (!S_ISREG(rpmfiFMode(fi))) {
James Antill ee2eaf
+        rpmlog(RPMLOG_DEBUG, "fapolicyd skipping non regular: path %s dest %s\n",
James Antill ee2eaf
+               path, dest);
James Antill ee2eaf
+        goto end;
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    fapolicyd_state.changed_files++;
James Antill ee2eaf
+
James Antill ee2eaf
+    char buffer[4096];
James Antill ee2eaf
+
James Antill ee2eaf
+    rpm_loff_t size = rpmfiFSize(fi);
James Antill ee2eaf
+    char * sha = rpmfiFDigestHex(fi, NULL);
James Antill ee2eaf
+
James Antill ee2eaf
+    snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
James Antill ee2eaf
+    (void) write_fifo(&fapolicyd_state, buffer);
James Antill ee2eaf
+
James Antill ee2eaf
+ end:
James Antill ee2eaf
+    return RPMRC_OK;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+struct rpmPluginHooks_s fapolicyd_hooks = {
James Antill ee2eaf
+    .init = fapolicyd_init,
James Antill ee2eaf
+    .cleanup = fapolicyd_cleanup,
James Antill ee2eaf
+    .scriptlet_pre = fapolicyd_scriptlet_pre,
James Antill ee2eaf
+    .tsm_post = fapolicyd_tsm_post,
James Antill ee2eaf
+    .fsm_file_prepare = fapolicyd_fsm_file_prepare,
James Antill ee2eaf
+};
James Antill ee2eaf
-- 
James Antill ee2eaf
2.29.2
James Antill ee2eaf
James Antill ee2eaf
commit c66cee32e74ce1e507c031605e3d7b2c1391a52c
James Antill ee2eaf
Author: Radovan Sroka <rsroka@redhat.com>
James Antill ee2eaf
Date:   Wed Feb 10 17:04:55 2021 +0100
James Antill ee2eaf
James Antill ee2eaf
    Fixed issues find by coverity
James Antill ee2eaf
    
James Antill ee2eaf
    - enhance the check for the file descriptor fd because 0 is also a valid
James Antill ee2eaf
    descriptor
James Antill ee2eaf
    
James Antill ee2eaf
    - added free() for sha so it doesn't leak memory for every file that is
James Antill ee2eaf
    processed
James Antill ee2eaf
    
James Antill ee2eaf
    Signed-off-by: Radovan Sroka <rsroka@redhat.com>
James Antill ee2eaf
James Antill ee2eaf
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
James Antill ee2eaf
index 50f50155c..48f65ae11 100644
James Antill ee2eaf
--- a/plugins/fapolicyd.c
James Antill ee2eaf
+++ b/plugins/fapolicyd.c
James Antill ee2eaf
@@ -58,7 +58,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
James Antill ee2eaf
     return RPMRC_OK;
James Antill ee2eaf
 
James Antill ee2eaf
  bad:
James Antill ee2eaf
-    if (fd > 0)
James Antill ee2eaf
+    if (fd >= 0)
James Antill ee2eaf
         close(fd);
James Antill ee2eaf
     return RPMRC_FAIL;
James Antill ee2eaf
 }
James Antill ee2eaf
@@ -176,6 +176,8 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
James Antill ee2eaf
     snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
James Antill ee2eaf
     (void) write_fifo(&fapolicyd_state, buffer);
James Antill ee2eaf
 
James Antill ee2eaf
+    free(sha);
James Antill ee2eaf
+
James Antill ee2eaf
  end:
James Antill ee2eaf
     return RPMRC_OK;
James Antill ee2eaf
 }