diff options
Diffstat (limited to 'security/selinux/ss/avtab.c')
-rw-r--r-- | security/selinux/ss/avtab.c | 129 |
1 files changed, 71 insertions, 58 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 8c5800750fa8..8480ec6c6e75 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -23,13 +23,13 @@ #include "avtab.h" #include "policydb.h" -static struct kmem_cache *avtab_node_cachep; -static struct kmem_cache *avtab_xperms_cachep; +static struct kmem_cache *avtab_node_cachep __ro_after_init; +static struct kmem_cache *avtab_xperms_cachep __ro_after_init; /* Based on MurmurHash3, written by Austin Appleby and placed in the * public domain. */ -static inline int avtab_hash(struct avtab_key *keyp, u32 mask) +static inline int avtab_hash(const struct avtab_key *keyp, u32 mask) { static const u32 c1 = 0xcc9e2d51; static const u32 c2 = 0x1b873593; @@ -40,15 +40,15 @@ static inline int avtab_hash(struct avtab_key *keyp, u32 mask) u32 hash = 0; -#define mix(input) { \ - u32 v = input; \ - v *= c1; \ - v = (v << r1) | (v >> (32 - r1)); \ - v *= c2; \ - hash ^= v; \ - hash = (hash << r2) | (hash >> (32 - r2)); \ - hash = hash * m + n; \ -} +#define mix(input) do { \ + u32 v = input; \ + v *= c1; \ + v = (v << r1) | (v >> (32 - r1)); \ + v *= c2; \ + hash ^= v; \ + hash = (hash << r2) | (hash >> (32 - r2)); \ + hash = hash * m + n; \ + } while (0) mix(keyp->target_class); mix(keyp->target_type); @@ -67,8 +67,8 @@ static inline int avtab_hash(struct avtab_key *keyp, u32 mask) static struct avtab_node* avtab_insert_node(struct avtab *h, int hvalue, - struct avtab_node *prev, struct avtab_node *cur, - struct avtab_key *key, struct avtab_datum *datum) + struct avtab_node *prev, + const struct avtab_key *key, const struct avtab_datum *datum) { struct avtab_node *newnode; struct avtab_extended_perms *xperms; @@ -103,13 +103,14 @@ avtab_insert_node(struct avtab *h, int hvalue, return newnode; } -static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum) +static int avtab_insert(struct avtab *h, const struct avtab_key *key, + const struct avtab_datum *datum) { int hvalue; struct avtab_node *prev, *cur, *newnode; u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); - if (!h) + if (!h || !h->nslot) return -EINVAL; hvalue = avtab_hash(key, h->mask); @@ -136,7 +137,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat break; } - newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum); + newnode = avtab_insert_node(h, hvalue, prev, key, datum); if (!newnode) return -ENOMEM; @@ -147,14 +148,15 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat * key/specified mask into the table, as needed by the conditional avtab. * It also returns a pointer to the node inserted. */ -struct avtab_node * -avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum) +struct avtab_node *avtab_insert_nonunique(struct avtab *h, + const struct avtab_key *key, + const struct avtab_datum *datum) { int hvalue; struct avtab_node *prev, *cur; u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); - if (!h) + if (!h || !h->nslot) return NULL; hvalue = avtab_hash(key, h->mask); for (prev = NULL, cur = h->htable[hvalue]; @@ -175,16 +177,16 @@ avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datu key->target_class < cur->key.target_class) break; } - return avtab_insert_node(h, hvalue, prev, cur, key, datum); + return avtab_insert_node(h, hvalue, prev, key, datum); } -struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key) +struct avtab_datum *avtab_search(struct avtab *h, const struct avtab_key *key) { int hvalue; struct avtab_node *cur; u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); - if (!h) + if (!h || !h->nslot) return NULL; hvalue = avtab_hash(key, h->mask); @@ -213,14 +215,14 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key) /* This search function returns a node pointer, and can be used in * conjunction with avtab_search_next_node() */ -struct avtab_node* -avtab_search_node(struct avtab *h, struct avtab_key *key) +struct avtab_node *avtab_search_node(struct avtab *h, + const struct avtab_key *key) { int hvalue; struct avtab_node *cur; u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); - if (!h) + if (!h || !h->nslot) return NULL; hvalue = avtab_hash(key, h->mask); @@ -295,52 +297,63 @@ void avtab_destroy(struct avtab *h) } kvfree(h->htable); h->htable = NULL; + h->nel = 0; h->nslot = 0; h->mask = 0; } -int avtab_init(struct avtab *h) +void avtab_init(struct avtab *h) { - kvfree(h->htable); h->htable = NULL; h->nel = 0; + h->nslot = 0; + h->mask = 0; +} + +static int avtab_alloc_common(struct avtab *h, u32 nslot) +{ + if (!nslot) + return 0; + + h->htable = kvcalloc(nslot, sizeof(void *), GFP_KERNEL); + if (!h->htable) + return -ENOMEM; + + h->nslot = nslot; + h->mask = nslot - 1; return 0; } int avtab_alloc(struct avtab *h, u32 nrules) { - u32 mask = 0; - u32 shift = 0; - u32 work = nrules; + int rc; u32 nslot = 0; - if (nrules == 0) - goto avtab_alloc_out; + if (nrules != 0) { + u32 shift = 1; + u32 work = nrules >> 3; + while (work) { + work >>= 1; + shift++; + } + nslot = 1 << shift; + if (nslot > MAX_AVTAB_HASH_BUCKETS) + nslot = MAX_AVTAB_HASH_BUCKETS; - while (work) { - work = work >> 1; - shift++; + rc = avtab_alloc_common(h, nslot); + if (rc) + return rc; } - if (shift > 2) - shift = shift - 2; - nslot = 1 << shift; - if (nslot > MAX_AVTAB_HASH_BUCKETS) - nslot = MAX_AVTAB_HASH_BUCKETS; - mask = nslot - 1; - - h->htable = kvcalloc(nslot, sizeof(void *), GFP_KERNEL); - if (!h->htable) - return -ENOMEM; - avtab_alloc_out: - h->nel = 0; - h->nslot = nslot; - h->mask = mask; - pr_debug("SELinux: %d avtab hash slots, %d rules.\n", - h->nslot, nrules); + pr_debug("SELinux: %d avtab hash slots, %d rules.\n", nslot, nrules); return 0; } +int avtab_alloc_dup(struct avtab *new, const struct avtab *orig) +{ + return avtab_alloc_common(new, orig->nslot); +} + void avtab_hash_eval(struct avtab *h, char *tag) { int i, chain_len, slots_used, max_chain_len; @@ -372,7 +385,7 @@ void avtab_hash_eval(struct avtab *h, char *tag) chain2_len_sum); } -static uint16_t spec_order[] = { +static const uint16_t spec_order[] = { AVTAB_ALLOWED, AVTAB_AUDITDENY, AVTAB_AUDITALLOW, @@ -385,8 +398,8 @@ static uint16_t spec_order[] = { }; int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, - int (*insertf)(struct avtab *a, struct avtab_key *k, - struct avtab_datum *d, void *p), + int (*insertf)(struct avtab *a, const struct avtab_key *k, + const struct avtab_datum *d, void *p), void *p) { __le16 buf16[4]; @@ -546,8 +559,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return insertf(a, &key, &datum, p); } -static int avtab_insertf(struct avtab *a, struct avtab_key *k, - struct avtab_datum *d, void *p) +static int avtab_insertf(struct avtab *a, const struct avtab_key *k, + const struct avtab_datum *d, void *p) { return avtab_insert(a, k, d); } @@ -596,7 +609,7 @@ bad: goto out; } -int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) +int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp) { __le16 buf16[4]; __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; |