1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2022 The FreeBSD Foundation 5 * 6 * This software was developed by Mark Johnston under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions are 11 * met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/capsicum.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 35 #include <atf-c.h> 36 #include <sysdecode.h> 37 38 /* 39 * Take a comma-separated list of capability rights and verify that all rights 40 * are present in the specified table, and that all rights in the table are 41 * present in the list. 42 */ 43 static void 44 check_sysdecode_cap_rights(FILE *fp, char **bufp, size_t *szp, 45 cap_rights_t *rightsp, const char *tab[]) 46 { 47 const char *next, *tok; 48 char *buf; 49 int i; 50 51 sysdecode_cap_rights(fp, rightsp); 52 53 ATF_REQUIRE(fflush(fp) == 0); 54 (*bufp)[*szp] = '\0'; 55 56 buf = strdup(*bufp); 57 for (tok = buf; (next = strsep(&buf, ",")), tok != NULL; tok = next) { 58 for (i = 0; tab[i] != NULL; i++) { 59 if (strcmp(tok, tab[i]) == 0) 60 break; 61 } 62 ATF_REQUIRE_MSG(tab[i] != NULL, 63 "did not find '%s' in table", tok); 64 } 65 free(buf); 66 67 for (i = 0; tab[i] != NULL; i++) { 68 buf = strdup(*bufp); 69 for (tok = buf; (next = strsep(&buf, ",")), tok != NULL; 70 tok = next) { 71 if (strcmp(tok, tab[i]) == 0) 72 break; 73 } 74 free(buf); 75 ATF_REQUIRE_MSG(tok != NULL, 76 "did not find '%s' in output stream", tab[i]); 77 } 78 79 ATF_REQUIRE(fseek(fp, 0, SEEK_SET) == 0); 80 } 81 82 /* 83 * Regression tests for sysdecode_cap_rights(3). 84 */ 85 ATF_TC_WITHOUT_HEAD(cap_rights); 86 ATF_TC_BODY(cap_rights, tc) 87 { 88 char *buf; 89 FILE *fp; 90 size_t sz; 91 cap_rights_t rights; 92 93 fp = open_memstream(&buf, &sz); 94 ATF_REQUIRE(fp != NULL); 95 96 /* 97 * libsysdecode emits a pseudo-right, CAP_NONE, when no rights are 98 * present. 99 */ 100 check_sysdecode_cap_rights(fp, &buf, &sz, 101 cap_rights_init(&rights), 102 (const char *[]){ "CAP_NONE", NULL, }); 103 104 check_sysdecode_cap_rights(fp, &buf, &sz, 105 cap_rights_init(&rights, CAP_READ, CAP_SEEK), 106 (const char *[]){ "CAP_PREAD", NULL, }); 107 108 check_sysdecode_cap_rights(fp, &buf, &sz, 109 cap_rights_init(&rights, CAP_READ, CAP_MMAP, CAP_SEEK_TELL), 110 (const char *[]){ "CAP_READ", "CAP_MMAP", "CAP_SEEK_TELL", NULL, }); 111 112 check_sysdecode_cap_rights(fp, &buf, &sz, 113 cap_rights_init(&rights, CAP_MMAP, CAP_READ, CAP_WRITE, CAP_SEEK), 114 (const char *[]){ "CAP_MMAP_RW", NULL, }); 115 116 check_sysdecode_cap_rights(fp, &buf, &sz, 117 cap_rights_init(&rights, CAP_READ, CAP_MMAP_X), 118 (const char *[]){ "CAP_MMAP_RX", NULL, }); 119 120 /* Aliases map back to the main definition. */ 121 check_sysdecode_cap_rights(fp, &buf, &sz, 122 cap_rights_init(&rights, CAP_RECV, CAP_SEND), 123 (const char *[]){ "CAP_READ", "CAP_WRITE", NULL, }); 124 125 /* This set straddles both indices. */ 126 check_sysdecode_cap_rights(fp, &buf, &sz, 127 cap_rights_init(&rights, CAP_READ, CAP_KQUEUE), 128 (const char *[]){ "CAP_READ", "CAP_KQUEUE", NULL, }); 129 130 /* Create a rights set with an unnamed flag. */ 131 cap_rights_init(&rights, CAP_SEEK); 132 cap_rights_clear(&rights, CAP_SEEK_TELL); 133 check_sysdecode_cap_rights(fp, &buf, &sz, 134 &rights, 135 (const char *[]){ "CAP_NONE", "unknown rights", NULL, }); 136 137 cap_rights_init(&rights, CAP_SEEK, CAP_KQUEUE_CHANGE); 138 cap_rights_clear(&rights, CAP_SEEK_TELL); 139 check_sysdecode_cap_rights(fp, &buf, &sz, 140 &rights, 141 (const char *[]){ "CAP_KQUEUE_CHANGE", "unknown rights", NULL, }); 142 143 ATF_REQUIRE(fclose(fp) == 0); 144 free(buf); 145 } 146 147 ATF_TP_ADD_TCS(tp) 148 { 149 ATF_TP_ADD_TC(tp, cap_rights); 150 151 return (atf_no_error()); 152 } 153