1221431Sjonathan/*- 2221431Sjonathan * Copyright (c) 2008-2011 Robert N. M. Watson 3224651Sjonathan * Copyright (c) 2011 Jonathan Anderson 4221431Sjonathan * All rights reserved. 5221431Sjonathan * 6221431Sjonathan * Redistribution and use in source and binary forms, with or without 7221431Sjonathan * modification, are permitted provided that the following conditions 8221431Sjonathan * are met: 9221431Sjonathan * 1. Redistributions of source code must retain the above copyright 10221431Sjonathan * notice, this list of conditions and the following disclaimer. 11221431Sjonathan * 2. Redistributions in binary form must reproduce the above copyright 12221431Sjonathan * notice, this list of conditions and the following disclaimer in the 13221431Sjonathan * documentation and/or other materials provided with the distribution. 14221431Sjonathan * 15221431Sjonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16221431Sjonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17221431Sjonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18221431Sjonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19221431Sjonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20221431Sjonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21221431Sjonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22221431Sjonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23221431Sjonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24221431Sjonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25221431Sjonathan * SUCH DAMAGE. 26221431Sjonathan * 27221431Sjonathan * $FreeBSD$ 28221431Sjonathan */ 29221431Sjonathan 30221431Sjonathan#ifndef CAP_TEST_H 31221431Sjonathan#define CAP_TEST_H 32221431Sjonathan 33224651Sjonathan#include <err.h> 34221431Sjonathan 35224651Sjonathan/* 36224651Sjonathan * Define a file required by a test. The test can't complete without the file, 37224651Sjonathan * so if we don't have it, just die. 38224651Sjonathan */ 39224651Sjonathan#define REQUIRE(fd) do { \ 40224651Sjonathan if ((fd) < 0) \ 41224651Sjonathan err(-1, "%s:%d: Missing required file '%s'", \ 42224651Sjonathan __FILE__, __LINE__, #fd); \ 43224651Sjonathan} while (0) 44224651Sjonathan 45224651Sjonathan/* Whether a test passed or failed. */ 46224651Sjonathan#define PASSED 0 47224651Sjonathan#define FAILED 1 48224651Sjonathan 49224651Sjonathan/* A test has failed; print a message and clear the 'success' flag. */ 50224651Sjonathan#define FAIL(...) do { \ 51224651Sjonathan warn(__VA_ARGS__); \ 52224651Sjonathan success = FAILED; \ 53224651Sjonathan} while (0) 54224651Sjonathan 55224651Sjonathan/* As above, but do not print the errno message. */ 56224651Sjonathan#define FAILX(...) do { \ 57224651Sjonathan warnx(__VA_ARGS__); \ 58224651Sjonathan success = FAILED; \ 59224651Sjonathan} while (0) 60224651Sjonathan 61224651Sjonathan/* Like an assertion, but don't kill the test, just fail and keep going. */ 62224651Sjonathan#define CHECK(condition) do { \ 63224651Sjonathan if (!(condition)) \ 64224651Sjonathan FAILX("%s:%d: Assertion '%s' failed", \ 65224651Sjonathan __func__, __LINE__, #condition); \ 66224651Sjonathan} while (0) 67224651Sjonathan 68224651Sjonathan/* Make sure that a system call's return value is >= 0. */ 69224651Sjonathan#define CHECK_SYSCALL_SUCCEEDS(syscall, ...) do { \ 70224651Sjonathan if (syscall(__VA_ARGS__) < 0) \ 71224651Sjonathan FAIL("%s() at line %d: %s failed", \ 72224651Sjonathan __func__, __LINE__, #syscall); \ 73224651Sjonathan} while (0) 74224651Sjonathan 75224651Sjonathan/* Make sure that a system call fails with the correct errno. */ 76224651Sjonathan#define CHECK_SYSCALL_FAILS(expected_errno, syscall, ...) do { \ 77224651Sjonathan if (syscall(__VA_ARGS__) < 0) { \ 78224651Sjonathan if (errno != expected_errno) \ 79224651Sjonathan FAIL("%s() at line %d: %s", \ 80224651Sjonathan __func__, __LINE__, #syscall); \ 81224651Sjonathan } else { \ 82224651Sjonathan FAILX("%s() at line %d: %s succeeded; it should've failed", \ 83224651Sjonathan __func__, __LINE__, #syscall); \ 84224651Sjonathan } \ 85224651Sjonathan} while (0) 86224651Sjonathan 87224651Sjonathan/* Make sure that a system call fails, but not with a particular errno. */ 88224651Sjonathan#define CHECK_SYSCALL_FAILS_BUT_NOT_WITH(bad_errno, syscall, ...) do { \ 89224651Sjonathan if (syscall(__VA_ARGS__) < 0) { \ 90224651Sjonathan if (errno == bad_errno) \ 91224651Sjonathan FAIL("%s() at line %d: %s", \ 92224651Sjonathan __func__, __LINE__, #syscall); \ 93224651Sjonathan } else { \ 94224651Sjonathan FAILX("%s() at line %d: %s succeeded; it should've failed", \ 95224651Sjonathan __func__, __LINE__, #syscall); \ 96224651Sjonathan } \ 97224651Sjonathan} while (0) 98224651Sjonathan 99224651Sjonathan/* A system call should fail with ECAPMODE. */ 100224651Sjonathan#define CHECK_CAPMODE(...) \ 101224651Sjonathan CHECK_SYSCALL_FAILS(ECAPMODE, __VA_ARGS__) 102224651Sjonathan 103224651Sjonathan/* A system call should fail, but not with ECAPMODE. */ 104224651Sjonathan#define CHECK_NOT_CAPMODE(...) \ 105224651Sjonathan CHECK_SYSCALL_FAILS_BUT_NOT_WITH(ECAPMODE, __VA_ARGS__) 106224651Sjonathan 107224651Sjonathan/* A system call should fail with ENOTCAPABLE. */ 108224651Sjonathan#define CHECK_NOTCAPABLE(...) \ 109224651Sjonathan CHECK_SYSCALL_FAILS(ENOTCAPABLE, __VA_ARGS__) 110224651Sjonathan 111224651Sjonathan/* Ensure that 'rights' are a subset of 'max'. */ 112224651Sjonathan#define CHECK_RIGHTS(rights, max) do { \ 113224651Sjonathan if ((success == PASSED) && (rights != max)) \ 114224651Sjonathan FAILX("Rights of opened file (%jx) > maximum (%jx)", \ 115224651Sjonathan (cap_rights_t) rights, (cap_rights_t) max); \ 116224651Sjonathan} while (0) 117224651Sjonathan 118224651Sjonathan/* Create a capability from a file descriptor, make sure it succeeds. */ 119224651Sjonathan#define MAKE_CAPABILITY(to, from, rights) do { \ 120224651Sjonathan cap_rights_t _rights; \ 121224651Sjonathan REQUIRE(to = cap_new(from, rights)); \ 122224651Sjonathan CHECK_SYSCALL_SUCCEEDS(cap_getrights, to, &_rights); \ 123224651Sjonathan if ((success == PASSED) && (_rights != (rights))) \ 124224651Sjonathan FAILX("New capability's rights (%jx) != %jx", \ 125224651Sjonathan _rights, (cap_rights_t) (rights)); \ 126224651Sjonathan} while (0) 127224651Sjonathan 128224651Sjonathan/* 129224651Sjonathan * A top-level test should take no arguments and return an integer value, 130224651Sjonathan * either PASSED or FAILED. 131224651Sjonathan * 132224651Sjonathan * Errors such as SIGSEGV will be caught and interpreted as FAILED. 133224651Sjonathan */ 134224651Sjonathantypedef int (*test_function)(void); 135224651Sjonathan 136224651Sjonathan/* Information about a test. */ 137224651Sjonathanstruct test { 138224651Sjonathan char *t_name; 139224651Sjonathan test_function t_run; 140224651Sjonathan int t_result; 141224651Sjonathan}; 142224651Sjonathan 143224651Sjonathan/* 144224651Sjonathan * Run a test in a child process so that cap_enter(2) doesn't mess up 145224651Sjonathan * subsequent tests. 146224651Sjonathan */ 147224651Sjonathanint execute(int id, struct test*); 148224651Sjonathan 149224651Sjonathanint test_capmode(void); 150224651Sjonathanint test_capabilities(void); 151224793Sjonathanint test_fcntl(void); 152224989Sjonathanint test_pdfork(void); 153224989Sjonathanint test_pdkill(void); 154224989Sjonathanint test_pdwait(void); 155224793Sjonathanint test_relative(void); 156224651Sjonathanint test_sysctl(void); 157224651Sjonathan 158221431Sjonathan#endif /* CAP_TEST_H */ 159