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