xref: /freebsd/sys/kern/subr_capability.c (revision 5b9c547c)
1 /*-
2  * Copyright (c) 2013 FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 /*
34  * Note that this file is compiled into the kernel and into libc.
35  */
36 
37 #include <sys/types.h>
38 #include <sys/capsicum.h>
39 
40 #ifdef _KERNEL
41 #include <sys/systm.h>
42 
43 #include <machine/stdarg.h>
44 #else	/* !_KERNEL */
45 #include <assert.h>
46 #include <stdarg.h>
47 #include <stdbool.h>
48 #include <stdint.h>
49 #include <string.h>
50 #endif
51 
52 #ifdef _KERNEL
53 #define	assert(exp)	KASSERT((exp), ("%s:%u", __func__, __LINE__))
54 #endif
55 
56 #define	CAPARSIZE_MIN	(CAP_RIGHTS_VERSION_00 + 2)
57 #define	CAPARSIZE_MAX	(CAP_RIGHTS_VERSION + 2)
58 
59 static __inline int
60 right_to_index(uint64_t right)
61 {
62 	static const int bit2idx[] = {
63 		-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
64 		4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
65 	};
66 	int idx;
67 
68 	idx = CAPIDXBIT(right);
69 	assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0]));
70 	return (bit2idx[idx]);
71 }
72 
73 static void
74 cap_rights_vset(cap_rights_t *rights, va_list ap)
75 {
76 	uint64_t right;
77 	int i, n;
78 
79 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
80 
81 	n = CAPARSIZE(rights);
82 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
83 
84 	for (;;) {
85 		right = (uint64_t)va_arg(ap, unsigned long long);
86 		if (right == 0)
87 			break;
88 		assert(CAPRVER(right) == 0);
89 		i = right_to_index(right);
90 		assert(i >= 0);
91 		assert(i < n);
92 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
93 		rights->cr_rights[i] |= right;
94 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
95 	}
96 }
97 
98 static void
99 cap_rights_vclear(cap_rights_t *rights, va_list ap)
100 {
101 	uint64_t right;
102 	int i, n;
103 
104 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
105 
106 	n = CAPARSIZE(rights);
107 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
108 
109 	for (;;) {
110 		right = (uint64_t)va_arg(ap, unsigned long long);
111 		if (right == 0)
112 			break;
113 		assert(CAPRVER(right) == 0);
114 		i = right_to_index(right);
115 		assert(i >= 0);
116 		assert(i < n);
117 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
118 		rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL);
119 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
120 	}
121 }
122 
123 static bool
124 cap_rights_is_vset(const cap_rights_t *rights, va_list ap)
125 {
126 	uint64_t right;
127 	int i, n;
128 
129 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
130 
131 	n = CAPARSIZE(rights);
132 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
133 
134 	for (;;) {
135 		right = (uint64_t)va_arg(ap, unsigned long long);
136 		if (right == 0)
137 			break;
138 		assert(CAPRVER(right) == 0);
139 		i = right_to_index(right);
140 		assert(i >= 0);
141 		assert(i < n);
142 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
143 		if ((rights->cr_rights[i] & right) != right)
144 			return (false);
145 	}
146 
147 	return (true);
148 }
149 
150 cap_rights_t *
151 __cap_rights_init(int version, cap_rights_t *rights, ...)
152 {
153 	unsigned int n;
154 	va_list ap;
155 
156 	assert(version == CAP_RIGHTS_VERSION_00);
157 
158 	n = version + 2;
159 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
160 	memset(rights->cr_rights, 0, sizeof(rights->cr_rights[0]) * n);
161 	CAP_NONE(rights);
162 	va_start(ap, rights);
163 	cap_rights_vset(rights, ap);
164 	va_end(ap);
165 
166 	return (rights);
167 }
168 
169 cap_rights_t *
170 __cap_rights_set(cap_rights_t *rights, ...)
171 {
172 	va_list ap;
173 
174 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
175 
176 	va_start(ap, rights);
177 	cap_rights_vset(rights, ap);
178 	va_end(ap);
179 
180 	return (rights);
181 }
182 
183 cap_rights_t *
184 __cap_rights_clear(cap_rights_t *rights, ...)
185 {
186 	va_list ap;
187 
188 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
189 
190 	va_start(ap, rights);
191 	cap_rights_vclear(rights, ap);
192 	va_end(ap);
193 
194 	return (rights);
195 }
196 
197 bool
198 __cap_rights_is_set(const cap_rights_t *rights, ...)
199 {
200 	va_list ap;
201 	bool ret;
202 
203 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
204 
205 	va_start(ap, rights);
206 	ret = cap_rights_is_vset(rights, ap);
207 	va_end(ap);
208 
209 	return (ret);
210 }
211 
212 bool
213 cap_rights_is_valid(const cap_rights_t *rights)
214 {
215 	cap_rights_t allrights;
216 	int i, j;
217 
218 	if (CAPVER(rights) != CAP_RIGHTS_VERSION_00)
219 		return (false);
220 	if (CAPARSIZE(rights) < CAPARSIZE_MIN ||
221 	    CAPARSIZE(rights) > CAPARSIZE_MAX) {
222 		return (false);
223 	}
224 	CAP_ALL(&allrights);
225 	if (!cap_rights_contains(&allrights, rights))
226 		return (false);
227 	for (i = 0; i < CAPARSIZE(rights); i++) {
228 		j = right_to_index(rights->cr_rights[i]);
229 		if (i != j)
230 			return (false);
231 		if (i > 0) {
232 			if (CAPRVER(rights->cr_rights[i]) != 0)
233 				return (false);
234 		}
235 	}
236 
237 	return (true);
238 }
239 
240 cap_rights_t *
241 cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src)
242 {
243 	unsigned int i, n;
244 
245 	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
246 	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
247 	assert(CAPVER(dst) == CAPVER(src));
248 	assert(cap_rights_is_valid(src));
249 	assert(cap_rights_is_valid(dst));
250 
251 	n = CAPARSIZE(dst);
252 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
253 
254 	for (i = 0; i < n; i++)
255 		dst->cr_rights[i] |= src->cr_rights[i];
256 
257 	assert(cap_rights_is_valid(src));
258 	assert(cap_rights_is_valid(dst));
259 
260 	return (dst);
261 }
262 
263 cap_rights_t *
264 cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src)
265 {
266 	unsigned int i, n;
267 
268 	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
269 	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
270 	assert(CAPVER(dst) == CAPVER(src));
271 	assert(cap_rights_is_valid(src));
272 	assert(cap_rights_is_valid(dst));
273 
274 	n = CAPARSIZE(dst);
275 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
276 
277 	for (i = 0; i < n; i++) {
278 		dst->cr_rights[i] &=
279 		    ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL);
280 	}
281 
282 	assert(cap_rights_is_valid(src));
283 	assert(cap_rights_is_valid(dst));
284 
285 	return (dst);
286 }
287 
288 bool
289 cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
290 {
291 	unsigned int i, n;
292 
293 	assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
294 	assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
295 	assert(CAPVER(big) == CAPVER(little));
296 
297 	n = CAPARSIZE(big);
298 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
299 
300 	for (i = 0; i < n; i++) {
301 		if ((big->cr_rights[i] & little->cr_rights[i]) !=
302 		    little->cr_rights[i]) {
303 			return (false);
304 		}
305 	}
306 
307 	return (true);
308 }
309