linux/security/selinux/ss/sidtab.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * A security identifier table (sidtab) is a lookup table
   4 * of security context structures indexed by SID value.
   5 *
   6 * Original author: Stephen Smalley, <sds@tycho.nsa.gov>
   7 * Author: Ondrej Mosnacek, <omosnacek@gmail.com>
   8 *
   9 * Copyright (C) 2018 Red Hat, Inc.
  10 */
  11#ifndef _SS_SIDTAB_H_
  12#define _SS_SIDTAB_H_
  13
  14#include <linux/spinlock_types.h>
  15#include <linux/log2.h>
  16#include <linux/hashtable.h>
  17
  18#include "context.h"
  19
  20struct sidtab_entry {
  21        u32 sid;
  22        u32 hash;
  23        struct context context;
  24#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
  25        struct sidtab_str_cache __rcu *cache;
  26#endif
  27        struct hlist_node list;
  28};
  29
  30union sidtab_entry_inner {
  31        struct sidtab_node_inner *ptr_inner;
  32        struct sidtab_node_leaf  *ptr_leaf;
  33};
  34
  35/* align node size to page boundary */
  36#define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT
  37#define SIDTAB_NODE_ALLOC_SIZE  PAGE_SIZE
  38
  39#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1))
  40
  41#define SIDTAB_INNER_SHIFT \
  42        (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner)))
  43#define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT)
  44#define SIDTAB_LEAF_ENTRIES \
  45        (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry))
  46
  47#define SIDTAB_MAX_BITS 32
  48#define SIDTAB_MAX U32_MAX
  49/* ensure enough tree levels for SIDTAB_MAX entries */
  50#define SIDTAB_MAX_LEVEL \
  51        DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \
  52                     SIDTAB_INNER_SHIFT)
  53
  54struct sidtab_node_leaf {
  55        struct sidtab_entry entries[SIDTAB_LEAF_ENTRIES];
  56};
  57
  58struct sidtab_node_inner {
  59        union sidtab_entry_inner entries[SIDTAB_INNER_ENTRIES];
  60};
  61
  62struct sidtab_isid_entry {
  63        int set;
  64        struct sidtab_entry entry;
  65};
  66
  67struct sidtab_convert_params {
  68        int (*func)(struct context *oldc, struct context *newc, void *args);
  69        void *args;
  70        struct sidtab *target;
  71};
  72
  73#define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS
  74#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
  75
  76struct sidtab {
  77        /*
  78         * lock-free read access only for as many items as a prior read of
  79         * 'count'
  80         */
  81        union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1];
  82        /*
  83         * access atomically via {READ|WRITE}_ONCE(); only increment under
  84         * spinlock
  85         */
  86        u32 count;
  87        /* access only under spinlock */
  88        struct sidtab_convert_params *convert;
  89        bool frozen;
  90        spinlock_t lock;
  91
  92#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
  93        /* SID -> context string cache */
  94        u32 cache_free_slots;
  95        struct list_head cache_lru_list;
  96        spinlock_t cache_lock;
  97#endif
  98
  99        /* index == SID - 1 (no entry for SECSID_NULL) */
 100        struct sidtab_isid_entry isids[SECINITSID_NUM];
 101
 102        /* Hash table for fast reverse context-to-sid lookups. */
 103        DECLARE_HASHTABLE(context_to_sid, SIDTAB_HASH_BITS);
 104};
 105
 106int sidtab_init(struct sidtab *s);
 107int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context);
 108struct sidtab_entry *sidtab_search_entry(struct sidtab *s, u32 sid);
 109struct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid);
 110
 111static inline struct context *sidtab_search(struct sidtab *s, u32 sid)
 112{
 113        struct sidtab_entry *entry = sidtab_search_entry(s, sid);
 114
 115        return entry ? &entry->context : NULL;
 116}
 117
 118static inline struct context *sidtab_search_force(struct sidtab *s, u32 sid)
 119{
 120        struct sidtab_entry *entry = sidtab_search_entry_force(s, sid);
 121
 122        return entry ? &entry->context : NULL;
 123}
 124
 125int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
 126
 127void sidtab_cancel_convert(struct sidtab *s);
 128
 129void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock);
 130void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock);
 131
 132int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
 133
 134void sidtab_destroy(struct sidtab *s);
 135
 136int sidtab_hash_stats(struct sidtab *sidtab, char *page);
 137
 138#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
 139void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry,
 140                        const char *str, u32 str_len);
 141int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry,
 142                       char **out, u32 *out_len);
 143#else
 144static inline void sidtab_sid2str_put(struct sidtab *s,
 145                                      struct sidtab_entry *entry,
 146                                      const char *str, u32 str_len)
 147{
 148}
 149static inline int sidtab_sid2str_get(struct sidtab *s,
 150                                     struct sidtab_entry *entry,
 151                                     char **out, u32 *out_len)
 152{
 153        return -ENOENT;
 154}
 155#endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */
 156
 157#endif  /* _SS_SIDTAB_H_ */
 158
 159
 160