diff --git a/audisp-restore-fix.patch b/audisp-restore-fix.patch new file mode 100644 index 0000000..82043bf --- /dev/null +++ b/audisp-restore-fix.patch @@ -0,0 +1,38 @@ +diff --git a/audisp/plugins/af_unix/audisp-af_unix.c b/audisp/plugins/af_unix/audisp-af_unix.c +index d85f15f8a..578533f52 100644 +--- a/audisp/plugins/af_unix/audisp-af_unix.c ++++ b/audisp/plugins/af_unix/audisp-af_unix.c +@@ -132,7 +132,7 @@ int setup_socket(int argc, char *argv[]) + if (errno) { + syslog(LOG_ERR, + "Error converting %s (%s)", +- arg[i], strerror(errno)); ++ argv[i], strerror(errno)); + mode = 0; + } + } else if (strchr(arg, '/') != NULL) { +@@ -265,16 +265,15 @@ void read_audit_record(int ifd) + do { + rc = writev(conn, vec, 2); + } while (rc < 0 && errno == EINTR); +- } +- +- if (rc < 0 && errno == EPIPE) { +- close(conn); +- conn = -1; +- client = 0; +- audit_fgets_clear(); +- } +- if (rc >= 0 && rc != len) { ++ if (rc < 0 && errno == EPIPE) { ++ close(conn); ++ conn = -1; ++ client = 0; ++ audit_fgets_clear(); ++ } ++ //if (rc >= 0 && rc != len) { + // what to do with leftovers? ++ //} + } + } + #endif diff --git a/audisp-restore.patch b/audisp-restore.patch new file mode 100644 index 0000000..f0cafb8 --- /dev/null +++ b/audisp-restore.patch @@ -0,0 +1,256 @@ +diff --git a/audisp/plugins/af_unix/Makefile.am b/audisp/plugins/af_unix/Makefile.am +index 501b35d43..e8faec7df 100644 +--- a/audisp/plugins/af_unix/Makefile.am ++++ b/audisp/plugins/af_unix/Makefile.am +@@ -25,7 +25,8 @@ CONFIG_CLEAN_FILES = *.rej *.orig + CONF_FILES = af_unix.conf + EXTRA_DIST = $(CONF_FILES) $(man_MANS) + +-AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/common ++AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/common -I${top_srcdir}/audisp ++LIBS = ${top_builddir}/lib/libaudit.la + prog_confdir = $(sysconfdir)/audit + plugin_confdir=$(prog_confdir)/plugins.d + plugin_conf = af_unix.conf +diff --git a/audisp/plugins/af_unix/audisp-af_unix.c b/audisp/plugins/af_unix/audisp-af_unix.c +index ffbf2ac07..d85f15f8a 100644 +--- a/audisp/plugins/af_unix/audisp-af_unix.c ++++ b/audisp/plugins/af_unix/audisp-af_unix.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -43,16 +44,19 @@ + #endif + #include "libaudit.h" + #include "common.h" ++#include "audispd-pconfig.h" + + #define DEFAULT_PATH "/var/run/audispd_events" ++#define MAX_AUDIT_EVENT_FRAME_SIZE (sizeof(struct audit_dispatcher_header) + MAX_AUDIT_MESSAGE_LENGTH) + //#define DEBUG + + /* Global Data */ + static volatile int stop = 0, hup = 0; +-char rx_buf[MAX_AUDIT_MESSAGE_LENGTH]; ++char rx_buf[MAX_AUDIT_EVENT_FRAME_SIZE+1]; + int sock = -1, conn = -1, client = 0; + struct pollfd pfd[3]; + unsigned mode = 0; ++format_t format = -1; + char *path = NULL; + + /* +@@ -119,77 +123,150 @@ int create_af_unix_socket(const char *spath, int mode) + + int setup_socket(int argc, char *argv[]) + { +- if (argc != 3) { +- syslog(LOG_ERR, "Missing arguments, using defaults"); +- mode = 0640; +- path = DEFAULT_PATH; +- } else { +- int i; +- for (i=1; i < 3; i++) { +- if (isdigit((unsigned char)argv[i][0])) { +- errno = 0; +- mode = strtoul(argv[i], NULL, 8); +- if (errno) { +- syslog(LOG_ERR, +- "Error converting %s (%s)", +- argv[i], strerror(errno)); +- mode = 0; +- } +- } else { +- char *base; +- path = argv[i]; +- // Make sure there are directories +- base = strchr(path, '/'); +- if (base) { +- DIR *d; +- char *dir = strdup(path); +- base = dirname(dir); +- d = opendir(base); +- if (d) { +- closedir(d); +- unlink(path); +- free(dir); +- } else { +- syslog(LOG_ERR, +- "Couldn't open %s (%s)", +- base, strerror(errno)); +- free(dir); +- exit(1); +- } +- ++ for (int i = 1; i < argc; i++) { ++ char *arg = argv[i]; ++ if (isdigit((unsigned char)arg[0])) { ++ // parse mode ++ errno = 0; ++ mode = strtoul(arg, NULL, 8); ++ if (errno) { ++ syslog(LOG_ERR, ++ "Error converting %s (%s)", ++ arg[i], strerror(errno)); ++ mode = 0; ++ } ++ } else if (strchr(arg, '/') != NULL) { ++ // parse path ++ char* base; ++ path = arg; ++ // Make sure there are directories ++ base = strchr(path, '/'); ++ if (base) { ++ DIR* d; ++ char* dir = strdup(path); ++ base = dirname(dir); ++ d = opendir(base); ++ if (d) { ++ closedir(d); ++ unlink(path); ++ free(dir); + } else { +- syslog(LOG_ERR, "Malformed path %s", +- path); ++ syslog(LOG_ERR, ++ "Couldn't open %s (%s)", ++ base, strerror(errno)); ++ free(dir); + exit(1); + } ++ ++ } else { ++ syslog(LOG_ERR, "Malformed path %s", ++ path); ++ exit(1); + } +- } +- if (mode == 0 || path == NULL) { +- syslog(LOG_ERR, "Bad arguments, using defaults"); +- mode = 0640; +- path = DEFAULT_PATH; ++ } else { ++ if (strcmp(arg, "string") == 0) ++ format = F_STRING; ++ else if (strcmp(arg, "binary") == 0) ++ format = F_BINARY; ++ else ++ syslog(LOG_ERR, "Invalid format detected"); + } + } ++ ++ if (mode == 0 || path == NULL || format == -1) { ++ syslog(LOG_ERR, "Bad or not enough arguments, using defaults"); ++ mode = 0640; ++ path = DEFAULT_PATH; ++ format = F_STRING; ++ } ++ + return create_af_unix_socket(path, mode); + } + ++static int event_to_string(struct audit_dispatcher_header *hdr, char *data, char **out, int *outlen) ++{ ++ char *v = NULL, *ptr, unknown[32]; ++ int len; ++ ++ if (hdr->ver == AUDISP_PROTOCOL_VER) { ++ const char *type; ++ ++ /* Get the event formatted */ ++ type = audit_msg_type_to_name(hdr->type); ++ if (type == NULL) { ++ snprintf(unknown, sizeof(unknown), ++ "UNKNOWN[%u]", hdr->type); ++ type = unknown; ++ } ++ len = asprintf(&v, "type=%s msg=%.*s\n", ++ type, hdr->size, data); ++ // Protocol 2 events are already formatted ++ } else if (hdr->ver == AUDISP_PROTOCOL_VER2) { ++ len = asprintf(&v, "%.*s\n", hdr->size, data); ++ } else ++ len = 0; ++ if (len <= 0) { ++ *out = NULL; ++ *outlen = 0; ++ return -1; ++ } ++ ++ /* Strip newlines from event record */ ++ ptr = v; ++ while ((ptr = strchr(ptr, 0x0A)) != NULL) { ++ if (ptr != &v[len-1]) ++ *ptr = ' '; ++ else ++ break; /* Done - exit loop */ ++ } ++ ++ *out = v; ++ *outlen = len; ++ return 1; ++} ++ + void read_audit_record(int ifd) + { + do { + int len; + + // Read stdin +- if ((len = audit_fgets(rx_buf, sizeof(rx_buf), ifd)) > 0) { ++ if ((len = audit_fgets(rx_buf, MAX_AUDIT_EVENT_FRAME_SIZE + 1, ifd)) > 0) { + #ifdef DEBUG + write(1, rx_buf, len); + #else ++ struct audit_dispatcher_header *hdr = (struct audit_dispatcher_header *)rx_buf; ++ char *data = rx_buf + sizeof(struct audit_dispatcher_header); + if (client) { + // Send it to the client + int rc; + +- do { +- rc = write(conn, rx_buf, len); +- } while (rc < 0 && errno == EINTR); ++ if (format == F_STRING) { ++ ++ char *str = NULL; ++ int str_len = 0; ++ if (event_to_string(hdr, data, &str, &str_len) < 0) { ++ // what to do with error? ++ continue; ++ } ++ ++ do { ++ rc = write(conn, str, str_len); ++ } while (rc < 0 && errno == EINTR); ++ } else if (format == F_BINARY) { ++ struct iovec vec[2]; ++ ++ vec[0].iov_base = hdr; ++ vec[0].iov_len = sizeof(struct audit_dispatcher_header); ++ ++ vec[1].iov_base = data; ++ vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH; ++ ++ do { ++ rc = writev(conn, vec, 2); ++ } while (rc < 0 && errno == EINTR); ++ } ++ + if (rc < 0 && errno == EPIPE) { + close(conn); + conn = -1; +@@ -203,7 +280,7 @@ void read_audit_record(int ifd) + #endif + } else if (audit_fgets_eof()) + stop = 1; +- } while (audit_fgets_more(sizeof(rx_buf))); ++ } while (audit_fgets_more(MAX_AUDIT_EVENT_FRAME_SIZE)); + } + + void accept_connection(void) diff --git a/audit.spec b/audit.spec index 0ffdedb..ed80ab1 100644 --- a/audit.spec +++ b/audit.spec @@ -2,13 +2,19 @@ Summary: User space tools for kernel auditing Name: audit Version: 3.1.5 -Release: 1%{?dist} +Release: 2%{?dist} License: GPLv2+ URL: http://people.redhat.com/sgrubb/audit/ Source0: http://people.redhat.com/sgrubb/audit/%{name}-%{version}.tar.gz Source1: https://www.gnu.org/licenses/lgpl-2.1.txt Patch1: 0001-Add-ausysrulevalidate.patch +Patch2: audisp-restore.patch +Patch3: audisp-restore-fix.patch +Patch4: readonly.patch +Patch5: disable-protectkernmelmodules.patch +Patch6: remote-logging-ordering-cycle.patch +Patch7: permtab-filter-unsupport.patch BuildRequires: make gcc swig BuildRequires: openldap-devel @@ -92,6 +98,12 @@ Management Facility) database, through an IBM Tivoli Directory Server %setup -q cp %{SOURCE1} . %patch -P 1 -p1 +%patch -P 2 -p1 +%patch -P 3 -p1 +%patch -P 4 -p1 +%patch -P 5 -p1 +%patch -P 6 -p1 +%patch -P 7 -p1 autoreconf -fv --install @@ -229,6 +241,7 @@ fi %attr(755,root,root) %{_bindir}/aulast %attr(755,root,root) %{_bindir}/aulastlog %attr(755,root,root) %{_bindir}/ausyscall +%attr(640,root,root) %{_tmpfilesdir}/audit.conf %attr(755,root,root) %{_bindir}/auvirt %attr(644,root,root) %{_unitdir}/auditd.service %attr(750,root,root) %dir %{_libexecdir}/initscripts/legacy-actions/auditd @@ -275,6 +288,18 @@ fi %attr(750,root,root) %{_sbindir}/audispd-zos-remote %changelog +* Wed Jan 08 2025 Attila Lakatos - 3.1.5-2 +- Disable ProtectKernelModules=true in service file + Resolves: RHEL-59570 +- af_unix plugin: restore original behavior in binary mode + Resolves: RHEL-59585 +- Support image mode + Resolves: RHEL-69033 +- Resolve ordering cycle when using remote logging + Resolves: RHEL-11252 +- Filter syscalls to ensure architecture-specific availability + Resolves: RHEL-70455 + * Tue Jul 09 2024 Attila Lakatos - 3.1.5-1 - New upstream maintenance release, 3.1.4 - Prevent scriplets from failing diff --git a/disable-protectkernmelmodules.patch b/disable-protectkernmelmodules.patch new file mode 100644 index 0000000..195dbd7 --- /dev/null +++ b/disable-protectkernmelmodules.patch @@ -0,0 +1,14 @@ +diff --git a/init.d/auditd.service b/init.d/auditd.service +index 8210c60eb..dd7ec694b 100644 +--- a/init.d/auditd.service ++++ b/init.d/auditd.service +@@ -38,7 +38,8 @@ MemoryDenyWriteExecute=true + LockPersonality=true + # The following control prevents rules on /proc so its off by default + #ProtectControlGroups=true +-ProtectKernelModules=true ++## The following control prevents rules on /usr/lib/modules/ its off by default ++#ProtectKernelModules=true + RestrictRealtime=true + + [Install] diff --git a/permtab-filter-unsupport.patch b/permtab-filter-unsupport.patch new file mode 100644 index 0000000..5c11a3c --- /dev/null +++ b/permtab-filter-unsupport.patch @@ -0,0 +1,102 @@ +diff --git a/lib/libaudit.c b/lib/libaudit.c +index 7a8c6d4b1..de34812f0 100644 +--- a/lib/libaudit.c ++++ b/lib/libaudit.c +@@ -100,6 +100,7 @@ static struct libaudit_conf config; + static int audit_failure_parser(const char *val, int line); + static int audit_name_to_uid(const char *name, uid_t *auid); + static int audit_name_to_gid(const char *name, gid_t *gid); ++static char* filter_supported_syscalls(const char* syscalls, int machine) __attr_dealloc_free; + + static const struct kw_pair keywords[] = + { +@@ -1524,6 +1525,50 @@ int _audit_parse_syscall(const char *optarg, struct audit_rule_data *rule) + return audit_rule_syscallbyname_data(rule, optarg); + } + ++/* ++ * Filters unsupported syscalls from a comma-separated string based ++ * on the given architecture. Returns a new string with supported syscalls ++ * or NULL on error. ++ */ ++static char* filter_supported_syscalls(const char* syscalls, int machine) ++{ ++ if (syscalls == NULL) { ++ return NULL; ++ } ++ ++ // Allocate memory for the filtered syscalls string ++ char* filtered_syscalls = malloc(strlen(syscalls) + 1); ++ if (filtered_syscalls == NULL) { ++ return NULL; ++ } ++ filtered_syscalls[0] = '\0'; // Initialize as empty string ++ ++ // Tokenize the syscalls string and filter unsupported syscalls ++ const char* delimiter = ","; ++ char* syscalls_copy = strdup(syscalls); ++ if (syscalls_copy == NULL) { ++ free(filtered_syscalls); ++ return NULL; ++ } ++ char* token = strtok(syscalls_copy, delimiter); ++ while (token != NULL) { ++ if (audit_name_to_syscall(token, machine) != -1) { ++ strcat(filtered_syscalls, token); ++ strcat(filtered_syscalls, delimiter); ++ } ++ token = strtok(NULL, delimiter); ++ } ++ free(syscalls_copy); ++ ++ // Remove the trailing delimiter, if present ++ size_t len = strlen(filtered_syscalls); ++ if (len > 0 && filtered_syscalls[len - 1] == ',') { ++ filtered_syscalls[len - 1] = '\0'; ++ } ++ ++ return filtered_syscalls; ++} ++ + static int audit_add_perm_syscalls(int perm, struct audit_rule_data *rule) + { + // We only get here if syscall notation is being used in the rule. +@@ -1536,20 +1581,36 @@ static int audit_add_perm_syscalls(int perm, struct audit_rule_data *rule) + return 0; + } + ++ const int machine = audit_elf_to_machine(_audit_elf); + const char *syscalls = audit_perm_to_name(perm); +- int rc = _audit_parse_syscall(syscalls, rule); ++ const char *syscalls_to_use; ++ ++ // The permtab table is hardcoded, but some syscalls, like rename ++ // on arm64, are unavailable on certain architectures. To ensure compatibility, ++ // we must avoid creating rules with unsupported syscalls. ++ char* filtered_syscalls = filter_supported_syscalls(syscalls, machine); ++ if (filtered_syscalls == NULL) { ++ // use original syscalls in case we failed to parse - should not happen ++ syscalls_to_use = syscalls; ++ audit_msg(LOG_WARNING, "Filtering syscalls failed; using original syscalls."); ++ } else { ++ syscalls_to_use = filtered_syscalls; ++ } ++ ++ int rc = _audit_parse_syscall(syscalls_to_use, rule); + switch (rc) + { + case 0: + _audit_syscalladded = 1; + break; + case -1: // Should never happen +- audit_msg(LOG_ERR, "Syscall name unknown: %s", syscalls); ++ audit_msg(LOG_ERR, "Syscall name unknown: %s", syscalls_to_use); + break; + default: // Error reported - do nothing here + break; + } + ++ free(filtered_syscalls); + return rc; + } + diff --git a/readonly.patch b/readonly.patch new file mode 100644 index 0000000..f416b35 --- /dev/null +++ b/readonly.patch @@ -0,0 +1,48 @@ +diff --git a/audit.spec b/audit.spec +index 39f640e36..313d803f1 100644 +--- a/audit.spec ++++ b/audit.spec +@@ -215,6 +215,7 @@ fi + %attr(755,root,root) %{_bindir}/aulast + %attr(755,root,root) %{_bindir}/aulastlog + %attr(755,root,root) %{_bindir}/ausyscall ++%attr(640,root,root) %{_tmpfilesdir}/audit.conf + %attr(755,root,root) %{_bindir}/auvirt + %attr(644,root,root) %{_unitdir}/auditd.service + %attr(750,root,root) %dir %{_libexecdir}/initscripts/legacy-actions/auditd +diff --git a/init.d/Makefile.am b/init.d/Makefile.am +index 3a73697a6..63fae2ab4 100644 +--- a/init.d/Makefile.am ++++ b/init.d/Makefile.am +@@ -23,6 +23,7 @@ + + CONFIG_CLEAN_FILES = *.rej *.orig + EXTRA_DIST = auditd.init auditd.service auditd.sysconfig auditd.conf \ ++ audit-tmpfiles.conf \ + auditd.cron libaudit.conf auditd.condrestart \ + auditd.reload auditd.restart auditd.resume \ + auditd.rotate auditd.state auditd.stop \ +@@ -43,6 +44,8 @@ sbin_SCRIPTS = augenrules + + install-data-hook: + $(INSTALL_DATA) -D -m 640 ${srcdir}/${libconfig} ${DESTDIR}${sysconfdir} ++ mkdir -p ${DESTDIR}$(prefix)/lib/tmpfiles.d/ ++ $(INSTALL_DATA) -m 640 ${srcdir}/audit-tmpfiles.conf ${DESTDIR}$(prefix)/lib/tmpfiles.d/audit.conf + if ENABLE_SYSTEMD + else + $(INSTALL_DATA) -D -m 640 ${srcdir}/auditd.sysconfig ${DESTDIR}${sysconfigdir}/auditd +@@ -69,6 +72,7 @@ endif + + uninstall-hook: + rm ${DESTDIR}${sysconfdir}/${libconfig} ++ rm ${DESTDIR}$(prefix)/lib/tmpfiles.d/audit.conf + if ENABLE_SYSTEMD + rm ${DESTDIR}${initdir}/auditd.service + rm ${DESTDIR}${legacydir}/rotate +diff --git a/init.d/audit-tmpfiles.conf b/init.d/audit-tmpfiles.conf +new file mode 100644 +index 000000000..5512a535a +--- /dev/null ++++ b/init.d/audit-tmpfiles.conf +@@ -0,0 +1 @@ ++d /var/log/audit 0700 root root - - diff --git a/remote-logging-ordering-cycle.patch b/remote-logging-ordering-cycle.patch new file mode 100644 index 0000000..aba17a0 --- /dev/null +++ b/remote-logging-ordering-cycle.patch @@ -0,0 +1,14 @@ +diff --git a/init.d/auditd.service b/init.d/auditd.service +index dd7ec694b..d5139ae92 100644 +--- a/init.d/auditd.service ++++ b/init.d/auditd.service +@@ -6,6 +6,9 @@ DefaultDependencies=no + ## uncomment the second so that network-online.target is part of After. + ## then comment the first Before and uncomment the second Before to remove + ## sysinit.target from "Before". ++## If using remote logging, ensure that the systemd-update-utmp.service file ++## is updated to remove the After=auditd.service directive to prevent a ++## boot-time ordering cycle. + After=local-fs.target systemd-tmpfiles-setup.service + ##After=network-online.target local-fs.target systemd-tmpfiles-setup.service + Before=sysinit.target shutdown.target