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