1*2d543d20SAndroid Build Coastguard Worker
2*2d543d20SAndroid Build Coastguard Worker /* Author : Stephen Smalley, <[email protected]> */
3*2d543d20SAndroid Build Coastguard Worker
4*2d543d20SAndroid Build Coastguard Worker /* FLASK */
5*2d543d20SAndroid Build Coastguard Worker
6*2d543d20SAndroid Build Coastguard Worker /*
7*2d543d20SAndroid Build Coastguard Worker * Implementation of the SID table type.
8*2d543d20SAndroid Build Coastguard Worker */
9*2d543d20SAndroid Build Coastguard Worker
10*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
11*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
12*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
13*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
14*2d543d20SAndroid Build Coastguard Worker
15*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/sidtab.h>
16*2d543d20SAndroid Build Coastguard Worker
17*2d543d20SAndroid Build Coastguard Worker #include "flask.h"
18*2d543d20SAndroid Build Coastguard Worker #include "private.h"
19*2d543d20SAndroid Build Coastguard Worker
20*2d543d20SAndroid Build Coastguard Worker #define SIDTAB_HASH(sid) \
21*2d543d20SAndroid Build Coastguard Worker (sid & SIDTAB_HASH_MASK)
22*2d543d20SAndroid Build Coastguard Worker
23*2d543d20SAndroid Build Coastguard Worker #define INIT_SIDTAB_LOCK(s)
24*2d543d20SAndroid Build Coastguard Worker #define SIDTAB_LOCK(s)
25*2d543d20SAndroid Build Coastguard Worker #define SIDTAB_UNLOCK(s)
26*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_init(sidtab_t * s)27*2d543d20SAndroid Build Coastguard Worker int sepol_sidtab_init(sidtab_t * s)
28*2d543d20SAndroid Build Coastguard Worker {
29*2d543d20SAndroid Build Coastguard Worker s->htable = calloc(SIDTAB_SIZE, sizeof(sidtab_ptr_t));
30*2d543d20SAndroid Build Coastguard Worker if (!s->htable)
31*2d543d20SAndroid Build Coastguard Worker return -ENOMEM;
32*2d543d20SAndroid Build Coastguard Worker s->nel = 0;
33*2d543d20SAndroid Build Coastguard Worker s->next_sid = 1;
34*2d543d20SAndroid Build Coastguard Worker s->shutdown = 0;
35*2d543d20SAndroid Build Coastguard Worker INIT_SIDTAB_LOCK(s);
36*2d543d20SAndroid Build Coastguard Worker return 0;
37*2d543d20SAndroid Build Coastguard Worker }
38*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_insert(sidtab_t * s,sepol_security_id_t sid,context_struct_t * context)39*2d543d20SAndroid Build Coastguard Worker int sepol_sidtab_insert(sidtab_t * s, sepol_security_id_t sid,
40*2d543d20SAndroid Build Coastguard Worker context_struct_t * context)
41*2d543d20SAndroid Build Coastguard Worker {
42*2d543d20SAndroid Build Coastguard Worker int hvalue;
43*2d543d20SAndroid Build Coastguard Worker sidtab_node_t *prev, *cur, *newnode;
44*2d543d20SAndroid Build Coastguard Worker
45*2d543d20SAndroid Build Coastguard Worker if (!s || !s->htable)
46*2d543d20SAndroid Build Coastguard Worker return -ENOMEM;
47*2d543d20SAndroid Build Coastguard Worker
48*2d543d20SAndroid Build Coastguard Worker hvalue = SIDTAB_HASH(sid);
49*2d543d20SAndroid Build Coastguard Worker prev = NULL;
50*2d543d20SAndroid Build Coastguard Worker cur = s->htable[hvalue];
51*2d543d20SAndroid Build Coastguard Worker while (cur != NULL && sid > cur->sid) {
52*2d543d20SAndroid Build Coastguard Worker prev = cur;
53*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
54*2d543d20SAndroid Build Coastguard Worker }
55*2d543d20SAndroid Build Coastguard Worker
56*2d543d20SAndroid Build Coastguard Worker if (cur && sid == cur->sid) {
57*2d543d20SAndroid Build Coastguard Worker errno = EEXIST;
58*2d543d20SAndroid Build Coastguard Worker return -EEXIST;
59*2d543d20SAndroid Build Coastguard Worker }
60*2d543d20SAndroid Build Coastguard Worker
61*2d543d20SAndroid Build Coastguard Worker newnode = (sidtab_node_t *) malloc(sizeof(sidtab_node_t));
62*2d543d20SAndroid Build Coastguard Worker if (newnode == NULL)
63*2d543d20SAndroid Build Coastguard Worker return -ENOMEM;
64*2d543d20SAndroid Build Coastguard Worker newnode->sid = sid;
65*2d543d20SAndroid Build Coastguard Worker if (context_cpy(&newnode->context, context)) {
66*2d543d20SAndroid Build Coastguard Worker free(newnode);
67*2d543d20SAndroid Build Coastguard Worker return -ENOMEM;
68*2d543d20SAndroid Build Coastguard Worker }
69*2d543d20SAndroid Build Coastguard Worker
70*2d543d20SAndroid Build Coastguard Worker if (prev) {
71*2d543d20SAndroid Build Coastguard Worker newnode->next = prev->next;
72*2d543d20SAndroid Build Coastguard Worker prev->next = newnode;
73*2d543d20SAndroid Build Coastguard Worker } else {
74*2d543d20SAndroid Build Coastguard Worker newnode->next = s->htable[hvalue];
75*2d543d20SAndroid Build Coastguard Worker s->htable[hvalue] = newnode;
76*2d543d20SAndroid Build Coastguard Worker }
77*2d543d20SAndroid Build Coastguard Worker
78*2d543d20SAndroid Build Coastguard Worker s->nel++;
79*2d543d20SAndroid Build Coastguard Worker if (sid >= s->next_sid)
80*2d543d20SAndroid Build Coastguard Worker s->next_sid = sid + 1;
81*2d543d20SAndroid Build Coastguard Worker return 0;
82*2d543d20SAndroid Build Coastguard Worker }
83*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_search(sidtab_t * s,sepol_security_id_t sid)84*2d543d20SAndroid Build Coastguard Worker context_struct_t *sepol_sidtab_search(sidtab_t * s, sepol_security_id_t sid)
85*2d543d20SAndroid Build Coastguard Worker {
86*2d543d20SAndroid Build Coastguard Worker int hvalue;
87*2d543d20SAndroid Build Coastguard Worker sidtab_node_t *cur;
88*2d543d20SAndroid Build Coastguard Worker
89*2d543d20SAndroid Build Coastguard Worker if (!s || !s->htable)
90*2d543d20SAndroid Build Coastguard Worker return NULL;
91*2d543d20SAndroid Build Coastguard Worker
92*2d543d20SAndroid Build Coastguard Worker hvalue = SIDTAB_HASH(sid);
93*2d543d20SAndroid Build Coastguard Worker cur = s->htable[hvalue];
94*2d543d20SAndroid Build Coastguard Worker while (cur != NULL && sid > cur->sid)
95*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
96*2d543d20SAndroid Build Coastguard Worker
97*2d543d20SAndroid Build Coastguard Worker if (cur == NULL || sid != cur->sid) {
98*2d543d20SAndroid Build Coastguard Worker /* Remap invalid SIDs to the unlabeled SID. */
99*2d543d20SAndroid Build Coastguard Worker sid = SECINITSID_UNLABELED;
100*2d543d20SAndroid Build Coastguard Worker hvalue = SIDTAB_HASH(sid);
101*2d543d20SAndroid Build Coastguard Worker cur = s->htable[hvalue];
102*2d543d20SAndroid Build Coastguard Worker while (cur != NULL && sid > cur->sid)
103*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
104*2d543d20SAndroid Build Coastguard Worker if (!cur || sid != cur->sid)
105*2d543d20SAndroid Build Coastguard Worker return NULL;
106*2d543d20SAndroid Build Coastguard Worker }
107*2d543d20SAndroid Build Coastguard Worker
108*2d543d20SAndroid Build Coastguard Worker return &cur->context;
109*2d543d20SAndroid Build Coastguard Worker }
110*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_map(sidtab_t * s,int (* apply)(sepol_security_id_t sid,context_struct_t * context,void * args),void * args)111*2d543d20SAndroid Build Coastguard Worker int sepol_sidtab_map(sidtab_t * s,
112*2d543d20SAndroid Build Coastguard Worker int (*apply) (sepol_security_id_t sid,
113*2d543d20SAndroid Build Coastguard Worker context_struct_t * context,
114*2d543d20SAndroid Build Coastguard Worker void *args), void *args)
115*2d543d20SAndroid Build Coastguard Worker {
116*2d543d20SAndroid Build Coastguard Worker int i, ret;
117*2d543d20SAndroid Build Coastguard Worker sidtab_node_t *cur;
118*2d543d20SAndroid Build Coastguard Worker
119*2d543d20SAndroid Build Coastguard Worker if (!s || !s->htable)
120*2d543d20SAndroid Build Coastguard Worker return 0;
121*2d543d20SAndroid Build Coastguard Worker
122*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < SIDTAB_SIZE; i++) {
123*2d543d20SAndroid Build Coastguard Worker cur = s->htable[i];
124*2d543d20SAndroid Build Coastguard Worker while (cur != NULL) {
125*2d543d20SAndroid Build Coastguard Worker ret = apply(cur->sid, &cur->context, args);
126*2d543d20SAndroid Build Coastguard Worker if (ret)
127*2d543d20SAndroid Build Coastguard Worker return ret;
128*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
129*2d543d20SAndroid Build Coastguard Worker }
130*2d543d20SAndroid Build Coastguard Worker }
131*2d543d20SAndroid Build Coastguard Worker return 0;
132*2d543d20SAndroid Build Coastguard Worker }
133*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_map_remove_on_error(sidtab_t * s,int (* apply)(sepol_security_id_t sid,context_struct_t * context,void * args),void * args)134*2d543d20SAndroid Build Coastguard Worker void sepol_sidtab_map_remove_on_error(sidtab_t * s,
135*2d543d20SAndroid Build Coastguard Worker int (*apply) (sepol_security_id_t sid,
136*2d543d20SAndroid Build Coastguard Worker context_struct_t * context,
137*2d543d20SAndroid Build Coastguard Worker void *args), void *args)
138*2d543d20SAndroid Build Coastguard Worker {
139*2d543d20SAndroid Build Coastguard Worker int i, ret;
140*2d543d20SAndroid Build Coastguard Worker sidtab_node_t *last, *cur, *temp;
141*2d543d20SAndroid Build Coastguard Worker
142*2d543d20SAndroid Build Coastguard Worker if (!s || !s->htable)
143*2d543d20SAndroid Build Coastguard Worker return;
144*2d543d20SAndroid Build Coastguard Worker
145*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < SIDTAB_SIZE; i++) {
146*2d543d20SAndroid Build Coastguard Worker last = NULL;
147*2d543d20SAndroid Build Coastguard Worker cur = s->htable[i];
148*2d543d20SAndroid Build Coastguard Worker while (cur != NULL) {
149*2d543d20SAndroid Build Coastguard Worker ret = apply(cur->sid, &cur->context, args);
150*2d543d20SAndroid Build Coastguard Worker if (ret) {
151*2d543d20SAndroid Build Coastguard Worker if (last) {
152*2d543d20SAndroid Build Coastguard Worker last->next = cur->next;
153*2d543d20SAndroid Build Coastguard Worker } else {
154*2d543d20SAndroid Build Coastguard Worker s->htable[i] = cur->next;
155*2d543d20SAndroid Build Coastguard Worker }
156*2d543d20SAndroid Build Coastguard Worker
157*2d543d20SAndroid Build Coastguard Worker temp = cur;
158*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
159*2d543d20SAndroid Build Coastguard Worker context_destroy(&temp->context);
160*2d543d20SAndroid Build Coastguard Worker free(temp);
161*2d543d20SAndroid Build Coastguard Worker s->nel--;
162*2d543d20SAndroid Build Coastguard Worker } else {
163*2d543d20SAndroid Build Coastguard Worker last = cur;
164*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
165*2d543d20SAndroid Build Coastguard Worker }
166*2d543d20SAndroid Build Coastguard Worker }
167*2d543d20SAndroid Build Coastguard Worker }
168*2d543d20SAndroid Build Coastguard Worker
169*2d543d20SAndroid Build Coastguard Worker return;
170*2d543d20SAndroid Build Coastguard Worker }
171*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_search_context(sidtab_t * s,context_struct_t * context)172*2d543d20SAndroid Build Coastguard Worker static inline sepol_security_id_t sepol_sidtab_search_context(sidtab_t * s,
173*2d543d20SAndroid Build Coastguard Worker context_struct_t *
174*2d543d20SAndroid Build Coastguard Worker context)
175*2d543d20SAndroid Build Coastguard Worker {
176*2d543d20SAndroid Build Coastguard Worker int i;
177*2d543d20SAndroid Build Coastguard Worker sidtab_node_t *cur;
178*2d543d20SAndroid Build Coastguard Worker
179*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < SIDTAB_SIZE; i++) {
180*2d543d20SAndroid Build Coastguard Worker cur = s->htable[i];
181*2d543d20SAndroid Build Coastguard Worker while (cur != NULL) {
182*2d543d20SAndroid Build Coastguard Worker if (context_cmp(&cur->context, context))
183*2d543d20SAndroid Build Coastguard Worker return cur->sid;
184*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
185*2d543d20SAndroid Build Coastguard Worker }
186*2d543d20SAndroid Build Coastguard Worker }
187*2d543d20SAndroid Build Coastguard Worker return 0;
188*2d543d20SAndroid Build Coastguard Worker }
189*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_context_to_sid(sidtab_t * s,context_struct_t * context,sepol_security_id_t * out_sid)190*2d543d20SAndroid Build Coastguard Worker int sepol_sidtab_context_to_sid(sidtab_t * s,
191*2d543d20SAndroid Build Coastguard Worker context_struct_t * context,
192*2d543d20SAndroid Build Coastguard Worker sepol_security_id_t * out_sid)
193*2d543d20SAndroid Build Coastguard Worker {
194*2d543d20SAndroid Build Coastguard Worker sepol_security_id_t sid;
195*2d543d20SAndroid Build Coastguard Worker int ret = 0;
196*2d543d20SAndroid Build Coastguard Worker
197*2d543d20SAndroid Build Coastguard Worker *out_sid = SEPOL_SECSID_NULL;
198*2d543d20SAndroid Build Coastguard Worker
199*2d543d20SAndroid Build Coastguard Worker sid = sepol_sidtab_search_context(s, context);
200*2d543d20SAndroid Build Coastguard Worker if (!sid) {
201*2d543d20SAndroid Build Coastguard Worker SIDTAB_LOCK(s);
202*2d543d20SAndroid Build Coastguard Worker /* Rescan now that we hold the lock. */
203*2d543d20SAndroid Build Coastguard Worker sid = sepol_sidtab_search_context(s, context);
204*2d543d20SAndroid Build Coastguard Worker if (sid)
205*2d543d20SAndroid Build Coastguard Worker goto unlock_out;
206*2d543d20SAndroid Build Coastguard Worker /* No SID exists for the context. Allocate a new one. */
207*2d543d20SAndroid Build Coastguard Worker if (s->next_sid == UINT_MAX || s->shutdown) {
208*2d543d20SAndroid Build Coastguard Worker ret = -ENOMEM;
209*2d543d20SAndroid Build Coastguard Worker goto unlock_out;
210*2d543d20SAndroid Build Coastguard Worker }
211*2d543d20SAndroid Build Coastguard Worker sid = s->next_sid++;
212*2d543d20SAndroid Build Coastguard Worker ret = sepol_sidtab_insert(s, sid, context);
213*2d543d20SAndroid Build Coastguard Worker if (ret)
214*2d543d20SAndroid Build Coastguard Worker s->next_sid--;
215*2d543d20SAndroid Build Coastguard Worker unlock_out:
216*2d543d20SAndroid Build Coastguard Worker SIDTAB_UNLOCK(s);
217*2d543d20SAndroid Build Coastguard Worker }
218*2d543d20SAndroid Build Coastguard Worker
219*2d543d20SAndroid Build Coastguard Worker if (ret)
220*2d543d20SAndroid Build Coastguard Worker return ret;
221*2d543d20SAndroid Build Coastguard Worker
222*2d543d20SAndroid Build Coastguard Worker *out_sid = sid;
223*2d543d20SAndroid Build Coastguard Worker return 0;
224*2d543d20SAndroid Build Coastguard Worker }
225*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_hash_eval(sidtab_t * h,char * tag)226*2d543d20SAndroid Build Coastguard Worker void sepol_sidtab_hash_eval(sidtab_t * h, char *tag)
227*2d543d20SAndroid Build Coastguard Worker {
228*2d543d20SAndroid Build Coastguard Worker int i, chain_len, slots_used, max_chain_len;
229*2d543d20SAndroid Build Coastguard Worker sidtab_node_t *cur;
230*2d543d20SAndroid Build Coastguard Worker
231*2d543d20SAndroid Build Coastguard Worker slots_used = 0;
232*2d543d20SAndroid Build Coastguard Worker max_chain_len = 0;
233*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < SIDTAB_SIZE; i++) {
234*2d543d20SAndroid Build Coastguard Worker cur = h->htable[i];
235*2d543d20SAndroid Build Coastguard Worker if (cur) {
236*2d543d20SAndroid Build Coastguard Worker slots_used++;
237*2d543d20SAndroid Build Coastguard Worker chain_len = 0;
238*2d543d20SAndroid Build Coastguard Worker while (cur) {
239*2d543d20SAndroid Build Coastguard Worker chain_len++;
240*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
241*2d543d20SAndroid Build Coastguard Worker }
242*2d543d20SAndroid Build Coastguard Worker
243*2d543d20SAndroid Build Coastguard Worker if (chain_len > max_chain_len)
244*2d543d20SAndroid Build Coastguard Worker max_chain_len = chain_len;
245*2d543d20SAndroid Build Coastguard Worker }
246*2d543d20SAndroid Build Coastguard Worker }
247*2d543d20SAndroid Build Coastguard Worker
248*2d543d20SAndroid Build Coastguard Worker printf
249*2d543d20SAndroid Build Coastguard Worker ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
250*2d543d20SAndroid Build Coastguard Worker tag, h->nel, slots_used, SIDTAB_SIZE, max_chain_len);
251*2d543d20SAndroid Build Coastguard Worker }
252*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_destroy(sidtab_t * s)253*2d543d20SAndroid Build Coastguard Worker void sepol_sidtab_destroy(sidtab_t * s)
254*2d543d20SAndroid Build Coastguard Worker {
255*2d543d20SAndroid Build Coastguard Worker int i;
256*2d543d20SAndroid Build Coastguard Worker sidtab_ptr_t cur, temp;
257*2d543d20SAndroid Build Coastguard Worker
258*2d543d20SAndroid Build Coastguard Worker if (!s || !s->htable)
259*2d543d20SAndroid Build Coastguard Worker return;
260*2d543d20SAndroid Build Coastguard Worker
261*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < SIDTAB_SIZE; i++) {
262*2d543d20SAndroid Build Coastguard Worker cur = s->htable[i];
263*2d543d20SAndroid Build Coastguard Worker while (cur != NULL) {
264*2d543d20SAndroid Build Coastguard Worker temp = cur;
265*2d543d20SAndroid Build Coastguard Worker cur = cur->next;
266*2d543d20SAndroid Build Coastguard Worker context_destroy(&temp->context);
267*2d543d20SAndroid Build Coastguard Worker free(temp);
268*2d543d20SAndroid Build Coastguard Worker }
269*2d543d20SAndroid Build Coastguard Worker s->htable[i] = NULL;
270*2d543d20SAndroid Build Coastguard Worker }
271*2d543d20SAndroid Build Coastguard Worker free(s->htable);
272*2d543d20SAndroid Build Coastguard Worker s->htable = NULL;
273*2d543d20SAndroid Build Coastguard Worker s->nel = 0;
274*2d543d20SAndroid Build Coastguard Worker s->next_sid = 1;
275*2d543d20SAndroid Build Coastguard Worker }
276*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_set(sidtab_t * dst,sidtab_t * src)277*2d543d20SAndroid Build Coastguard Worker void sepol_sidtab_set(sidtab_t * dst, sidtab_t * src)
278*2d543d20SAndroid Build Coastguard Worker {
279*2d543d20SAndroid Build Coastguard Worker SIDTAB_LOCK(src);
280*2d543d20SAndroid Build Coastguard Worker dst->htable = src->htable;
281*2d543d20SAndroid Build Coastguard Worker dst->nel = src->nel;
282*2d543d20SAndroid Build Coastguard Worker dst->next_sid = src->next_sid;
283*2d543d20SAndroid Build Coastguard Worker dst->shutdown = 0;
284*2d543d20SAndroid Build Coastguard Worker SIDTAB_UNLOCK(src);
285*2d543d20SAndroid Build Coastguard Worker }
286*2d543d20SAndroid Build Coastguard Worker
sepol_sidtab_shutdown(sidtab_t * s)287*2d543d20SAndroid Build Coastguard Worker void sepol_sidtab_shutdown(sidtab_t * s)
288*2d543d20SAndroid Build Coastguard Worker {
289*2d543d20SAndroid Build Coastguard Worker SIDTAB_LOCK(s);
290*2d543d20SAndroid Build Coastguard Worker s->shutdown = 1;
291*2d543d20SAndroid Build Coastguard Worker SIDTAB_UNLOCK(s);
292*2d543d20SAndroid Build Coastguard Worker }
293*2d543d20SAndroid Build Coastguard Worker
294*2d543d20SAndroid Build Coastguard Worker /* FLASK */
295