Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F160365976
D28451.id84196.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D28451.id84196.diff
View Options
diff --git a/tests/sys/audit/Makefile b/tests/sys/audit/Makefile
--- a/tests/sys/audit/Makefile
+++ b/tests/sys/audit/Makefile
@@ -48,10 +48,19 @@
TEST_METADATA+= timeout="30"
TEST_METADATA+= required_user="root"
+# Only one process can be auditing, if we attempt to run these tests in parallel
+# some of them will fail to start auditing.
+# TODO: it would be nice to be able to run them in parallel with other non-audit
+# tests using some internal form of synchronization.
+# TODO: In addititon to test failures, running in parallel can trigger a kernel
+# panic: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=253616
TEST_METADATA+= is_exclusive="true"
TEST_METADATA+= required_files="/etc/rc.d/auditd /dev/auditpipe"
LDFLAGS+= -lbsm -lutil
+OPENBSMDIR=${SRCTOP}/contrib/openbsm
+CFLAGS+= -I${OPENBSMDIR}
+LDADD+= ${LIBAUDITD}
CFLAGS.process-control.c+= -I${SRCTOP}/tests
diff --git a/tests/sys/audit/administrative.c b/tests/sys/audit/administrative.c
--- a/tests/sys/audit/administrative.c
+++ b/tests/sys/audit/administrative.c
@@ -341,10 +341,16 @@
* at the configured path. To reset this, we need to stop and start the
* auditd(8) again. Here, we check if auditd(8) was running already
* before the test started. If so, we stop and start it again.
+ *
+ * TODO: should we skip this test if auditd(8) is already running to
+ * avoid restarting it?
*/
- system("service auditd onestop > /dev/null 2>&1");
- if (!atf_utils_file_exists("started_auditd"))
+ if (!atf_utils_file_exists("started_fake_auditd")) {
+ system("service auditd onestop > /dev/null 2>&1");
system("service auditd onestart > /dev/null 2>&1");
+ } else {
+ cleanup();
+ }
}
diff --git a/tests/sys/audit/utils.c b/tests/sys/audit/utils.c
--- a/tests/sys/audit/utils.c
+++ b/tests/sys/audit/utils.c
@@ -30,6 +30,7 @@
#include <sys/ioctl.h>
#include <bsm/libbsm.h>
+#include <bsm/auditd_lib.h>
#include <security/audit/audit_ioctl.h>
#include <atf-c.h>
@@ -222,13 +223,44 @@
}
}
-FILE
-*setup(struct pollfd fd[], const char *name)
+static bool
+is_auditd_running(void)
+{
+ int trigger;
+ int err;
+
+ /*
+ * AUDIT_TRIGGER_INITIALIZE is a no-op message on FreeBSD and can
+ * therefore be used to check whether auditd has already been started.
+ * This is significantly cheaper than running `service auditd onestatus`
+ * for each test case. It is also slightly less racy since it will only
+ * return true once auditd() has opened the trigger file rather than
+ * just when the pidfile has been created.
+ */
+ trigger = AUDIT_TRIGGER_INITIALIZE;
+ err = auditon(A_SENDTRIGGER, &trigger, sizeof(trigger));
+ if (err == 0) {
+ fprintf(stderr, "auditd(8) is running.\n");
+ return (true);
+ } else {
+ /*
+ * A_SENDTRIGGER returns ENODEV if auditd isn't listening,
+ * all other error codes indicate a fatal error.
+ */
+ ATF_REQUIRE_MSG(errno == ENODEV,
+ "Unexpected error from auditon(2): %s", strerror(errno));
+ return (false);
+ }
+
+}
+
+FILE *
+setup(struct pollfd fd[], const char *name)
{
au_mask_t fmask, nomask;
+ FILE *pipestream;
fmask = get_audit_mask(name);
nomask = get_audit_mask("no");
- FILE *pipestream;
ATF_REQUIRE((fd[0].fd = open("/dev/auditpipe", O_RDONLY)) != -1);
ATF_REQUIRE((pipestream = fdopen(fd[0].fd, "r")) != NULL);
@@ -244,12 +276,39 @@
/* Set local preselection audit_class as "no" for audit startup */
set_preselect_mode(fd[0].fd, &nomask);
- ATF_REQUIRE_EQ(0, system("service auditd onestatus || \
- { service auditd onestart && touch started_auditd ; }"));
-
- /* If 'started_auditd' exists, that means we started auditd(8) */
- if (atf_utils_file_exists("started_auditd"))
+ if (!is_auditd_running()) {
+ fprintf(stderr, "Running audit_quick_start() for testing... ");
+ /*
+ * Previously, this test started auditd using
+ * `service auditd onestart`. However, there is a race condition
+ * there since service can return before auditd(8) has
+ * fully started (once the daemon parent process has forked)
+ * and this can cause check_audit_startup() to fail sometimes.
+ *
+ * In the CheriBSD CI this caused the first test executed by
+ * kyua (administrative:acct_failure) to fail every time, but
+ * subsequent ones would almost always succeed.
+ *
+ * To avoid this problem (and as a nice side-effect this speeds
+ * up the test quite a bit), we register this process as a
+ * "fake" auditd(8) using the audit_quick_start() function from
+ * libauditd.
+ */
+ atf_utils_create_file("started_fake_auditd", "yes\n");
+ ATF_REQUIRE(atf_utils_file_exists("started_fake_auditd"));
+ ATF_REQUIRE_EQ_MSG(0, audit_quick_start(),
+ "Failed to start fake auditd: %m");
+ fprintf(stderr, "done.\n");
+ /* audit_quick_start() should log an audit start event. */
check_audit_startup(fd, "audit startup", pipestream);
+ /*
+ * If we exit cleanly shutdown audit_quick_start(), if not
+ * cleanup() will take care of it.
+ * This is not required, but makes it easier to run individual
+ * tests outside of kyua.
+ */
+ atexit(cleanup);
+ }
/* Set local preselection parameters specific to "name" audit_class */
set_preselect_mode(fd[0].fd, &fmask);
@@ -259,6 +318,13 @@
void
cleanup(void)
{
- if (atf_utils_file_exists("started_auditd"))
- system("service auditd onestop > /dev/null 2>&1");
+ if (atf_utils_file_exists("started_fake_auditd")) {
+ fprintf(stderr, "Running audit_quick_stop()... ");
+ if (audit_quick_stop() != 0) {
+ fprintf(stderr, "Failed to stop fake auditd: %m\n");
+ abort();
+ }
+ fprintf(stderr, "done.\n");
+ unlink("started_fake_auditd");
+ }
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jun 24, 6:12 PM (6 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34166250
Default Alt Text
D28451.id84196.diff (5 KB)
Attached To
Mode
D28451: tests/sys/audit: Avoid race caused by starting auditd(8) for testing
Attached
Detach File
Event Timeline
Log In to Comment