1255219Spjd/*-
2255219Spjd * Copyright (c) 2013 FreeBSD Foundation
3255219Spjd * All rights reserved.
4255219Spjd *
5255219Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6255219Spjd * the FreeBSD Foundation.
7255219Spjd *
8255219Spjd * Redistribution and use in source and binary forms, with or without
9255219Spjd * modification, are permitted provided that the following conditions
10255219Spjd * are met:
11255219Spjd * 1. Redistributions of source code must retain the above copyright
12255219Spjd *    notice, this list of conditions and the following disclaimer.
13255219Spjd * 2. Redistributions in binary form must reproduce the above copyright
14255219Spjd *    notice, this list of conditions and the following disclaimer in the
15255219Spjd *    documentation and/or other materials provided with the distribution.
16255219Spjd *
17255219Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18255219Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19255219Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20255219Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21255219Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22255219Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23255219Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24255219Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25255219Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26255219Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27255219Spjd * SUCH DAMAGE.
28255219Spjd */
29255219Spjd
30255219Spjd#include <sys/cdefs.h>
31255219Spjd__FBSDID("$FreeBSD$");
32255219Spjd
33258148Spjd/*
34258148Spjd * Note that this file is compiled into the kernel and into libc.
35258148Spjd */
36258148Spjd
37255219Spjd#include <sys/types.h>
38263233Srwatson#include <sys/capsicum.h>
39267914Spjd
40267914Spjd#ifdef _KERNEL
41255219Spjd#include <sys/systm.h>
42255219Spjd
43255219Spjd#include <machine/stdarg.h>
44255219Spjd#else	/* !_KERNEL */
45255219Spjd#include <assert.h>
46255219Spjd#include <stdarg.h>
47255219Spjd#include <stdbool.h>
48255219Spjd#include <stdint.h>
49255219Spjd#include <string.h>
50255219Spjd#endif
51255219Spjd
52255219Spjd#ifdef _KERNEL
53255219Spjd#define	assert(exp)	KASSERT((exp), ("%s:%u", __func__, __LINE__))
54255219Spjd#endif
55255219Spjd
56255372Spjd#define	CAPARSIZE_MIN	(CAP_RIGHTS_VERSION_00 + 2)
57255372Spjd#define	CAPARSIZE_MAX	(CAP_RIGHTS_VERSION + 2)
58255372Spjd
59255372Spjdstatic __inline int
60255219Spjdright_to_index(uint64_t right)
61255219Spjd{
62255219Spjd	static const int bit2idx[] = {
63255219Spjd		-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
64255219Spjd		4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
65255219Spjd	};
66255219Spjd	int idx;
67255219Spjd
68255219Spjd	idx = CAPIDXBIT(right);
69255372Spjd	assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0]));
70255372Spjd	return (bit2idx[idx]);
71255219Spjd}
72255219Spjd
73255219Spjdstatic void
74255219Spjdcap_rights_vset(cap_rights_t *rights, va_list ap)
75255219Spjd{
76255219Spjd	uint64_t right;
77255372Spjd	int i, n;
78255219Spjd
79255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
80255219Spjd
81255219Spjd	n = CAPARSIZE(rights);
82255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
83255219Spjd
84255219Spjd	for (;;) {
85255219Spjd		right = (uint64_t)va_arg(ap, unsigned long long);
86255219Spjd		if (right == 0)
87255219Spjd			break;
88255219Spjd		assert(CAPRVER(right) == 0);
89255219Spjd		i = right_to_index(right);
90255372Spjd		assert(i >= 0);
91255219Spjd		assert(i < n);
92255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
93255219Spjd		rights->cr_rights[i] |= right;
94255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
95255219Spjd	}
96255219Spjd}
97255219Spjd
98255219Spjdstatic void
99255219Spjdcap_rights_vclear(cap_rights_t *rights, va_list ap)
100255219Spjd{
101255219Spjd	uint64_t right;
102255372Spjd	int i, n;
103255219Spjd
104255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
105255219Spjd
106255219Spjd	n = CAPARSIZE(rights);
107255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
108255219Spjd
109255219Spjd	for (;;) {
110255219Spjd		right = (uint64_t)va_arg(ap, unsigned long long);
111255219Spjd		if (right == 0)
112255219Spjd			break;
113255219Spjd		assert(CAPRVER(right) == 0);
114255219Spjd		i = right_to_index(right);
115255372Spjd		assert(i >= 0);
116255219Spjd		assert(i < n);
117255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
118255219Spjd		rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL);
119255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
120255219Spjd	}
121255219Spjd}
122255219Spjd
123255219Spjdstatic bool
124255219Spjdcap_rights_is_vset(const cap_rights_t *rights, va_list ap)
125255219Spjd{
126255219Spjd	uint64_t right;
127255372Spjd	int i, n;
128255219Spjd
129255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
130255219Spjd
131255219Spjd	n = CAPARSIZE(rights);
132255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
133255219Spjd
134255219Spjd	for (;;) {
135255219Spjd		right = (uint64_t)va_arg(ap, unsigned long long);
136255219Spjd		if (right == 0)
137255219Spjd			break;
138255219Spjd		assert(CAPRVER(right) == 0);
139255219Spjd		i = right_to_index(right);
140255372Spjd		assert(i >= 0);
141255219Spjd		assert(i < n);
142255219Spjd		assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
143255219Spjd		if ((rights->cr_rights[i] & right) != right)
144255219Spjd			return (false);
145255219Spjd	}
146255219Spjd
147255219Spjd	return (true);
148255219Spjd}
149255219Spjd
150255219Spjdcap_rights_t *
151255219Spjd__cap_rights_init(int version, cap_rights_t *rights, ...)
152255219Spjd{
153255219Spjd	unsigned int n;
154255219Spjd	va_list ap;
155255219Spjd
156255219Spjd	assert(version == CAP_RIGHTS_VERSION_00);
157255219Spjd
158255219Spjd	n = version + 2;
159255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
160255219Spjd	CAP_NONE(rights);
161255219Spjd	va_start(ap, rights);
162255219Spjd	cap_rights_vset(rights, ap);
163255219Spjd	va_end(ap);
164255219Spjd
165255219Spjd	return (rights);
166255219Spjd}
167255219Spjd
168258149Spjdcap_rights_t *
169255219Spjd__cap_rights_set(cap_rights_t *rights, ...)
170255219Spjd{
171255219Spjd	va_list ap;
172255219Spjd
173255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
174255219Spjd
175255219Spjd	va_start(ap, rights);
176255219Spjd	cap_rights_vset(rights, ap);
177255219Spjd	va_end(ap);
178258149Spjd
179258149Spjd	return (rights);
180255219Spjd}
181255219Spjd
182258149Spjdcap_rights_t *
183255219Spjd__cap_rights_clear(cap_rights_t *rights, ...)
184255219Spjd{
185255219Spjd	va_list ap;
186255219Spjd
187255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
188255219Spjd
189255219Spjd	va_start(ap, rights);
190255219Spjd	cap_rights_vclear(rights, ap);
191255219Spjd	va_end(ap);
192258149Spjd
193258149Spjd	return (rights);
194255219Spjd}
195255219Spjd
196255219Spjdbool
197255219Spjd__cap_rights_is_set(const cap_rights_t *rights, ...)
198255219Spjd{
199255219Spjd	va_list ap;
200255219Spjd	bool ret;
201255219Spjd
202255219Spjd	assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
203255219Spjd
204255219Spjd	va_start(ap, rights);
205255219Spjd	ret = cap_rights_is_vset(rights, ap);
206255219Spjd	va_end(ap);
207255219Spjd
208255219Spjd	return (ret);
209255219Spjd}
210255219Spjd
211255219Spjdbool
212255219Spjdcap_rights_is_valid(const cap_rights_t *rights)
213255219Spjd{
214255219Spjd	cap_rights_t allrights;
215255372Spjd	int i, j;
216255219Spjd
217255219Spjd	if (CAPVER(rights) != CAP_RIGHTS_VERSION_00)
218255219Spjd		return (false);
219255372Spjd	if (CAPARSIZE(rights) < CAPARSIZE_MIN ||
220255372Spjd	    CAPARSIZE(rights) > CAPARSIZE_MAX) {
221255372Spjd		return (false);
222255372Spjd	}
223255219Spjd	CAP_ALL(&allrights);
224255219Spjd	if (!cap_rights_contains(&allrights, rights))
225255219Spjd		return (false);
226255219Spjd	for (i = 0; i < CAPARSIZE(rights); i++) {
227255219Spjd		j = right_to_index(rights->cr_rights[i]);
228255219Spjd		if (i != j)
229255219Spjd			return (false);
230255219Spjd		if (i > 0) {
231255219Spjd			if (CAPRVER(rights->cr_rights[i]) != 0)
232255219Spjd				return (false);
233255219Spjd		}
234255219Spjd	}
235255219Spjd
236255219Spjd	return (true);
237255219Spjd}
238255219Spjd
239258149Spjdcap_rights_t *
240255219Spjdcap_rights_merge(cap_rights_t *dst, const cap_rights_t *src)
241255219Spjd{
242255219Spjd	unsigned int i, n;
243255219Spjd
244255219Spjd	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
245255219Spjd	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
246255219Spjd	assert(CAPVER(dst) == CAPVER(src));
247255219Spjd	assert(cap_rights_is_valid(src));
248255219Spjd	assert(cap_rights_is_valid(dst));
249255219Spjd
250255219Spjd	n = CAPARSIZE(dst);
251255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
252255219Spjd
253255219Spjd	for (i = 0; i < n; i++)
254255219Spjd		dst->cr_rights[i] |= src->cr_rights[i];
255255219Spjd
256255219Spjd	assert(cap_rights_is_valid(src));
257255219Spjd	assert(cap_rights_is_valid(dst));
258258149Spjd
259258149Spjd	return (dst);
260255219Spjd}
261255219Spjd
262258149Spjdcap_rights_t *
263255219Spjdcap_rights_remove(cap_rights_t *dst, const cap_rights_t *src)
264255219Spjd{
265255219Spjd	unsigned int i, n;
266255219Spjd
267255219Spjd	assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
268255219Spjd	assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
269255219Spjd	assert(CAPVER(dst) == CAPVER(src));
270255219Spjd	assert(cap_rights_is_valid(src));
271255219Spjd	assert(cap_rights_is_valid(dst));
272255219Spjd
273255219Spjd	n = CAPARSIZE(dst);
274255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
275255219Spjd
276255219Spjd	for (i = 0; i < n; i++) {
277255219Spjd		dst->cr_rights[i] &=
278255219Spjd		    ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL);
279255219Spjd	}
280255219Spjd
281255219Spjd	assert(cap_rights_is_valid(src));
282255219Spjd	assert(cap_rights_is_valid(dst));
283258149Spjd
284258149Spjd	return (dst);
285255219Spjd}
286255219Spjd
287255219Spjdbool
288255219Spjdcap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
289255219Spjd{
290255219Spjd	unsigned int i, n;
291255219Spjd
292255219Spjd	assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
293255219Spjd	assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
294255219Spjd	assert(CAPVER(big) == CAPVER(little));
295255219Spjd
296255219Spjd	n = CAPARSIZE(big);
297255372Spjd	assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
298255219Spjd
299255219Spjd	for (i = 0; i < n; i++) {
300255219Spjd		if ((big->cr_rights[i] & little->cr_rights[i]) !=
301255219Spjd		    little->cr_rights[i]) {
302255219Spjd			return (false);
303255219Spjd		}
304255219Spjd	}
305255219Spjd
306255219Spjd	return (true);
307255219Spjd}
308