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