diff --git a/tests/sys/audit/process-control.c b/tests/sys/audit/process-control.c index 8dff62ac9297..b92382b3f0b4 100644 --- a/tests/sys/audit/process-control.c +++ b/tests/sys/audit/process-control.c @@ -26,6 +26,7 @@ */ #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include @@ -85,6 +87,35 @@ ATF_TC_CLEANUP(fork_success, tc) */ +ATF_TC_WITH_CLEANUP(_exit_success); +ATF_TC_HEAD(_exit_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "_exit(2) call"); +} + +ATF_TC_BODY(_exit_success, tc) +{ + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((pid = fork()) != -1); + if (pid) { + snprintf(pcregex, sizeof(pcregex), "exit.*%d.*success", pid); + check_audit(fds, pcregex, pipefd); + } + else + _exit(0); +} + +ATF_TC_CLEANUP(_exit_success, tc) +{ + cleanup(); +} + +/* + * _exit(2) never returns, hence the auditing by default is always successful + */ + + ATF_TC_WITH_CLEANUP(rfork_success); ATF_TC_HEAD(rfork_success, tc) { @@ -1472,9 +1503,104 @@ ATF_TC_CLEANUP(procctl_failure, tc) } +ATF_TC_WITH_CLEANUP(cap_enter_success); +ATF_TC_HEAD(cap_enter_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "cap_enter(2) call"); +} + +ATF_TC_BODY(cap_enter_success, tc) +{ + int capinfo; + size_t len = sizeof(capinfo); + const char *capname = "kern.features.security_capability_mode"; + ATF_REQUIRE_EQ(0, sysctlbyname(capname, &capinfo, &len, NULL, 0)); + + /* Without CAPABILITY_MODE enabled, cap_enter() returns ENOSYS */ + if (!capinfo) + atf_tc_skip("Capsicum is not enabled in the system"); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((pid = fork()) != -1); + if (pid) { + snprintf(pcregex, sizeof(pcregex), + "cap_enter.*%d.*return,success", pid); + ATF_REQUIRE(wait(&status) != -1); + check_audit(fds, pcregex, pipefd); + } + else { + ATF_REQUIRE_EQ(0, cap_enter()); + _exit(0); + } +} + +ATF_TC_CLEANUP(cap_enter_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(cap_getmode_success); +ATF_TC_HEAD(cap_getmode_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "cap_getmode(2) call"); +} + +ATF_TC_BODY(cap_getmode_success, tc) +{ + int capinfo, modep; + size_t len = sizeof(capinfo); + const char *capname = "kern.features.security_capability_mode"; + ATF_REQUIRE_EQ(0, sysctlbyname(capname, &capinfo, &len, NULL, 0)); + + /* Without CAPABILITY_MODE enabled, cap_getmode() returns ENOSYS */ + if (!capinfo) + atf_tc_skip("Capsicum is not enabled in the system"); + + pid = getpid(); + snprintf(pcregex, sizeof(pcregex), "cap_getmode.*%d.*success", pid); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(0, cap_getmode(&modep)); + check_audit(fds, pcregex, pipefd); +} + +ATF_TC_CLEANUP(cap_getmode_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(cap_getmode_failure); +ATF_TC_HEAD(cap_getmode_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "cap_getmode(2) call"); +} + +ATF_TC_BODY(cap_getmode_failure, tc) +{ + pid = getpid(); + snprintf(pcregex, sizeof(pcregex), "cap_getmode.*%d.*failure", pid); + + FILE *pipefd = setup(fds, auclass); + /* cap_getmode(2) can either fail with EFAULT or ENOSYS */ + ATF_REQUIRE_EQ(-1, cap_getmode(NULL)); + check_audit(fds, pcregex, pipefd); +} + +ATF_TC_CLEANUP(cap_getmode_failure, tc) +{ + cleanup(); +} + + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, fork_success); + ATF_TP_ADD_TC(tp, _exit_success); ATF_TP_ADD_TC(tp, rfork_success); ATF_TP_ADD_TC(tp, rfork_failure); @@ -1540,5 +1666,9 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, procctl_success); ATF_TP_ADD_TC(tp, procctl_failure); + ATF_TP_ADD_TC(tp, cap_enter_success); + ATF_TP_ADD_TC(tp, cap_getmode_success); + ATF_TP_ADD_TC(tp, cap_getmode_failure); + return (atf_no_error()); } diff --git a/tests/sys/audit/utils.c b/tests/sys/audit/utils.c index 30e313677ed3..531c99ea77da 100644 --- a/tests/sys/audit/utils.c +++ b/tests/sys/audit/utils.c @@ -211,6 +211,14 @@ FILE 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 || \