xref: /freebsd/sys/kern/subr_capability.c (revision 3a92d97ff0f22d21608e1c19b83104c4937523b6)
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 #ifdef _KERNEL
38 #include <sys/types.h>
39 #include <sys/capability.h>
40 #include <sys/systm.h>
41 
42 #include <machine/stdarg.h>
43 #else	/* !_KERNEL */
44 #include <sys/types.h>
45 #include <sys/capability.h>
46 
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 #endif
57 
58 #define	CAPARSIZE_MIN	(CAP_RIGHTS_VERSION_00 + 2)
59 #define	CAPARSIZE_MAX	(CAP_RIGHTS_VERSION + 2)
60 
61 static __inline int
62 right_to_index(uint64_t right)
63 {
64 	static const int bit2idx[] = {
65 		-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
66 		4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
67 	};
68 	int idx;
69 
70 	idx = CAPIDXBIT(right);
71 	assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0]));
72 	return (bit2idx[idx]);
73 }
74 
75 static void
76 cap_rights_vset(cap_rights_t *rights, va_list ap)
77 {
78 	uint64_t right;
79 	int i, n;
80 
81 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
82 
83 	n = CAPARSIZE(rights);
84 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
85 
86 	for (;;) {
87 		right = (uint64_t)va_arg(ap, unsigned long long);
88 		if (right == 0)
89 			break;
90 		assert(CAPRVER(right) == 0);
91 		i = right_to_index(right);
92 		assert(i >= 0);
93 		assert(i < n);
94 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
95 		rights->cr_rights[i] |= right;
96 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
97 	}
98 }
99 
100 static void
101 cap_rights_vclear(cap_rights_t *rights, va_list ap)
102 {
103 	uint64_t right;
104 	int i, n;
105 
106 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
107 
108 	n = CAPARSIZE(rights);
109 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
110 
111 	for (;;) {
112 		right = (uint64_t)va_arg(ap, unsigned long long);
113 		if (right == 0)
114 			break;
115 		assert(CAPRVER(right) == 0);
116 		i = right_to_index(right);
117 		assert(i >= 0);
118 		assert(i < n);
119 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
120 		rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL);
121 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
122 	}
123 }
124 
125 static bool
126 cap_rights_is_vset(const cap_rights_t *rights, va_list ap)
127 {
128 	uint64_t right;
129 	int i, n;
130 
131 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
132 
133 	n = CAPARSIZE(rights);
134 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
135 
136 	for (;;) {
137 		right = (uint64_t)va_arg(ap, unsigned long long);
138 		if (right == 0)
139 			break;
140 		assert(CAPRVER(right) == 0);
141 		i = right_to_index(right);
142 		assert(i >= 0);
143 		assert(i < n);
144 		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
145 		if ((rights->cr_rights[i] & right) != right)
146 			return (false);
147 	}
148 
149 	return (true);
150 }
151 
152 cap_rights_t *
153 __cap_rights_init(int version, cap_rights_t *rights, ...)
154 {
155 	unsigned int n;
156 	va_list ap;
157 
158 	assert(version == CAP_RIGHTS_VERSION_00);
159 
160 	n = version + 2;
161 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
162 	memset(rights->cr_rights, 0, sizeof(rights->cr_rights[0]) * n);
163 	CAP_NONE(rights);
164 	va_start(ap, rights);
165 	cap_rights_vset(rights, ap);
166 	va_end(ap);
167 
168 	return (rights);
169 }
170 
171 cap_rights_t *
172 __cap_rights_set(cap_rights_t *rights, ...)
173 {
174 	va_list ap;
175 
176 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
177 
178 	va_start(ap, rights);
179 	cap_rights_vset(rights, ap);
180 	va_end(ap);
181 
182 	return (rights);
183 }
184 
185 cap_rights_t *
186 __cap_rights_clear(cap_rights_t *rights, ...)
187 {
188 	va_list ap;
189 
190 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
191 
192 	va_start(ap, rights);
193 	cap_rights_vclear(rights, ap);
194 	va_end(ap);
195 
196 	return (rights);
197 }
198 
199 bool
200 __cap_rights_is_set(const cap_rights_t *rights, ...)
201 {
202 	va_list ap;
203 	bool ret;
204 
205 	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
206 
207 	va_start(ap, rights);
208 	ret = cap_rights_is_vset(rights, ap);
209 	va_end(ap);
210 
211 	return (ret);
212 }
213 
214 bool
215 cap_rights_is_valid(const cap_rights_t *rights)
216 {
217 	cap_rights_t allrights;
218 	int i, j;
219 
220 	if (CAPVER(rights) != CAP_RIGHTS_VERSION_00)
221 		return (false);
222 	if (CAPARSIZE(rights) < CAPARSIZE_MIN ||
223 	    CAPARSIZE(rights) > CAPARSIZE_MAX) {
224 		return (false);
225 	}
226 	CAP_ALL(&allrights);
227 	if (!cap_rights_contains(&allrights, rights))
228 		return (false);
229 	for (i = 0; i < CAPARSIZE(rights); i++) {
230 		j = right_to_index(rights->cr_rights[i]);
231 		if (i != j)
232 			return (false);
233 		if (i > 0) {
234 			if (CAPRVER(rights->cr_rights[i]) != 0)
235 				return (false);
236 		}
237 	}
238 
239 	return (true);
240 }
241 
242 cap_rights_t *
243 cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src)
244 {
245 	unsigned int i, n;
246 
247 	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
248 	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
249 	assert(CAPVER(dst) == CAPVER(src));
250 	assert(cap_rights_is_valid(src));
251 	assert(cap_rights_is_valid(dst));
252 
253 	n = CAPARSIZE(dst);
254 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
255 
256 	for (i = 0; i < n; i++)
257 		dst->cr_rights[i] |= src->cr_rights[i];
258 
259 	assert(cap_rights_is_valid(src));
260 	assert(cap_rights_is_valid(dst));
261 
262 	return (dst);
263 }
264 
265 cap_rights_t *
266 cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src)
267 {
268 	unsigned int i, n;
269 
270 	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
271 	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
272 	assert(CAPVER(dst) == CAPVER(src));
273 	assert(cap_rights_is_valid(src));
274 	assert(cap_rights_is_valid(dst));
275 
276 	n = CAPARSIZE(dst);
277 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
278 
279 	for (i = 0; i < n; i++) {
280 		dst->cr_rights[i] &=
281 		    ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL);
282 	}
283 
284 	assert(cap_rights_is_valid(src));
285 	assert(cap_rights_is_valid(dst));
286 
287 	return (dst);
288 }
289 
290 bool
291 cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
292 {
293 	unsigned int i, n;
294 
295 	assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
296 	assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
297 	assert(CAPVER(big) == CAPVER(little));
298 
299 	n = CAPARSIZE(big);
300 	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
301 
302 	for (i = 0; i < n; i++) {
303 		if ((big->cr_rights[i] & little->cr_rights[i]) !=
304 		    little->cr_rights[i]) {
305 			return (false);
306 		}
307 	}
308 
309 	return (true);
310 }
311