1 // SPDX-License-Identifier: GPL-2.0
3 * Implementation of the SID table type.
5 * Author : Stephen Smalley, <sds@tycho.nsa.gov>
7 #include <linux/kernel.h>
8 #include <linux/slab.h>
9 #include <linux/spinlock.h>
10 #include <linux/errno.h>
15 #define SIDTAB_HASH(sid) \
16 (sid & SIDTAB_HASH_MASK)
18 int sidtab_init(struct sidtab
*s
)
22 s
->htable
= kmalloc_array(SIDTAB_SIZE
, sizeof(*s
->htable
), GFP_ATOMIC
);
25 for (i
= 0; i
< SIDTAB_SIZE
; i
++)
30 spin_lock_init(&s
->lock
);
34 int sidtab_insert(struct sidtab
*s
, u32 sid
, struct context
*context
)
37 struct sidtab_node
*prev
, *cur
, *newnode
;
42 hvalue
= SIDTAB_HASH(sid
);
44 cur
= s
->htable
[hvalue
];
45 while (cur
&& sid
> cur
->sid
) {
50 if (cur
&& sid
== cur
->sid
)
53 newnode
= kmalloc(sizeof(*newnode
), GFP_ATOMIC
);
58 if (context_cpy(&newnode
->context
, context
)) {
64 newnode
->next
= prev
->next
;
68 newnode
->next
= s
->htable
[hvalue
];
70 s
->htable
[hvalue
] = newnode
;
74 if (sid
>= s
->next_sid
)
75 s
->next_sid
= sid
+ 1;
79 static struct context
*sidtab_search_core(struct sidtab
*s
, u32 sid
, int force
)
82 struct sidtab_node
*cur
;
87 hvalue
= SIDTAB_HASH(sid
);
88 cur
= s
->htable
[hvalue
];
89 while (cur
&& sid
> cur
->sid
)
92 if (force
&& cur
&& sid
== cur
->sid
&& cur
->context
.len
)
95 if (!cur
|| sid
!= cur
->sid
|| cur
->context
.len
) {
96 /* Remap invalid SIDs to the unlabeled SID. */
97 sid
= SECINITSID_UNLABELED
;
98 hvalue
= SIDTAB_HASH(sid
);
99 cur
= s
->htable
[hvalue
];
100 while (cur
&& sid
> cur
->sid
)
102 if (!cur
|| sid
!= cur
->sid
)
106 return &cur
->context
;
109 struct context
*sidtab_search(struct sidtab
*s
, u32 sid
)
111 return sidtab_search_core(s
, sid
, 0);
114 struct context
*sidtab_search_force(struct sidtab
*s
, u32 sid
)
116 return sidtab_search_core(s
, sid
, 1);
119 int sidtab_map(struct sidtab
*s
,
120 int (*apply
) (u32 sid
,
121 struct context
*context
,
126 struct sidtab_node
*cur
;
131 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
134 rc
= apply(cur
->sid
, &cur
->context
, args
);
144 static void sidtab_update_cache(struct sidtab
*s
, struct sidtab_node
*n
, int loc
)
146 BUG_ON(loc
>= SIDTAB_CACHE_LEN
);
149 s
->cache
[loc
] = s
->cache
[loc
- 1];
155 static inline u32
sidtab_search_context(struct sidtab
*s
,
156 struct context
*context
)
159 struct sidtab_node
*cur
;
161 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
164 if (context_cmp(&cur
->context
, context
)) {
165 sidtab_update_cache(s
, cur
, SIDTAB_CACHE_LEN
- 1);
174 static inline u32
sidtab_search_cache(struct sidtab
*s
, struct context
*context
)
177 struct sidtab_node
*node
;
179 for (i
= 0; i
< SIDTAB_CACHE_LEN
; i
++) {
183 if (context_cmp(&node
->context
, context
)) {
184 sidtab_update_cache(s
, node
, i
);
191 int sidtab_context_to_sid(struct sidtab
*s
,
192 struct context
*context
,
199 *out_sid
= SECSID_NULL
;
201 sid
= sidtab_search_cache(s
, context
);
203 sid
= sidtab_search_context(s
, context
);
205 spin_lock_irqsave(&s
->lock
, flags
);
206 /* Rescan now that we hold the lock. */
207 sid
= sidtab_search_context(s
, context
);
210 /* No SID exists for the context. Allocate a new one. */
211 if (s
->next_sid
== UINT_MAX
|| s
->shutdown
) {
218 "SELinux: Context %s is not valid (left unmapped).\n",
220 ret
= sidtab_insert(s
, sid
, context
);
224 spin_unlock_irqrestore(&s
->lock
, flags
);
234 void sidtab_hash_eval(struct sidtab
*h
, char *tag
)
236 int i
, chain_len
, slots_used
, max_chain_len
;
237 struct sidtab_node
*cur
;
241 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
251 if (chain_len
> max_chain_len
)
252 max_chain_len
= chain_len
;
256 printk(KERN_DEBUG
"%s: %d entries and %d/%d buckets used, longest "
257 "chain length %d\n", tag
, h
->nel
, slots_used
, SIDTAB_SIZE
,
261 void sidtab_destroy(struct sidtab
*s
)
264 struct sidtab_node
*cur
, *temp
;
269 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
274 context_destroy(&temp
->context
);
285 void sidtab_set(struct sidtab
*dst
, struct sidtab
*src
)
290 spin_lock_irqsave(&src
->lock
, flags
);
291 dst
->htable
= src
->htable
;
293 dst
->next_sid
= src
->next_sid
;
295 for (i
= 0; i
< SIDTAB_CACHE_LEN
; i
++)
296 dst
->cache
[i
] = NULL
;
297 spin_unlock_irqrestore(&src
->lock
, flags
);
300 void sidtab_shutdown(struct sidtab
*s
)
304 spin_lock_irqsave(&s
->lock
, flags
);
306 spin_unlock_irqrestore(&s
->lock
, flags
);