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