1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
check_sysdecode_cap_rights(FILE * fp,char ** bufp,size_t * szp,cap_rights_t * rightsp,const char * tab[])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);
ATF_TC_BODY(cap_rights,tc)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
ATF_TP_ADD_TCS(tp)147 ATF_TP_ADD_TCS(tp)
148 {
149 ATF_TP_ADD_TC(tp, cap_rights);
150
151 return (atf_no_error());
152 }
153