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 59 static __inline int 60 right_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 73 static void 74 cap_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 98 static void 99 cap_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 123 static bool 124 cap_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 150 cap_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 168 cap_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 182 cap_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 196 bool 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 211 bool 212 cap_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 239 cap_rights_t * 240 cap_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 262 cap_rights_t * 263 cap_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 287 bool 288 cap_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