Files
systemd/src/shared/libaudit-util.c
T
Daan De Meyer d158595dc7 tree-wide: move static dl handles into their dlopen_*() functions
Each dlopen_*() wrapper kept its dl handle as a file-scope
'static void *xxx_dl = NULL;' even though only the wrapper itself
ever referenced it. Move each one inside the corresponding function
so its scope matches its actual use, leaving the rest of each
translation unit free of the unused file-scope name.

In pcre2-util.c the assert(pcre2_dl) in pattern_matches_and_log()
becomes assert(sym_pcre2_match), which carries the same invariant
(pattern_compile_and_log() ran dlopen_pcre2()).
2026-05-19 19:22:06 +00:00

160 lines
4.9 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/audit.h>
#include <linux/netlink.h>
#include <sys/socket.h>
#include "sd-dlopen.h"
#include "errno-util.h"
#include "fd-util.h"
#include "iovec-util.h"
#include "libaudit-util.h"
#include "log.h"
#include "socket-util.h"
#if HAVE_AUDIT
static DLSYM_PROTOTYPE(audit_close) = NULL;
DLSYM_PROTOTYPE(audit_log_acct_message) = NULL;
DLSYM_PROTOTYPE(audit_log_user_avc_message) = NULL;
DLSYM_PROTOTYPE(audit_log_user_comm_message) = NULL;
static DLSYM_PROTOTYPE(audit_open) = NULL;
#endif
int dlopen_libaudit(int log_level) {
#if HAVE_AUDIT
static void *libaudit_dl = NULL;
SD_ELF_NOTE_DLOPEN(
"audit",
"Support for Audit logging",
SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
"libaudit.so.1");
return dlopen_many_sym_or_warn(
&libaudit_dl,
"libaudit.so.1",
log_level,
DLSYM_ARG(audit_close),
DLSYM_ARG(audit_log_acct_message),
DLSYM_ARG(audit_log_user_avc_message),
DLSYM_ARG(audit_log_user_comm_message),
DLSYM_ARG(audit_open));
#else
return log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
"libaudit support is not compiled in.");
#endif
}
#if HAVE_AUDIT
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 = IOVEC_MAKE(&msg, 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 n;
if (n != NLMSG_LENGTH(sizeof(struct nlmsgerr)))
return -EIO;
if (msg.hdr.nlmsg_type != NLMSG_ERROR)
return -EINVAL;
return msg.err.error;
}
#endif
bool use_audit(void) {
#if HAVE_AUDIT
static int cached_use = -1;
int r;
if (cached_use >= 0)
return cached_use;
if (dlopen_libaudit(LOG_DEBUG) < 0)
return (cached_use = false);
_cleanup_close_ int fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
if (fd < 0) {
cached_use = !ERRNO_IS_PRIVILEGE(errno) && !ERRNO_IS_NOT_SUPPORTED(errno);
if (cached_use)
log_debug_errno(errno, "Unexpected error while creating audit socket, proceeding with its use: %m");
else
log_debug_errno(errno, "Won't talk to audit, because feature or privilege absent: %m");
} else {
/* 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;
}
return cached_use;
#else
return false;
#endif
}
int close_audit_fd(int fd) {
#if HAVE_AUDIT
if (fd >= 0)
sym_audit_close(fd);
#else
assert(fd < 0);
#endif
return -EBADF;
}
int open_audit_fd_or_warn(void) {
#if HAVE_AUDIT
int r;
r = dlopen_libaudit(LOG_DEBUG);
if (r < 0)
return r;
/* If the kernel lacks netlink or audit support, don't worry about it. */
int fd = sym_audit_open();
if (fd < 0)
return log_full_errno(ERRNO_IS_NOT_SUPPORTED(errno) ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to connect to audit log, ignoring: %m");
return fd;
#else
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libaudit support not compiled in");
#endif
}