summaryrefslogtreecommitdiffstats
path: root/src/basic/audit-util.c
diff options
context:
space:
mode:
authorNick Rosbrook <nick.rosbrook@canonical.com>2023-05-02 18:30:31 +0200
committerLuca Boccassi <luca.boccassi@gmail.com>2023-05-05 22:06:16 +0200
commit362235bf59f8ddc6d67be3d6c8604f7fd05d383d (patch)
tree76a7682ca37a01940f98722b5169ad2d2dbf5b78 /src/basic/audit-util.c
parentMerge pull request #27536 from dtardon/checked-fd-parsing (diff)
downloadsystemd-362235bf59f8ddc6d67be3d6c8604f7fd05d383d.tar.xz
systemd-362235bf59f8ddc6d67be3d6c8604f7fd05d383d.zip
basic/audit-util: make a test request before enabling use of audit
If a container manager does not follow the guidance in https://systemd.io/CONTAINER_INTERFACE/ regarding audit capabilities, then the current check may not be sufficient to determine that audit will function properly. In particular, when calling bind() on the audit fd, we will get EPERM if running in a user-namespaced container. Expand the check to make an AUDIT_GET_FEATURE request on the audit fd to test if it is working. If this fails with ECONNREFUSED, we know it is because the kernel does not support the use of audit outside of the initial user namespace. Note that the approach of this patch was suggested here: https://github.com/systemd/systemd/pull/19443#issuecomment-829566659 Fixes: #6519
Diffstat (limited to 'src/basic/audit-util.c')
-rw-r--r--src/basic/audit-util.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c
index 1bf88b1e52..f2dce206b3 100644
--- a/src/basic/audit-util.c
+++ b/src/basic/audit-util.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
+#include <linux/audit.h>
#include <linux/netlink.h>
#include <stdio.h>
#include <sys/socket.h>
@@ -12,6 +13,7 @@
#include "macro.h"
#include "parse-util.h"
#include "process-util.h"
+#include "socket-util.h"
#include "user-util.h"
int audit_session_from_pid(pid_t pid, uint32_t *id) {
@@ -68,8 +70,50 @@ int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
return 0;
}
+static int try_audit_request(int fd) {
+ struct iovec iov;
+ struct msghdr mh;
+ ssize_t n;
+
+ assert(fd >= 0);
+
+ struct {
+ struct nlmsghdr hdr;
+ struct nlmsgerr err;
+ } _packed_ msg = {
+ .hdr.nlmsg_len = NLMSG_LENGTH(0),
+ .hdr.nlmsg_type = AUDIT_GET_FEATURE,
+ .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ };
+ iov = (struct iovec) {
+ .iov_base = &msg,
+ .iov_len = msg.hdr.nlmsg_len,
+ };
+ mh = (struct msghdr) {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0)
+ return -errno;
+
+ iov.iov_len = sizeof(msg);
+
+ n = recvmsg_safe(fd, &mh, 0);
+ if (n < 0)
+ return -errno;
+ if (n != NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+ return -EIO;
+
+ if (msg.hdr.nlmsg_type != NLMSG_ERROR)
+ return -EINVAL;
+
+ return msg.err.error;
+}
+
bool use_audit(void) {
static int cached_use = -1;
+ int r;
if (cached_use < 0) {
int fd;
@@ -80,7 +124,22 @@ bool use_audit(void) {
if (!cached_use)
log_debug_errno(errno, "Won't talk to audit: %m");
} else {
- cached_use = true;
+ /* If we try and use the audit fd but get -ECONNREFUSED, it is because
+ * we are not in the initial user namespace, and the kernel does not
+ * have support for audit outside of the initial user namespace
+ * (see https://elixir.bootlin.com/linux/latest/C/ident/audit_netlink_ok).
+ *
+ * If we receive any other error, do not disable audit because we are not
+ * sure that the error indicates that audit will not work in general. */
+ r = try_audit_request(fd);
+ if (r < 0) {
+ cached_use = r != -ECONNREFUSED;
+ log_debug_errno(r, cached_use ?
+ "Failed to make request on audit fd, ignoring: %m" :
+ "Won't talk to audit: %m");
+ } else
+ cached_use = true;
+
safe_close(fd);
}
}