diff options
author | dec05eba <dec05eba@protonmail.com> | 2024-02-10 19:05:02 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2024-02-11 02:11:41 +0100 |
commit | 667a6b3b1bc20516d1bf7d8a4611cd3a4d3f3bc6 (patch) | |
tree | 2770b29323939cec51670dd0d1aebd39a8041914 /depends/libcap/libcap/cap_flag.c |
Initial commit, done
Diffstat (limited to 'depends/libcap/libcap/cap_flag.c')
-rw-r--r-- | depends/libcap/libcap/cap_flag.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/depends/libcap/libcap/cap_flag.c b/depends/libcap/libcap/cap_flag.c new file mode 100644 index 0000000..94afd1e --- /dev/null +++ b/depends/libcap/libcap/cap_flag.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 1997-8,2008,20-21 Andrew G. Morgan <morgan@kernel.org> + * + * This file deals with flipping of capabilities on internal + * capability sets as specified by POSIX.1e (formerlly, POSIX 6). + * + * It also contains similar code for bit flipping cap_iab_t values. + */ + +#include "libcap.h" + +/* + * Return the state of a specified capability flag. The state is + * returned as the contents of *raised. The capability is from one of + * the sets stored in cap_d as specified by set and value + */ +int cap_get_flag(cap_t cap_d, cap_value_t value, cap_flag_t set, + cap_flag_value_t *raised) +{ + /* + * Do we have a set and a place to store its value? + * Is it a known capability? + */ + + if (raised && good_cap_t(cap_d) && value >= 0 && value < __CAP_MAXBITS + && set >= 0 && set < NUMBER_OF_CAP_SETS) { + _cap_mu_lock(&cap_d->mutex); + *raised = isset_cap(cap_d,value,set) ? CAP_SET:CAP_CLEAR; + _cap_mu_unlock(&cap_d->mutex); + return 0; + } else { + _cap_debug("invalid arguments"); + errno = EINVAL; + return -1; + } +} + +/* + * raise/lower a selection of capabilities + */ + +int cap_set_flag(cap_t cap_d, cap_flag_t set, + int no_values, const cap_value_t *array_values, + cap_flag_value_t raise) +{ + /* + * Do we have a set and a place to store its value? + * Is it a known capability? + */ + + if (good_cap_t(cap_d) && no_values > 0 && no_values < __CAP_MAXBITS + && (set >= 0) && (set < NUMBER_OF_CAP_SETS) + && (raise == CAP_SET || raise == CAP_CLEAR) ) { + int i; + _cap_mu_lock(&cap_d->mutex); + for (i=0; i<no_values; ++i) { + if (array_values[i] < 0 || array_values[i] >= __CAP_MAXBITS) { + _cap_debug("weird capability (%d) - skipped", array_values[i]); + } else { + int value = array_values[i]; + + if (raise == CAP_SET) { + cap_d->raise_cap(value,set); + } else { + cap_d->lower_cap(value,set); + } + } + } + _cap_mu_unlock(&cap_d->mutex); + return 0; + } else { + _cap_debug("invalid arguments"); + errno = EINVAL; + return -1; + } +} + +/* + * Reset the capability to be empty (nothing raised) + */ + +int cap_clear(cap_t cap_d) +{ + if (good_cap_t(cap_d)) { + _cap_mu_lock(&cap_d->mutex); + memset(&(cap_d->u), 0, sizeof(cap_d->u)); + _cap_mu_unlock(&cap_d->mutex); + return 0; + } else { + _cap_debug("invalid pointer"); + errno = EINVAL; + return -1; + } +} + +/* + * Reset the all of the capability bits for one of the flag sets + */ + +int cap_clear_flag(cap_t cap_d, cap_flag_t flag) +{ + switch (flag) { + case CAP_EFFECTIVE: + case CAP_PERMITTED: + case CAP_INHERITABLE: + if (good_cap_t(cap_d)) { + unsigned i; + + _cap_mu_lock(&cap_d->mutex); + for (i=0; i<_LIBCAP_CAPABILITY_U32S; i++) { + cap_d->u[i].flat[flag] = 0; + } + _cap_mu_unlock(&cap_d->mutex); + return 0; + } + /* + * fall through + */ + + default: + _cap_debug("invalid pointer"); + errno = EINVAL; + return -1; + } +} + +/* + * Compare two capability sets + */ +int cap_compare(cap_t a, cap_t b) +{ + unsigned i; + int result; + + if (!(good_cap_t(a) && good_cap_t(b))) { + _cap_debug("invalid arguments"); + errno = EINVAL; + return -1; + } + + /* + * To avoid a deadlock corner case, we operate on an unlocked + * private copy of b + */ + b = cap_dup(b); + if (b == NULL) { + return -1; + } + _cap_mu_lock(&a->mutex); + for (i=0, result=0; i<_LIBCAP_CAPABILITY_U32S; i++) { + result |= + ((a->u[i].flat[CAP_EFFECTIVE] != b->u[i].flat[CAP_EFFECTIVE]) + ? LIBCAP_EFF : 0) + | ((a->u[i].flat[CAP_INHERITABLE] != b->u[i].flat[CAP_INHERITABLE]) + ? LIBCAP_INH : 0) + | ((a->u[i].flat[CAP_PERMITTED] != b->u[i].flat[CAP_PERMITTED]) + ? LIBCAP_PER : 0); + } + _cap_mu_unlock(&a->mutex); + cap_free(b); + return result; +} + +/* + * cap_fill_flag copies a bit-vector of capability state in one cap_t from one + * flag to another flag of another cap_t. + */ +int cap_fill_flag(cap_t cap_d, cap_flag_t to, cap_t ref, cap_flag_t from) +{ + int i; + cap_t orig; + + if (!good_cap_t(cap_d) || !good_cap_t(ref)) { + errno = EINVAL; + return -1; + } + + if (to < CAP_EFFECTIVE || to > CAP_INHERITABLE || + from < CAP_EFFECTIVE || from > CAP_INHERITABLE) { + errno = EINVAL; + return -1; + } + + orig = cap_dup(ref); + if (orig == NULL) { + return -1; + } + + _cap_mu_lock(&cap_d->mutex); + for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) { + cap_d->u[i].flat[to] = orig->u[i].flat[from]; + } + _cap_mu_unlock(&cap_d->mutex); + + cap_free(orig); + return 0; +} + +/* + * cap_fill copies a bit-vector of capability state in a cap_t from + * one flag to another. + */ +int cap_fill(cap_t cap_d, cap_flag_t to, cap_flag_t from) +{ + return cap_fill_flag(cap_d, to, cap_d, from); +} + +/* + * cap_iab_get_vector reads the single bit value from an IAB vector set. + */ +cap_flag_value_t cap_iab_get_vector(cap_iab_t iab, cap_iab_vector_t vec, + cap_value_t bit) +{ + if (!good_cap_iab_t(iab) || bit >= cap_max_bits()) { + return 0; + } + + unsigned o = (bit >> 5); + __u32 mask = 1u << (bit & 31); + cap_flag_value_t ret; + + _cap_mu_lock(&iab->mutex); + switch (vec) { + case CAP_IAB_INH: + ret = !!(iab->i[o] & mask); + break; + case CAP_IAB_AMB: + ret = !!(iab->a[o] & mask); + break; + case CAP_IAB_BOUND: + ret = !!(iab->nb[o] & mask); + break; + default: + ret = 0; + } + _cap_mu_unlock(&iab->mutex); + + return ret; +} + +/* + * cap_iab_set_vector sets the bits in an IAB to the value + * raised. Note, setting A implies setting I too, lowering I implies + * lowering A too. The B bits are, however, independently settable. + */ +int cap_iab_set_vector(cap_iab_t iab, cap_iab_vector_t vec, cap_value_t bit, + cap_flag_value_t raised) +{ + if (!good_cap_iab_t(iab) || (raised >> 1) || bit >= cap_max_bits()) { + errno = EINVAL; + return -1; + } + + unsigned o = (bit >> 5); + __u32 on = 1u << (bit & 31); + __u32 mask = ~on; + + _cap_mu_lock(&iab->mutex); + switch (vec) { + case CAP_IAB_INH: + iab->i[o] = (iab->i[o] & mask) | (raised ? on : 0); + iab->a[o] &= iab->i[o]; + break; + case CAP_IAB_AMB: + iab->a[o] = (iab->a[o] & mask) | (raised ? on : 0); + iab->i[o] |= iab->a[o]; + break; + case CAP_IAB_BOUND: + iab->nb[o] = (iab->nb[o] & mask) | (raised ? on : 0); + break; + default: + errno = EINVAL; + _cap_mu_unlock_return(&iab->mutex, -1); + } + + _cap_mu_unlock(&iab->mutex); + return 0; +} + +/* + * cap_iab_fill copies a bit-vector of capability state from a cap_t + * to a cap_iab_t. Note, because the bounding bits in an iab are to be + * dropped when applied, the copying process, when to a CAP_IAB_BOUND + * vector involves inverting the bits. Also, adjusting I will mask + * bits in A, and adjusting A may implicitly raise bits in I. + */ +int cap_iab_fill(cap_iab_t iab, cap_iab_vector_t vec, + cap_t cap_d, cap_flag_t flag) +{ + int i, ret = 0; + + if (!good_cap_t(cap_d) || !good_cap_iab_t(iab)) { + errno = EINVAL; + return -1; + } + + switch (flag) { + case CAP_EFFECTIVE: + case CAP_INHERITABLE: + case CAP_PERMITTED: + break; + default: + errno = EINVAL; + return -1; + } + + /* + * Make a private copy so we don't need to hold two locks at once + * avoiding a recipe for a deadlock. + */ + cap_d = cap_dup(cap_d); + if (cap_d == NULL) { + return -1; + } + + _cap_mu_lock(&iab->mutex); + for (i = 0; !ret && i < _LIBCAP_CAPABILITY_U32S; i++) { + switch (vec) { + case CAP_IAB_INH: + iab->i[i] = cap_d->u[i].flat[flag]; + iab->a[i] &= iab->i[i]; + break; + case CAP_IAB_AMB: + iab->a[i] = cap_d->u[i].flat[flag]; + iab->i[i] |= cap_d->u[i].flat[flag]; + break; + case CAP_IAB_BOUND: + iab->nb[i] = ~cap_d->u[i].flat[flag]; + break; + default: + errno = EINVAL; + ret = -1; + break; + } + } + _cap_mu_unlock(&iab->mutex); + + cap_free(cap_d); + return ret; +} + +/* + * cap_iab_compare compares two iab tuples. + */ +int cap_iab_compare(cap_iab_t a, cap_iab_t b) +{ + int j, result; + if (!(good_cap_iab_t(a) && good_cap_iab_t(b))) { + _cap_debug("invalid arguments"); + errno = EINVAL; + return -1; + } + b = cap_iab_dup(b); + if (b == NULL) { + return -1; + } + + _cap_mu_lock(&a->mutex); + for (j=0, result=0; j<_LIBCAP_CAPABILITY_U32S; j++) { + result |= + (a->i[j] == b->i[j] ? 0 : (1 << CAP_IAB_INH)) | + (a->a[j] == b->a[j] ? 0 : (1 << CAP_IAB_AMB)) | + (a->nb[j] == b->nb[j] ? 0 : (1 << CAP_IAB_BOUND)); + } + _cap_mu_unlock(&a->mutex); + cap_free(b); + + return result; +} |