dcavalca / rpms / rpm

Forked from rpms/rpm a year ago
Clone
James Antill ee2eaf
From 820dcc1db9f2130a21fdaf721217034376eb8e38 Mon Sep 17 00:00:00 2001
James Antill ee2eaf
Message-Id: <820dcc1db9f2130a21fdaf721217034376eb8e38.1544785848.git.pmatilai@redhat.com>
James Antill ee2eaf
From: Panu Matilainen <pmatilai@redhat.com>
James Antill ee2eaf
Date: Fri, 30 Nov 2018 13:10:44 +0200
James Antill ee2eaf
Subject: [PATCH] Add support for logging audit events for package installs as
James Antill ee2eaf
 per OSPP v4.2
James Antill ee2eaf
James Antill ee2eaf
If enabled at build-time, log audit events for package install, update
James Antill ee2eaf
and remove. The log includes the operation, package nevra, signature
James Antill ee2eaf
check result, whether signatures are being enforced enforced and overall
James Antill ee2eaf
success result. Package install/update/remove are logged as such,
James Antill ee2eaf
obsoletion is logged as install + remove (whereas the erasure element
James Antill ee2eaf
on updates is silent)
James Antill ee2eaf
James Antill ee2eaf
Loosely based on initial RHEL 7-8 implementations by Pavlina Moravcova
James Antill ee2eaf
Varekova and Florian Festi (RhBug:1555326, RhBug:1607612)
James Antill ee2eaf
James Antill ee2eaf
(cherry picked from commit cfc9dde70fe65e91c83e03e9a9441e627b741489)
James Antill ee2eaf
---
James Antill ee2eaf
 configure.ac         |  21 +++++++++
James Antill ee2eaf
 lib/Makefile.am      |   1 +
James Antill ee2eaf
 lib/rpmte.c          |  11 +++++
James Antill ee2eaf
 lib/rpmte_internal.h |   6 +++
James Antill ee2eaf
 lib/transaction.c    | 104 +++++++++++++++++++++++++++++++++++++++++++
James Antill ee2eaf
 5 files changed, 143 insertions(+)
James Antill ee2eaf
James Antill ee2eaf
diff --git a/configure.ac b/configure.ac
James Antill ee2eaf
index 34ea85f9f..ab8a368d3 100644
James Antill ee2eaf
--- a/configure.ac
James Antill ee2eaf
+++ b/configure.ac
James Antill ee2eaf
@@ -312,6 +312,27 @@ fi
James Antill ee2eaf
 AC_SUBST(WITH_BEECRYPT_LIB)
James Antill ee2eaf
 AC_SUBST(WITH_BEECRYPT_INCLUDE)
James Antill ee2eaf
 
James Antill ee2eaf
+
James Antill ee2eaf
+#=================
James Antill ee2eaf
+# Check for audit library.
James Antill ee2eaf
+AC_ARG_WITH(audit,
James Antill ee2eaf
+AS_HELP_STRING([--with-audit],[log results using Linux Audit]),
James Antill ee2eaf
+with_audit=$withval,
James Antill ee2eaf
+with_audit=auto)
James Antill ee2eaf
+
James Antill ee2eaf
+WITH_AUDIT_LIB=
James Antill ee2eaf
+AS_IF([test "x$with_audit" != xno],[
James Antill ee2eaf
+    AC_SEARCH_LIBS([audit_open],[audit],[
James Antill ee2eaf
+    WITH_AUDIT_LIB="$ac_res"
James Antill ee2eaf
+    AC_DEFINE(WITH_AUDIT, 1, [libaudit support])
James Antill ee2eaf
+    ],
James Antill ee2eaf
+       [if test "x$with_audit" != xauto; then
James Antill ee2eaf
+		AC_MSG_ERROR([missing audit library])
James Antill ee2eaf
+	fi
James Antill ee2eaf
+    ])
James Antill ee2eaf
+])
James Antill ee2eaf
+AC_SUBST(WITH_AUDIT_LIB)
James Antill ee2eaf
+
James Antill ee2eaf
 #=================
James Antill ee2eaf
 # Check for OpenSSL library.
James Antill ee2eaf
 # We need evp.h from OpenSSL.
James Antill ee2eaf
diff --git a/lib/Makefile.am b/lib/Makefile.am
James Antill ee2eaf
index baf3238ee..c055962a3 100644
James Antill ee2eaf
--- a/lib/Makefile.am
James Antill ee2eaf
+++ b/lib/Makefile.am
James Antill ee2eaf
@@ -51,6 +51,7 @@ librpm_la_LIBADD = \
James Antill ee2eaf
 	@WITH_POPT_LIB@ \
James Antill ee2eaf
 	@WITH_CAP_LIB@ \
James Antill ee2eaf
 	@WITH_ACL_LIB@ \
James Antill ee2eaf
+	@WITH_AUDIT_LIB@ \
James Antill ee2eaf
 	@LIBINTL@
James Antill ee2eaf
 
James Antill ee2eaf
 if WITH_LUA
James Antill ee2eaf
diff --git a/lib/rpmte.c b/lib/rpmte.c
James Antill ee2eaf
index d980a37a4..bd5d53edc 100644
James Antill ee2eaf
--- a/lib/rpmte.c
James Antill ee2eaf
+++ b/lib/rpmte.c
James Antill ee2eaf
@@ -69,6 +69,7 @@ struct rpmte_s {
James Antill ee2eaf
     int nrelocs;		/*!< (TR_ADDED) No. of relocations. */
James Antill ee2eaf
     uint8_t *badrelocs;		/*!< (TR_ADDED) Bad relocations (or NULL) */
James Antill ee2eaf
     FD_t fd;			/*!< (TR_ADDED) Payload file descriptor. */
James Antill ee2eaf
+    int verified;		/*!< (TR_ADDED) Verification status */
James Antill ee2eaf
 
James Antill ee2eaf
 #define RPMTE_HAVE_PRETRANS	(1 << 0)
James Antill ee2eaf
 #define RPMTE_HAVE_POSTTRANS	(1 << 1)
James Antill ee2eaf
@@ -753,6 +754,16 @@ rpmfs rpmteGetFileStates(rpmte te)
James Antill ee2eaf
     return te->fs;
James Antill ee2eaf
 }
James Antill ee2eaf
 
James Antill ee2eaf
+void rpmteSetVerified(rpmte te, int verified)
James Antill ee2eaf
+{
James Antill ee2eaf
+    te->verified = verified;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+int rpmteGetVerified(rpmte te)
James Antill ee2eaf
+{
James Antill ee2eaf
+    return te->verified;
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
 int rpmteProcess(rpmte te, pkgGoal goal, int num)
James Antill ee2eaf
 {
James Antill ee2eaf
     /* Only install/erase resets pkg file info */
James Antill ee2eaf
diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h
James Antill ee2eaf
index a5a991ec5..2895925ce 100644
James Antill ee2eaf
--- a/lib/rpmte_internal.h
James Antill ee2eaf
+++ b/lib/rpmte_internal.h
James Antill ee2eaf
@@ -86,6 +86,12 @@ int rpmteHaveTransScript(rpmte te, rpmTagVal tag);
James Antill ee2eaf
 /* XXX should be internal too but build code needs for now... */
James Antill ee2eaf
 rpmfs rpmteGetFileStates(rpmte te);
James Antill ee2eaf
 
James Antill ee2eaf
+RPM_GNUC_INTERNAL
James Antill ee2eaf
+void rpmteSetVerified(rpmte te, int verified);
James Antill ee2eaf
+
James Antill ee2eaf
+RPM_GNUC_INTERNAL
James Antill ee2eaf
+int rpmteGetVerified(rpmte te);
James Antill ee2eaf
+
James Antill ee2eaf
 /** \ingroup rpmte
James Antill ee2eaf
  * Retrieve size in bytes of package header.
James Antill ee2eaf
  * @param te		transaction element
James Antill ee2eaf
diff --git a/lib/transaction.c b/lib/transaction.c
James Antill ee2eaf
index 67b9db579..866e87fc2 100644
James Antill ee2eaf
--- a/lib/transaction.c
James Antill ee2eaf
+++ b/lib/transaction.c
James Antill ee2eaf
@@ -7,6 +7,10 @@
James Antill ee2eaf
 #include <inttypes.h>
James Antill ee2eaf
 #include <libgen.h>
James Antill ee2eaf
 
James Antill ee2eaf
+#if WITH_AUDIT
James Antill ee2eaf
+#include <libaudit.h>
James Antill ee2eaf
+#endif
James Antill ee2eaf
+
James Antill ee2eaf
 #include <rpm/rpmlib.h>		/* rpmMachineScore, rpmReadPackageFile */
James Antill ee2eaf
 #include <rpm/rpmmacro.h>	/* XXX for rpmExpand */
James Antill ee2eaf
 #include <rpm/rpmlog.h>
James Antill ee2eaf
@@ -1195,12 +1199,17 @@ static rpm_loff_t countPkgs(rpmts ts, rpmElementTypes types)
James Antill ee2eaf
 
James Antill ee2eaf
 struct vfydata_s {
James Antill ee2eaf
     char *msg;
James Antill ee2eaf
+    int signature;
James Antill ee2eaf
     int vfylevel;
James Antill ee2eaf
 };
James Antill ee2eaf
 
James Antill ee2eaf
 static int vfyCb(struct rpmsinfo_s *sinfo, void *cbdata)
James Antill ee2eaf
 {
James Antill ee2eaf
     struct vfydata_s *vd = cbdata;
James Antill ee2eaf
+
James Antill ee2eaf
+    if (sinfo->type == RPMSIG_SIGNATURE_TYPE && sinfo->rc == RPMRC_OK)
James Antill ee2eaf
+	vd->signature = RPMRC_OK;
James Antill ee2eaf
+
James Antill ee2eaf
     switch (sinfo->rc) {
James Antill ee2eaf
     case RPMRC_OK:
James Antill ee2eaf
 	break;
James Antill ee2eaf
@@ -1241,6 +1250,7 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)
James Antill ee2eaf
 	struct rpmvs_s *vs = rpmvsCreate(vfylevel, vsflags, keyring);
James Antill ee2eaf
 	struct vfydata_s vd = {
James Antill ee2eaf
 	    .msg = NULL,
James Antill ee2eaf
+	    .signature = RPMRC_NOTFOUND,
James Antill ee2eaf
 	    .vfylevel = vfylevel,
James Antill ee2eaf
 	};
James Antill ee2eaf
 	rpmRC prc = RPMRC_FAIL;
James Antill ee2eaf
@@ -1255,6 +1265,9 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total)
James Antill ee2eaf
 	if (prc == RPMRC_OK)
James Antill ee2eaf
 	    prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd);
James Antill ee2eaf
 
James Antill ee2eaf
+	/* Record verify result, signatures only for now */
James Antill ee2eaf
+	rpmteSetVerified(p, vd.signature == RPMRC_OK);
James Antill ee2eaf
+
James Antill ee2eaf
 	if (prc)
James Antill ee2eaf
 	    rpmteAddProblem(p, RPMPROB_VERIFY, NULL, vd.msg, 0);
James Antill ee2eaf
 
James Antill ee2eaf
@@ -1619,6 +1632,95 @@ rpmRC runScript(rpmts ts, rpmte te, Header h, ARGV_const_t prefixes,
James Antill ee2eaf
     return rc;
James Antill ee2eaf
 }
James Antill ee2eaf
 
James Antill ee2eaf
+#if WITH_AUDIT
James Antill ee2eaf
+struct teop {
James Antill ee2eaf
+    rpmte te;
James Antill ee2eaf
+    const char *op;
James Antill ee2eaf
+};
James Antill ee2eaf
+
James Antill ee2eaf
+/*
James Antill ee2eaf
+ * Figure out the actual operations:
James Antill ee2eaf
+ * Install and remove are straightforward. Updates need to discovered 
James Antill ee2eaf
+ * via their erasure element: locate the updating element, adjust it's
James Antill ee2eaf
+ * op to update and silence the erasure part. Obsoletion is handled as
James Antill ee2eaf
+ * as install + remove, which it technically is.
James Antill ee2eaf
+ */
James Antill ee2eaf
+static void getAuditOps(rpmts ts, struct teop *ops, int nelem)
James Antill ee2eaf
+{
James Antill ee2eaf
+    rpmtsi pi = rpmtsiInit(ts);
James Antill ee2eaf
+    rpmte p;
James Antill ee2eaf
+    int i = 0;
James Antill ee2eaf
+    while ((p = rpmtsiNext(pi, 0)) != NULL) {
James Antill ee2eaf
+	const char *op = NULL;
James Antill ee2eaf
+	if (rpmteType(p) == TR_ADDED) {
James Antill ee2eaf
+	    op = "install";
James Antill ee2eaf
+	} else {
James Antill ee2eaf
+	    op = "remove";
James Antill ee2eaf
+	    rpmte d = rpmteDependsOn(p);
James Antill ee2eaf
+	    /* Fixup op on updating elements, silence the cleanup stage */
James Antill ee2eaf
+	    if (d != NULL && rstreq(rpmteN(d), rpmteN(p))) {
James Antill ee2eaf
+		/* Linear lookup, but we're only dealing with a few thousand */
James Antill ee2eaf
+		for (int x = 0; x < i; x++) {
James Antill ee2eaf
+		    if (ops[x].te == d) {
James Antill ee2eaf
+			ops[x].op = "update";
James Antill ee2eaf
+			op = NULL;
James Antill ee2eaf
+			break;
James Antill ee2eaf
+		    }
James Antill ee2eaf
+		}
James Antill ee2eaf
+	    }
James Antill ee2eaf
+	}
James Antill ee2eaf
+	ops[i].te = p;
James Antill ee2eaf
+	ops[i].op = op;
James Antill ee2eaf
+	i++;
James Antill ee2eaf
+    }
James Antill ee2eaf
+    rpmtsiFree(pi);
James Antill ee2eaf
+}
James Antill ee2eaf
+
James Antill ee2eaf
+/*
James Antill ee2eaf
+ * If enabled, log audit events for the operations in this transaction.
James Antill ee2eaf
+ * In the event values, 1 means true/success and 0 false/failure. Shockingly.
James Antill ee2eaf
+ */
James Antill ee2eaf
+static void rpmtsAudit(rpmts ts)
James Antill ee2eaf
+{
James Antill ee2eaf
+    int auditFd = audit_open();
James Antill ee2eaf
+    if (auditFd < 0)
James Antill ee2eaf
+	return;
James Antill ee2eaf
+
James Antill ee2eaf
+    int nelem = rpmtsNElements(ts);
James Antill ee2eaf
+    struct teop *ops = xcalloc(nelem, sizeof(*ops));
James Antill ee2eaf
+    char *dir = audit_encode_nv_string("root_dir", rpmtsRootDir(ts), 0);
James Antill ee2eaf
+    int enforce = (rpmtsVfyLevel(ts) & RPMSIG_SIGNATURE_TYPE) != 0;
James Antill ee2eaf
+
James Antill ee2eaf
+    getAuditOps(ts, ops, nelem);
James Antill ee2eaf
+
James Antill ee2eaf
+    for (int i = 0; i < nelem; i++) {
James Antill ee2eaf
+	const char *op = ops[i].op;
James Antill ee2eaf
+	if (op) {
James Antill ee2eaf
+	    rpmte p = ops[i].te;
James Antill ee2eaf
+	    char *nevra = audit_encode_nv_string("sw", rpmteNEVRA(p), 0);
James Antill ee2eaf
+	    char eventTxt[256];
James Antill ee2eaf
+	    int verified = rpmteGetVerified(p);
James Antill ee2eaf
+	    int result = (rpmteFailed(p) == 0);
James Antill ee2eaf
+
James Antill ee2eaf
+	    snprintf(eventTxt, sizeof(eventTxt),
James Antill ee2eaf
+		    "op=%s %s sw_type=rpm key_enforce=%u gpg_res=%u %s",
James Antill ee2eaf
+		    op, nevra, enforce, verified, dir);
James Antill ee2eaf
+	    audit_log_user_comm_message(auditFd, AUDIT_SOFTWARE_UPDATE,
James Antill ee2eaf
+				    eventTxt, NULL, NULL, NULL, NULL, result);
James Antill ee2eaf
+	    free(nevra);
James Antill ee2eaf
+	}
James Antill ee2eaf
+    }
James Antill ee2eaf
+
James Antill ee2eaf
+    free(dir);
James Antill ee2eaf
+    free(ops);
James Antill ee2eaf
+    audit_close(auditFd);
James Antill ee2eaf
+}
James Antill ee2eaf
+#else
James Antill ee2eaf
+static void rpmtsAudit(rpmts ts)
James Antill ee2eaf
+{
James Antill ee2eaf
+}
James Antill ee2eaf
+#endif
James Antill ee2eaf
+
James Antill ee2eaf
 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
James Antill ee2eaf
 {
James Antill ee2eaf
     int rc = -1; /* assume failure */
James Antill ee2eaf
@@ -1732,6 +1834,8 @@ exit:
James Antill ee2eaf
 	rpmpluginsCallTsmPost(rpmtsPlugins(ts), ts, rc);
James Antill ee2eaf
 
James Antill ee2eaf
     /* Finish up... */
James Antill ee2eaf
+    if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)))
James Antill ee2eaf
+	rpmtsAudit(ts);
James Antill ee2eaf
     (void) umask(oldmask);
James Antill ee2eaf
     (void) rpmtsFinish(ts);
James Antill ee2eaf
     rpmpsFree(tsprobs);
James Antill ee2eaf
-- 
James Antill ee2eaf
2.19.2
James Antill ee2eaf