]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - security/selinux/ss/sidtab.c
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_array(SIDTAB_SIZE
, sizeof(*s
->htable
), 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
;
41 hvalue
= SIDTAB_HASH(sid
);
43 cur
= s
->htable
[hvalue
];
44 while (cur
&& sid
> cur
->sid
) {
49 if (cur
&& sid
== cur
->sid
)
52 newnode
= kmalloc(sizeof(*newnode
), GFP_ATOMIC
);
57 if (context_cpy(&newnode
->context
, context
)) {
63 newnode
->next
= prev
->next
;
67 newnode
->next
= s
->htable
[hvalue
];
69 s
->htable
[hvalue
] = newnode
;
73 if (sid
>= s
->next_sid
)
74 s
->next_sid
= sid
+ 1;
78 static struct context
*sidtab_search_core(struct sidtab
*s
, u32 sid
, int force
)
81 struct sidtab_node
*cur
;
86 hvalue
= SIDTAB_HASH(sid
);
87 cur
= s
->htable
[hvalue
];
88 while (cur
&& sid
> cur
->sid
)
91 if (force
&& cur
&& sid
== cur
->sid
&& cur
->context
.len
)
94 if (!cur
|| sid
!= cur
->sid
|| cur
->context
.len
) {
95 /* Remap invalid SIDs to the unlabeled SID. */
96 sid
= SECINITSID_UNLABELED
;
97 hvalue
= SIDTAB_HASH(sid
);
98 cur
= s
->htable
[hvalue
];
99 while (cur
&& sid
> cur
->sid
)
101 if (!cur
|| sid
!= cur
->sid
)
105 return &cur
->context
;
108 struct context
*sidtab_search(struct sidtab
*s
, u32 sid
)
110 return sidtab_search_core(s
, sid
, 0);
113 struct context
*sidtab_search_force(struct sidtab
*s
, u32 sid
)
115 return sidtab_search_core(s
, sid
, 1);
118 int sidtab_map(struct sidtab
*s
,
119 int (*apply
) (u32 sid
,
120 struct context
*context
,
125 struct sidtab_node
*cur
;
130 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
133 rc
= apply(cur
->sid
, &cur
->context
, args
);
143 static void sidtab_update_cache(struct sidtab
*s
, struct sidtab_node
*n
, int loc
)
145 BUG_ON(loc
>= SIDTAB_CACHE_LEN
);
148 s
->cache
[loc
] = s
->cache
[loc
- 1];
154 static inline u32
sidtab_search_context(struct sidtab
*s
,
155 struct context
*context
)
158 struct sidtab_node
*cur
;
160 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
163 if (context_cmp(&cur
->context
, context
)) {
164 sidtab_update_cache(s
, cur
, SIDTAB_CACHE_LEN
- 1);
173 static inline u32
sidtab_search_cache(struct sidtab
*s
, struct context
*context
)
176 struct sidtab_node
*node
;
178 for (i
= 0; i
< SIDTAB_CACHE_LEN
; i
++) {
182 if (context_cmp(&node
->context
, context
)) {
183 sidtab_update_cache(s
, node
, i
);
190 int sidtab_context_to_sid(struct sidtab
*s
,
191 struct context
*context
,
198 *out_sid
= SECSID_NULL
;
200 sid
= sidtab_search_cache(s
, context
);
202 sid
= sidtab_search_context(s
, context
);
204 spin_lock_irqsave(&s
->lock
, flags
);
205 /* Rescan now that we hold the lock. */
206 sid
= sidtab_search_context(s
, context
);
209 /* No SID exists for the context. Allocate a new one. */
210 if (s
->next_sid
== UINT_MAX
|| s
->shutdown
) {
217 "SELinux: Context %s is not valid (left unmapped).\n",
219 ret
= sidtab_insert(s
, sid
, context
);
223 spin_unlock_irqrestore(&s
->lock
, flags
);
233 void sidtab_hash_eval(struct sidtab
*h
, char *tag
)
235 int i
, chain_len
, slots_used
, max_chain_len
;
236 struct sidtab_node
*cur
;
240 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
250 if (chain_len
> max_chain_len
)
251 max_chain_len
= chain_len
;
255 printk(KERN_DEBUG
"%s: %d entries and %d/%d buckets used, longest "
256 "chain length %d\n", tag
, h
->nel
, slots_used
, SIDTAB_SIZE
,
260 void sidtab_destroy(struct sidtab
*s
)
263 struct sidtab_node
*cur
, *temp
;
268 for (i
= 0; i
< SIDTAB_SIZE
; i
++) {
273 context_destroy(&temp
->context
);
284 void sidtab_set(struct sidtab
*dst
, struct sidtab
*src
)
289 spin_lock_irqsave(&src
->lock
, flags
);
290 dst
->htable
= src
->htable
;
292 dst
->next_sid
= src
->next_sid
;
294 for (i
= 0; i
< SIDTAB_CACHE_LEN
; i
++)
295 dst
->cache
[i
] = NULL
;
296 spin_unlock_irqrestore(&src
->lock
, flags
);
299 void sidtab_shutdown(struct sidtab
*s
)
303 spin_lock_irqsave(&s
->lock
, flags
);
305 spin_unlock_irqrestore(&s
->lock
, flags
);