ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / security / selinux / ss / avtab.c
1 /*
2  * Implementation of the access vector table type.
3  *
4  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5  */
6
7 /* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
8  *
9  *      Added conditional policy language extensions
10  *
11  * Copyright (C) 2003 Tresys Technology, LLC
12  *      This program is free software; you can redistribute it and/or modify
13  *      it under the terms of the GNU General Public License as published by
14  *      the Free Software Foundation, version 2.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/vmalloc.h>
20 #include <linux/errno.h>
21
22 #include "avtab.h"
23 #include "policydb.h"
24
25 #define AVTAB_HASH(keyp) \
26 ((keyp->target_class + \
27  (keyp->target_type << 2) + \
28  (keyp->source_type << 9)) & \
29  AVTAB_HASH_MASK)
30
31 static struct avtab_node*
32 avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
33                   struct avtab_key *key, struct avtab_datum *datum)
34 {
35         struct avtab_node * newnode;
36         newnode = (struct avtab_node *) kmalloc(sizeof(struct avtab_node),GFP_KERNEL);
37         if (newnode == NULL)
38                 return NULL;
39         memset(newnode, 0, sizeof(struct avtab_node));
40         newnode->key = *key;
41         newnode->datum = *datum;
42         if (prev) {
43                 newnode->next = prev->next;
44                 prev->next = newnode;
45         } else {
46                 newnode->next = h->htable[hvalue];
47                 h->htable[hvalue] = newnode;
48         }
49
50         h->nel++;
51         return newnode;
52 }
53
54 int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
55 {
56         int hvalue;
57         struct avtab_node *prev, *cur, *newnode;
58
59         if (!h)
60                 return -EINVAL;
61
62         hvalue = AVTAB_HASH(key);
63         for (prev = NULL, cur = h->htable[hvalue];
64              cur;
65              prev = cur, cur = cur->next) {
66                 if (key->source_type == cur->key.source_type &&
67                     key->target_type == cur->key.target_type &&
68                     key->target_class == cur->key.target_class &&
69                     (datum->specified & cur->datum.specified))
70                         return -EEXIST;
71                 if (key->source_type < cur->key.source_type)
72                         break;
73                 if (key->source_type == cur->key.source_type &&
74                     key->target_type < cur->key.target_type)
75                         break;
76                 if (key->source_type == cur->key.source_type &&
77                     key->target_type == cur->key.target_type &&
78                     key->target_class < cur->key.target_class)
79                         break;
80         }
81
82         newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
83         if(!newnode)
84                 return -ENOMEM;
85
86         return 0;
87 }
88
89 /* Unlike avtab_insert(), this function allow multiple insertions of the same
90  * key/specified mask into the table, as needed by the conditional avtab.
91  * It also returns a pointer to the node inserted.
92  */
93 struct avtab_node *
94 avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum)
95 {
96         int hvalue;
97         struct avtab_node *prev, *cur, *newnode;
98
99         if (!h)
100                 return NULL;
101         hvalue = AVTAB_HASH(key);
102         for (prev = NULL, cur = h->htable[hvalue];
103              cur;
104              prev = cur, cur = cur->next) {
105                 if (key->source_type == cur->key.source_type &&
106                     key->target_type == cur->key.target_type &&
107                     key->target_class == cur->key.target_class &&
108                     (datum->specified & cur->datum.specified))
109                         break;
110                 if (key->source_type < cur->key.source_type)
111                         break;
112                 if (key->source_type == cur->key.source_type &&
113                     key->target_type < cur->key.target_type)
114                         break;
115                 if (key->source_type == cur->key.source_type &&
116                     key->target_type == cur->key.target_type &&
117                     key->target_class < cur->key.target_class)
118                         break;
119         }
120         newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
121
122         return newnode;
123 }
124
125 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
126 {
127         int hvalue;
128         struct avtab_node *cur;
129
130         if (!h)
131                 return NULL;
132
133         hvalue = AVTAB_HASH(key);
134         for (cur = h->htable[hvalue]; cur; cur = cur->next) {
135                 if (key->source_type == cur->key.source_type &&
136                     key->target_type == cur->key.target_type &&
137                     key->target_class == cur->key.target_class &&
138                     (specified & cur->datum.specified))
139                         return &cur->datum;
140
141                 if (key->source_type < cur->key.source_type)
142                         break;
143                 if (key->source_type == cur->key.source_type &&
144                     key->target_type < cur->key.target_type)
145                         break;
146                 if (key->source_type == cur->key.source_type &&
147                     key->target_type == cur->key.target_type &&
148                     key->target_class < cur->key.target_class)
149                         break;
150         }
151
152         return NULL;
153 }
154
155 /* This search function returns a node pointer, and can be used in
156  * conjunction with avtab_search_next_node()
157  */
158 struct avtab_node*
159 avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
160 {
161         int hvalue;
162         struct avtab_node *cur;
163
164         if (!h)
165                 return NULL;
166
167         hvalue = AVTAB_HASH(key);
168         for (cur = h->htable[hvalue]; cur; cur = cur->next) {
169                 if (key->source_type == cur->key.source_type &&
170                     key->target_type == cur->key.target_type &&
171                     key->target_class == cur->key.target_class &&
172                     (specified & cur->datum.specified))
173                         return cur;
174
175                 if (key->source_type < cur->key.source_type)
176                         break;
177                 if (key->source_type == cur->key.source_type &&
178                     key->target_type < cur->key.target_type)
179                         break;
180                 if (key->source_type == cur->key.source_type &&
181                     key->target_type == cur->key.target_type &&
182                     key->target_class < cur->key.target_class)
183                         break;
184         }
185         return NULL;
186 }
187
188 struct avtab_node*
189 avtab_search_node_next(struct avtab_node *node, int specified)
190 {
191         struct avtab_node *cur;
192
193         if (!node)
194                 return NULL;
195
196         for (cur = node->next; cur; cur = cur->next) {
197                 if (node->key.source_type == cur->key.source_type &&
198                     node->key.target_type == cur->key.target_type &&
199                     node->key.target_class == cur->key.target_class &&
200                     (specified & cur->datum.specified))
201                         return cur;
202
203                 if (node->key.source_type < cur->key.source_type)
204                         break;
205                 if (node->key.source_type == cur->key.source_type &&
206                     node->key.target_type < cur->key.target_type)
207                         break;
208                 if (node->key.source_type == cur->key.source_type &&
209                     node->key.target_type == cur->key.target_type &&
210                     node->key.target_class < cur->key.target_class)
211                         break;
212         }
213         return NULL;
214 }
215
216 void avtab_destroy(struct avtab *h)
217 {
218         int i;
219         struct avtab_node *cur, *temp;
220
221         if (!h || !h->htable)
222                 return;
223
224         for (i = 0; i < AVTAB_SIZE; i++) {
225                 cur = h->htable[i];
226                 while (cur != NULL) {
227                         temp = cur;
228                         cur = cur->next;
229                         kfree(temp);
230                 }
231                 h->htable[i] = NULL;
232         }
233         vfree(h->htable);
234         h->htable = NULL;
235 }
236
237
238 int avtab_map(struct avtab *h,
239               int (*apply) (struct avtab_key *k,
240                             struct avtab_datum *d,
241                             void *args),
242               void *args)
243 {
244         int i, ret;
245         struct avtab_node *cur;
246
247         if (!h)
248                 return 0;
249
250         for (i = 0; i < AVTAB_SIZE; i++) {
251                 cur = h->htable[i];
252                 while (cur != NULL) {
253                         ret = apply(&cur->key, &cur->datum, args);
254                         if (ret)
255                                 return ret;
256                         cur = cur->next;
257                 }
258         }
259         return 0;
260 }
261
262 int avtab_init(struct avtab *h)
263 {
264         int i;
265
266         h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
267         if (!h->htable)
268                 return -ENOMEM;
269         for (i = 0; i < AVTAB_SIZE; i++)
270                 h->htable[i] = NULL;
271         h->nel = 0;
272         return 0;
273 }
274
275 void avtab_hash_eval(struct avtab *h, char *tag)
276 {
277         int i, chain_len, slots_used, max_chain_len;
278         struct avtab_node *cur;
279
280         slots_used = 0;
281         max_chain_len = 0;
282         for (i = 0; i < AVTAB_SIZE; i++) {
283                 cur = h->htable[i];
284                 if (cur) {
285                         slots_used++;
286                         chain_len = 0;
287                         while (cur) {
288                                 chain_len++;
289                                 cur = cur->next;
290                         }
291
292                         if (chain_len > max_chain_len)
293                                 max_chain_len = chain_len;
294                 }
295         }
296
297         printk(KERN_INFO "%s:  %d entries and %d/%d buckets used, longest "
298                "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
299                max_chain_len);
300 }
301
302 int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
303 {
304         __u32 *buf;
305         __u32 items, items2;
306
307         memset(avkey, 0, sizeof(struct avtab_key));
308         memset(avdatum, 0, sizeof(struct avtab_datum));
309
310         buf = next_entry(fp, sizeof(__u32));
311         if (!buf) {
312                 printk(KERN_ERR "security: avtab: truncated entry\n");
313                 goto bad;
314         }
315         items2 = le32_to_cpu(buf[0]);
316         buf = next_entry(fp, sizeof(__u32)*items2);
317         if (!buf) {
318                 printk(KERN_ERR "security: avtab: truncated entry\n");
319                 goto bad;
320         }
321         items = 0;
322         avkey->source_type = le32_to_cpu(buf[items++]);
323         avkey->target_type = le32_to_cpu(buf[items++]);
324         avkey->target_class = le32_to_cpu(buf[items++]);
325         avdatum->specified = le32_to_cpu(buf[items++]);
326         if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
327                 printk(KERN_ERR "security: avtab: null entry\n");
328                 goto bad;
329         }
330         if ((avdatum->specified & AVTAB_AV) &&
331             (avdatum->specified & AVTAB_TYPE)) {
332                 printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
333                 goto bad;
334         }
335         if (avdatum->specified & AVTAB_AV) {
336                 if (avdatum->specified & AVTAB_ALLOWED)
337                         avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
338                 if (avdatum->specified & AVTAB_AUDITDENY)
339                         avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
340                 if (avdatum->specified & AVTAB_AUDITALLOW)
341                         avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
342         } else {
343                 if (avdatum->specified & AVTAB_TRANSITION)
344                         avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
345                 if (avdatum->specified & AVTAB_CHANGE)
346                         avtab_change(avdatum) = le32_to_cpu(buf[items++]);
347                 if (avdatum->specified & AVTAB_MEMBER)
348                         avtab_member(avdatum) = le32_to_cpu(buf[items++]);
349         }
350         if (items != items2) {
351                 printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
352                        items2, items);
353                 goto bad;
354         }
355
356         return 0;
357 bad:
358         return -1;
359 }
360
361 int avtab_read(struct avtab *a, void *fp, u32 config)
362 {
363         int i, rc = -EINVAL;
364         struct avtab_key avkey;
365         struct avtab_datum avdatum;
366         u32 *buf;
367         u32 nel;
368
369
370         buf = next_entry(fp, sizeof(u32));
371         if (!buf) {
372                 printk(KERN_ERR "security: avtab: truncated table\n");
373                 goto bad;
374         }
375         nel = le32_to_cpu(buf[0]);
376         if (!nel) {
377                 printk(KERN_ERR "security: avtab: table is empty\n");
378                 goto bad;
379         }
380         for (i = 0; i < nel; i++) {
381                 if (avtab_read_item(fp, &avdatum, &avkey))
382                         goto bad;
383                 rc = avtab_insert(a, &avkey, &avdatum);
384                 if (rc) {
385                         if (rc == -ENOMEM)
386                                 printk(KERN_ERR "security: avtab: out of memory\n");
387                         if (rc == -EEXIST)
388                                 printk(KERN_ERR "security: avtab: duplicate entry\n");
389                         goto bad;
390                 }
391         }
392
393         rc = 0;
394 out:
395         return rc;
396
397 bad:
398         avtab_destroy(a);
399         goto out;
400 }
401