162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * A security identifier table (sidtab) is a lookup table 462306a36Sopenharmony_ci * of security context structures indexed by SID value. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Original author: Stephen Smalley, <stephen.smalley.work@gmail.com> 762306a36Sopenharmony_ci * Author: Ondrej Mosnacek, <omosnacek@gmail.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2018 Red Hat, Inc. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#ifndef _SS_SIDTAB_H_ 1262306a36Sopenharmony_ci#define _SS_SIDTAB_H_ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/spinlock_types.h> 1562306a36Sopenharmony_ci#include <linux/log2.h> 1662306a36Sopenharmony_ci#include <linux/hashtable.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "context.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct sidtab_entry { 2162306a36Sopenharmony_ci u32 sid; 2262306a36Sopenharmony_ci u32 hash; 2362306a36Sopenharmony_ci struct context context; 2462306a36Sopenharmony_ci#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 2562306a36Sopenharmony_ci struct sidtab_str_cache __rcu *cache; 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci struct hlist_node list; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciunion sidtab_entry_inner { 3162306a36Sopenharmony_ci struct sidtab_node_inner *ptr_inner; 3262306a36Sopenharmony_ci struct sidtab_node_leaf *ptr_leaf; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* align node size to page boundary */ 3662306a36Sopenharmony_ci#define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT 3762306a36Sopenharmony_ci#define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1)) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define SIDTAB_INNER_SHIFT \ 4262306a36Sopenharmony_ci (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner))) 4362306a36Sopenharmony_ci#define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT) 4462306a36Sopenharmony_ci#define SIDTAB_LEAF_ENTRIES \ 4562306a36Sopenharmony_ci (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry)) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define SIDTAB_MAX_BITS 32 4862306a36Sopenharmony_ci#define SIDTAB_MAX U32_MAX 4962306a36Sopenharmony_ci/* ensure enough tree levels for SIDTAB_MAX entries */ 5062306a36Sopenharmony_ci#define SIDTAB_MAX_LEVEL \ 5162306a36Sopenharmony_ci DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \ 5262306a36Sopenharmony_ci SIDTAB_INNER_SHIFT) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct sidtab_node_leaf { 5562306a36Sopenharmony_ci struct sidtab_entry entries[SIDTAB_LEAF_ENTRIES]; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct sidtab_node_inner { 5962306a36Sopenharmony_ci union sidtab_entry_inner entries[SIDTAB_INNER_ENTRIES]; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistruct sidtab_isid_entry { 6362306a36Sopenharmony_ci int set; 6462306a36Sopenharmony_ci struct sidtab_entry entry; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistruct sidtab_convert_params { 6862306a36Sopenharmony_ci struct convert_context_args *args; 6962306a36Sopenharmony_ci struct sidtab *target; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS 7362306a36Sopenharmony_ci#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistruct sidtab { 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * lock-free read access only for as many items as a prior read of 7862306a36Sopenharmony_ci * 'count' 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1]; 8162306a36Sopenharmony_ci /* 8262306a36Sopenharmony_ci * access atomically via {READ|WRITE}_ONCE(); only increment under 8362306a36Sopenharmony_ci * spinlock 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci u32 count; 8662306a36Sopenharmony_ci /* access only under spinlock */ 8762306a36Sopenharmony_ci struct sidtab_convert_params *convert; 8862306a36Sopenharmony_ci bool frozen; 8962306a36Sopenharmony_ci spinlock_t lock; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 9262306a36Sopenharmony_ci /* SID -> context string cache */ 9362306a36Sopenharmony_ci u32 cache_free_slots; 9462306a36Sopenharmony_ci struct list_head cache_lru_list; 9562306a36Sopenharmony_ci spinlock_t cache_lock; 9662306a36Sopenharmony_ci#endif 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* index == SID - 1 (no entry for SECSID_NULL) */ 9962306a36Sopenharmony_ci struct sidtab_isid_entry isids[SECINITSID_NUM]; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Hash table for fast reverse context-to-sid lookups. */ 10262306a36Sopenharmony_ci DECLARE_HASHTABLE(context_to_sid, SIDTAB_HASH_BITS); 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ciint sidtab_init(struct sidtab *s); 10662306a36Sopenharmony_ciint sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context); 10762306a36Sopenharmony_cistruct sidtab_entry *sidtab_search_entry(struct sidtab *s, u32 sid); 10862306a36Sopenharmony_cistruct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic inline struct context *sidtab_search(struct sidtab *s, u32 sid) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct sidtab_entry *entry = sidtab_search_entry(s, sid); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return entry ? &entry->context : NULL; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic inline struct context *sidtab_search_force(struct sidtab *s, u32 sid) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct sidtab_entry *entry = sidtab_search_entry_force(s, sid); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return entry ? &entry->context : NULL; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciint sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_civoid sidtab_cancel_convert(struct sidtab *s); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_civoid sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock); 12962306a36Sopenharmony_civoid sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciint sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_civoid sidtab_destroy(struct sidtab *s); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ciint sidtab_hash_stats(struct sidtab *sidtab, char *page); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 13862306a36Sopenharmony_civoid sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry, 13962306a36Sopenharmony_ci const char *str, u32 str_len); 14062306a36Sopenharmony_ciint sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, 14162306a36Sopenharmony_ci char **out, u32 *out_len); 14262306a36Sopenharmony_ci#else 14362306a36Sopenharmony_cistatic inline void sidtab_sid2str_put(struct sidtab *s, 14462306a36Sopenharmony_ci struct sidtab_entry *entry, 14562306a36Sopenharmony_ci const char *str, u32 str_len) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_cistatic inline int sidtab_sid2str_get(struct sidtab *s, 14962306a36Sopenharmony_ci struct sidtab_entry *entry, 15062306a36Sopenharmony_ci char **out, u32 *out_len) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci return -ENOENT; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci#endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#endif /* _SS_SIDTAB_H_ */ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci 159