diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d928ce763bf..629366ac9ea 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -2724,7 +2724,7 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, if (fp == NULL) return (EBADF); #ifdef CAPABILITIES - error = cap_check(&haverights, needrightsp); + error = cap_check_inline(&haverights, needrightsp); if (error != 0) return (error); #endif diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c index 677e3a49840..559dc8e52cc 100644 --- a/sys/kern/subr_capability.c +++ b/sys/kern/subr_capability.c @@ -394,25 +394,3 @@ cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src) return (dst); } - -bool -cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little) -{ - unsigned int i, n; - - assert(CAPVER(big) == CAP_RIGHTS_VERSION_00); - assert(CAPVER(little) == CAP_RIGHTS_VERSION_00); - assert(CAPVER(big) == CAPVER(little)); - - n = CAPARSIZE(big); - assert(n >= CAPARSIZE_MIN && n <= CAPARSIZE_MAX); - - for (i = 0; i < n; i++) { - if ((big->cr_rights[i] & little->cr_rights[i]) != - little->cr_rights[i]) { - return (false); - } - } - - return (true); -} diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index 807521f55f3..8ad0eabd427 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -179,6 +179,17 @@ cap_check(const cap_rights_t *havep, const cap_rights_t *needp) return (_cap_check(havep, needp, CAPFAIL_NOTCAPABLE)); } +int +cap_check_failed_notcapable(const cap_rights_t *havep, const cap_rights_t *needp) +{ + +#ifdef KTRACE + if (KTRPOINT(curthread, KTR_CAPFAIL)) + ktrcapfail(CAPFAIL_NOTCAPABLE, needp, havep); +#endif + return (ENOTCAPABLE); +} + /* * Convert capability rights into VM access flags. */ diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h index 7abb4a7b2e0..305465a3157 100644 --- a/sys/sys/capsicum.h +++ b/sys/sys/capsicum.h @@ -342,9 +342,38 @@ bool __cap_rights_is_set(const cap_rights_t *rights, ...); bool cap_rights_is_valid(const cap_rights_t *rights); cap_rights_t *cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src); cap_rights_t *cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src); -bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little); void __cap_rights_sysinit(void *arg); + +/* + * We only support one size to reduce branching. + */ +_Static_assert(CAP_RIGHTS_VERSION == CAP_RIGHTS_VERSION_00, + "unsupported version of capsicum rights"); + +static inline bool +cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little) +{ + + if (__predict_true( + (big->cr_rights[0] & little->cr_rights[0]) == little->cr_rights[0] && + (big->cr_rights[1] & little->cr_rights[1]) == little->cr_rights[1])) + return (true); + return (false); +} + +int cap_check_failed_notcapable(const cap_rights_t *havep, + const cap_rights_t *needp); + +static inline int +cap_check_inline(const cap_rights_t *havep, const cap_rights_t *needp) +{ + + if (__predict_false(!cap_rights_contains(havep, needp))) + return (cap_check_failed_notcapable(havep, needp)); + return (0); +} + __END_DECLS struct cap_rights_init_args { cap_rights_t *cria_rights;