Commit f5fc9e4a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'selinux-pr-20231030' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:

 - improve the SELinux debugging configuration controls in Kconfig

 - print additional information about the hash table chain lengths when
   when printing SELinux debugging information

 - simplify the SELinux access vector hash table calcaulations

 - use a better hashing function for the SELinux role tansition hash
   table

 - improve SELinux load policy time through the use of optimized
   functions for calculating the number of bits set in a field

 - addition of a __counted_by annotation

 - simplify the avtab_inert_node() function through a simplified
   prototype

* tag 'selinux-pr-20231030' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: simplify avtab_insert_node() prototype
  selinux: hweight optimization in avtab_read_item
  selinux: improve role transition hashing
  selinux: simplify avtab slot calculation
  selinux: improve debug configuration
  selinux: print sum of chain lengths^2 for hash tables
  selinux: Annotate struct sidtab_str_cache with __counted_by
parents b9886c97 19c1c991
...@@ -77,3 +77,13 @@ config SECURITY_SELINUX_DEBUG ...@@ -77,3 +77,13 @@ config SECURITY_SELINUX_DEBUG
This enables debugging code designed to help SELinux kernel This enables debugging code designed to help SELinux kernel
developers, unless you know what this does in the kernel code you developers, unless you know what this does in the kernel code you
should leave this disabled. should leave this disabled.
To fine control the messages to be printed enable
CONFIG_DYNAMIC_DEBUG and see
Documentation/admin-guide/dynamic-debug-howto.rst for additional
information.
Example usage:
echo -n 'file "security/selinux/*" +p' > \
/proc/dynamic_debug/control
...@@ -12,6 +12,8 @@ obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ...@@ -12,6 +12,8 @@ obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \ selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
netnode.o netport.o status.o \ netnode.o netport.o status.o \
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \ ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* Tuned number of hash slots for avtab to reduce memory usage * Tuned number of hash slots for avtab to reduce memory usage
*/ */
#include <linux/bitops.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -66,8 +67,7 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask) ...@@ -66,8 +67,7 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask)
} }
static struct avtab_node* static struct avtab_node*
avtab_insert_node(struct avtab *h, u32 hvalue, avtab_insert_node(struct avtab *h, struct avtab_node **dst,
struct avtab_node *prev,
const struct avtab_key *key, const struct avtab_datum *datum) const struct avtab_key *key, const struct avtab_datum *datum)
{ {
struct avtab_node *newnode; struct avtab_node *newnode;
...@@ -89,15 +89,8 @@ avtab_insert_node(struct avtab *h, u32 hvalue, ...@@ -89,15 +89,8 @@ avtab_insert_node(struct avtab *h, u32 hvalue,
newnode->datum.u.data = datum->u.data; newnode->datum.u.data = datum->u.data;
} }
if (prev) { newnode->next = *dst;
newnode->next = prev->next; *dst = newnode;
prev->next = newnode;
} else {
struct avtab_node **n = &h->htable[hvalue];
newnode->next = *n;
*n = newnode;
}
h->nel++; h->nel++;
return newnode; return newnode;
...@@ -137,7 +130,8 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key, ...@@ -137,7 +130,8 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key,
break; break;
} }
newnode = avtab_insert_node(h, hvalue, prev, key, datum); newnode = avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue],
key, datum);
if (!newnode) if (!newnode)
return -ENOMEM; return -ENOMEM;
...@@ -177,7 +171,8 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h, ...@@ -177,7 +171,8 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
key->target_class < cur->key.target_class) key->target_class < cur->key.target_class)
break; break;
} }
return avtab_insert_node(h, hvalue, prev, key, datum); return avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue],
key, datum);
} }
/* This search function returns a node pointer, and can be used in /* This search function returns a node pointer, and can be used in
...@@ -298,13 +293,7 @@ int avtab_alloc(struct avtab *h, u32 nrules) ...@@ -298,13 +293,7 @@ int avtab_alloc(struct avtab *h, u32 nrules)
u32 nslot = 0; u32 nslot = 0;
if (nrules != 0) { if (nrules != 0) {
u32 shift = 1; nslot = nrules > 3 ? rounddown_pow_of_two(nrules / 2) : 2;
u32 work = nrules >> 3;
while (work) {
work >>= 1;
shift++;
}
nslot = 1 << shift;
if (nslot > MAX_AVTAB_HASH_BUCKETS) if (nslot > MAX_AVTAB_HASH_BUCKETS)
nslot = MAX_AVTAB_HASH_BUCKETS; nslot = MAX_AVTAB_HASH_BUCKETS;
...@@ -349,7 +338,7 @@ void avtab_hash_eval(struct avtab *h, const char *tag) ...@@ -349,7 +338,7 @@ void avtab_hash_eval(struct avtab *h, const char *tag)
} }
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, " pr_debug("SELinux: %s: %d entries and %d/%d buckets used, "
"longest chain length %d sum of chain length^2 %llu\n", "longest chain length %d, sum of chain length^2 %llu\n",
tag, h->nel, slots_used, h->nslot, max_chain_len, tag, h->nel, slots_used, h->nslot, max_chain_len,
chain2_len_sum); chain2_len_sum);
} }
...@@ -477,11 +466,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, ...@@ -477,11 +466,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
return -EINVAL; return -EINVAL;
} }
set = 0; set = hweight16(key.specified & (AVTAB_XPERMS | AVTAB_TYPE | AVTAB_AV));
for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
if (key.specified & spec_order[i])
set++;
}
if (!set || set > 1) { if (!set || set > 1) {
pr_err("SELinux: avtab: more than one specifier\n"); pr_err("SELinux: avtab: more than one specifier\n");
return -EINVAL; return -EINVAL;
......
...@@ -107,10 +107,12 @@ int hashtab_map(struct hashtab *h, ...@@ -107,10 +107,12 @@ int hashtab_map(struct hashtab *h,
void hashtab_stat(struct hashtab *h, struct hashtab_info *info) void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
{ {
u32 i, chain_len, slots_used, max_chain_len; u32 i, chain_len, slots_used, max_chain_len;
u64 chain2_len_sum;
struct hashtab_node *cur; struct hashtab_node *cur;
slots_used = 0; slots_used = 0;
max_chain_len = 0; max_chain_len = 0;
chain2_len_sum = 0;
for (i = 0; i < h->size; i++) { for (i = 0; i < h->size; i++) {
cur = h->htable[i]; cur = h->htable[i];
if (cur) { if (cur) {
...@@ -123,11 +125,14 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info) ...@@ -123,11 +125,14 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
if (chain_len > max_chain_len) if (chain_len > max_chain_len)
max_chain_len = chain_len; max_chain_len = chain_len;
chain2_len_sum += (u64)chain_len * chain_len;
} }
} }
info->slots_used = slots_used; info->slots_used = slots_used;
info->max_chain_len = max_chain_len; info->max_chain_len = max_chain_len;
info->chain2_len_sum = chain2_len_sum;
} }
#endif /* CONFIG_SECURITY_SELINUX_DEBUG */ #endif /* CONFIG_SECURITY_SELINUX_DEBUG */
......
...@@ -38,6 +38,7 @@ struct hashtab { ...@@ -38,6 +38,7 @@ struct hashtab {
struct hashtab_info { struct hashtab_info {
u32 slots_used; u32 slots_used;
u32 max_chain_len; u32 max_chain_len;
u64 chain2_len_sum;
}; };
/* /*
......
...@@ -491,7 +491,7 @@ static u32 role_trans_hash(const void *k) ...@@ -491,7 +491,7 @@ static u32 role_trans_hash(const void *k)
{ {
const struct role_trans_key *key = k; const struct role_trans_key *key = k;
return key->role + (key->type << 3) + (key->tclass << 5); return jhash_3words(key->role, key->type, (u32)key->tclass << 16 | key->tclass, 0);
} }
static int role_trans_cmp(const void *k1, const void *k2) static int role_trans_cmp(const void *k1, const void *k2)
...@@ -684,9 +684,9 @@ static void hash_eval(struct hashtab *h, const char *hash_name) ...@@ -684,9 +684,9 @@ static void hash_eval(struct hashtab *h, const char *hash_name)
struct hashtab_info info; struct hashtab_info info;
hashtab_stat(h, &info); hashtab_stat(h, &info);
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n", pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n",
hash_name, h->nel, info.slots_used, h->size, hash_name, h->nel, info.slots_used, h->size,
info.max_chain_len); info.max_chain_len, info.chain2_len_sum);
} }
static void symtab_hash_eval(struct symtab *s) static void symtab_hash_eval(struct symtab *s)
......
...@@ -25,7 +25,7 @@ struct sidtab_str_cache { ...@@ -25,7 +25,7 @@ struct sidtab_str_cache {
struct list_head lru_member; struct list_head lru_member;
struct sidtab_entry *parent; struct sidtab_entry *parent;
u32 len; u32 len;
char str[]; char str[] __counted_by(len);
}; };
#define index_to_sid(index) ((index) + SECINITSID_NUM + 1) #define index_to_sid(index) ((index) + SECINITSID_NUM + 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment