subr_capability.c revision 255372
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: head/sys/kern/subr_capability.c 255372 2013-09-07 19:03:16Z pjd $");
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
57static __inline int
58right_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
71static void
72cap_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
96static void
97cap_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
121static bool
122cap_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
148cap_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
167void
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
179void
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
191bool
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
206bool
207cap_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
234void
235cap_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
255void
256cap_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
278bool
279cap_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