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