xref: /freebsd/sys/kern/subr_capability.c (revision f1f230439fa48581f40a57f095627f667a9713c3)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 FreeBSD Foundation
5  *
6  * This software was developed by Pawel Jakub Dawidek 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
11  * are 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 the
16  *    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/cdefs.h>
32 /*
33  * Note that this file is compiled into the kernel and into libc.
34  */
35 
36 #include <sys/types.h>
37 #include <sys/capsicum.h>
38 
39 #ifdef _KERNEL
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/stdarg.h>
43 #else	/* !_KERNEL */
44 #include <assert.h>
45 #include <stdarg.h>
46 #include <stdbool.h>
47 #include <stdint.h>
48 #include <string.h>
49 #endif
50 
51 #ifdef _KERNEL
52 #define	assert(exp)	KASSERT((exp), ("%s:%u", __func__, __LINE__))
53 const cap_rights_t cap_accept_rights = CAP_RIGHTS_INITIALIZER(CAP_ACCEPT);
54 const cap_rights_t cap_bind_rights = CAP_RIGHTS_INITIALIZER(CAP_BIND);
55 const cap_rights_t cap_connect_rights = CAP_RIGHTS_INITIALIZER(CAP_CONNECT);
56 const cap_rights_t cap_event_rights = CAP_RIGHTS_INITIALIZER(CAP_EVENT);
57 const cap_rights_t cap_fchdir_rights = CAP_RIGHTS_INITIALIZER(CAP_FCHDIR);
58 const cap_rights_t cap_fchflags_rights = CAP_RIGHTS_INITIALIZER(CAP_FCHFLAGS);
59 const cap_rights_t cap_fchmod_rights = CAP_RIGHTS_INITIALIZER(CAP_FCHMOD);
60 const cap_rights_t cap_fchown_rights = CAP_RIGHTS_INITIALIZER(CAP_FCHOWN);
61 const cap_rights_t cap_fchroot_rights = CAP_RIGHTS_INITIALIZER(CAP_FCHROOT);
62 const cap_rights_t cap_fcntl_rights = CAP_RIGHTS_INITIALIZER(CAP_FCNTL);
63 const cap_rights_t cap_fexecve_rights = CAP_RIGHTS_INITIALIZER(CAP_FEXECVE);
64 const cap_rights_t cap_flock_rights = CAP_RIGHTS_INITIALIZER(CAP_FLOCK);
65 const cap_rights_t cap_fpathconf_rights = CAP_RIGHTS_INITIALIZER(CAP_FPATHCONF);
66 const cap_rights_t cap_fstat_rights = CAP_RIGHTS_INITIALIZER(CAP_FSTAT);
67 const cap_rights_t cap_fstatfs_rights = CAP_RIGHTS_INITIALIZER(CAP_FSTATFS);
68 const cap_rights_t cap_fsync_rights = CAP_RIGHTS_INITIALIZER(CAP_FSYNC);
69 const cap_rights_t cap_ftruncate_rights = CAP_RIGHTS_INITIALIZER(CAP_FTRUNCATE);
70 const cap_rights_t cap_futimes_rights = CAP_RIGHTS_INITIALIZER(CAP_FUTIMES);
71 const cap_rights_t cap_getpeername_rights =
72     CAP_RIGHTS_INITIALIZER(CAP_GETPEERNAME);
73 const cap_rights_t cap_getsockopt_rights =
74     CAP_RIGHTS_INITIALIZER(CAP_GETSOCKOPT);
75 const cap_rights_t cap_getsockname_rights =
76     CAP_RIGHTS_INITIALIZER(CAP_GETSOCKNAME);
77 const cap_rights_t cap_inotify_add_rights =
78     CAP_RIGHTS_INITIALIZER(CAP_INOTIFY_ADD);
79 const cap_rights_t cap_inotify_rm_rights =
80     CAP_RIGHTS_INITIALIZER(CAP_INOTIFY_RM);
81 const cap_rights_t cap_ioctl_rights = CAP_RIGHTS_INITIALIZER(CAP_IOCTL);
82 const cap_rights_t cap_listen_rights = CAP_RIGHTS_INITIALIZER(CAP_LISTEN);
83 const cap_rights_t cap_linkat_source_rights =
84     CAP_RIGHTS_INITIALIZER(CAP_LINKAT_SOURCE);
85 const cap_rights_t cap_linkat_target_rights =
86     CAP_RIGHTS_INITIALIZER(CAP_LINKAT_TARGET);
87 const cap_rights_t cap_mmap_rights = CAP_RIGHTS_INITIALIZER(CAP_MMAP);
88 const cap_rights_t cap_mkdirat_rights = CAP_RIGHTS_INITIALIZER(CAP_MKDIRAT);
89 const cap_rights_t cap_mkfifoat_rights = CAP_RIGHTS_INITIALIZER(CAP_MKFIFOAT);
90 const cap_rights_t cap_mknodat_rights = CAP_RIGHTS_INITIALIZER(CAP_MKNODAT);
91 const cap_rights_t cap_pdgetpid_rights = CAP_RIGHTS_INITIALIZER(CAP_PDGETPID);
92 const cap_rights_t cap_pdkill_rights = CAP_RIGHTS_INITIALIZER(CAP_PDKILL);
93 const cap_rights_t cap_pread_rights = CAP_RIGHTS_INITIALIZER(CAP_PREAD);
94 const cap_rights_t cap_pwrite_rights = CAP_RIGHTS_INITIALIZER(CAP_PWRITE);
95 const cap_rights_t cap_read_rights = CAP_RIGHTS_INITIALIZER(CAP_READ);
96 const cap_rights_t cap_recv_rights = CAP_RIGHTS_INITIALIZER(CAP_RECV);
97 const cap_rights_t cap_renameat_source_rights =
98     CAP_RIGHTS_INITIALIZER(CAP_RENAMEAT_SOURCE);
99 const cap_rights_t cap_renameat_target_rights =
100     CAP_RIGHTS_INITIALIZER(CAP_RENAMEAT_TARGET);
101 const cap_rights_t cap_seek_rights = CAP_RIGHTS_INITIALIZER(CAP_SEEK);
102 const cap_rights_t cap_send_rights = CAP_RIGHTS_INITIALIZER(CAP_SEND);
103 const cap_rights_t cap_send_connect_rights =
104     CAP_RIGHTS_INITIALIZER2(CAP_SEND, CAP_CONNECT);
105 const cap_rights_t cap_setsockopt_rights =
106     CAP_RIGHTS_INITIALIZER(CAP_SETSOCKOPT);
107 const cap_rights_t cap_shutdown_rights = CAP_RIGHTS_INITIALIZER(CAP_SHUTDOWN);
108 const cap_rights_t cap_symlinkat_rights = CAP_RIGHTS_INITIALIZER(CAP_SYMLINKAT);
109 const cap_rights_t cap_unlinkat_rights = CAP_RIGHTS_INITIALIZER(CAP_UNLINKAT);
110 const cap_rights_t cap_write_rights = CAP_RIGHTS_INITIALIZER(CAP_WRITE);
111 const cap_rights_t cap_no_rights = CAP_RIGHTS_INITIALIZER(0ULL);
112 #endif
113 
114 #define	CAPARSIZE_MIN	(CAP_RIGHTS_VERSION_00 + 2)
115 #define	CAPARSIZE_MAX	(CAP_RIGHTS_VERSION + 2)
116 
117 static __inline int
right_to_index(uint64_t right)118 right_to_index(uint64_t right)
119 {
120 	static const int bit2idx[] = {
121 		-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
122 		4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
123 	};
124 	int idx;
125 
126 	idx = CAPIDXBIT(right);
127 	assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0]));
128 	return (bit2idx[idx]);
129 }
130 
131 static void
cap_rights_vset(cap_rights_t * rights,va_list ap)132 cap_rights_vset(cap_rights_t *rights, va_list ap)
133 {
134 	uint64_t right;
135 	int i, n __unused;
136 
137 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
138 
139 	n = CAPARSIZE(rights);
140 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
141 
142 	for (;;) {
143 		right = (uint64_t)va_arg(ap, unsigned long long);
144 		if (right == 0)
145 			break;
146 		assert(CAPRVER(right) == 0);
147 		i = right_to_index(right);
148 		assert(i >= 0);
149 		assert(i < n);
150 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
151 		rights->cr_rights[i] |= right;
152 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
153 	}
154 }
155 
156 static void
cap_rights_vclear(cap_rights_t * rights,va_list ap)157 cap_rights_vclear(cap_rights_t *rights, va_list ap)
158 {
159 	uint64_t right;
160 	int i, n __unused;
161 
162 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
163 
164 	n = CAPARSIZE(rights);
165 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
166 
167 	for (;;) {
168 		right = (uint64_t)va_arg(ap, unsigned long long);
169 		if (right == 0)
170 			break;
171 		assert(CAPRVER(right) == 0);
172 		i = right_to_index(right);
173 		assert(i >= 0);
174 		assert(i < n);
175 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
176 		rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL);
177 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
178 	}
179 }
180 
181 static bool
cap_rights_is_vset(const cap_rights_t * rights,va_list ap)182 cap_rights_is_vset(const cap_rights_t *rights, va_list ap)
183 {
184 	uint64_t right;
185 	int i, n __unused;
186 
187 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
188 
189 	n = CAPARSIZE(rights);
190 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
191 
192 	for (;;) {
193 		right = (uint64_t)va_arg(ap, unsigned long long);
194 		if (right == 0)
195 			break;
196 		assert(CAPRVER(right) == 0);
197 		i = right_to_index(right);
198 		assert(i >= 0);
199 		assert(i < n);
200 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
201 		if ((rights->cr_rights[i] & right) != right)
202 			return (false);
203 	}
204 
205 	return (true);
206 }
207 
208 cap_rights_t *
__cap_rights_init(int version,cap_rights_t * rights,...)209 __cap_rights_init(int version, cap_rights_t *rights, ...)
210 {
211 	unsigned int n __unused;
212 	va_list ap;
213 
214 	assert(version == CAP_RIGHTS_VERSION_00);
215 
216 	n = version + 2;
217 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
218 	CAP_NONE(rights);
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 *
__cap_rights_set(cap_rights_t * rights,...)227 __cap_rights_set(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_vset(rights, ap);
235 	va_end(ap);
236 
237 	return (rights);
238 }
239 
240 cap_rights_t *
__cap_rights_clear(cap_rights_t * rights,...)241 __cap_rights_clear(cap_rights_t *rights, ...)
242 {
243 	va_list ap;
244 
245 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
246 
247 	va_start(ap, rights);
248 	cap_rights_vclear(rights, ap);
249 	va_end(ap);
250 
251 	return (rights);
252 }
253 
254 bool
__cap_rights_is_set(const cap_rights_t * rights,...)255 __cap_rights_is_set(const cap_rights_t *rights, ...)
256 {
257 	va_list ap;
258 	bool ret;
259 
260 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
261 
262 	va_start(ap, rights);
263 	ret = cap_rights_is_vset(rights, ap);
264 	va_end(ap);
265 
266 	return (ret);
267 }
268 
269 bool
cap_rights_is_empty(const cap_rights_t * rights)270 cap_rights_is_empty(const cap_rights_t *rights)
271 {
272 #ifndef _KERNEL
273 	cap_rights_t cap_no_rights;
274 	cap_rights_init(&cap_no_rights);
275 #endif
276 
277 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
278 	assert(CAPVER(&cap_no_rights) == CAP_RIGHTS_VERSION_00);
279 
280 	for (int i = 0; i < CAPARSIZE(rights); i++) {
281 		if (rights->cr_rights[i] != cap_no_rights.cr_rights[i])
282 			return (false);
283 	}
284 
285 	return (true);
286 }
287 
288 bool
cap_rights_is_valid(const cap_rights_t * rights)289 cap_rights_is_valid(const cap_rights_t *rights)
290 {
291 	cap_rights_t allrights;
292 	int i, j;
293 
294 	if (CAPVER(rights) != CAP_RIGHTS_VERSION_00)
295 		return (false);
296 	if (CAPARSIZE(rights) < CAPARSIZE_MIN ||
297 	    CAPARSIZE(rights) > CAPARSIZE_MAX) {
298 		return (false);
299 	}
300 	CAP_ALL(&allrights);
301 	if (!cap_rights_contains(&allrights, rights))
302 		return (false);
303 	for (i = 0; i < CAPARSIZE(rights); i++) {
304 		j = right_to_index(rights->cr_rights[i]);
305 		if (i != j)
306 			return (false);
307 		if (i > 0) {
308 			if (CAPRVER(rights->cr_rights[i]) != 0)
309 				return (false);
310 		}
311 	}
312 
313 	return (true);
314 }
315 
316 cap_rights_t *
cap_rights_merge(cap_rights_t * dst,const cap_rights_t * src)317 cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src)
318 {
319 	unsigned int i, n;
320 
321 	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
322 	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
323 	assert(CAPVER(dst) == CAPVER(src));
324 	assert(cap_rights_is_valid(src));
325 	assert(cap_rights_is_valid(dst));
326 
327 	n = CAPARSIZE(dst);
328 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
329 
330 	for (i = 0; i < n; i++)
331 		dst->cr_rights[i] |= src->cr_rights[i];
332 
333 	assert(cap_rights_is_valid(src));
334 	assert(cap_rights_is_valid(dst));
335 
336 	return (dst);
337 }
338 
339 cap_rights_t *
cap_rights_remove(cap_rights_t * dst,const cap_rights_t * src)340 cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src)
341 {
342 	unsigned int i, n;
343 
344 	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
345 	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
346 	assert(CAPVER(dst) == CAPVER(src));
347 	assert(cap_rights_is_valid(src));
348 	assert(cap_rights_is_valid(dst));
349 
350 	n = CAPARSIZE(dst);
351 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
352 
353 	for (i = 0; i < n; i++) {
354 		dst->cr_rights[i] &=
355 		    ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL);
356 	}
357 
358 	assert(cap_rights_is_valid(src));
359 	assert(cap_rights_is_valid(dst));
360 
361 	return (dst);
362 }
363 
364 #ifndef _KERNEL
365 bool
cap_rights_contains(const cap_rights_t * big,const cap_rights_t * little)366 cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
367 {
368 	unsigned int i, n;
369 
370 	assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
371 	assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
372 	assert(CAPVER(big) == CAPVER(little));
373 
374 	n = CAPARSIZE(big);
375 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
376 
377 	for (i = 0; i < n; i++) {
378 		if ((big->cr_rights[i] & little->cr_rights[i]) !=
379 		    little->cr_rights[i]) {
380 			return (false);
381 		}
382 	}
383 
384 	return (true);
385 }
386 #endif
387