]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_capability.c
Eliminate the overhead of gratuitous repeated reinitialization of cap_rights
[FreeBSD/FreeBSD.git] / sys / kern / subr_capability.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2013 FreeBSD Foundation
5  * All rights reserved.
6  *
7  * This software was developed by Pawel Jakub Dawidek under sponsorship from
8  * the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 /*
36  * Note that this file is compiled into the kernel and into libc.
37  */
38
39 #include <sys/types.h>
40 #include <sys/capsicum.h>
41
42 #ifdef _KERNEL
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <machine/stdarg.h>
46 #else   /* !_KERNEL */
47 #include <assert.h>
48 #include <stdarg.h>
49 #include <stdbool.h>
50 #include <stdint.h>
51 #include <string.h>
52 #endif
53
54 #ifdef _KERNEL
55 #define assert(exp)     KASSERT((exp), ("%s:%u", __func__, __LINE__))
56
57 CAP_RIGHTS_DEFINE1(cap_accept_rights, CAP_ACCEPT);
58 CAP_RIGHTS_DEFINE1(cap_bind_rights, CAP_BIND);
59 CAP_RIGHTS_DEFINE1(cap_connect_rights, CAP_CONNECT);
60 CAP_RIGHTS_DEFINE1(cap_event_rights, CAP_EVENT);
61 CAP_RIGHTS_DEFINE1(cap_fchdir_rights, CAP_FCHDIR);
62 CAP_RIGHTS_DEFINE1(cap_fcntl_rights, CAP_FCNTL);
63 CAP_RIGHTS_DEFINE1(cap_fexecve_rights, CAP_FEXECVE);
64 CAP_RIGHTS_DEFINE1(cap_flock_rights, CAP_FLOCK);
65 CAP_RIGHTS_DEFINE1(cap_fpathconf_rights, CAP_FPATHCONF);
66 CAP_RIGHTS_DEFINE1(cap_fstat_rights, CAP_FSTAT);
67 CAP_RIGHTS_DEFINE1(cap_fsync_rights, CAP_FSYNC);
68 CAP_RIGHTS_DEFINE1(cap_ftruncate_rights, CAP_FTRUNCATE);
69 CAP_RIGHTS_DEFINE1(cap_getpeername_rights, CAP_GETPEERNAME);
70 CAP_RIGHTS_DEFINE1(cap_getsockname_rights, CAP_GETSOCKNAME);
71 CAP_RIGHTS_DEFINE1(cap_getsockopt_rights, CAP_GETSOCKOPT);
72 CAP_RIGHTS_DEFINE1(cap_ioctl_rights, CAP_IOCTL);
73 CAP_RIGHTS_DEFINE1(cap_listen_rights, CAP_LISTEN);
74 CAP_RIGHTS_DEFINE1(cap_mmap_rights, CAP_MMAP);
75 CAP_RIGHTS_DEFINE1(cap_pdgetpid_rights, CAP_PDGETPID);
76 CAP_RIGHTS_DEFINE1(cap_pdkill_rights, CAP_PDKILL);
77 CAP_RIGHTS_DEFINE1(cap_pread_rights, CAP_PREAD);
78 CAP_RIGHTS_DEFINE1(cap_pwrite_rights, CAP_PWRITE);
79 CAP_RIGHTS_DEFINE1(cap_read_rights, CAP_READ);
80 CAP_RIGHTS_DEFINE1(cap_recv_rights, CAP_RECV);
81 CAP_RIGHTS_DEFINE1(cap_send_rights, CAP_SEND);
82 CAP_RIGHTS_DEFINE1(cap_setsockopt_rights, CAP_SETSOCKOPT);
83 CAP_RIGHTS_DEFINE1(cap_shutdown_rights, CAP_SHUTDOWN);
84 CAP_RIGHTS_DEFINE1(cap_write_rights, CAP_WRITE);
85
86 __read_mostly cap_rights_t cap_no_rights;
87 CAP_RIGHTS_SYSINIT0(cap_no_rights, cap_no_rights);
88 #endif
89
90 #define CAPARSIZE_MIN   (CAP_RIGHTS_VERSION_00 + 2)
91 #define CAPARSIZE_MAX   (CAP_RIGHTS_VERSION + 2)
92
93 static __inline int
94 right_to_index(uint64_t right)
95 {
96         static const int bit2idx[] = {
97                 -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
98                 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
99         };
100         int idx;
101
102         idx = CAPIDXBIT(right);
103         assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0]));
104         return (bit2idx[idx]);
105 }
106
107 static void
108 cap_rights_vset(cap_rights_t *rights, va_list ap)
109 {
110         uint64_t right;
111         int i, n;
112
113         assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
114
115         n = CAPARSIZE(rights);
116         assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
117
118         for (;;) {
119                 right = (uint64_t)va_arg(ap, unsigned long long);
120                 if (right == 0)
121                         break;
122                 assert(CAPRVER(right) == 0);
123                 i = right_to_index(right);
124                 assert(i >= 0);
125                 assert(i < n);
126                 assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
127                 rights->cr_rights[i] |= right;
128                 assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
129         }
130 }
131
132 static void
133 cap_rights_vclear(cap_rights_t *rights, va_list ap)
134 {
135         uint64_t right;
136         int i, n;
137
138         assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
139
140         n = CAPARSIZE(rights);
141         assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
142
143         for (;;) {
144                 right = (uint64_t)va_arg(ap, unsigned long long);
145                 if (right == 0)
146                         break;
147                 assert(CAPRVER(right) == 0);
148                 i = right_to_index(right);
149                 assert(i >= 0);
150                 assert(i < n);
151                 assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
152                 rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL);
153                 assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
154         }
155 }
156
157 static bool
158 cap_rights_is_vset(const cap_rights_t *rights, va_list ap)
159 {
160         uint64_t right;
161         int i, n;
162
163         assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
164
165         n = CAPARSIZE(rights);
166         assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
167
168         for (;;) {
169                 right = (uint64_t)va_arg(ap, unsigned long long);
170                 if (right == 0)
171                         break;
172                 assert(CAPRVER(right) == 0);
173                 i = right_to_index(right);
174                 assert(i >= 0);
175                 assert(i < n);
176                 assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
177                 if ((rights->cr_rights[i] & right) != right)
178                         return (false);
179         }
180
181         return (true);
182 }
183
184 void
185 __cap_rights_sysinit(void *arg)
186 {
187         struct cap_rights_init_args *cria = arg;
188         cap_rights_t *rights = cria->cria_rights;
189
190         __cap_rights_init(CAP_RIGHTS_VERSION, rights, cria->cria_value1,
191        cria->cria_value2, cria->cria_value3, cria->cria_value4, 0ULL);
192 }
193
194 cap_rights_t *
195 __cap_rights_init(int version, cap_rights_t *rights, ...)
196 {
197         unsigned int n;
198         va_list ap;
199
200         assert(version == CAP_RIGHTS_VERSION_00);
201
202         n = version + 2;
203         assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
204         CAP_NONE(rights);
205         va_start(ap, rights);
206         cap_rights_vset(rights, ap);
207         va_end(ap);
208
209         return (rights);
210 }
211
212 cap_rights_t *
213 __cap_rights_set(cap_rights_t *rights, ...)
214 {
215         va_list ap;
216
217         assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
218
219         va_start(ap, rights);
220         cap_rights_vset(rights, ap);
221         va_end(ap);
222
223         return (rights);
224 }
225
226 cap_rights_t *
227 __cap_rights_clear(cap_rights_t *rights, ...)
228 {
229         va_list ap;
230
231         assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
232
233         va_start(ap, rights);
234         cap_rights_vclear(rights, ap);
235         va_end(ap);
236
237         return (rights);
238 }
239
240 bool
241 __cap_rights_is_set(const cap_rights_t *rights, ...)
242 {
243         va_list ap;
244         bool ret;
245
246         assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
247
248         va_start(ap, rights);
249         ret = cap_rights_is_vset(rights, ap);
250         va_end(ap);
251
252         return (ret);
253 }
254
255 bool
256 cap_rights_is_valid(const cap_rights_t *rights)
257 {
258         cap_rights_t allrights;
259         int i, j;
260
261         if (CAPVER(rights) != CAP_RIGHTS_VERSION_00)
262                 return (false);
263         if (CAPARSIZE(rights) < CAPARSIZE_MIN ||
264             CAPARSIZE(rights) > CAPARSIZE_MAX) {
265                 return (false);
266         }
267         CAP_ALL(&allrights);
268         if (!cap_rights_contains(&allrights, rights))
269                 return (false);
270         for (i = 0; i < CAPARSIZE(rights); i++) {
271                 j = right_to_index(rights->cr_rights[i]);
272                 if (i != j)
273                         return (false);
274                 if (i > 0) {
275                         if (CAPRVER(rights->cr_rights[i]) != 0)
276                                 return (false);
277                 }
278         }
279
280         return (true);
281 }
282
283 cap_rights_t *
284 cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src)
285 {
286         unsigned int i, n;
287
288         assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
289         assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
290         assert(CAPVER(dst) == CAPVER(src));
291         assert(cap_rights_is_valid(src));
292         assert(cap_rights_is_valid(dst));
293
294         n = CAPARSIZE(dst);
295         assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
296
297         for (i = 0; i < n; i++)
298                 dst->cr_rights[i] |= src->cr_rights[i];
299
300         assert(cap_rights_is_valid(src));
301         assert(cap_rights_is_valid(dst));
302
303         return (dst);
304 }
305
306 cap_rights_t *
307 cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src)
308 {
309         unsigned int i, n;
310
311         assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
312         assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
313         assert(CAPVER(dst) == CAPVER(src));
314         assert(cap_rights_is_valid(src));
315         assert(cap_rights_is_valid(dst));
316
317         n = CAPARSIZE(dst);
318         assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
319
320         for (i = 0; i < n; i++) {
321                 dst->cr_rights[i] &=
322                     ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL);
323         }
324
325         assert(cap_rights_is_valid(src));
326         assert(cap_rights_is_valid(dst));
327
328         return (dst);
329 }
330
331 bool
332 cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
333 {
334         unsigned int i, n;
335
336         assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
337         assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
338         assert(CAPVER(big) == CAPVER(little));
339
340         n = CAPARSIZE(big);
341         assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX);
342
343         for (i = 0; i < n; i++) {
344                 if ((big->cr_rights[i] & little->cr_rights[i]) !=
345                     little->cr_rights[i]) {
346                         return (false);
347                 }
348         }
349
350         return (true);
351 }