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 33258324Spjd/* 34258324Spjd * Note that this file is compiled into the kernel and into libc. 35258324Spjd */ 36258324Spjd 37255219Spjd#ifdef _KERNEL 38255219Spjd#include <sys/types.h> 39255219Spjd#include <sys/capability.h> 40255219Spjd#include <sys/systm.h> 41255219Spjd 42255219Spjd#include <machine/stdarg.h> 43255219Spjd#else /* !_KERNEL */ 44255219Spjd#include <sys/types.h> 45255219Spjd#include <sys/capability.h> 46255219Spjd 47255219Spjd#include <assert.h> 48255219Spjd#include <stdarg.h> 49255219Spjd#include <stdbool.h> 50255219Spjd#include <stdint.h> 51255219Spjd#include <string.h> 52255219Spjd#endif 53255219Spjd 54255219Spjd#ifdef _KERNEL 55255219Spjd#define assert(exp) KASSERT((exp), ("%s:%u", __func__, __LINE__)) 56255219Spjd#endif 57255219Spjd 58255372Spjd#define CAPARSIZE_MIN (CAP_RIGHTS_VERSION_00 + 2) 59255372Spjd#define CAPARSIZE_MAX (CAP_RIGHTS_VERSION + 2) 60255372Spjd 61255372Spjdstatic __inline int 62255219Spjdright_to_index(uint64_t right) 63255219Spjd{ 64255219Spjd static const int bit2idx[] = { 65255219Spjd -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 66255219Spjd 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 67255219Spjd }; 68255219Spjd int idx; 69255219Spjd 70255219Spjd idx = CAPIDXBIT(right); 71255372Spjd assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0])); 72255372Spjd return (bit2idx[idx]); 73255219Spjd} 74255219Spjd 75255219Spjdstatic void 76255219Spjdcap_rights_vset(cap_rights_t *rights, va_list ap) 77255219Spjd{ 78255219Spjd uint64_t right; 79255372Spjd int i, n; 80255219Spjd 81255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 82255219Spjd 83255219Spjd n = CAPARSIZE(rights); 84255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 85255219Spjd 86255219Spjd for (;;) { 87255219Spjd right = (uint64_t)va_arg(ap, unsigned long long); 88255219Spjd if (right == 0) 89255219Spjd break; 90255219Spjd assert(CAPRVER(right) == 0); 91255219Spjd i = right_to_index(right); 92255372Spjd assert(i >= 0); 93255219Spjd assert(i < n); 94255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 95255219Spjd rights->cr_rights[i] |= right; 96255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 97255219Spjd } 98255219Spjd} 99255219Spjd 100255219Spjdstatic void 101255219Spjdcap_rights_vclear(cap_rights_t *rights, va_list ap) 102255219Spjd{ 103255219Spjd uint64_t right; 104255372Spjd int i, n; 105255219Spjd 106255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 107255219Spjd 108255219Spjd n = CAPARSIZE(rights); 109255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 110255219Spjd 111255219Spjd for (;;) { 112255219Spjd right = (uint64_t)va_arg(ap, unsigned long long); 113255219Spjd if (right == 0) 114255219Spjd break; 115255219Spjd assert(CAPRVER(right) == 0); 116255219Spjd i = right_to_index(right); 117255372Spjd assert(i >= 0); 118255219Spjd assert(i < n); 119255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 120255219Spjd rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL); 121255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 122255219Spjd } 123255219Spjd} 124255219Spjd 125255219Spjdstatic bool 126255219Spjdcap_rights_is_vset(const cap_rights_t *rights, va_list ap) 127255219Spjd{ 128255219Spjd uint64_t right; 129255372Spjd int i, n; 130255219Spjd 131255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 132255219Spjd 133255219Spjd n = CAPARSIZE(rights); 134255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 135255219Spjd 136255219Spjd for (;;) { 137255219Spjd right = (uint64_t)va_arg(ap, unsigned long long); 138255219Spjd if (right == 0) 139255219Spjd break; 140255219Spjd assert(CAPRVER(right) == 0); 141255219Spjd i = right_to_index(right); 142255372Spjd assert(i >= 0); 143255219Spjd assert(i < n); 144255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 145255219Spjd if ((rights->cr_rights[i] & right) != right) 146255219Spjd return (false); 147255219Spjd } 148255219Spjd 149255219Spjd return (true); 150255219Spjd} 151255219Spjd 152255219Spjdcap_rights_t * 153255219Spjd__cap_rights_init(int version, cap_rights_t *rights, ...) 154255219Spjd{ 155255219Spjd unsigned int n; 156255219Spjd va_list ap; 157255219Spjd 158255219Spjd assert(version == CAP_RIGHTS_VERSION_00); 159255219Spjd 160255219Spjd n = version + 2; 161255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 162255219Spjd memset(rights->cr_rights, 0, sizeof(rights->cr_rights[0]) * n); 163255219Spjd CAP_NONE(rights); 164255219Spjd va_start(ap, rights); 165255219Spjd cap_rights_vset(rights, ap); 166255219Spjd va_end(ap); 167255219Spjd 168255219Spjd return (rights); 169255219Spjd} 170255219Spjd 171258324Spjdcap_rights_t * 172255219Spjd__cap_rights_set(cap_rights_t *rights, ...) 173255219Spjd{ 174255219Spjd va_list ap; 175255219Spjd 176255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 177255219Spjd 178255219Spjd va_start(ap, rights); 179255219Spjd cap_rights_vset(rights, ap); 180255219Spjd va_end(ap); 181258324Spjd 182258324Spjd return (rights); 183255219Spjd} 184255219Spjd 185258324Spjdcap_rights_t * 186255219Spjd__cap_rights_clear(cap_rights_t *rights, ...) 187255219Spjd{ 188255219Spjd va_list ap; 189255219Spjd 190255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 191255219Spjd 192255219Spjd va_start(ap, rights); 193255219Spjd cap_rights_vclear(rights, ap); 194255219Spjd va_end(ap); 195258324Spjd 196258324Spjd return (rights); 197255219Spjd} 198255219Spjd 199255219Spjdbool 200255219Spjd__cap_rights_is_set(const cap_rights_t *rights, ...) 201255219Spjd{ 202255219Spjd va_list ap; 203255219Spjd bool ret; 204255219Spjd 205255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 206255219Spjd 207255219Spjd va_start(ap, rights); 208255219Spjd ret = cap_rights_is_vset(rights, ap); 209255219Spjd va_end(ap); 210255219Spjd 211255219Spjd return (ret); 212255219Spjd} 213255219Spjd 214255219Spjdbool 215255219Spjdcap_rights_is_valid(const cap_rights_t *rights) 216255219Spjd{ 217255219Spjd cap_rights_t allrights; 218255372Spjd int i, j; 219255219Spjd 220255219Spjd if (CAPVER(rights) != CAP_RIGHTS_VERSION_00) 221255219Spjd return (false); 222255372Spjd if (CAPARSIZE(rights) < CAPARSIZE_MIN || 223255372Spjd CAPARSIZE(rights) > CAPARSIZE_MAX) { 224255372Spjd return (false); 225255372Spjd } 226255219Spjd CAP_ALL(&allrights); 227255219Spjd if (!cap_rights_contains(&allrights, rights)) 228255219Spjd return (false); 229255219Spjd for (i = 0; i < CAPARSIZE(rights); i++) { 230255219Spjd j = right_to_index(rights->cr_rights[i]); 231255219Spjd if (i != j) 232255219Spjd return (false); 233255219Spjd if (i > 0) { 234255219Spjd if (CAPRVER(rights->cr_rights[i]) != 0) 235255219Spjd return (false); 236255219Spjd } 237255219Spjd } 238255219Spjd 239255219Spjd return (true); 240255219Spjd} 241255219Spjd 242258324Spjdcap_rights_t * 243255219Spjdcap_rights_merge(cap_rights_t *dst, const cap_rights_t *src) 244255219Spjd{ 245255219Spjd unsigned int i, n; 246255219Spjd 247255219Spjd assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00); 248255219Spjd assert(CAPVER(src) == CAP_RIGHTS_VERSION_00); 249255219Spjd assert(CAPVER(dst) == CAPVER(src)); 250255219Spjd assert(cap_rights_is_valid(src)); 251255219Spjd assert(cap_rights_is_valid(dst)); 252255219Spjd 253255219Spjd n = CAPARSIZE(dst); 254255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 255255219Spjd 256255219Spjd for (i = 0; i < n; i++) 257255219Spjd dst->cr_rights[i] |= src->cr_rights[i]; 258255219Spjd 259255219Spjd assert(cap_rights_is_valid(src)); 260255219Spjd assert(cap_rights_is_valid(dst)); 261258324Spjd 262258324Spjd return (dst); 263255219Spjd} 264255219Spjd 265258324Spjdcap_rights_t * 266255219Spjdcap_rights_remove(cap_rights_t *dst, const cap_rights_t *src) 267255219Spjd{ 268255219Spjd unsigned int i, n; 269255219Spjd 270255219Spjd assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00); 271255219Spjd assert(CAPVER(src) == CAP_RIGHTS_VERSION_00); 272255219Spjd assert(CAPVER(dst) == CAPVER(src)); 273255219Spjd assert(cap_rights_is_valid(src)); 274255219Spjd assert(cap_rights_is_valid(dst)); 275255219Spjd 276255219Spjd n = CAPARSIZE(dst); 277255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 278255219Spjd 279255219Spjd for (i = 0; i < n; i++) { 280255219Spjd dst->cr_rights[i] &= 281255219Spjd ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL); 282255219Spjd } 283255219Spjd 284255219Spjd assert(cap_rights_is_valid(src)); 285255219Spjd assert(cap_rights_is_valid(dst)); 286258324Spjd 287258324Spjd return (dst); 288255219Spjd} 289255219Spjd 290255219Spjdbool 291255219Spjdcap_rights_contains(const cap_rights_t *big, const cap_rights_t *little) 292255219Spjd{ 293255219Spjd unsigned int i, n; 294255219Spjd 295255219Spjd assert(CAPVER(big) == CAP_RIGHTS_VERSION_00); 296255219Spjd assert(CAPVER(little) == CAP_RIGHTS_VERSION_00); 297255219Spjd assert(CAPVER(big) == CAPVER(little)); 298255219Spjd 299255219Spjd n = CAPARSIZE(big); 300255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 301255219Spjd 302255219Spjd for (i = 0; i < n; i++) { 303255219Spjd if ((big->cr_rights[i] & little->cr_rights[i]) != 304255219Spjd little->cr_rights[i]) { 305255219Spjd return (false); 306255219Spjd } 307255219Spjd } 308255219Spjd 309255219Spjd return (true); 310255219Spjd} 311