Branch data Line data Source code
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 : :
20 : : struct sidtab_entry {
21 : : u32 sid;
22 : : struct context context;
23 : : #if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
24 : : struct sidtab_str_cache __rcu *cache;
25 : : #endif
26 : : struct hlist_node list;
27 : : };
28 : :
29 : : union sidtab_entry_inner {
30 : : struct sidtab_node_inner *ptr_inner;
31 : : struct sidtab_node_leaf *ptr_leaf;
32 : : };
33 : :
34 : : /* align node size to page boundary */
35 : : #define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT
36 : : #define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE
37 : :
38 : : #define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1))
39 : :
40 : : #define SIDTAB_INNER_SHIFT \
41 : : (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner)))
42 : : #define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT)
43 : : #define SIDTAB_LEAF_ENTRIES \
44 : : (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry))
45 : :
46 : : #define SIDTAB_MAX_BITS 32
47 : : #define SIDTAB_MAX U32_MAX
48 : : /* ensure enough tree levels for SIDTAB_MAX entries */
49 : : #define SIDTAB_MAX_LEVEL \
50 : : DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \
51 : : SIDTAB_INNER_SHIFT)
52 : :
53 : : struct sidtab_node_leaf {
54 : : struct sidtab_entry entries[SIDTAB_LEAF_ENTRIES];
55 : : };
56 : :
57 : : struct sidtab_node_inner {
58 : : union sidtab_entry_inner entries[SIDTAB_INNER_ENTRIES];
59 : : };
60 : :
61 : : struct sidtab_isid_entry {
62 : : int set;
63 : : struct sidtab_entry entry;
64 : : };
65 : :
66 : : struct sidtab_convert_params {
67 : : int (*func)(struct context *oldc, struct context *newc, void *args);
68 : : void *args;
69 : : struct sidtab *target;
70 : : };
71 : :
72 : : #define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS
73 : : #define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
74 : :
75 : : struct sidtab {
76 : : /*
77 : : * lock-free read access only for as many items as a prior read of
78 : : * 'count'
79 : : */
80 : : union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1];
81 : : /*
82 : : * access atomically via {READ|WRITE}_ONCE(); only increment under
83 : : * spinlock
84 : : */
85 : : u32 count;
86 : : /* access only under spinlock */
87 : : struct sidtab_convert_params *convert;
88 : : spinlock_t lock;
89 : :
90 : : #if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
91 : : /* SID -> context string cache */
92 : : u32 cache_free_slots;
93 : : struct list_head cache_lru_list;
94 : : spinlock_t cache_lock;
95 : : #endif
96 : :
97 : : /* index == SID - 1 (no entry for SECSID_NULL) */
98 : : struct sidtab_isid_entry isids[SECINITSID_NUM];
99 : :
100 : : /* Hash table for fast reverse context-to-sid lookups. */
101 : : DECLARE_HASHTABLE(context_to_sid, SIDTAB_HASH_BITS);
102 : : };
103 : :
104 : : int sidtab_init(struct sidtab *s);
105 : : int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context);
106 : : struct sidtab_entry *sidtab_search_entry(struct sidtab *s, u32 sid);
107 : : struct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid);
108 : :
109 : 0 : static inline struct context *sidtab_search(struct sidtab *s, u32 sid)
110 : : {
111 : 0 : struct sidtab_entry *entry = sidtab_search_entry(s, sid);
112 : :
113 [ # # # # : 0 : return entry ? &entry->context : NULL;
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
114 : : }
115 : :
116 : : static inline struct context *sidtab_search_force(struct sidtab *s, u32 sid)
117 : : {
118 : : struct sidtab_entry *entry = sidtab_search_entry_force(s, sid);
119 : :
120 : : return entry ? &entry->context : NULL;
121 : : }
122 : :
123 : : int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
124 : :
125 : : int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
126 : :
127 : : void sidtab_destroy(struct sidtab *s);
128 : :
129 : : int sidtab_hash_stats(struct sidtab *sidtab, char *page);
130 : :
131 : : #if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
132 : : void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry,
133 : : const char *str, u32 str_len);
134 : : int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry,
135 : : char **out, u32 *out_len);
136 : : #else
137 : : static inline void sidtab_sid2str_put(struct sidtab *s,
138 : : struct sidtab_entry *entry,
139 : : const char *str, u32 str_len)
140 : : {
141 : : }
142 : : static inline int sidtab_sid2str_get(struct sidtab *s,
143 : : struct sidtab_entry *entry,
144 : : char **out, u32 *out_len)
145 : : {
146 : : return -ENOENT;
147 : : }
148 : : #endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */
149 : :
150 : : #endif /* _SS_SIDTAB_H_ */
151 : :
152 : :
|