|
|
45afda |
From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001
|
|
|
45afda |
From: Jes Sorensen <jsorensen@fb.com>
|
|
|
45afda |
Date: Mon, 20 Apr 2020 11:11:25 -0400
|
|
|
45afda |
Subject: [PATCH 27/33] plugins/fsverity: Install fsverity signatures
|
|
|
45afda |
|
|
|
45afda |
This plugin installs fsverity signatures for regular files, when a signature
|
|
|
45afda |
is found in the RPM. It tries to enable them unconditionally, but fails
|
|
|
45afda |
gracefully if fsverity isn't supported or enabled.
|
|
|
45afda |
|
|
|
45afda |
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
|
|
|
45afda |
---
|
|
|
45afda |
configure.ac | 29 ++++++++
|
|
|
45afda |
macros.in | 4 +
|
|
|
45afda |
plugins/Makefile.am | 7 ++
|
|
|
45afda |
plugins/fsverity.c | 177 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
45afda |
4 files changed, 217 insertions(+)
|
|
|
45afda |
create mode 100644 plugins/fsverity.c
|
|
|
45afda |
|
|
|
45afda |
diff --git a/configure.ac b/configure.ac
|
|
|
45afda |
index cc7144440..7d3c31831 100644
|
|
|
45afda |
--- a/configure.ac
|
|
|
45afda |
+++ b/configure.ac
|
|
|
45afda |
@@ -1049,6 +1049,35 @@ AS_IF([test "$enable_plugins" != no],[
|
|
|
45afda |
])
|
|
|
45afda |
AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])
|
|
|
45afda |
|
|
|
45afda |
+AS_IF([test "$enable_plugins" != no],[
|
|
|
45afda |
+AC_CHECK_HEADERS([linux/fsverity.h],[FSVERITY_IOCTL="yes"])
|
|
|
45afda |
+])
|
|
|
45afda |
+AM_CONDITIONAL(FSVERITY_IOCTL,[test "x$FSVERITY_IOCTL" = xyes])
|
|
|
45afda |
+
|
|
|
45afda |
+#=================
|
|
|
45afda |
+# Check for audit library.
|
|
|
45afda |
+AC_ARG_WITH(audit,
|
|
|
45afda |
+AS_HELP_STRING([--with-audit],[Linux audit plugin]),
|
|
|
45afda |
+with_audit=$withval,
|
|
|
45afda |
+with_audit=auto)
|
|
|
45afda |
+
|
|
|
45afda |
+WITH_AUDIT_LIB=
|
|
|
45afda |
+AS_IF([test "$enable_plugins" != no],[
|
|
|
45afda |
+ AS_IF([test "x$with_audit" != xno],[
|
|
|
45afda |
+ AC_SEARCH_LIBS([audit_open],[audit],[
|
|
|
45afda |
+ WITH_AUDIT_LIB="$ac_res"
|
|
|
45afda |
+ AC_DEFINE(WITH_AUDIT, 1, [libaudit support])
|
|
|
45afda |
+ with_audit=yes
|
|
|
45afda |
+ ],[
|
|
|
45afda |
+ if test "x$with_audit" != xauto; then
|
|
|
45afda |
+ AC_MSG_ERROR([missing audit library])
|
|
|
45afda |
+ fi
|
|
|
45afda |
+ ])
|
|
|
45afda |
+ ])
|
|
|
45afda |
+])
|
|
|
45afda |
+AC_SUBST(WITH_AUDIT_LIB)
|
|
|
45afda |
+AM_CONDITIONAL(AUDIT,[test "$with_audit" = yes])
|
|
|
45afda |
+
|
|
|
45afda |
user_with_uid0=$(awk -F: '$3==0 {print $1;exit}' /etc/passwd)
|
|
|
45afda |
group_with_gid0=$(awk -F: '$3==0 {print $1;exit}' /etc/group)
|
|
|
45afda |
AC_DEFINE_UNQUOTED([UID_0_USER],["$user_with_uid0"],[Get the user name having userid 0])
|
|
|
45afda |
diff --git a/macros.in b/macros.in
|
|
|
45afda |
index fe8862903..3c722146b 100644
|
|
|
45afda |
--- a/macros.in
|
|
|
45afda |
+++ b/macros.in
|
|
|
45afda |
@@ -767,6 +767,9 @@ package or when debugging this package.\
|
|
|
45afda |
# performance for rotational disks)
|
|
|
45afda |
#%_flush_io 0
|
|
|
45afda |
|
|
|
45afda |
+# Set to 1 to have fsverity signatures written for %config files.
|
|
|
45afda |
+#%_fsverity_sign_config_files 0
|
|
|
45afda |
+
|
|
|
45afda |
#
|
|
|
45afda |
# Default output format string for rpm -qa
|
|
|
45afda |
#
|
|
|
45afda |
@@ -1185,6 +1188,7 @@ package or when debugging this package.\
|
|
|
45afda |
%__transaction_syslog %{__plugindir}/syslog.so
|
|
|
45afda |
%__transaction_ima %{__plugindir}/ima.so
|
|
|
45afda |
%__transaction_fapolicyd %{__plugindir}/fapolicyd.so
|
|
|
45afda |
+%__transaction_fsverity %{__plugindir}/fsverity.so
|
|
|
45afda |
%__transaction_prioreset %{__plugindir}/prioreset.so
|
|
|
45afda |
|
|
|
45afda |
#------------------------------------------------------------------------------
|
|
|
45afda |
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
|
|
|
45afda |
index cbfb81e19..e51b71f62 100644
|
|
|
45afda |
--- a/plugins/Makefile.am
|
|
|
45afda |
+++ b/plugins/Makefile.am
|
|
|
45afda |
@@ -48,3 +48,10 @@ fapolicyd_la_sources = fapolicyd.c
|
|
|
45afda |
fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
|
|
|
45afda |
plugins_LTLIBRARIES += fapolicyd.la
|
|
|
45afda |
endif
|
|
|
45afda |
+
|
|
|
45afda |
+if FSVERITY_IOCTL
|
|
|
45afda |
+fsverity_la_sources = fsverity.c
|
|
|
45afda |
+fsverity_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
|
|
|
45afda |
+plugins_LTLIBRARIES += fsverity.la
|
|
|
45afda |
+endif
|
|
|
45afda |
+
|
|
|
45afda |
diff --git a/plugins/fsverity.c b/plugins/fsverity.c
|
|
|
45afda |
new file mode 100644
|
|
|
45afda |
index 000000000..15ddcf33e
|
|
|
45afda |
--- /dev/null
|
|
|
45afda |
+++ b/plugins/fsverity.c
|
|
|
45afda |
@@ -0,0 +1,177 @@
|
|
|
45afda |
+/**
|
|
|
45afda |
+ * Copyright (C) 2020 Facebook
|
|
|
45afda |
+ *
|
|
|
45afda |
+ * Author: Jes Sorensen <jsorensen@fb.com>
|
|
|
45afda |
+ */
|
|
|
45afda |
+
|
|
|
45afda |
+#include "system.h"
|
|
|
45afda |
+
|
|
|
45afda |
+#include <errno.h>
|
|
|
45afda |
+#include <fcntl.h>
|
|
|
45afda |
+#include <sys/ioctl.h>
|
|
|
45afda |
+#include <linux/fsverity.h>
|
|
|
45afda |
+
|
|
|
45afda |
+#include <rpm/rpmfi.h>
|
|
|
45afda |
+#include <rpm/rpmte.h>
|
|
|
45afda |
+#include <rpm/rpmfiles.h>
|
|
|
45afda |
+#include <rpm/rpmtypes.h>
|
|
|
45afda |
+#include <rpm/rpmlog.h>
|
|
|
45afda |
+#include <rpmio/rpmstring.h>
|
|
|
45afda |
+#include <rpmio/rpmmacro.h>
|
|
|
45afda |
+
|
|
|
45afda |
+#include "lib/rpmfs.h"
|
|
|
45afda |
+#include "lib/rpmplugin.h"
|
|
|
45afda |
+#include "lib/rpmte_internal.h"
|
|
|
45afda |
+
|
|
|
45afda |
+#include "sign/rpmsignverity.h"
|
|
|
45afda |
+
|
|
|
45afda |
+static int sign_config_files = 0;
|
|
|
45afda |
+
|
|
|
45afda |
+/*
|
|
|
45afda |
+ * This unconditionally tries to apply the fsverity signature to a file,
|
|
|
45afda |
+ * but fails gracefully if the file system doesn't support it or the
|
|
|
45afda |
+ * verity feature flag isn't enabled in the file system (ext4).
|
|
|
45afda |
+ */
|
|
|
45afda |
+static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
|
|
|
45afda |
+ const char *path, const char *dest,
|
|
|
45afda |
+ mode_t file_mode, rpmFsmOp op)
|
|
|
45afda |
+{
|
|
|
45afda |
+ struct fsverity_enable_arg arg;
|
|
|
45afda |
+ const unsigned char * signature = NULL;
|
|
|
45afda |
+ size_t len;
|
|
|
45afda |
+ int rc = RPMRC_OK;
|
|
|
45afda |
+ int fd;
|
|
|
45afda |
+ rpmFileAction action = XFO_ACTION(op);
|
|
|
45afda |
+ char *buffer;
|
|
|
45afda |
+
|
|
|
45afda |
+ /* Ignore skipped files and unowned directories */
|
|
|
45afda |
+ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) {
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity skipping early: path %s dest %s\n",
|
|
|
45afda |
+ path, dest);
|
|
|
45afda |
+ goto exit;
|
|
|
45afda |
+ }
|
|
|
45afda |
+
|
|
|
45afda |
+ /*
|
|
|
45afda |
+ * Do not install signatures for config files unless the
|
|
|
45afda |
+ * user explicitly asks for it.
|
|
|
45afda |
+ */
|
|
|
45afda |
+ if (rpmfiFFlags(fi) & RPMFILE_CONFIG) {
|
|
|
45afda |
+ if (!(rpmfiFMode(fi) & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
|
|
|
45afda |
+ !sign_config_files) {
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity skipping: path %s dest %s\n",
|
|
|
45afda |
+ path, dest);
|
|
|
45afda |
+
|
|
|
45afda |
+ goto exit;
|
|
|
45afda |
+ }
|
|
|
45afda |
+ }
|
|
|
45afda |
+
|
|
|
45afda |
+ /*
|
|
|
45afda |
+ * Right now fsverity doesn't deal with symlinks or directories, so do
|
|
|
45afda |
+ * not try to install signatures for non regular files.
|
|
|
45afda |
+ */
|
|
|
45afda |
+ if (!S_ISREG(rpmfiFMode(fi))) {
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity skipping non regular: path %s dest %s\n",
|
|
|
45afda |
+ path, dest);
|
|
|
45afda |
+ goto exit;
|
|
|
45afda |
+ }
|
|
|
45afda |
+
|
|
|
45afda |
+ signature = rpmfiVSignature(fi, &len;;
|
|
|
45afda |
+ if (!signature || !len) {
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n",
|
|
|
45afda |
+ path, dest);
|
|
|
45afda |
+ goto exit;
|
|
|
45afda |
+ }
|
|
|
45afda |
+
|
|
|
45afda |
+ memset(&arg, 0, sizeof(arg));
|
|
|
45afda |
+ arg.version = 1;
|
|
|
45afda |
+ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
|
|
|
45afda |
+ arg.block_size = RPM_FSVERITY_BLKSZ;
|
|
|
45afda |
+ arg.sig_ptr = (uintptr_t)signature;
|
|
|
45afda |
+ arg.sig_size = len;
|
|
|
45afda |
+
|
|
|
45afda |
+ buffer = pgpHexStr(signature, arg.sig_size);
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "applying signature: %s\n", buffer);
|
|
|
45afda |
+ free(buffer);
|
|
|
45afda |
+
|
|
|
45afda |
+ fd = open(path, O_RDONLY);
|
|
|
45afda |
+ if (fd < 0) {
|
|
|
45afda |
+ rpmlog(RPMLOG_ERR, "failed to open path %s\n", path);
|
|
|
45afda |
+ goto exit;
|
|
|
45afda |
+ }
|
|
|
45afda |
+
|
|
|
45afda |
+ /*
|
|
|
45afda |
+ * Enable fsverity on the file.
|
|
|
45afda |
+ * fsverity not supported by file system (ENOTTY) and fsverity not
|
|
|
45afda |
+ * enabled on file system are expected and not considered
|
|
|
45afda |
+ * errors. Every other non-zero error code will result in the
|
|
|
45afda |
+ * installation failing.
|
|
|
45afda |
+ */
|
|
|
45afda |
+ if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) != 0) {
|
|
|
45afda |
+ switch(errno) {
|
|
|
45afda |
+ case EBADMSG:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "invalid or malformed fsverity signature for %s\n", path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case EEXIST:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity signature already enabled %s\n",
|
|
|
45afda |
+ path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case EINVAL:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "invalid arguments for ioctl %s\n", path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case EKEYREJECTED:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "signature doesn't match file %s\n", path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case EMSGSIZE:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "invalid signature size for %s\n", path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case ENOPKG:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "unsupported signature algoritm (%i) for %s\n",
|
|
|
45afda |
+ arg.hash_algorithm, path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case ETXTBSY:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "file is open by other process %s\n",
|
|
|
45afda |
+ path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case ENOTTY:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity not supported by file system for %s\n",
|
|
|
45afda |
+ path);
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ case EOPNOTSUPP:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity not enabled on file system for %s\n",
|
|
|
45afda |
+ path);
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ default:
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "failed to enable verity (errno %i) for %s\n",
|
|
|
45afda |
+ errno, path);
|
|
|
45afda |
+ rc = RPMRC_FAIL;
|
|
|
45afda |
+ break;
|
|
|
45afda |
+ }
|
|
|
45afda |
+ }
|
|
|
45afda |
+
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity enabled signature for: path %s dest %s\n",
|
|
|
45afda |
+ path, dest);
|
|
|
45afda |
+ close(fd);
|
|
|
45afda |
+exit:
|
|
|
45afda |
+ return rc;
|
|
|
45afda |
+}
|
|
|
45afda |
+
|
|
|
45afda |
+static rpmRC fsverity_init(rpmPlugin plugin, rpmts ts)
|
|
|
45afda |
+{
|
|
|
45afda |
+ sign_config_files = rpmExpandNumeric("%{?_fsverity_sign_config_files}");
|
|
|
45afda |
+
|
|
|
45afda |
+ rpmlog(RPMLOG_DEBUG, "fsverity_init\n");
|
|
|
45afda |
+
|
|
|
45afda |
+ return RPMRC_OK;
|
|
|
45afda |
+}
|
|
|
45afda |
+
|
|
|
45afda |
+struct rpmPluginHooks_s fsverity_hooks = {
|
|
|
45afda |
+ .init = fsverity_init,
|
|
|
45afda |
+ .fsm_file_prepare = fsverity_fsm_file_prepare,
|
|
|
45afda |
+};
|
|
|
45afda |
--
|
|
|
45afda |
2.27.0
|
|
|
45afda |
|