/*- * Copyright (c) 2008-2011 Robert N. M. Watson * Copyright (c) 2011 Jonathan Anderson * All rights reserved. * * 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 * 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 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CAP_TEST_H #define CAP_TEST_H #include /* * Define a file required by a test. The test can't complete without the file, * so if we don't have it, just die. */ #define REQUIRE(fd) do { \ if ((fd) < 0) \ err(-1, "%s:%d: Missing required file '%s'", \ __FILE__, __LINE__, #fd); \ } while (0) /* Whether a test passed or failed. */ #define PASSED 0 #define FAILED 1 /* A test has failed; print a message and clear the 'success' flag. */ #define FAIL(...) do { \ warn(__VA_ARGS__); \ success = FAILED; \ } while (0) /* As above, but do not print the errno message. */ #define FAILX(...) do { \ warnx(__VA_ARGS__); \ success = FAILED; \ } while (0) /* Like an assertion, but don't kill the test, just fail and keep going. */ #define CHECK(condition) do { \ if (!(condition)) \ FAILX("%s:%d: Assertion '%s' failed", \ __func__, __LINE__, #condition); \ } while (0) /* Make sure that a system call's return value is >= 0. */ #define CHECK_SYSCALL_SUCCEEDS(syscall, ...) do { \ if (syscall(__VA_ARGS__) < 0) \ FAIL("%s() at line %d: %s failed", \ __func__, __LINE__, #syscall); \ } while (0) /* Make sure that a system call fails with the correct errno. */ #define CHECK_SYSCALL_FAILS(expected_errno, syscall, ...) do { \ if (syscall(__VA_ARGS__) < 0) { \ if (errno != expected_errno) \ FAIL("%s() at line %d: %s", \ __func__, __LINE__, #syscall); \ } else { \ FAILX("%s() at line %d: %s succeeded; it should've failed", \ __func__, __LINE__, #syscall); \ } \ } while (0) /* Make sure that a system call fails, but not with a particular errno. */ #define CHECK_SYSCALL_FAILS_BUT_NOT_WITH(bad_errno, syscall, ...) do { \ if (syscall(__VA_ARGS__) < 0) { \ if (errno == bad_errno) \ FAIL("%s() at line %d: %s", \ __func__, __LINE__, #syscall); \ } else { \ FAILX("%s() at line %d: %s succeeded; it should've failed", \ __func__, __LINE__, #syscall); \ } \ } while (0) /* A system call should fail with ECAPMODE. */ #define CHECK_CAPMODE(...) \ CHECK_SYSCALL_FAILS(ECAPMODE, __VA_ARGS__) /* A system call should fail, but not with ECAPMODE. */ #define CHECK_NOT_CAPMODE(...) \ CHECK_SYSCALL_FAILS_BUT_NOT_WITH(ECAPMODE, __VA_ARGS__) /* A system call should fail with ENOTCAPABLE. */ #define CHECK_NOTCAPABLE(...) \ CHECK_SYSCALL_FAILS(ENOTCAPABLE, __VA_ARGS__) /* Ensure that 'rights' are a subset of 'max'. */ #define CHECK_RIGHTS(rights, max) do { \ if ((success == PASSED) && (rights != max)) \ FAILX("Rights of opened file (%jx) > maximum (%jx)", \ (cap_rights_t) rights, (cap_rights_t) max); \ } while (0) /* Create a capability from a file descriptor, make sure it succeeds. */ #define MAKE_CAPABILITY(to, from, rights) do { \ cap_rights_t _rights; \ REQUIRE(to = cap_new(from, rights)); \ CHECK_SYSCALL_SUCCEEDS(cap_getrights, to, &_rights); \ if ((success == PASSED) && (_rights != (rights))) \ FAILX("New capability's rights (%jx) != %jx", \ _rights, (cap_rights_t) (rights)); \ } while (0) /* * A top-level test should take no arguments and return an integer value, * either PASSED or FAILED. * * Errors such as SIGSEGV will be caught and interpreted as FAILED. */ typedef int (*test_function)(void); /* Information about a test. */ struct test { char *t_name; test_function t_run; int t_result; }; /* * Run a test in a child process so that cap_enter(2) doesn't mess up * subsequent tests. */ int execute(int id, struct test*); int test_capmode(void); int test_capabilities(void); int test_fcntl(void); int test_pdfork(void); int test_pdkill(void); int test_pdwait(void); int test_relative(void); int test_sysctl(void); #endif /* CAP_TEST_H */