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 33258148Spjd/* 34258148Spjd * Note that this file is compiled into the kernel and into libc. 35258148Spjd */ 36258148Spjd 37255219Spjd#include <sys/types.h> 38263233Srwatson#include <sys/capsicum.h> 39267914Spjd 40267914Spjd#ifdef _KERNEL 41255219Spjd#include <sys/systm.h> 42255219Spjd 43255219Spjd#include <machine/stdarg.h> 44255219Spjd#else /* !_KERNEL */ 45255219Spjd#include <assert.h> 46255219Spjd#include <stdarg.h> 47255219Spjd#include <stdbool.h> 48255219Spjd#include <stdint.h> 49255219Spjd#include <string.h> 50255219Spjd#endif 51255219Spjd 52255219Spjd#ifdef _KERNEL 53255219Spjd#define assert(exp) KASSERT((exp), ("%s:%u", __func__, __LINE__)) 54255219Spjd#endif 55255219Spjd 56255372Spjd#define CAPARSIZE_MIN (CAP_RIGHTS_VERSION_00 + 2) 57255372Spjd#define CAPARSIZE_MAX (CAP_RIGHTS_VERSION + 2) 58255372Spjd 59255372Spjdstatic __inline int 60255219Spjdright_to_index(uint64_t right) 61255219Spjd{ 62255219Spjd static const int bit2idx[] = { 63255219Spjd -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 64255219Spjd 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 65255219Spjd }; 66255219Spjd int idx; 67255219Spjd 68255219Spjd idx = CAPIDXBIT(right); 69255372Spjd assert(idx >= 0 && idx < sizeof(bit2idx) / sizeof(bit2idx[0])); 70255372Spjd return (bit2idx[idx]); 71255219Spjd} 72255219Spjd 73255219Spjdstatic void 74255219Spjdcap_rights_vset(cap_rights_t *rights, va_list ap) 75255219Spjd{ 76255219Spjd uint64_t right; 77255372Spjd int i, n; 78255219Spjd 79255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 80255219Spjd 81255219Spjd n = CAPARSIZE(rights); 82255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 83255219Spjd 84255219Spjd for (;;) { 85255219Spjd right = (uint64_t)va_arg(ap, unsigned long long); 86255219Spjd if (right == 0) 87255219Spjd break; 88255219Spjd assert(CAPRVER(right) == 0); 89255219Spjd i = right_to_index(right); 90255372Spjd assert(i >= 0); 91255219Spjd assert(i < n); 92255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 93255219Spjd rights->cr_rights[i] |= right; 94255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 95255219Spjd } 96255219Spjd} 97255219Spjd 98255219Spjdstatic void 99255219Spjdcap_rights_vclear(cap_rights_t *rights, va_list ap) 100255219Spjd{ 101255219Spjd uint64_t right; 102255372Spjd int i, n; 103255219Spjd 104255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 105255219Spjd 106255219Spjd n = CAPARSIZE(rights); 107255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 108255219Spjd 109255219Spjd for (;;) { 110255219Spjd right = (uint64_t)va_arg(ap, unsigned long long); 111255219Spjd if (right == 0) 112255219Spjd break; 113255219Spjd assert(CAPRVER(right) == 0); 114255219Spjd i = right_to_index(right); 115255372Spjd assert(i >= 0); 116255219Spjd assert(i < n); 117255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 118255219Spjd rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL); 119255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 120255219Spjd } 121255219Spjd} 122255219Spjd 123255219Spjdstatic bool 124255219Spjdcap_rights_is_vset(const cap_rights_t *rights, va_list ap) 125255219Spjd{ 126255219Spjd uint64_t right; 127255372Spjd int i, n; 128255219Spjd 129255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 130255219Spjd 131255219Spjd n = CAPARSIZE(rights); 132255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 133255219Spjd 134255219Spjd for (;;) { 135255219Spjd right = (uint64_t)va_arg(ap, unsigned long long); 136255219Spjd if (right == 0) 137255219Spjd break; 138255219Spjd assert(CAPRVER(right) == 0); 139255219Spjd i = right_to_index(right); 140255372Spjd assert(i >= 0); 141255219Spjd assert(i < n); 142255219Spjd assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right)); 143255219Spjd if ((rights->cr_rights[i] & right) != right) 144255219Spjd return (false); 145255219Spjd } 146255219Spjd 147255219Spjd return (true); 148255219Spjd} 149255219Spjd 150255219Spjdcap_rights_t * 151255219Spjd__cap_rights_init(int version, cap_rights_t *rights, ...) 152255219Spjd{ 153255219Spjd unsigned int n; 154255219Spjd va_list ap; 155255219Spjd 156255219Spjd assert(version == CAP_RIGHTS_VERSION_00); 157255219Spjd 158255219Spjd n = version + 2; 159255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 160255219Spjd CAP_NONE(rights); 161255219Spjd va_start(ap, rights); 162255219Spjd cap_rights_vset(rights, ap); 163255219Spjd va_end(ap); 164255219Spjd 165255219Spjd return (rights); 166255219Spjd} 167255219Spjd 168258149Spjdcap_rights_t * 169255219Spjd__cap_rights_set(cap_rights_t *rights, ...) 170255219Spjd{ 171255219Spjd va_list ap; 172255219Spjd 173255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 174255219Spjd 175255219Spjd va_start(ap, rights); 176255219Spjd cap_rights_vset(rights, ap); 177255219Spjd va_end(ap); 178258149Spjd 179258149Spjd return (rights); 180255219Spjd} 181255219Spjd 182258149Spjdcap_rights_t * 183255219Spjd__cap_rights_clear(cap_rights_t *rights, ...) 184255219Spjd{ 185255219Spjd va_list ap; 186255219Spjd 187255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 188255219Spjd 189255219Spjd va_start(ap, rights); 190255219Spjd cap_rights_vclear(rights, ap); 191255219Spjd va_end(ap); 192258149Spjd 193258149Spjd return (rights); 194255219Spjd} 195255219Spjd 196255219Spjdbool 197255219Spjd__cap_rights_is_set(const cap_rights_t *rights, ...) 198255219Spjd{ 199255219Spjd va_list ap; 200255219Spjd bool ret; 201255219Spjd 202255219Spjd assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00); 203255219Spjd 204255219Spjd va_start(ap, rights); 205255219Spjd ret = cap_rights_is_vset(rights, ap); 206255219Spjd va_end(ap); 207255219Spjd 208255219Spjd return (ret); 209255219Spjd} 210255219Spjd 211255219Spjdbool 212255219Spjdcap_rights_is_valid(const cap_rights_t *rights) 213255219Spjd{ 214255219Spjd cap_rights_t allrights; 215255372Spjd int i, j; 216255219Spjd 217255219Spjd if (CAPVER(rights) != CAP_RIGHTS_VERSION_00) 218255219Spjd return (false); 219255372Spjd if (CAPARSIZE(rights) < CAPARSIZE_MIN || 220255372Spjd CAPARSIZE(rights) > CAPARSIZE_MAX) { 221255372Spjd return (false); 222255372Spjd } 223255219Spjd CAP_ALL(&allrights); 224255219Spjd if (!cap_rights_contains(&allrights, rights)) 225255219Spjd return (false); 226255219Spjd for (i = 0; i < CAPARSIZE(rights); i++) { 227255219Spjd j = right_to_index(rights->cr_rights[i]); 228255219Spjd if (i != j) 229255219Spjd return (false); 230255219Spjd if (i > 0) { 231255219Spjd if (CAPRVER(rights->cr_rights[i]) != 0) 232255219Spjd return (false); 233255219Spjd } 234255219Spjd } 235255219Spjd 236255219Spjd return (true); 237255219Spjd} 238255219Spjd 239258149Spjdcap_rights_t * 240255219Spjdcap_rights_merge(cap_rights_t *dst, const cap_rights_t *src) 241255219Spjd{ 242255219Spjd unsigned int i, n; 243255219Spjd 244255219Spjd assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00); 245255219Spjd assert(CAPVER(src) == CAP_RIGHTS_VERSION_00); 246255219Spjd assert(CAPVER(dst) == CAPVER(src)); 247255219Spjd assert(cap_rights_is_valid(src)); 248255219Spjd assert(cap_rights_is_valid(dst)); 249255219Spjd 250255219Spjd n = CAPARSIZE(dst); 251255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 252255219Spjd 253255219Spjd for (i = 0; i < n; i++) 254255219Spjd dst->cr_rights[i] |= src->cr_rights[i]; 255255219Spjd 256255219Spjd assert(cap_rights_is_valid(src)); 257255219Spjd assert(cap_rights_is_valid(dst)); 258258149Spjd 259258149Spjd return (dst); 260255219Spjd} 261255219Spjd 262258149Spjdcap_rights_t * 263255219Spjdcap_rights_remove(cap_rights_t *dst, const cap_rights_t *src) 264255219Spjd{ 265255219Spjd unsigned int i, n; 266255219Spjd 267255219Spjd assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00); 268255219Spjd assert(CAPVER(src) == CAP_RIGHTS_VERSION_00); 269255219Spjd assert(CAPVER(dst) == CAPVER(src)); 270255219Spjd assert(cap_rights_is_valid(src)); 271255219Spjd assert(cap_rights_is_valid(dst)); 272255219Spjd 273255219Spjd n = CAPARSIZE(dst); 274255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 275255219Spjd 276255219Spjd for (i = 0; i < n; i++) { 277255219Spjd dst->cr_rights[i] &= 278255219Spjd ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL); 279255219Spjd } 280255219Spjd 281255219Spjd assert(cap_rights_is_valid(src)); 282255219Spjd assert(cap_rights_is_valid(dst)); 283258149Spjd 284258149Spjd return (dst); 285255219Spjd} 286255219Spjd 287255219Spjdbool 288255219Spjdcap_rights_contains(const cap_rights_t *big, const cap_rights_t *little) 289255219Spjd{ 290255219Spjd unsigned int i, n; 291255219Spjd 292255219Spjd assert(CAPVER(big) == CAP_RIGHTS_VERSION_00); 293255219Spjd assert(CAPVER(little) == CAP_RIGHTS_VERSION_00); 294255219Spjd assert(CAPVER(big) == CAPVER(little)); 295255219Spjd 296255219Spjd n = CAPARSIZE(big); 297255372Spjd assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); 298255219Spjd 299255219Spjd for (i = 0; i < n; i++) { 300255219Spjd if ((big->cr_rights[i] & little->cr_rights[i]) != 301255219Spjd little->cr_rights[i]) { 302255219Spjd return (false); 303255219Spjd } 304255219Spjd } 305255219Spjd 306255219Spjd return (true); 307255219Spjd} 308