diff options
Diffstat (limited to 'security/selinux/ss/sidtab.h')
-rw-r--r-- | security/selinux/ss/sidtab.h | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h index e657ae6bf996..bbd5c0d1f3bd 100644 --- a/security/selinux/ss/sidtab.h +++ b/security/selinux/ss/sidtab.h @@ -1,41 +1,82 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * A security identifier table (sidtab) is a hash table + * A security identifier table (sidtab) is a lookup table * of security context structures indexed by SID value. * - * Author : Stephen Smalley, <sds@tycho.nsa.gov> + * Original author: Stephen Smalley, <sds@tycho.nsa.gov> + * Author: Ondrej Mosnacek, <omosnacek@gmail.com> + * + * Copyright (C) 2018 Red Hat, Inc. */ #ifndef _SS_SIDTAB_H_ #define _SS_SIDTAB_H_ +#include <linux/spinlock_types.h> +#include <linux/log2.h> + #include "context.h" -struct sidtab_node { - u32 sid; /* security identifier */ - struct context context; /* security context structure */ - struct sidtab_node *next; +struct sidtab_entry_leaf { + struct context context; +}; + +struct sidtab_node_inner; +struct sidtab_node_leaf; + +union sidtab_entry_inner { + struct sidtab_node_inner *ptr_inner; + struct sidtab_node_leaf *ptr_leaf; }; -#define SIDTAB_HASH_BITS 7 -#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) -#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1) +/* align node size to page boundary */ +#define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT +#define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE + +#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1)) + +#define SIDTAB_INNER_SHIFT \ + (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner))) +#define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT) +#define SIDTAB_LEAF_ENTRIES \ + (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf)) -#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS +#define SIDTAB_MAX_BITS 31 /* limited to INT_MAX due to atomic_t range */ +#define SIDTAB_MAX (((u32)1 << SIDTAB_MAX_BITS) - 1) +/* ensure enough tree levels for SIDTAB_MAX entries */ +#define SIDTAB_MAX_LEVEL \ + DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \ + SIDTAB_INNER_SHIFT) + +struct sidtab_node_leaf { + struct sidtab_entry_leaf entries[SIDTAB_LEAF_ENTRIES]; +}; + +struct sidtab_node_inner { + union sidtab_entry_inner entries[SIDTAB_INNER_ENTRIES]; +}; struct sidtab_isid_entry { int set; struct context context; }; +struct sidtab_convert_params { + int (*func)(struct context *oldc, struct context *newc, void *args); + void *args; + struct sidtab *target; +}; + +#define SIDTAB_RCACHE_SIZE 3 + struct sidtab { - struct sidtab_node **htable; - unsigned int nel; /* number of elements */ - unsigned int next_sid; /* next SID to allocate */ - unsigned char shutdown; -#define SIDTAB_CACHE_LEN 3 - struct sidtab_node *cache[SIDTAB_CACHE_LEN]; + union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1]; + atomic_t count; + struct sidtab_convert_params *convert; spinlock_t lock; + /* reverse lookup cache */ + atomic_t rcache[SIDTAB_RCACHE_SIZE]; + /* index == SID - 1 (no entry for SECSID_NULL) */ struct sidtab_isid_entry isids[SECINITSID_NUM]; }; @@ -45,15 +86,10 @@ int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context); struct context *sidtab_search(struct sidtab *s, u32 sid); struct context *sidtab_search_force(struct sidtab *s, u32 sid); -int sidtab_convert(struct sidtab *s, struct sidtab *news, - int (*apply)(u32 sid, - struct context *context, - void *args), - void *args); +int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params); int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid); -void sidtab_hash_eval(struct sidtab *h, char *tag); void sidtab_destroy(struct sidtab *s); #endif /* _SS_SIDTAB_H_ */ |