auditd: Fix signal handling

Rewrite the main loop to use ppoll() instead of just blocking on read,
blocking the signals we care about when we aren't polling.

I didn't bother replacing alarm() with setitimer(); the alarm code
is dead anyway since there is no way for max_idletime to acquire a
non-zero value.

While here, avoid leaking the pid file and trigger descriptors to the
log child.

PR:		295840
MFC after:	1 week
Sponsored by:	Klara, Inc.
Reviewed by:	kevans
Differential Revision:	https://reviews.freebsd.org/D57451
This commit is contained in:
Dag-Erling Smørgrav
2026-06-09 00:45:34 +02:00
parent 05f132adc5
commit 5bd78cfc80
4 changed files with 86 additions and 50 deletions
+4
View File
@@ -29,6 +29,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@@ -57,6 +58,9 @@ auditwarnlog(char *args[])
/* /*
* Child. * Child.
*/ */
#ifndef USE_MACH_IPC
sigprocmask(SIG_SETMASK, &auditd_origmask, NULL);
#endif /* !USE_MACH_IPC */
execv(AUDITWARN_SCRIPT, loc_args); execv(AUDITWARN_SCRIPT, loc_args);
syslog(LOG_ERR, "Could not exec %s (%m)\n", syslog(LOG_ERR, "Could not exec %s (%m)\n",
AUDITWARN_SCRIPT); AUDITWARN_SCRIPT);
+40 -10
View File
@@ -107,6 +107,19 @@ static gid_t audit_review_gid = -1;
*/ */
static char *lastfile = NULL; static char *lastfile = NULL;
/*
* File descriptor to our locked pid file.
*/
static int pidfd;
#ifndef USE_MACH_IPC
/*
* Original signal mask in effect at startup. Used by the main event loop
* and the log child.
*/
sigset_t auditd_origmask;
#endif /* !USE_MACH_IPC */
/* /*
* Error starting auditd. Run warn script and exit. * Error starting auditd. Run warn script and exit.
*/ */
@@ -354,12 +367,20 @@ close_misc(void)
auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE); auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE);
return (1); return (1);
} }
close(pidfd);
pidfd = -1;
endac(); endac();
if (auditd_close_trigger() != 0) { if (auditd_close_trigger() != 0) {
auditd_log_err("Error closing trigger messaging mechanism"); auditd_log_err("Error closing trigger messaging mechanism");
return (1); return (1);
} }
#ifndef USE_MACH_IPC
/* Restore the original signal mask. */
sigprocmask(SIG_SETMASK, &auditd_origmask, NULL);
#endif /* !USE_MACH_IPC */
return (0); return (0);
} }
@@ -416,9 +437,17 @@ static int
register_daemon(void) register_daemon(void)
{ {
struct sigaction action; struct sigaction action;
FILE * pidfile; sigset_t sigmask;
int fd;
pid_t pid; #ifndef USE_MACH_IPC
/* Set up the signal mask. */
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGTERM);
sigaddset(&sigmask, SIGALRM);
sigaddset(&sigmask, SIGCHLD);
sigaddset(&sigmask, SIGHUP);
sigprocmask(SIG_BLOCK, &sigmask, &auditd_origmask);
#endif /* !USE_MACH_IPC */
/* Set up the signal hander. */ /* Set up the signal hander. */
action.sa_handler = auditd_relay_signal; action.sa_handler = auditd_relay_signal;
@@ -449,29 +478,30 @@ register_daemon(void)
fail_exit(); fail_exit();
} }
if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) { /* Open the pid file. */
pidfd = open(AUDITD_PIDFILE, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (pidfd < 0) {
auditd_log_err("Could not open PID file"); auditd_log_err("Could not open PID file");
audit_warn_tmpfile(); audit_warn_tmpfile();
return (-1); return (-1);
} }
/* Attempt to lock the pid file; if a lock is present, exit. */ /* Attempt to lock the pid file; if a lock is present, exit. */
fd = fileno(pidfile); if (flock(pidfd, LOCK_EX | LOCK_NB) < 0) {
if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
auditd_log_err( auditd_log_err(
"PID file is locked (is another auditd running?)."); "PID file is locked (is another auditd running?).");
audit_warn_ebusy(); audit_warn_ebusy();
return (-1); return (-1);
} }
pid = getpid(); /* Write our pid to the pid file and leave it open. */
ftruncate(fd, 0); ftruncate(pidfd, 0);
if (fprintf(pidfile, "%u\n", pid) < 0) { if (dprintf(pidfd, "%u\n", getpid()) < 0) {
/* Should not start the daemon. */ /* Should not start the daemon. */
fail_exit(); fail_exit();
} }
fflush(pidfile);
return (0); return (0);
} }
+3
View File
@@ -96,5 +96,8 @@ void auditd_terminate(void);
int auditd_config_controls(void); int auditd_config_controls(void);
void auditd_reap_children(void); void auditd_reap_children(void);
#ifndef USE_MACH_IPC
extern sigset_t auditd_origmask;
#endif /* !USE_MACH_IPC */
#endif /* !_AUDITD_H_ */ #endif /* !_AUDITD_H_ */
+34 -35
View File
@@ -33,6 +33,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h>
#include <stdarg.h> #include <stdarg.h>
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
@@ -57,10 +58,7 @@ static int auditing_state = AUD_STATE_INIT;
*/ */
static int max_idletime = 0; static int max_idletime = 0;
static int sigchlds, sigchlds_handled; static volatile sig_atomic_t signaled[NSIG];
static int sighups, sighups_handled;
static int sigterms, sigterms_handled;
static int sigalrms, sigalrms_handled;
static int triggerfd = 0; static int triggerfd = 0;
@@ -173,7 +171,6 @@ auditd_set_state(int state)
int int
auditd_get_state(void) auditd_get_state(void)
{ {
if (auditing_state == AUD_STATE_INIT) if (auditing_state == AUD_STATE_INIT)
init_audit_state(); init_audit_state();
@@ -186,8 +183,8 @@ auditd_get_state(void)
int int
auditd_open_trigger(int __unused launchd_flag) auditd_open_trigger(int __unused launchd_flag)
{ {
triggerfd = open(AUDIT_TRIGGER_FILE, O_RDONLY | O_CLOEXEC);
return ((triggerfd = open(AUDIT_TRIGGER_FILE, O_RDONLY, 0))); return (triggerfd);
} }
/* /*
@@ -196,7 +193,6 @@ auditd_open_trigger(int __unused launchd_flag)
int int
auditd_close_trigger(void) auditd_close_trigger(void)
{ {
return (close(triggerfd)); return (close(triggerfd));
} }
@@ -207,45 +203,56 @@ auditd_close_trigger(void)
void void
auditd_wait_for_events(void) auditd_wait_for_events(void)
{ {
int num; struct pollfd pfd;
ssize_t ret;
unsigned int trigger; unsigned int trigger;
pfd.fd = triggerfd;
pfd.events = POLLIN;
pfd.revents = 0;
for (;;) { for (;;) {
num = read(triggerfd, &trigger, sizeof(trigger));
if ((num == -1) && (errno != EINTR)) {
auditd_log_err("%s: error %d", __FUNCTION__, errno);
return;
}
/* Reset the idle time alarm, if used. */ /* Reset the idle time alarm, if used. */
if (max_idletime) if (max_idletime != 0)
alarm(max_idletime); alarm(max_idletime);
if (sigterms != sigterms_handled) { /* Check if any signals were caught. */
if (signaled[SIGTERM]) {
signaled[SIGTERM] = 0;
auditd_log_debug("%s: SIGTERM", __FUNCTION__); auditd_log_debug("%s: SIGTERM", __FUNCTION__);
auditd_terminate(); auditd_terminate();
/* not reached */ /* not reached */
} }
if (sigalrms != sigalrms_handled) { if (signaled[SIGALRM]) {
signaled[SIGALRM] = 0;
auditd_log_debug("%s: SIGALRM", __FUNCTION__); auditd_log_debug("%s: SIGALRM", __FUNCTION__);
auditd_terminate(); auditd_terminate();
/* not reached */ /* not reached */
} }
if (sigchlds != sigchlds_handled) { if (signaled[SIGCHLD]) {
sigchlds_handled = sigchlds; signaled[SIGCHLD] = 0;
auditd_reap_children(); auditd_reap_children();
} }
if (sighups != sighups_handled) { if (signaled[SIGHUP]) {
signaled[SIGHUP] = 0;
auditd_log_debug("%s: SIGHUP", __FUNCTION__); auditd_log_debug("%s: SIGHUP", __FUNCTION__);
sighups_handled = sighups;
auditd_config_controls(); auditd_config_controls();
} }
if (num == -1) /* Now wait for a trigger or signal. */
if ((ret = ppoll(&pfd, 1, NULL, &auditd_origmask)) < 0 &&
errno != EINTR) {
auditd_log_err("%s: error %d", __FUNCTION__, errno);
break;
}
if (ret <= 0)
continue; continue;
if (num == 0) { if ((ret = read(triggerfd, &trigger, sizeof(trigger))) < 0) {
auditd_log_err("%s: error %d", __FUNCTION__, errno);
break;
}
if (ret == 0) {
auditd_log_err("%s: read EOF", __FUNCTION__); auditd_log_err("%s: read EOF", __FUNCTION__);
return; break;
} }
auditd_handle_trigger(trigger); auditd_handle_trigger(trigger);
} }
@@ -258,15 +265,7 @@ auditd_wait_for_events(void)
* context. * context.
*/ */
void void
auditd_relay_signal(int signal) auditd_relay_signal(int signo)
{ {
if (signal == SIGHUP) signaled[signo] = 1;
sighups++;
if (signal == SIGTERM)
sigterms++;
if (signal == SIGCHLD)
sigchlds++;
if (signal == SIGALRM)
sigalrms++;
} }