Add plugin for logging audit events for package operations as per OSPP v4.2
When enabled, log audit events for package install, update and remove. The log includes the operation, package nevra, signature check result, whether signatures are being enforced enforced and overall operation result code. Package install/update/remove are logged as such, obsoletion is logged as install + remove (whereas the erasure element on updates is silent). Enable compilation in CI. Loosely based on initial RHEL 7-8 implementations by Pavlina Moravcova Varekova and Florian Festi (RhBug:1555326, RhBug:1607612)
This commit is contained in:
parent
eecd3d5d05
commit
ad16a04b6e
|
@ -30,6 +30,7 @@ RUN dnf -y install \
|
|||
ima-evm-utils \
|
||||
libcap-devel \
|
||||
libacl-devel \
|
||||
audit-libs-devel \
|
||||
lua-devel readline-devel \
|
||||
python3-devel \
|
||||
dbus-devel \
|
||||
|
@ -48,6 +49,7 @@ RUN ./configure \
|
|||
--with-cap \
|
||||
--with-acl \
|
||||
--with-lua \
|
||||
--with-audit \
|
||||
--enable-python \
|
||||
--enable-silent-rules
|
||||
RUN make
|
||||
|
|
24
configure.ac
24
configure.ac
|
@ -970,6 +970,30 @@ AS_IF([test "$enable_plugins" != no],[
|
|||
])
|
||||
AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])
|
||||
|
||||
#=================
|
||||
# Check for audit library.
|
||||
AC_ARG_WITH(audit,
|
||||
AS_HELP_STRING([--with-audit],[Linux audit plugin]),
|
||||
with_audit=$withval,
|
||||
with_audit=auto)
|
||||
|
||||
WITH_AUDIT_LIB=
|
||||
AS_IF([test "$enable_plugins" != no],[
|
||||
AS_IF([test "x$with_audit" != xno],[
|
||||
AC_SEARCH_LIBS([audit_open],[audit],[
|
||||
WITH_AUDIT_LIB="$ac_res"
|
||||
AC_DEFINE(WITH_AUDIT, 1, [libaudit support])
|
||||
with_audit=yes
|
||||
],[
|
||||
if test "x$with_audit" != xauto; then
|
||||
AC_MSG_ERROR([missing audit library])
|
||||
fi
|
||||
])
|
||||
])
|
||||
])
|
||||
AC_SUBST(WITH_AUDIT_LIB)
|
||||
AM_CONDITIONAL(AUDIT,[test "$with_audit" = yes])
|
||||
|
||||
with_dmalloc=no
|
||||
AC_ARG_WITH(dmalloc, [AS_HELP_STRING([--with-dmalloc],[build with dmalloc debugging support])])
|
||||
if test "$with_dmalloc" = yes ; then
|
||||
|
|
|
@ -1145,6 +1145,7 @@ package or when debugging this package.\
|
|||
%__transaction_syslog %{__plugindir}/syslog.so
|
||||
%__transaction_ima %{__plugindir}/ima.so
|
||||
%__transaction_prioreset %{__plugindir}/prioreset.so
|
||||
%__transaction_audit %{__plugindir}/audit.so
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Macros for further automated spec %setup and patch application
|
||||
|
|
|
@ -42,3 +42,9 @@ ima_la_sources = ima.c
|
|||
ima_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
|
||||
plugins_LTLIBRARIES += ima.la
|
||||
endif
|
||||
|
||||
if AUDIT
|
||||
audit_la_sources = audit.c
|
||||
audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@
|
||||
plugins_LTLIBRARIES += audit.la
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
#include "system.h"
|
||||
|
||||
#include <libaudit.h>
|
||||
|
||||
#include <rpm/rpmts.h>
|
||||
#include "lib/rpmplugin.h"
|
||||
|
||||
struct teop {
|
||||
rpmte te;
|
||||
const char *op;
|
||||
};
|
||||
|
||||
/*
|
||||
* Figure out the actual operations:
|
||||
* Install and remove are straightforward. Updates need to be discovered
|
||||
* via their erasure element: locate the updating element, adjust it's
|
||||
* op to update and silence the erasure part. Obsoletion is handled as
|
||||
* as install + remove, which it technically is.
|
||||
*/
|
||||
static void getAuditOps(rpmts ts, struct teop *ops, int nelem)
|
||||
{
|
||||
rpmtsi pi = rpmtsiInit(ts);
|
||||
rpmte p;
|
||||
int i = 0;
|
||||
while ((p = rpmtsiNext(pi, 0)) != NULL) {
|
||||
const char *op = NULL;
|
||||
if (rpmteType(p) == TR_ADDED) {
|
||||
op = "install";
|
||||
} else {
|
||||
op = "remove";
|
||||
rpmte d = rpmteDependsOn(p);
|
||||
/* Fixup op on updating elements, silence the cleanup stage */
|
||||
if (d != NULL && rstreq(rpmteN(d), rpmteN(p))) {
|
||||
/* Linear lookup, but we're only dealing with a few thousand */
|
||||
for (int x = 0; x < i; x++) {
|
||||
if (ops[x].te == d) {
|
||||
ops[x].op = "update";
|
||||
op = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ops[i].te = p;
|
||||
ops[i].op = op;
|
||||
i++;
|
||||
}
|
||||
rpmtsiFree(pi);
|
||||
}
|
||||
|
||||
/*
|
||||
* If enabled, log audit events for the operations in this transaction.
|
||||
* In the event values, 1 means true/success and 0 false/failure. Shockingly.
|
||||
*/
|
||||
static rpmRC audit_tsm_post(rpmPlugin plugin, rpmts ts, int res)
|
||||
{
|
||||
if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
|
||||
goto exit;
|
||||
|
||||
int auditFd = audit_open();
|
||||
if (auditFd < 0)
|
||||
goto exit;
|
||||
|
||||
int nelem = rpmtsNElements(ts);
|
||||
struct teop *ops = xcalloc(nelem, sizeof(*ops));
|
||||
char *dir = audit_encode_nv_string("root_dir", rpmtsRootDir(ts), 0);
|
||||
int enforce = (rpmtsVfyLevel(ts) & RPMSIG_SIGNATURE_TYPE) != 0;
|
||||
|
||||
getAuditOps(ts, ops, nelem);
|
||||
|
||||
for (int i = 0; i < nelem; i++) {
|
||||
const char *op = ops[i].op;
|
||||
if (op) {
|
||||
rpmte p = ops[i].te;
|
||||
char *nevra = audit_encode_nv_string("sw", rpmteNEVRA(p), 0);
|
||||
char *eventTxt = NULL;
|
||||
int verified = (rpmteVerified(p) & RPMSIG_SIGNATURE_TYPE) ? 1 : 0;
|
||||
int result = (rpmteFailed(p) == 0);
|
||||
|
||||
rasprintf(&eventTxt,
|
||||
"op=%s %s sw_type=rpm key_enforce=%u gpg_res=%u %s",
|
||||
op, nevra, enforce, verified, dir);
|
||||
audit_log_user_comm_message(auditFd, AUDIT_SOFTWARE_UPDATE,
|
||||
eventTxt, NULL, NULL, NULL, NULL, result);
|
||||
free(nevra);
|
||||
free(eventTxt);
|
||||
}
|
||||
}
|
||||
|
||||
free(dir);
|
||||
free(ops);
|
||||
audit_close(auditFd);
|
||||
|
||||
exit:
|
||||
return RPMRC_OK;
|
||||
}
|
||||
|
||||
struct rpmPluginHooks_s audit_hooks = {
|
||||
.tsm_post = audit_tsm_post,
|
||||
};
|
Loading…
Reference in New Issue