2 * Implementation of the SID table type.
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
6 #include <linux/kernel.h>
7 #include <linux/slab.h>
8 #include <linux/spinlock.h>
9 #include <linux/errno.h>
14 #define SIDTAB_HASH(sid) \
15 (sid & SIDTAB_HASH_MASK)
17 int sidtab_init(struct sidtab
*s
)
21 s
->htable
= kmalloc(sizeof(*(s
->htable
)) * SIDTAB_SIZE
, GFP_ATOMIC
);
24 for (i
= 0; i
< SIDTAB_SIZE
; i
++)
29 spin_lock_init(&s
->lock
);
33 int sidtab_insert(struct sidtab
*s
, u32 sid
, struct context
*context
)
36 struct sidtab_node
*prev
, *cur
, *newnode
;
43 hvalue
= SIDTAB_HASH(sid
);
45 cur
= s
->htable
[hvalue
];
46 while (cur
&& sid
> cur
->sid
) {
51 if (cur
&& sid
== cur
->sid
) {
56 newnode
= kmalloc(sizeof(*newnode
), GFP_ATOMIC
);
57 if (newnode
== NULL
) {
62 if (context_cpy(&newnode
->context
, context
)) {
69 newnode
->next
= prev
->next
;
73 newnode
->next
= s
->htable
[hvalue
];
75 s
->htable
[hvalue
] = newnode
;
79 if (sid
>= s
->next_sid
)
80 s
->next_sid
= sid
+ 1;
85 static struct context
*sidtab_search_core(struct sidtab
*s
, u32 sid
, int force
)
88 struct sidtab_node
*cur
;
93 hvalue
= SIDTAB_HASH(sid
);
94 cur
= s
->htable
[hvalue
];
95 while (cur
&& sid
> cur
->sid
)
98 if (force
&& cur
&& sid
== cur
->sid
&& cur
->context
.len
)
101 if (cur
== NULL
|| sid
!= cur
->sid
|| cur
->context
.len
) {
102 /* Remap invalid SIDs to the unlabeled SID. */
103 sid
= SECINITSID_UNLABELED
;
104 hvalue
= SIDTAB_HASH(sid
);
105 cur
= s
->htable
[hvalue
];
106 while (cur
&& sid
> cur
->sid
)
108 if (!cur
|| sid
!= cur
->sid
)
112 return &cur
->context
;
115 struct context
*sidtab_search(struct sidtab
*s
, u32 sid
)
117 return sidtab_search_core(s
, sid
, 0);
120 struct context
*sidtab_search_force(struct sidtab
*s
, u32 sid
)
122 return sidtab_search_core(s
, sid
, 1);
125 int sidtab_map(struct sidtab
*s
,
126 int (*apply
) (u32 sid
,
127 struct context
*context
,
132 struct sidtab_node
*cur
;
137 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
140 rc
= apply(cur
->sid
, &cur
->context
, args
);
150 static inline u32
sidtab_search_context(struct sidtab
*s
,
151 struct context
*context
)
154 struct sidtab_node
*cur
;
156 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
159 if (context_cmp(&cur
->context
, context
))
167 int sidtab_context_to_sid(struct sidtab
*s
,
168 struct context
*context
,
175 *out_sid
= SECSID_NULL
;
177 sid
= sidtab_search_context(s
, context
);
179 spin_lock_irqsave(&s
->lock
, flags
);
180 /* Rescan now that we hold the lock. */
181 sid
= sidtab_search_context(s
, context
);
184 /* No SID exists for the context. Allocate a new one. */
185 if (s
->next_sid
== UINT_MAX
|| s
->shutdown
) {
192 "SELinux: Context %s is not valid (left unmapped).\n",
194 ret
= sidtab_insert(s
, sid
, context
);
198 spin_unlock_irqrestore(&s
->lock
, flags
);
208 void sidtab_hash_eval(struct sidtab
*h
, char *tag
)
210 int i
, chain_len
, slots_used
, max_chain_len
;
211 struct sidtab_node
*cur
;
215 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
225 if (chain_len
> max_chain_len
)
226 max_chain_len
= chain_len
;
230 printk(KERN_DEBUG
"%s: %d entries and %d/%d buckets used, longest "
231 "chain length %d\n", tag
, h
->nel
, slots_used
, SIDTAB_SIZE
,
235 void sidtab_destroy(struct sidtab
*s
)
238 struct sidtab_node
*cur
, *temp
;
243 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
248 context_destroy(&temp
->context
);
259 void sidtab_set(struct sidtab
*dst
, struct sidtab
*src
)
263 spin_lock_irqsave(&src
->lock
, flags
);
264 dst
->htable
= src
->htable
;
266 dst
->next_sid
= src
->next_sid
;
268 spin_unlock_irqrestore(&src
->lock
, flags
);
271 void sidtab_shutdown(struct sidtab
*s
)
275 spin_lock_irqsave(&s
->lock
, flags
);
277 spin_unlock_irqrestore(&s
->lock
, flags
);