subr_capability.c revision 255219
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 255219 2013-09-05 00:09:56Z 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
54static __inline unsigned int
55right_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
72static void
73cap_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
95static void
96cap_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
118static bool
119cap_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
143cap_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
161void
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
173void
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
185bool
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
200bool
201cap_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
224void
225cap_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
244void
245cap_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
266bool
267cap_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