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