diff --git a/tests/sys/audit/Makefile b/tests/sys/audit/Makefile index 215740020eb5..4cacd86d009a 100644 --- a/tests/sys/audit/Makefile +++ b/tests/sys/audit/Makefile @@ -1,59 +1,68 @@ # $FreeBSD$ TESTSDIR= ${TESTSBASE}/sys/audit ATF_TESTS_C= file-attribute-access ATF_TESTS_C+= file-attribute-modify ATF_TESTS_C+= file-create ATF_TESTS_C+= file-delete ATF_TESTS_C+= file-close ATF_TESTS_C+= file-write ATF_TESTS_C+= file-read ATF_TESTS_C+= open ATF_TESTS_C+= ioctl ATF_TESTS_C+= network ATF_TESTS_C+= inter-process ATF_TESTS_C+= administrative ATF_TESTS_C+= process-control ATF_TESTS_C+= miscellaneous SRCS.file-attribute-access+= file-attribute-access.c SRCS.file-attribute-access+= utils.c SRCS.file-attribute-modify+= file-attribute-modify.c SRCS.file-attribute-modify+= utils.c SRCS.file-create+= file-create.c SRCS.file-create+= utils.c SRCS.file-delete+= file-delete.c SRCS.file-delete+= utils.c SRCS.file-close+= file-close.c SRCS.file-close+= utils.c SRCS.file-write+= file-write.c SRCS.file-write+= utils.c SRCS.file-read+= file-read.c SRCS.file-read+= utils.c SRCS.open+= open.c SRCS.open+= utils.c SRCS.ioctl+= ioctl.c SRCS.ioctl+= utils.c SRCS.network+= network.c SRCS.network+= utils.c SRCS.inter-process+= inter-process.c SRCS.inter-process+= utils.c SRCS.administrative+= administrative.c SRCS.administrative+= utils.c SRCS.process-control+= process-control.c SRCS.process-control+= utils.c SRCS.miscellaneous+= miscellaneous.c SRCS.miscellaneous+= utils.c 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" MK_PIE:= no # XXX libprivateauditd.a is not PIE LDFLAGS+= -lbsm -lutil +OPENBSMDIR=${SRCTOP}/contrib/openbsm +CFLAGS+= -I${OPENBSMDIR} +LDADD+= ${LIBAUDITD} CFLAGS.process-control.c+= -I${SRCTOP}/tests .include diff --git a/tests/sys/audit/administrative.c b/tests/sys/audit/administrative.c index 4ec73f4710e0..d75f6147cdf4 100644 --- a/tests/sys/audit/administrative.c +++ b/tests/sys/audit/administrative.c @@ -1,1688 +1,1694 @@ /*- * Copyright (c) 2018 Aniket Pandey * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" static pid_t pid; static int filedesc; /* Default argument for handling ENOSYS in auditon(2) functions */ static int auditon_def = 0; static mode_t mode = 0777; static struct pollfd fds[1]; static char adregex[80]; static const char *auclass = "ad"; static const char *path = "fileforaudit"; static const char *successreg = "fileforaudit.*return,success"; ATF_TC_WITH_CLEANUP(settimeofday_success); ATF_TC_HEAD(settimeofday_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "settimeofday(2) call"); } ATF_TC_BODY(settimeofday_success, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "settimeofday.*%d.*success", pid); struct timeval tp; struct timezone tzp; ATF_REQUIRE_EQ(0, gettimeofday(&tp, &tzp)); FILE *pipefd = setup(fds, auclass); /* Setting the same time as obtained by gettimeofday(2) */ ATF_REQUIRE_EQ(0, settimeofday(&tp, &tzp)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(settimeofday_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(settimeofday_failure); ATF_TC_HEAD(settimeofday_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "settimeofday(2) call"); } ATF_TC_BODY(settimeofday_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "settimeofday.*%d.*failure", pid); struct timeval tp; struct timezone tzp; ATF_REQUIRE_EQ(0, gettimeofday(&tp, &tzp)); FILE *pipefd = setup(fds, auclass); tp.tv_sec = -1; /* Failure reason: Invalid value for tp.tv_sec; */ ATF_REQUIRE_EQ(-1, settimeofday(&tp, &tzp)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(settimeofday_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(clock_settime_success); ATF_TC_HEAD(clock_settime_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "clock_settime(2) call"); } ATF_TC_BODY(clock_settime_success, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "clock_settime.*%d.*success", pid); struct timespec tp; ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_REALTIME, &tp)); FILE *pipefd = setup(fds, auclass); /* Setting the same time as obtained by clock_gettime(2) */ ATF_REQUIRE_EQ(0, clock_settime(CLOCK_REALTIME, &tp)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(clock_settime_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(clock_settime_failure); ATF_TC_HEAD(clock_settime_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "clock_settime(2) call"); } ATF_TC_BODY(clock_settime_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "clock_settime.*%d.*failure", pid); struct timespec tp; ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp)); FILE *pipefd = setup(fds, auclass); /* Failure reason: cannot use CLOCK_MONOTONIC to set the system time */ ATF_REQUIRE_EQ(-1, clock_settime(CLOCK_MONOTONIC, &tp)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(clock_settime_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(adjtime_success); ATF_TC_HEAD(adjtime_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "adjtime(2) call"); } ATF_TC_BODY(adjtime_success, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "adjtime.*%d.*return,success", pid); FILE *pipefd = setup(fds, auclass); /* We don't want to change the system time, hence NULL */ ATF_REQUIRE_EQ(0, adjtime(NULL, NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(adjtime_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(adjtime_failure); ATF_TC_HEAD(adjtime_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "adjtime(2) call"); } ATF_TC_BODY(adjtime_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "adjtime.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(-1, adjtime((struct timeval *)(-1), NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(adjtime_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(ntp_adjtime_success); ATF_TC_HEAD(ntp_adjtime_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "ntp_adjtime(2) call"); } ATF_TC_BODY(ntp_adjtime_success, tc) { struct timex timebuff; bzero(&timebuff, sizeof(timebuff)); pid = getpid(); snprintf(adregex, sizeof(adregex), "ntp_adjtime.*%d.*success", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE(ntp_adjtime(&timebuff) != -1); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(ntp_adjtime_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(ntp_adjtime_failure); ATF_TC_HEAD(ntp_adjtime_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "ntp_adjtime(2) call"); } ATF_TC_BODY(ntp_adjtime_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "ntp_adjtime.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(-1, ntp_adjtime(NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(ntp_adjtime_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(nfs_getfh_success); ATF_TC_HEAD(nfs_getfh_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "getfh(2) call"); } ATF_TC_BODY(nfs_getfh_success, tc) { fhandle_t fhp; pid = getpid(); snprintf(adregex, sizeof(adregex), "nfs_getfh.*%d.*ret.*success", pid); /* File needs to exist to call getfh(2) */ ATF_REQUIRE((filedesc = open(path, O_CREAT, mode)) != -1); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, getfh(path, &fhp)); check_audit(fds, adregex, pipefd); close(filedesc); } ATF_TC_CLEANUP(nfs_getfh_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(nfs_getfh_failure); ATF_TC_HEAD(nfs_getfh_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "getfh(2) call"); } ATF_TC_BODY(nfs_getfh_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "nfs_getfh.*%d.*ret.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: file does not exist */ ATF_REQUIRE_EQ(-1, getfh(path, NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(nfs_getfh_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditctl_success); ATF_TC_HEAD(auditctl_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditctl(2) call"); } ATF_TC_BODY(auditctl_success, tc) { /* File needs to exist in order to call auditctl(2) */ ATF_REQUIRE((filedesc = open(path, O_CREAT | O_WRONLY, mode)) != -1); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditctl(path)); check_audit(fds, successreg, pipefd); close(filedesc); } ATF_TC_CLEANUP(auditctl_success, tc) { /* * auditctl(2) disables audit log at /var/audit and initiates auditing * 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(); + } } ATF_TC_WITH_CLEANUP(auditctl_failure); ATF_TC_HEAD(auditctl_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditctl(2) call"); } ATF_TC_BODY(auditctl_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "auditctl.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: file does not exist */ ATF_REQUIRE_EQ(-1, auditctl(NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditctl_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(acct_success); ATF_TC_HEAD(acct_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "acct(2) call"); atf_tc_set_md_var(tc, "require.files", "/etc/rc.d/accounting /etc/rc.d/auditd"); } ATF_TC_BODY(acct_success, tc) { int acctinfo, filedesc2; size_t len = sizeof(acctinfo); const char *acctname = "kern.acct_configured"; ATF_REQUIRE_EQ(0, sysctlbyname(acctname, &acctinfo, &len, NULL, 0)); /* File needs to exist to start system accounting */ ATF_REQUIRE((filedesc = open(path, O_CREAT | O_RDWR, mode)) != -1); /* * acctinfo = 0: System accounting was disabled * acctinfo = 1: System accounting was enabled */ if (acctinfo) { ATF_REQUIRE((filedesc2 = open("acct_ok", O_CREAT, mode)) != -1); close(filedesc2); } pid = getpid(); snprintf(adregex, sizeof(adregex), "acct.*%s.*%d.*return,success", path, pid); /* * We temporarily switch the accounting record to a file at * our own configured path in order to confirm acct(2)'s successful * auditing. Then we set everything back to its original state. */ FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, acct(path)); check_audit(fds, adregex, pipefd); close(filedesc); } ATF_TC_CLEANUP(acct_success, tc) { /* Reset accounting configured path */ ATF_REQUIRE_EQ(0, system("service accounting onestop")); if (atf_utils_file_exists("acct_ok")) { ATF_REQUIRE_EQ(0, system("service accounting onestart")); } cleanup(); } ATF_TC_WITH_CLEANUP(acct_failure); ATF_TC_HEAD(acct_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "acct(2) call"); } ATF_TC_BODY(acct_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "acct.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: File does not exist */ ATF_REQUIRE_EQ(-1, acct(path)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(acct_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(getauid_success); ATF_TC_HEAD(getauid_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "getauid(2) call"); } ATF_TC_BODY(getauid_success, tc) { au_id_t auid; pid = getpid(); snprintf(adregex, sizeof(adregex), "getauid.*%d.*return,success", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, getauid(&auid)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(getauid_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(getauid_failure); ATF_TC_HEAD(getauid_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "getauid(2) call"); } ATF_TC_BODY(getauid_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "getauid.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Bad address */ ATF_REQUIRE_EQ(-1, getauid(NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(getauid_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(setauid_success); ATF_TC_HEAD(setauid_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "setauid(2) call"); } ATF_TC_BODY(setauid_success, tc) { au_id_t auid; pid = getpid(); snprintf(adregex, sizeof(adregex), "setauid.*%d.*return,success", pid); ATF_REQUIRE_EQ(0, getauid(&auid)); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, setauid(&auid)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(setauid_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(setauid_failure); ATF_TC_HEAD(setauid_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "setauid(2) call"); } ATF_TC_BODY(setauid_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "setauid.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Bad address */ ATF_REQUIRE_EQ(-1, setauid(NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(setauid_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(getaudit_success); ATF_TC_HEAD(getaudit_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "getaudit(2) call"); } ATF_TC_BODY(getaudit_success, tc) { pid = getpid(); auditinfo_t auditinfo; snprintf(adregex, sizeof(adregex), "getaudit.*%d.*return,success", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, getaudit(&auditinfo)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(getaudit_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(getaudit_failure); ATF_TC_HEAD(getaudit_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "getaudit(2) call"); } ATF_TC_BODY(getaudit_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "getaudit.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Bad address */ ATF_REQUIRE_EQ(-1, getaudit(NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(getaudit_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(setaudit_success); ATF_TC_HEAD(setaudit_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "setaudit(2) call"); } ATF_TC_BODY(setaudit_success, tc) { pid = getpid(); auditinfo_t auditinfo; snprintf(adregex, sizeof(adregex), "setaudit.*%d.*return,success", pid); ATF_REQUIRE_EQ(0, getaudit(&auditinfo)); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, setaudit(&auditinfo)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(setaudit_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(setaudit_failure); ATF_TC_HEAD(setaudit_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "setaudit(2) call"); } ATF_TC_BODY(setaudit_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "setaudit.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Bad address */ ATF_REQUIRE_EQ(-1, setaudit(NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(setaudit_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(getaudit_addr_success); ATF_TC_HEAD(getaudit_addr_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "getaudit_addr(2) call"); } ATF_TC_BODY(getaudit_addr_success, tc) { pid = getpid(); auditinfo_addr_t auditinfo; snprintf(adregex, sizeof(adregex), "getaudit_addr.*%d.*return,success", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, getaudit_addr(&auditinfo, sizeof(auditinfo))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(getaudit_addr_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(getaudit_addr_failure); ATF_TC_HEAD(getaudit_addr_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "getaudit_addr(2) call"); } ATF_TC_BODY(getaudit_addr_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "getaudit_addr.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Bad address */ ATF_REQUIRE_EQ(-1, getaudit_addr(NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(getaudit_addr_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(setaudit_addr_success); ATF_TC_HEAD(setaudit_addr_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "setaudit_addr(2) call"); } ATF_TC_BODY(setaudit_addr_success, tc) { pid = getpid(); auditinfo_addr_t auditinfo; snprintf(adregex, sizeof(adregex), "setaudit_addr.*%d.*return,success", pid); ATF_REQUIRE_EQ(0, getaudit_addr(&auditinfo, sizeof(auditinfo))); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, setaudit_addr(&auditinfo, sizeof(auditinfo))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(setaudit_addr_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(setaudit_addr_failure); ATF_TC_HEAD(setaudit_addr_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "setaudit_addr(2) call"); } ATF_TC_BODY(setaudit_addr_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "setaudit_addr.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Bad address */ ATF_REQUIRE_EQ(-1, setaudit_addr(NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(setaudit_addr_failure, tc) { cleanup(); } /* * Note: The test-case uses A_GETFSIZE as the command argument but since it is * not an independent audit event, it will be used to check the default mode * auditing of auditon(2) system call. * * Please See: sys/security/audit/audit_bsm_klib.c * function(): au_event_t auditon_command_event() :: case A_GETFSIZE: */ ATF_TC_WITH_CLEANUP(auditon_default_success); ATF_TC_HEAD(auditon_default_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call"); } ATF_TC_BODY(auditon_default_success, tc) { au_fstat_t fsize_arg; bzero(&fsize_arg, sizeof(au_fstat_t)); pid = getpid(); snprintf(adregex, sizeof(adregex), "auditon.*%d.*return,success", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_GETFSIZE, &fsize_arg, sizeof(fsize_arg))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_default_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_default_failure); ATF_TC_HEAD(auditon_default_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call"); } ATF_TC_BODY(auditon_default_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "auditon.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid argument */ ATF_REQUIRE_EQ(-1, auditon(A_GETFSIZE, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_default_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getpolicy_success); ATF_TC_HEAD(auditon_getpolicy_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_GETPOLICY"); } ATF_TC_BODY(auditon_getpolicy_success, tc) { int aupolicy; pid = getpid(); snprintf(adregex, sizeof(adregex), "GPOLICY command.*%d.*success", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_GETPOLICY, &aupolicy, sizeof(aupolicy))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getpolicy_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getpolicy_failure); ATF_TC_HEAD(auditon_getpolicy_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETPOLICY"); } ATF_TC_BODY(auditon_getpolicy_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "GPOLICY command.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid argument */ ATF_REQUIRE_EQ(-1, auditon(A_GETPOLICY, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getpolicy_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setpolicy_success); ATF_TC_HEAD(auditon_setpolicy_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_SETPOLICY"); } ATF_TC_BODY(auditon_setpolicy_success, tc) { int aupolicy; pid = getpid(); snprintf(adregex, sizeof(adregex), "SPOLICY command.*%d.*success", pid); /* Retrieve the current auditing policy, to be used with A_SETPOLICY */ ATF_REQUIRE_EQ(0, auditon(A_GETPOLICY, &aupolicy, sizeof(aupolicy))); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_SETPOLICY, &aupolicy, sizeof(aupolicy))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setpolicy_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setpolicy_failure); ATF_TC_HEAD(auditon_setpolicy_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETPOLICY"); } ATF_TC_BODY(auditon_setpolicy_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "SPOLICY command.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid argument */ ATF_REQUIRE_EQ(-1, auditon(A_SETPOLICY, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setpolicy_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getkmask_success); ATF_TC_HEAD(auditon_getkmask_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_GETKMASK"); } ATF_TC_BODY(auditon_getkmask_success, tc) { pid = getpid(); au_mask_t evmask; snprintf(adregex, sizeof(adregex), "get kernel mask.*%d.*success", pid); bzero(&evmask, sizeof(evmask)); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_GETKMASK, &evmask, sizeof(evmask))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getkmask_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getkmask_failure); ATF_TC_HEAD(auditon_getkmask_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETKMASK"); } ATF_TC_BODY(auditon_getkmask_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "get kernel mask.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid au_mask_t structure */ ATF_REQUIRE_EQ(-1, auditon(A_GETKMASK, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getkmask_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setkmask_success); ATF_TC_HEAD(auditon_setkmask_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_SETKMASK"); } ATF_TC_BODY(auditon_setkmask_success, tc) { pid = getpid(); au_mask_t evmask; snprintf(adregex, sizeof(adregex), "set kernel mask.*%d.*success", pid); /* Retrieve the current audit mask to be used with A_SETKMASK */ bzero(&evmask, sizeof(evmask)); ATF_REQUIRE_EQ(0, auditon(A_GETKMASK, &evmask, sizeof(evmask))); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_SETKMASK, &evmask, sizeof(evmask))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setkmask_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setkmask_failure); ATF_TC_HEAD(auditon_setkmask_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETKMASK"); } ATF_TC_BODY(auditon_setkmask_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "set kernel mask.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid au_mask_t structure */ ATF_REQUIRE_EQ(-1, auditon(A_SETKMASK, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setkmask_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getqctrl_success); ATF_TC_HEAD(auditon_getqctrl_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_GETQCTRL"); } ATF_TC_BODY(auditon_getqctrl_success, tc) { pid = getpid(); au_qctrl_t evqctrl; snprintf(adregex, sizeof(adregex), "GQCTRL command.*%d.*success", pid); bzero(&evqctrl, sizeof(evqctrl)); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_GETQCTRL, &evqctrl, sizeof(evqctrl))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getqctrl_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getqctrl_failure); ATF_TC_HEAD(auditon_getqctrl_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETQCTRL"); } ATF_TC_BODY(auditon_getqctrl_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "GQCTRL command.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid au_qctrl_t structure */ ATF_REQUIRE_EQ(-1, auditon(A_GETQCTRL, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getqctrl_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setqctrl_success); ATF_TC_HEAD(auditon_setqctrl_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_SETKMASK"); } ATF_TC_BODY(auditon_setqctrl_success, tc) { pid = getpid(); au_qctrl_t evqctrl; snprintf(adregex, sizeof(adregex), "SQCTRL command.*%d.*success", pid); /* Retrieve the current audit mask to be used with A_SETQCTRL */ bzero(&evqctrl, sizeof(evqctrl)); ATF_REQUIRE_EQ(0, auditon(A_GETQCTRL, &evqctrl, sizeof(evqctrl))); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_SETQCTRL, &evqctrl, sizeof(evqctrl))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setqctrl_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setqctrl_failure); ATF_TC_HEAD(auditon_setqctrl_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETKMASK"); } ATF_TC_BODY(auditon_setqctrl_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "SQCTRL command.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid au_qctrl_t structure */ ATF_REQUIRE_EQ(-1, auditon(A_SETQCTRL, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setqctrl_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getclass_success); ATF_TC_HEAD(auditon_getclass_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_GETCLASS"); } ATF_TC_BODY(auditon_getclass_success, tc) { pid = getpid(); au_evclass_map_t evclass; snprintf(adregex, sizeof(adregex), "get event class.*%d.*success", pid); /* Initialize evclass to get the event-class mapping for auditon(2) */ evclass.ec_number = AUE_AUDITON; evclass.ec_class = 0; FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_GETCLASS, &evclass, sizeof(evclass))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getclass_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getclass_failure); ATF_TC_HEAD(auditon_getclass_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETCLASS"); } ATF_TC_BODY(auditon_getclass_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "get event class.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid au_evclass_map_t structure */ ATF_REQUIRE_EQ(-1, auditon(A_GETCLASS, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getclass_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setclass_success); ATF_TC_HEAD(auditon_setclass_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_SETCLASS"); } ATF_TC_BODY(auditon_setclass_success, tc) { pid = getpid(); au_evclass_map_t evclass; snprintf(adregex, sizeof(adregex), "set event class.*%d.*success", pid); /* Initialize evclass and get the event-class mapping for auditon(2) */ evclass.ec_number = AUE_AUDITON; evclass.ec_class = 0; ATF_REQUIRE_EQ(0, auditon(A_GETCLASS, &evclass, sizeof(evclass))); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_SETCLASS, &evclass, sizeof(evclass))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setclass_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setclass_failure); ATF_TC_HEAD(auditon_setclass_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETCLASS"); } ATF_TC_BODY(auditon_setclass_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "set event class.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid au_evclass_map_t structure */ ATF_REQUIRE_EQ(-1, auditon(A_SETCLASS, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setclass_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getcond_success); ATF_TC_HEAD(auditon_getcond_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_GETCOND"); } ATF_TC_BODY(auditon_getcond_success, tc) { int auditcond; pid = getpid(); snprintf(adregex, sizeof(adregex), "get audit state.*%d.*success", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(0, auditon(A_GETCOND, &auditcond, sizeof(auditcond))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getcond_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getcond_failure); ATF_TC_HEAD(auditon_getcond_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETCOND"); } ATF_TC_BODY(auditon_getcond_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "get audit state.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid argument */ ATF_REQUIRE_EQ(-1, auditon(A_GETCOND, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getcond_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setcond_success); ATF_TC_HEAD(auditon_setcond_success, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " "auditon(2) call for cmd: A_SETCOND"); } ATF_TC_BODY(auditon_setcond_success, tc) { int auditcond = AUC_AUDITING; pid = getpid(); snprintf(adregex, sizeof(adregex), "set audit state.*%d.*success", pid); FILE *pipefd = setup(fds, auclass); /* At this point auditd is running, so the audit state is AUC_AUDITING */ ATF_REQUIRE_EQ(0, auditon(A_SETCOND, &auditcond, sizeof(auditcond))); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setcond_success, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setcond_failure); ATF_TC_HEAD(auditon_setcond_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETCOND"); } ATF_TC_BODY(auditon_setcond_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "set audit state.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid argument */ ATF_REQUIRE_EQ(-1, auditon(A_SETCOND, NULL, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setcond_failure, tc) { cleanup(); } /* * Following test-cases for auditon(2) are all in failure mode only as although * auditable, they have not been implemented and return ENOSYS whenever called. * * Commands: A_GETCWD A_GETCAR A_GETSTAT A_SETSTAT A_SETUMASK A_SETSMASK */ ATF_TC_WITH_CLEANUP(auditon_getcwd_failure); ATF_TC_HEAD(auditon_getcwd_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETCWD"); } ATF_TC_BODY(auditon_getcwd_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "get cwd.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_ERRNO(ENOSYS, auditon(A_GETCWD, &auditon_def, sizeof(auditon_def)) == -1); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getcwd_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getcar_failure); ATF_TC_HEAD(auditon_getcar_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETCAR"); } ATF_TC_BODY(auditon_getcar_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "get car.*%d.*failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_ERRNO(ENOSYS, auditon(A_GETCAR, &auditon_def, sizeof(auditon_def)) == -1); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getcar_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_getstat_failure); ATF_TC_HEAD(auditon_getstat_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_GETSTAT"); } ATF_TC_BODY(auditon_getstat_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "get audit statistics.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_ERRNO(ENOSYS, auditon(A_GETSTAT, &auditon_def, sizeof(auditon_def)) == -1); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_getstat_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setstat_failure); ATF_TC_HEAD(auditon_setstat_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETSTAT"); } ATF_TC_BODY(auditon_setstat_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "set audit statistics.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_ERRNO(ENOSYS, auditon(A_SETSTAT, &auditon_def, sizeof(auditon_def)) == -1); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setstat_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setumask_failure); ATF_TC_HEAD(auditon_setumask_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETUMASK"); } ATF_TC_BODY(auditon_setumask_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "set mask per uid.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_ERRNO(ENOSYS, auditon(A_SETUMASK, &auditon_def, sizeof(auditon_def)) == -1); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setumask_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(auditon_setsmask_failure); ATF_TC_HEAD(auditon_setsmask_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "auditon(2) call for cmd: A_SETSMASK"); } ATF_TC_BODY(auditon_setsmask_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "set mask per session.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_ERRNO(ENOSYS, auditon(A_SETSMASK, &auditon_def, sizeof(auditon_def)) == -1); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(auditon_setsmask_failure, tc) { cleanup(); } /* * Audit of reboot(2) cannot be tested in normal conditions as we don't want * to reboot the system while running the tests */ ATF_TC_WITH_CLEANUP(reboot_failure); ATF_TC_HEAD(reboot_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "reboot(2) call"); } ATF_TC_BODY(reboot_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "reboot.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(-1, reboot(-1)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(reboot_failure, tc) { cleanup(); } /* * Audit of quotactl(2) cannot be tested in normal conditions as we don't want * to tamper with filesystem quotas */ ATF_TC_WITH_CLEANUP(quotactl_failure); ATF_TC_HEAD(quotactl_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "quotactl(2) call"); } ATF_TC_BODY(quotactl_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "quotactl.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(-1, quotactl(NULL, 0, 0, NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(quotactl_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(mount_failure); ATF_TC_HEAD(mount_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "mount(2) call"); } ATF_TC_BODY(mount_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "mount.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(-1, mount(NULL, NULL, 0, NULL)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(mount_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(nmount_failure); ATF_TC_HEAD(nmount_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "nmount(2) call"); } ATF_TC_BODY(nmount_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "nmount.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); ATF_REQUIRE_EQ(-1, nmount(NULL, 0, 0)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(nmount_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(swapon_failure); ATF_TC_HEAD(swapon_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "swapon(2) call"); } ATF_TC_BODY(swapon_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "swapon.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Block device required */ ATF_REQUIRE_EQ(-1, swapon(path)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(swapon_failure, tc) { cleanup(); } ATF_TC_WITH_CLEANUP(swapoff_failure); ATF_TC_HEAD(swapoff_failure, tc) { atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " "swapoff(2) call"); } ATF_TC_BODY(swapoff_failure, tc) { pid = getpid(); snprintf(adregex, sizeof(adregex), "swapoff.*%d.*return,failure", pid); FILE *pipefd = setup(fds, auclass); /* Failure reason: Block device required */ ATF_REQUIRE_EQ(-1, swapoff(path)); check_audit(fds, adregex, pipefd); } ATF_TC_CLEANUP(swapoff_failure, tc) { cleanup(); } ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, settimeofday_success); ATF_TP_ADD_TC(tp, settimeofday_failure); ATF_TP_ADD_TC(tp, clock_settime_success); ATF_TP_ADD_TC(tp, clock_settime_failure); ATF_TP_ADD_TC(tp, adjtime_success); ATF_TP_ADD_TC(tp, adjtime_failure); ATF_TP_ADD_TC(tp, ntp_adjtime_success); ATF_TP_ADD_TC(tp, ntp_adjtime_failure); ATF_TP_ADD_TC(tp, nfs_getfh_success); ATF_TP_ADD_TC(tp, nfs_getfh_failure); ATF_TP_ADD_TC(tp, acct_success); ATF_TP_ADD_TC(tp, acct_failure); ATF_TP_ADD_TC(tp, auditctl_success); ATF_TP_ADD_TC(tp, auditctl_failure); ATF_TP_ADD_TC(tp, getauid_success); ATF_TP_ADD_TC(tp, getauid_failure); ATF_TP_ADD_TC(tp, setauid_success); ATF_TP_ADD_TC(tp, setauid_failure); ATF_TP_ADD_TC(tp, getaudit_success); ATF_TP_ADD_TC(tp, getaudit_failure); ATF_TP_ADD_TC(tp, setaudit_success); ATF_TP_ADD_TC(tp, setaudit_failure); ATF_TP_ADD_TC(tp, getaudit_addr_success); ATF_TP_ADD_TC(tp, getaudit_addr_failure); ATF_TP_ADD_TC(tp, setaudit_addr_success); ATF_TP_ADD_TC(tp, setaudit_addr_failure); ATF_TP_ADD_TC(tp, auditon_default_success); ATF_TP_ADD_TC(tp, auditon_default_failure); ATF_TP_ADD_TC(tp, auditon_getpolicy_success); ATF_TP_ADD_TC(tp, auditon_getpolicy_failure); ATF_TP_ADD_TC(tp, auditon_setpolicy_success); ATF_TP_ADD_TC(tp, auditon_setpolicy_failure); ATF_TP_ADD_TC(tp, auditon_getkmask_success); ATF_TP_ADD_TC(tp, auditon_getkmask_failure); ATF_TP_ADD_TC(tp, auditon_setkmask_success); ATF_TP_ADD_TC(tp, auditon_setkmask_failure); ATF_TP_ADD_TC(tp, auditon_getqctrl_success); ATF_TP_ADD_TC(tp, auditon_getqctrl_failure); ATF_TP_ADD_TC(tp, auditon_setqctrl_success); ATF_TP_ADD_TC(tp, auditon_setqctrl_failure); ATF_TP_ADD_TC(tp, auditon_getclass_success); ATF_TP_ADD_TC(tp, auditon_getclass_failure); ATF_TP_ADD_TC(tp, auditon_setclass_success); ATF_TP_ADD_TC(tp, auditon_setclass_failure); ATF_TP_ADD_TC(tp, auditon_getcond_success); ATF_TP_ADD_TC(tp, auditon_getcond_failure); ATF_TP_ADD_TC(tp, auditon_setcond_success); ATF_TP_ADD_TC(tp, auditon_setcond_failure); ATF_TP_ADD_TC(tp, auditon_getcwd_failure); ATF_TP_ADD_TC(tp, auditon_getcar_failure); ATF_TP_ADD_TC(tp, auditon_getstat_failure); ATF_TP_ADD_TC(tp, auditon_setstat_failure); ATF_TP_ADD_TC(tp, auditon_setumask_failure); ATF_TP_ADD_TC(tp, auditon_setsmask_failure); ATF_TP_ADD_TC(tp, reboot_failure); ATF_TP_ADD_TC(tp, quotactl_failure); ATF_TP_ADD_TC(tp, mount_failure); ATF_TP_ADD_TC(tp, nmount_failure); ATF_TP_ADD_TC(tp, swapon_failure); ATF_TP_ADD_TC(tp, swapoff_failure); return (atf_no_error()); } diff --git a/tests/sys/audit/utils.c b/tests/sys/audit/utils.c index be31f4138412..e94279ff93bf 100644 --- a/tests/sys/audit/utils.c +++ b/tests/sys/audit/utils.c @@ -1,264 +1,330 @@ /*- * Copyright 2018 Aniket Pandey * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include +#include #include #include #include #include #include #include #include #include #include "utils.h" /* * Checks the presence of "auditregex" in auditpipe(4) after the * corresponding system call has been triggered. */ static bool get_records(const char *auditregex, FILE *pipestream) { uint8_t *buff; tokenstr_t token; ssize_t size = 1024; char membuff[size]; char del[] = ","; int reclen, bytes = 0; FILE *memstream; /* * Open a stream on 'membuff' (address to memory buffer) for storing * the audit records in the default mode.'reclen' is the length of the * available records from auditpipe which is passed to the functions * au_fetch_tok(3) and au_print_flags_tok(3) for further use. */ ATF_REQUIRE((memstream = fmemopen(membuff, size, "w")) != NULL); ATF_REQUIRE((reclen = au_read_rec(pipestream, &buff)) != -1); /* * Iterate through each BSM token, extracting the bits that are * required to start processing the token sequences. */ while (bytes < reclen) { if (au_fetch_tok(&token, buff + bytes, reclen - bytes) == -1) { perror("au_read_rec"); atf_tc_fail("Incomplete Audit Record"); } /* Print the tokens as they are obtained, in the default form */ au_print_flags_tok(memstream, &token, del, AU_OFLAG_NONE); bytes += token.len; } free(buff); ATF_REQUIRE_EQ(0, fclose(memstream)); return (atf_utils_grep_string("%s", membuff, auditregex)); } /* * Override the system-wide audit mask settings in /etc/security/audit_control * and set the auditpipe's maximum allowed queue length limit */ static void set_preselect_mode(int filedesc, au_mask_t *fmask) { int qlimit_max; int fmode = AUDITPIPE_PRESELECT_MODE_LOCAL; /* Set local preselection mode for auditing */ if (ioctl(filedesc, AUDITPIPE_SET_PRESELECT_MODE, &fmode) < 0) atf_tc_fail("Preselection mode: %s", strerror(errno)); /* Set local preselection flag corresponding to the audit_event */ if (ioctl(filedesc, AUDITPIPE_SET_PRESELECT_FLAGS, fmask) < 0) atf_tc_fail("Preselection flag: %s", strerror(errno)); /* Set local preselection flag for non-attributable audit_events */ if (ioctl(filedesc, AUDITPIPE_SET_PRESELECT_NAFLAGS, fmask) < 0) atf_tc_fail("Preselection naflag: %s", strerror(errno)); /* Query the maximum possible queue length limit for auditpipe */ if (ioctl(filedesc, AUDITPIPE_GET_QLIMIT_MAX, &qlimit_max) < 0) atf_tc_fail("Query max-limit: %s", strerror(errno)); /* Set the queue length limit as obtained from previous step */ if (ioctl(filedesc, AUDITPIPE_SET_QLIMIT, &qlimit_max) < 0) atf_tc_fail("Set max-qlimit: %s", strerror(errno)); /* This removes any outstanding record on the auditpipe */ if (ioctl(filedesc, AUDITPIPE_FLUSH) < 0) atf_tc_fail("Auditpipe flush: %s", strerror(errno)); } /* * Get the corresponding audit_mask for class-name "name" then set the * success and failure bits for fmask to be used as the ioctl argument */ static au_mask_t get_audit_mask(const char *name) { au_mask_t fmask; au_class_ent_t *class; ATF_REQUIRE((class = getauclassnam(name)) != NULL); fmask.am_success = class->ac_class; fmask.am_failure = class->ac_class; return (fmask); } /* * Loop until the auditpipe returns something, check if it is what * we want, else repeat the procedure until ppoll(2) times out. */ static void check_auditpipe(struct pollfd fd[], const char *auditregex, FILE *pipestream) { struct timespec currtime, endtime, timeout; /* Set the expire time for poll(2) while waiting for syscall audit */ ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC, &endtime)); /* Set limit to 30 seconds total and ~10s without an event. */ endtime.tv_sec += 30; for (;;) { /* Update the time left for auditpipe to return any event */ ATF_REQUIRE_EQ(0, clock_gettime(CLOCK_MONOTONIC, &currtime)); timespecsub(&endtime, &currtime, &timeout); timeout.tv_sec = MIN(timeout.tv_sec, 9); if (timeout.tv_sec < 0) { atf_tc_fail("%s not found in auditpipe within the " "time limit", auditregex); } switch (ppoll(fd, 1, &timeout, NULL)) { /* ppoll(2) returns, check if it's what we want */ case 1: if (fd[0].revents & POLLIN) { if (get_records(auditregex, pipestream)) return; } else { atf_tc_fail("Auditpipe returned an " "unknown event %#x", fd[0].revents); } break; /* poll(2) timed out */ case 0: atf_tc_fail("%s not found in auditpipe within the " "time limit", auditregex); break; /* poll(2) standard error */ case -1: atf_tc_fail("Poll: %s", strerror(errno)); break; default: atf_tc_fail("Poll returned too many file descriptors"); } } } /* * Wrapper functions around static "check_auditpipe" */ static void check_audit_startup(struct pollfd fd[], const char *auditrgx, FILE *pipestream){ check_auditpipe(fd, auditrgx, pipestream); } void check_audit(struct pollfd fd[], const char *auditrgx, FILE *pipestream) { check_auditpipe(fd, auditrgx, pipestream); /* Teardown: /dev/auditpipe's instance opened for this test-suite */ ATF_REQUIRE_EQ(0, fclose(pipestream)); } void skip_if_extattr_not_supported(const char *path) { ssize_t result; /* * Some file systems (e.g. tmpfs) do not support extattr, so we need * skip tests that use extattrs. To detect this we can check whether * the extattr_list_file returns EOPNOTSUPP. */ result = extattr_list_file(path, EXTATTR_NAMESPACE_USER, NULL, 0); if (result == -1 && errno == EOPNOTSUPP) { atf_tc_skip("File system does not support extattrs."); } } -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); fd[0].events = POLLIN; /* * Disable stream buffering for read operations from /dev/auditpipe. * Otherwise it is possible that fread(3), called via au_read_rec(3), * can store buffered data in user-space unbeknown to ppoll(2), which * as a result, reports that /dev/auditpipe is empty. */ ATF_REQUIRE_EQ(0, setvbuf(pipestream, NULL, _IONBF, 0)); /* 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); return (pipestream); } 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"); + } }