aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/ss')
-rw-r--r--security/selinux/ss/Makefile9
-rw-r--r--security/selinux/ss/avtab.c399
-rw-r--r--security/selinux/ss/avtab.h85
-rw-r--r--security/selinux/ss/conditional.c489
-rw-r--r--security/selinux/ss/conditional.h77
-rw-r--r--security/selinux/ss/constraint.h61
-rw-r--r--security/selinux/ss/context.h107
-rw-r--r--security/selinux/ss/ebitmap.c293
-rw-r--r--security/selinux/ss/ebitmap.h48
-rw-r--r--security/selinux/ss/hashtab.c167
-rw-r--r--security/selinux/ss/hashtab.h87
-rw-r--r--security/selinux/ss/mls.c527
-rw-r--r--security/selinux/ss/mls.h42
-rw-r--r--security/selinux/ss/mls_types.h56
-rw-r--r--security/selinux/ss/policydb.c1843
-rw-r--r--security/selinux/ss/policydb.h275
-rw-r--r--security/selinux/ss/services.c1777
-rw-r--r--security/selinux/ss/services.h15
-rw-r--r--security/selinux/ss/sidtab.c305
-rw-r--r--security/selinux/ss/sidtab.h59
-rw-r--r--security/selinux/ss/symtab.c44
-rw-r--r--security/selinux/ss/symtab.h23
22 files changed, 6788 insertions, 0 deletions
diff --git a/security/selinux/ss/Makefile b/security/selinux/ss/Makefile
new file mode 100644
index 000000000000..bad78779b9b0
--- /dev/null
+++ b/security/selinux/ss/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for building the SELinux security server as part of the kernel tree.
3#
4
5EXTRA_CFLAGS += -Isecurity/selinux/include
6obj-y := ss.o
7
8ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o
9
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
new file mode 100644
index 000000000000..f238c034c44e
--- /dev/null
+++ b/security/selinux/ss/avtab.c
@@ -0,0 +1,399 @@
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
31static kmem_cache_t *avtab_node_cachep;
32
33static struct avtab_node*
34avtab_insert_node(struct avtab *h, int hvalue,
35 struct avtab_node * prev, struct avtab_node * cur,
36 struct avtab_key *key, struct avtab_datum *datum)
37{
38 struct avtab_node * newnode;
39 newnode = kmem_cache_alloc(avtab_node_cachep, SLAB_KERNEL);
40 if (newnode == NULL)
41 return NULL;
42 memset(newnode, 0, sizeof(struct avtab_node));
43 newnode->key = *key;
44 newnode->datum = *datum;
45 if (prev) {
46 newnode->next = prev->next;
47 prev->next = newnode;
48 } else {
49 newnode->next = h->htable[hvalue];
50 h->htable[hvalue] = newnode;
51 }
52
53 h->nel++;
54 return newnode;
55}
56
57static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
58{
59 int hvalue;
60 struct avtab_node *prev, *cur, *newnode;
61
62 if (!h)
63 return -EINVAL;
64
65 hvalue = AVTAB_HASH(key);
66 for (prev = NULL, cur = h->htable[hvalue];
67 cur;
68 prev = cur, cur = cur->next) {
69 if (key->source_type == cur->key.source_type &&
70 key->target_type == cur->key.target_type &&
71 key->target_class == cur->key.target_class &&
72 (datum->specified & cur->datum.specified))
73 return -EEXIST;
74 if (key->source_type < cur->key.source_type)
75 break;
76 if (key->source_type == cur->key.source_type &&
77 key->target_type < cur->key.target_type)
78 break;
79 if (key->source_type == cur->key.source_type &&
80 key->target_type == cur->key.target_type &&
81 key->target_class < cur->key.target_class)
82 break;
83 }
84
85 newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
86 if(!newnode)
87 return -ENOMEM;
88
89 return 0;
90}
91
92/* Unlike avtab_insert(), this function allow multiple insertions of the same
93 * key/specified mask into the table, as needed by the conditional avtab.
94 * It also returns a pointer to the node inserted.
95 */
96struct avtab_node *
97avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum)
98{
99 int hvalue;
100 struct avtab_node *prev, *cur, *newnode;
101
102 if (!h)
103 return NULL;
104 hvalue = AVTAB_HASH(key);
105 for (prev = NULL, cur = h->htable[hvalue];
106 cur;
107 prev = cur, cur = cur->next) {
108 if (key->source_type == cur->key.source_type &&
109 key->target_type == cur->key.target_type &&
110 key->target_class == cur->key.target_class &&
111 (datum->specified & cur->datum.specified))
112 break;
113 if (key->source_type < cur->key.source_type)
114 break;
115 if (key->source_type == cur->key.source_type &&
116 key->target_type < cur->key.target_type)
117 break;
118 if (key->source_type == cur->key.source_type &&
119 key->target_type == cur->key.target_type &&
120 key->target_class < cur->key.target_class)
121 break;
122 }
123 newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
124
125 return newnode;
126}
127
128struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
129{
130 int hvalue;
131 struct avtab_node *cur;
132
133 if (!h)
134 return NULL;
135
136 hvalue = AVTAB_HASH(key);
137 for (cur = h->htable[hvalue]; cur; cur = cur->next) {
138 if (key->source_type == cur->key.source_type &&
139 key->target_type == cur->key.target_type &&
140 key->target_class == cur->key.target_class &&
141 (specified & cur->datum.specified))
142 return &cur->datum;
143
144 if (key->source_type < cur->key.source_type)
145 break;
146 if (key->source_type == cur->key.source_type &&
147 key->target_type < cur->key.target_type)
148 break;
149 if (key->source_type == cur->key.source_type &&
150 key->target_type == cur->key.target_type &&
151 key->target_class < cur->key.target_class)
152 break;
153 }
154
155 return NULL;
156}
157
158/* This search function returns a node pointer, and can be used in
159 * conjunction with avtab_search_next_node()
160 */
161struct avtab_node*
162avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
163{
164 int hvalue;
165 struct avtab_node *cur;
166
167 if (!h)
168 return NULL;
169
170 hvalue = AVTAB_HASH(key);
171 for (cur = h->htable[hvalue]; cur; cur = cur->next) {
172 if (key->source_type == cur->key.source_type &&
173 key->target_type == cur->key.target_type &&
174 key->target_class == cur->key.target_class &&
175 (specified & cur->datum.specified))
176 return cur;
177
178 if (key->source_type < cur->key.source_type)
179 break;
180 if (key->source_type == cur->key.source_type &&
181 key->target_type < cur->key.target_type)
182 break;
183 if (key->source_type == cur->key.source_type &&
184 key->target_type == cur->key.target_type &&
185 key->target_class < cur->key.target_class)
186 break;
187 }
188 return NULL;
189}
190
191struct avtab_node*
192avtab_search_node_next(struct avtab_node *node, int specified)
193{
194 struct avtab_node *cur;
195
196 if (!node)
197 return NULL;
198
199 for (cur = node->next; cur; cur = cur->next) {
200 if (node->key.source_type == cur->key.source_type &&
201 node->key.target_type == cur->key.target_type &&
202 node->key.target_class == cur->key.target_class &&
203 (specified & cur->datum.specified))
204 return cur;
205
206 if (node->key.source_type < cur->key.source_type)
207 break;
208 if (node->key.source_type == cur->key.source_type &&
209 node->key.target_type < cur->key.target_type)
210 break;
211 if (node->key.source_type == cur->key.source_type &&
212 node->key.target_type == cur->key.target_type &&
213 node->key.target_class < cur->key.target_class)
214 break;
215 }
216 return NULL;
217}
218
219void avtab_destroy(struct avtab *h)
220{
221 int i;
222 struct avtab_node *cur, *temp;
223
224 if (!h || !h->htable)
225 return;
226
227 for (i = 0; i < AVTAB_SIZE; i++) {
228 cur = h->htable[i];
229 while (cur != NULL) {
230 temp = cur;
231 cur = cur->next;
232 kmem_cache_free(avtab_node_cachep, temp);
233 }
234 h->htable[i] = NULL;
235 }
236 vfree(h->htable);
237 h->htable = NULL;
238}
239
240
241int avtab_init(struct avtab *h)
242{
243 int i;
244
245 h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
246 if (!h->htable)
247 return -ENOMEM;
248 for (i = 0; i < AVTAB_SIZE; i++)
249 h->htable[i] = NULL;
250 h->nel = 0;
251 return 0;
252}
253
254void avtab_hash_eval(struct avtab *h, char *tag)
255{
256 int i, chain_len, slots_used, max_chain_len;
257 struct avtab_node *cur;
258
259 slots_used = 0;
260 max_chain_len = 0;
261 for (i = 0; i < AVTAB_SIZE; i++) {
262 cur = h->htable[i];
263 if (cur) {
264 slots_used++;
265 chain_len = 0;
266 while (cur) {
267 chain_len++;
268 cur = cur->next;
269 }
270
271 if (chain_len > max_chain_len)
272 max_chain_len = chain_len;
273 }
274 }
275
276 printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
277 "chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
278 max_chain_len);
279}
280
281int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
282{
283 u32 buf[7];
284 u32 items, items2;
285 int rc;
286
287 memset(avkey, 0, sizeof(struct avtab_key));
288 memset(avdatum, 0, sizeof(struct avtab_datum));
289
290 rc = next_entry(buf, fp, sizeof(u32));
291 if (rc < 0) {
292 printk(KERN_ERR "security: avtab: truncated entry\n");
293 goto bad;
294 }
295 items2 = le32_to_cpu(buf[0]);
296 if (items2 > ARRAY_SIZE(buf)) {
297 printk(KERN_ERR "security: avtab: entry overflow\n");
298 goto bad;
299 }
300 rc = next_entry(buf, fp, sizeof(u32)*items2);
301 if (rc < 0) {
302 printk(KERN_ERR "security: avtab: truncated entry\n");
303 goto bad;
304 }
305 items = 0;
306 avkey->source_type = le32_to_cpu(buf[items++]);
307 avkey->target_type = le32_to_cpu(buf[items++]);
308 avkey->target_class = le32_to_cpu(buf[items++]);
309 avdatum->specified = le32_to_cpu(buf[items++]);
310 if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
311 printk(KERN_ERR "security: avtab: null entry\n");
312 goto bad;
313 }
314 if ((avdatum->specified & AVTAB_AV) &&
315 (avdatum->specified & AVTAB_TYPE)) {
316 printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
317 goto bad;
318 }
319 if (avdatum->specified & AVTAB_AV) {
320 if (avdatum->specified & AVTAB_ALLOWED)
321 avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
322 if (avdatum->specified & AVTAB_AUDITDENY)
323 avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
324 if (avdatum->specified & AVTAB_AUDITALLOW)
325 avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
326 } else {
327 if (avdatum->specified & AVTAB_TRANSITION)
328 avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
329 if (avdatum->specified & AVTAB_CHANGE)
330 avtab_change(avdatum) = le32_to_cpu(buf[items++]);
331 if (avdatum->specified & AVTAB_MEMBER)
332 avtab_member(avdatum) = le32_to_cpu(buf[items++]);
333 }
334 if (items != items2) {
335 printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
336 items2, items);
337 goto bad;
338 }
339
340 return 0;
341bad:
342 return -1;
343}
344
345int avtab_read(struct avtab *a, void *fp, u32 config)
346{
347 int rc;
348 struct avtab_key avkey;
349 struct avtab_datum avdatum;
350 u32 buf[1];
351 u32 nel, i;
352
353
354 rc = next_entry(buf, fp, sizeof(u32));
355 if (rc < 0) {
356 printk(KERN_ERR "security: avtab: truncated table\n");
357 goto bad;
358 }
359 nel = le32_to_cpu(buf[0]);
360 if (!nel) {
361 printk(KERN_ERR "security: avtab: table is empty\n");
362 rc = -EINVAL;
363 goto bad;
364 }
365 for (i = 0; i < nel; i++) {
366 if (avtab_read_item(fp, &avdatum, &avkey)) {
367 rc = -EINVAL;
368 goto bad;
369 }
370 rc = avtab_insert(a, &avkey, &avdatum);
371 if (rc) {
372 if (rc == -ENOMEM)
373 printk(KERN_ERR "security: avtab: out of memory\n");
374 if (rc == -EEXIST)
375 printk(KERN_ERR "security: avtab: duplicate entry\n");
376 goto bad;
377 }
378 }
379
380 rc = 0;
381out:
382 return rc;
383
384bad:
385 avtab_destroy(a);
386 goto out;
387}
388
389void avtab_cache_init(void)
390{
391 avtab_node_cachep = kmem_cache_create("avtab_node",
392 sizeof(struct avtab_node),
393 0, SLAB_PANIC, NULL, NULL);
394}
395
396void avtab_cache_destroy(void)
397{
398 kmem_cache_destroy (avtab_node_cachep);
399}
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
new file mode 100644
index 000000000000..519d4f6dc655
--- /dev/null
+++ b/security/selinux/ss/avtab.h
@@ -0,0 +1,85 @@
1/*
2 * An access vector table (avtab) is a hash table
3 * of access vectors and transition types indexed
4 * by a type pair and a class. An access vector
5 * table is used to represent the type enforcement
6 * tables.
7 *
8 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
9 */
10
11/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
12 *
13 * Added conditional policy language extensions
14 *
15 * Copyright (C) 2003 Tresys Technology, LLC
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, version 2.
19 */
20#ifndef _SS_AVTAB_H_
21#define _SS_AVTAB_H_
22
23struct avtab_key {
24 u32 source_type; /* source type */
25 u32 target_type; /* target type */
26 u32 target_class; /* target object class */
27};
28
29struct avtab_datum {
30#define AVTAB_ALLOWED 1
31#define AVTAB_AUDITALLOW 2
32#define AVTAB_AUDITDENY 4
33#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
34#define AVTAB_TRANSITION 16
35#define AVTAB_MEMBER 32
36#define AVTAB_CHANGE 64
37#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
38#define AVTAB_ENABLED 0x80000000 /* reserved for used in cond_avtab */
39 u32 specified; /* what fields are specified */
40 u32 data[3]; /* access vectors or types */
41#define avtab_allowed(x) (x)->data[0]
42#define avtab_auditdeny(x) (x)->data[1]
43#define avtab_auditallow(x) (x)->data[2]
44#define avtab_transition(x) (x)->data[0]
45#define avtab_change(x) (x)->data[1]
46#define avtab_member(x) (x)->data[2]
47};
48
49struct avtab_node {
50 struct avtab_key key;
51 struct avtab_datum datum;
52 struct avtab_node *next;
53};
54
55struct avtab {
56 struct avtab_node **htable;
57 u32 nel; /* number of elements */
58};
59
60int avtab_init(struct avtab *);
61struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified);
62void avtab_destroy(struct avtab *h);
63void avtab_hash_eval(struct avtab *h, char *tag);
64
65int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
66int avtab_read(struct avtab *a, void *fp, u32 config);
67
68struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
69 struct avtab_datum *datum);
70
71struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified);
72
73struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
74
75void avtab_cache_init(void);
76void avtab_cache_destroy(void);
77
78#define AVTAB_HASH_BITS 15
79#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
80#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
81
82#define AVTAB_SIZE AVTAB_HASH_BUCKETS
83
84#endif /* _SS_AVTAB_H_ */
85
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
new file mode 100644
index 000000000000..b53441184aca
--- /dev/null
+++ b/security/selinux/ss/conditional.c
@@ -0,0 +1,489 @@
1/* Authors: Karl MacMillan <kmacmillan@tresys.com>
2 * Frank Mayer <mayerf@tresys.com>
3 *
4 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2.
8 */
9
10#include <linux/kernel.h>
11#include <linux/errno.h>
12#include <linux/string.h>
13#include <linux/spinlock.h>
14#include <asm/semaphore.h>
15#include <linux/slab.h>
16
17#include "security.h"
18#include "conditional.h"
19
20/*
21 * cond_evaluate_expr evaluates a conditional expr
22 * in reverse polish notation. It returns true (1), false (0),
23 * or undefined (-1). Undefined occurs when the expression
24 * exceeds the stack depth of COND_EXPR_MAXDEPTH.
25 */
26static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
27{
28
29 struct cond_expr *cur;
30 int s[COND_EXPR_MAXDEPTH];
31 int sp = -1;
32
33 for (cur = expr; cur != NULL; cur = cur->next) {
34 switch (cur->expr_type) {
35 case COND_BOOL:
36 if (sp == (COND_EXPR_MAXDEPTH - 1))
37 return -1;
38 sp++;
39 s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
40 break;
41 case COND_NOT:
42 if (sp < 0)
43 return -1;
44 s[sp] = !s[sp];
45 break;
46 case COND_OR:
47 if (sp < 1)
48 return -1;
49 sp--;
50 s[sp] |= s[sp + 1];
51 break;
52 case COND_AND:
53 if (sp < 1)
54 return -1;
55 sp--;
56 s[sp] &= s[sp + 1];
57 break;
58 case COND_XOR:
59 if (sp < 1)
60 return -1;
61 sp--;
62 s[sp] ^= s[sp + 1];
63 break;
64 case COND_EQ:
65 if (sp < 1)
66 return -1;
67 sp--;
68 s[sp] = (s[sp] == s[sp + 1]);
69 break;
70 case COND_NEQ:
71 if (sp < 1)
72 return -1;
73 sp--;
74 s[sp] = (s[sp] != s[sp + 1]);
75 break;
76 default:
77 return -1;
78 }
79 }
80 return s[0];
81}
82
83/*
84 * evaluate_cond_node evaluates the conditional stored in
85 * a struct cond_node and if the result is different than the
86 * current state of the node it sets the rules in the true/false
87 * list appropriately. If the result of the expression is undefined
88 * all of the rules are disabled for safety.
89 */
90int evaluate_cond_node(struct policydb *p, struct cond_node *node)
91{
92 int new_state;
93 struct cond_av_list* cur;
94
95 new_state = cond_evaluate_expr(p, node->expr);
96 if (new_state != node->cur_state) {
97 node->cur_state = new_state;
98 if (new_state == -1)
99 printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n");
100 /* turn the rules on or off */
101 for (cur = node->true_list; cur != NULL; cur = cur->next) {
102 if (new_state <= 0) {
103 cur->node->datum.specified &= ~AVTAB_ENABLED;
104 } else {
105 cur->node->datum.specified |= AVTAB_ENABLED;
106 }
107 }
108
109 for (cur = node->false_list; cur != NULL; cur = cur->next) {
110 /* -1 or 1 */
111 if (new_state) {
112 cur->node->datum.specified &= ~AVTAB_ENABLED;
113 } else {
114 cur->node->datum.specified |= AVTAB_ENABLED;
115 }
116 }
117 }
118 return 0;
119}
120
121int cond_policydb_init(struct policydb *p)
122{
123 p->bool_val_to_struct = NULL;
124 p->cond_list = NULL;
125 if (avtab_init(&p->te_cond_avtab))
126 return -1;
127
128 return 0;
129}
130
131static void cond_av_list_destroy(struct cond_av_list *list)
132{
133 struct cond_av_list *cur, *next;
134 for (cur = list; cur != NULL; cur = next) {
135 next = cur->next;
136 /* the avtab_ptr_t node is destroy by the avtab */
137 kfree(cur);
138 }
139}
140
141static void cond_node_destroy(struct cond_node *node)
142{
143 struct cond_expr *cur_expr, *next_expr;
144
145 for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) {
146 next_expr = cur_expr->next;
147 kfree(cur_expr);
148 }
149 cond_av_list_destroy(node->true_list);
150 cond_av_list_destroy(node->false_list);
151 kfree(node);
152}
153
154static void cond_list_destroy(struct cond_node *list)
155{
156 struct cond_node *next, *cur;
157
158 if (list == NULL)
159 return;
160
161 for (cur = list; cur != NULL; cur = next) {
162 next = cur->next;
163 cond_node_destroy(cur);
164 }
165}
166
167void cond_policydb_destroy(struct policydb *p)
168{
169 if (p->bool_val_to_struct != NULL)
170 kfree(p->bool_val_to_struct);
171 avtab_destroy(&p->te_cond_avtab);
172 cond_list_destroy(p->cond_list);
173}
174
175int cond_init_bool_indexes(struct policydb *p)
176{
177 if (p->bool_val_to_struct)
178 kfree(p->bool_val_to_struct);
179 p->bool_val_to_struct = (struct cond_bool_datum**)
180 kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL);
181 if (!p->bool_val_to_struct)
182 return -1;
183 return 0;
184}
185
186int cond_destroy_bool(void *key, void *datum, void *p)
187{
188 if (key)
189 kfree(key);
190 kfree(datum);
191 return 0;
192}
193
194int cond_index_bool(void *key, void *datum, void *datap)
195{
196 struct policydb *p;
197 struct cond_bool_datum *booldatum;
198
199 booldatum = datum;
200 p = datap;
201
202 if (!booldatum->value || booldatum->value > p->p_bools.nprim)
203 return -EINVAL;
204
205 p->p_bool_val_to_name[booldatum->value - 1] = key;
206 p->bool_val_to_struct[booldatum->value -1] = booldatum;
207
208 return 0;
209}
210
211static int bool_isvalid(struct cond_bool_datum *b)
212{
213 if (!(b->state == 0 || b->state == 1))
214 return 0;
215 return 1;
216}
217
218int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
219{
220 char *key = NULL;
221 struct cond_bool_datum *booldatum;
222 u32 buf[3], len;
223 int rc;
224
225 booldatum = kmalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
226 if (!booldatum)
227 return -1;
228 memset(booldatum, 0, sizeof(struct cond_bool_datum));
229
230 rc = next_entry(buf, fp, sizeof buf);
231 if (rc < 0)
232 goto err;
233
234 booldatum->value = le32_to_cpu(buf[0]);
235 booldatum->state = le32_to_cpu(buf[1]);
236
237 if (!bool_isvalid(booldatum))
238 goto err;
239
240 len = le32_to_cpu(buf[2]);
241
242 key = kmalloc(len + 1, GFP_KERNEL);
243 if (!key)
244 goto err;
245 rc = next_entry(key, fp, len);
246 if (rc < 0)
247 goto err;
248 key[len] = 0;
249 if (hashtab_insert(h, key, booldatum))
250 goto err;
251
252 return 0;
253err:
254 cond_destroy_bool(key, booldatum, NULL);
255 return -1;
256}
257
258static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list,
259 struct cond_av_list *other)
260{
261 struct cond_av_list *list, *last = NULL, *cur;
262 struct avtab_key key;
263 struct avtab_datum datum;
264 struct avtab_node *node_ptr;
265 int rc;
266 u32 buf[1], i, len;
267 u8 found;
268
269 *ret_list = NULL;
270
271 len = 0;
272 rc = next_entry(buf, fp, sizeof buf);
273 if (rc < 0)
274 return -1;
275
276 len = le32_to_cpu(buf[0]);
277 if (len == 0) {
278 return 0;
279 }
280
281 for (i = 0; i < len; i++) {
282 if (avtab_read_item(fp, &datum, &key))
283 goto err;
284
285 /*
286 * For type rules we have to make certain there aren't any
287 * conflicting rules by searching the te_avtab and the
288 * cond_te_avtab.
289 */
290 if (datum.specified & AVTAB_TYPE) {
291 if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) {
292 printk("security: type rule already exists outside of a conditional.");
293 goto err;
294 }
295 /*
296 * If we are reading the false list other will be a pointer to
297 * the true list. We can have duplicate entries if there is only
298 * 1 other entry and it is in our true list.
299 *
300 * If we are reading the true list (other == NULL) there shouldn't
301 * be any other entries.
302 */
303 if (other) {
304 node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE);
305 if (node_ptr) {
306 if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) {
307 printk("security: too many conflicting type rules.");
308 goto err;
309 }
310 found = 0;
311 for (cur = other; cur != NULL; cur = cur->next) {
312 if (cur->node == node_ptr) {
313 found = 1;
314 break;
315 }
316 }
317 if (!found) {
318 printk("security: conflicting type rules.");
319 goto err;
320 }
321 }
322 } else {
323 if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) {
324 printk("security: conflicting type rules when adding type rule for true.");
325 goto err;
326 }
327 }
328 }
329 node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum);
330 if (!node_ptr) {
331 printk("security: could not insert rule.");
332 goto err;
333 }
334
335 list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
336 if (!list)
337 goto err;
338 memset(list, 0, sizeof(struct cond_av_list));
339
340 list->node = node_ptr;
341 if (i == 0)
342 *ret_list = list;
343 else
344 last->next = list;
345 last = list;
346
347 }
348
349 return 0;
350err:
351 cond_av_list_destroy(*ret_list);
352 *ret_list = NULL;
353 return -1;
354}
355
356static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
357{
358 if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
359 printk("security: conditional expressions uses unknown operator.\n");
360 return 0;
361 }
362
363 if (expr->bool > p->p_bools.nprim) {
364 printk("security: conditional expressions uses unknown bool.\n");
365 return 0;
366 }
367 return 1;
368}
369
370static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
371{
372 u32 buf[2], len, i;
373 int rc;
374 struct cond_expr *expr = NULL, *last = NULL;
375
376 rc = next_entry(buf, fp, sizeof(u32));
377 if (rc < 0)
378 return -1;
379
380 node->cur_state = le32_to_cpu(buf[0]);
381
382 len = 0;
383 rc = next_entry(buf, fp, sizeof(u32));
384 if (rc < 0)
385 return -1;
386
387 /* expr */
388 len = le32_to_cpu(buf[0]);
389
390 for (i = 0; i < len; i++ ) {
391 rc = next_entry(buf, fp, sizeof(u32) * 2);
392 if (rc < 0)
393 goto err;
394
395 expr = kmalloc(sizeof(struct cond_expr), GFP_KERNEL);
396 if (!expr) {
397 goto err;
398 }
399 memset(expr, 0, sizeof(struct cond_expr));
400
401 expr->expr_type = le32_to_cpu(buf[0]);
402 expr->bool = le32_to_cpu(buf[1]);
403
404 if (!expr_isvalid(p, expr)) {
405 kfree(expr);
406 goto err;
407 }
408
409 if (i == 0) {
410 node->expr = expr;
411 } else {
412 last->next = expr;
413 }
414 last = expr;
415 }
416
417 if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
418 goto err;
419 if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
420 goto err;
421 return 0;
422err:
423 cond_node_destroy(node);
424 return -1;
425}
426
427int cond_read_list(struct policydb *p, void *fp)
428{
429 struct cond_node *node, *last = NULL;
430 u32 buf[1], i, len;
431 int rc;
432
433 rc = next_entry(buf, fp, sizeof buf);
434 if (rc < 0)
435 return -1;
436
437 len = le32_to_cpu(buf[0]);
438
439 for (i = 0; i < len; i++) {
440 node = kmalloc(sizeof(struct cond_node), GFP_KERNEL);
441 if (!node)
442 goto err;
443 memset(node, 0, sizeof(struct cond_node));
444
445 if (cond_read_node(p, node, fp) != 0)
446 goto err;
447
448 if (i == 0) {
449 p->cond_list = node;
450 } else {
451 last->next = node;
452 }
453 last = node;
454 }
455 return 0;
456err:
457 cond_list_destroy(p->cond_list);
458 return -1;
459}
460
461/* Determine whether additional permissions are granted by the conditional
462 * av table, and if so, add them to the result
463 */
464void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
465{
466 struct avtab_node *node;
467
468 if(!ctab || !key || !avd)
469 return;
470
471 for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL;
472 node = avtab_search_node_next(node, AVTAB_AV)) {
473 if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
474 (node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
475 avd->allowed |= avtab_allowed(&node->datum);
476 if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
477 (node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
478 /* Since a '0' in an auditdeny mask represents a
479 * permission we do NOT want to audit (dontaudit), we use
480 * the '&' operand to ensure that all '0's in the mask
481 * are retained (much unlike the allow and auditallow cases).
482 */
483 avd->auditdeny &= avtab_auditdeny(&node->datum);
484 if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
485 (node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
486 avd->auditallow |= avtab_auditallow(&node->datum);
487 }
488 return;
489}
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
new file mode 100644
index 000000000000..f3a1fc6e5d66
--- /dev/null
+++ b/security/selinux/ss/conditional.h
@@ -0,0 +1,77 @@
1/* Authors: Karl MacMillan <kmacmillan@tresys.com>
2 * Frank Mayer <mayerf@tresys.com>
3 *
4 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2.
8 */
9
10#ifndef _CONDITIONAL_H_
11#define _CONDITIONAL_H_
12
13#include "avtab.h"
14#include "symtab.h"
15#include "policydb.h"
16
17#define COND_EXPR_MAXDEPTH 10
18
19/*
20 * A conditional expression is a list of operators and operands
21 * in reverse polish notation.
22 */
23struct cond_expr {
24#define COND_BOOL 1 /* plain bool */
25#define COND_NOT 2 /* !bool */
26#define COND_OR 3 /* bool || bool */
27#define COND_AND 4 /* bool && bool */
28#define COND_XOR 5 /* bool ^ bool */
29#define COND_EQ 6 /* bool == bool */
30#define COND_NEQ 7 /* bool != bool */
31#define COND_LAST 8
32 __u32 expr_type;
33 __u32 bool;
34 struct cond_expr *next;
35};
36
37/*
38 * Each cond_node contains a list of rules to be enabled/disabled
39 * depending on the current value of the conditional expression. This
40 * struct is for that list.
41 */
42struct cond_av_list {
43 struct avtab_node *node;
44 struct cond_av_list *next;
45};
46
47/*
48 * A cond node represents a conditional block in a policy. It
49 * contains a conditional expression, the current state of the expression,
50 * two lists of rules to enable/disable depending on the value of the
51 * expression (the true list corresponds to if and the false list corresponds
52 * to else)..
53 */
54struct cond_node {
55 int cur_state;
56 struct cond_expr *expr;
57 struct cond_av_list *true_list;
58 struct cond_av_list *false_list;
59 struct cond_node *next;
60};
61
62int cond_policydb_init(struct policydb* p);
63void cond_policydb_destroy(struct policydb* p);
64
65int cond_init_bool_indexes(struct policydb* p);
66int cond_destroy_bool(void *key, void *datum, void *p);
67
68int cond_index_bool(void *key, void *datum, void *datap);
69
70int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
71int cond_read_list(struct policydb *p, void *fp);
72
73void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
74
75int evaluate_cond_node(struct policydb *p, struct cond_node *node);
76
77#endif /* _CONDITIONAL_H_ */
diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h
new file mode 100644
index 000000000000..149dda731fd3
--- /dev/null
+++ b/security/selinux/ss/constraint.h
@@ -0,0 +1,61 @@
1/*
2 * A constraint is a condition that must be satisfied in
3 * order for one or more permissions to be granted.
4 * Constraints are used to impose additional restrictions
5 * beyond the type-based rules in `te' or the role-based
6 * transition rules in `rbac'. Constraints are typically
7 * used to prevent a process from transitioning to a new user
8 * identity or role unless it is in a privileged type.
9 * Constraints are likewise typically used to prevent a
10 * process from labeling an object with a different user
11 * identity.
12 *
13 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
14 */
15#ifndef _SS_CONSTRAINT_H_
16#define _SS_CONSTRAINT_H_
17
18#include "ebitmap.h"
19
20#define CEXPR_MAXDEPTH 5
21
22struct constraint_expr {
23#define CEXPR_NOT 1 /* not expr */
24#define CEXPR_AND 2 /* expr and expr */
25#define CEXPR_OR 3 /* expr or expr */
26#define CEXPR_ATTR 4 /* attr op attr */
27#define CEXPR_NAMES 5 /* attr op names */
28 u32 expr_type; /* expression type */
29
30#define CEXPR_USER 1 /* user */
31#define CEXPR_ROLE 2 /* role */
32#define CEXPR_TYPE 4 /* type */
33#define CEXPR_TARGET 8 /* target if set, source otherwise */
34#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */
35#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */
36#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */
37#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */
38#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */
39#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */
40#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */
41 u32 attr; /* attribute */
42
43#define CEXPR_EQ 1 /* == or eq */
44#define CEXPR_NEQ 2 /* != */
45#define CEXPR_DOM 3 /* dom */
46#define CEXPR_DOMBY 4 /* domby */
47#define CEXPR_INCOMP 5 /* incomp */
48 u32 op; /* operator */
49
50 struct ebitmap names; /* names */
51
52 struct constraint_expr *next; /* next expression */
53};
54
55struct constraint_node {
56 u32 permissions; /* constrained permissions */
57 struct constraint_expr *expr; /* constraint on permissions */
58 struct constraint_node *next; /* next constraint */
59};
60
61#endif /* _SS_CONSTRAINT_H_ */
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
new file mode 100644
index 000000000000..0562bacb7b99
--- /dev/null
+++ b/security/selinux/ss/context.h
@@ -0,0 +1,107 @@
1/*
2 * A security context is a set of security attributes
3 * associated with each subject and object controlled
4 * by the security policy. Security contexts are
5 * externally represented as variable-length strings
6 * that can be interpreted by a user or application
7 * with an understanding of the security policy.
8 * Internally, the security server uses a simple
9 * structure. This structure is private to the
10 * security server and can be changed without affecting
11 * clients of the security server.
12 *
13 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
14 */
15#ifndef _SS_CONTEXT_H_
16#define _SS_CONTEXT_H_
17
18#include "ebitmap.h"
19#include "mls_types.h"
20#include "security.h"
21
22/*
23 * A security context consists of an authenticated user
24 * identity, a role, a type and a MLS range.
25 */
26struct context {
27 u32 user;
28 u32 role;
29 u32 type;
30 struct mls_range range;
31};
32
33static inline void mls_context_init(struct context *c)
34{
35 memset(&c->range, 0, sizeof(c->range));
36}
37
38static inline int mls_context_cpy(struct context *dst, struct context *src)
39{
40 int rc;
41
42 if (!selinux_mls_enabled)
43 return 0;
44
45 dst->range.level[0].sens = src->range.level[0].sens;
46 rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
47 if (rc)
48 goto out;
49
50 dst->range.level[1].sens = src->range.level[1].sens;
51 rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
52 if (rc)
53 ebitmap_destroy(&dst->range.level[0].cat);
54out:
55 return rc;
56}
57
58static inline int mls_context_cmp(struct context *c1, struct context *c2)
59{
60 if (!selinux_mls_enabled)
61 return 1;
62
63 return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
64 ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) &&
65 (c1->range.level[1].sens == c2->range.level[1].sens) &&
66 ebitmap_cmp(&c1->range.level[1].cat,&c2->range.level[1].cat));
67}
68
69static inline void mls_context_destroy(struct context *c)
70{
71 if (!selinux_mls_enabled)
72 return;
73
74 ebitmap_destroy(&c->range.level[0].cat);
75 ebitmap_destroy(&c->range.level[1].cat);
76 mls_context_init(c);
77}
78
79static inline void context_init(struct context *c)
80{
81 memset(c, 0, sizeof(*c));
82}
83
84static inline int context_cpy(struct context *dst, struct context *src)
85{
86 dst->user = src->user;
87 dst->role = src->role;
88 dst->type = src->type;
89 return mls_context_cpy(dst, src);
90}
91
92static inline void context_destroy(struct context *c)
93{
94 c->user = c->role = c->type = 0;
95 mls_context_destroy(c);
96}
97
98static inline int context_cmp(struct context *c1, struct context *c2)
99{
100 return ((c1->user == c2->user) &&
101 (c1->role == c2->role) &&
102 (c1->type == c2->type) &&
103 mls_context_cmp(c1, c2));
104}
105
106#endif /* _SS_CONTEXT_H_ */
107
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
new file mode 100644
index 000000000000..d8ce9cc0b9f1
--- /dev/null
+++ b/security/selinux/ss/ebitmap.c
@@ -0,0 +1,293 @@
1/*
2 * Implementation of the extensible bitmap type.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6#include <linux/kernel.h>
7#include <linux/slab.h>
8#include <linux/errno.h>
9#include "ebitmap.h"
10#include "policydb.h"
11
12int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
13{
14 struct ebitmap_node *n1, *n2;
15
16 if (e1->highbit != e2->highbit)
17 return 0;
18
19 n1 = e1->node;
20 n2 = e2->node;
21 while (n1 && n2 &&
22 (n1->startbit == n2->startbit) &&
23 (n1->map == n2->map)) {
24 n1 = n1->next;
25 n2 = n2->next;
26 }
27
28 if (n1 || n2)
29 return 0;
30
31 return 1;
32}
33
34int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
35{
36 struct ebitmap_node *n, *new, *prev;
37
38 ebitmap_init(dst);
39 n = src->node;
40 prev = NULL;
41 while (n) {
42 new = kmalloc(sizeof(*new), GFP_ATOMIC);
43 if (!new) {
44 ebitmap_destroy(dst);
45 return -ENOMEM;
46 }
47 memset(new, 0, sizeof(*new));
48 new->startbit = n->startbit;
49 new->map = n->map;
50 new->next = NULL;
51 if (prev)
52 prev->next = new;
53 else
54 dst->node = new;
55 prev = new;
56 n = n->next;
57 }
58
59 dst->highbit = src->highbit;
60 return 0;
61}
62
63int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
64{
65 struct ebitmap_node *n1, *n2;
66
67 if (e1->highbit < e2->highbit)
68 return 0;
69
70 n1 = e1->node;
71 n2 = e2->node;
72 while (n1 && n2 && (n1->startbit <= n2->startbit)) {
73 if (n1->startbit < n2->startbit) {
74 n1 = n1->next;
75 continue;
76 }
77 if ((n1->map & n2->map) != n2->map)
78 return 0;
79
80 n1 = n1->next;
81 n2 = n2->next;
82 }
83
84 if (n2)
85 return 0;
86
87 return 1;
88}
89
90int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
91{
92 struct ebitmap_node *n;
93
94 if (e->highbit < bit)
95 return 0;
96
97 n = e->node;
98 while (n && (n->startbit <= bit)) {
99 if ((n->startbit + MAPSIZE) > bit) {
100 if (n->map & (MAPBIT << (bit - n->startbit)))
101 return 1;
102 else
103 return 0;
104 }
105 n = n->next;
106 }
107
108 return 0;
109}
110
111int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
112{
113 struct ebitmap_node *n, *prev, *new;
114
115 prev = NULL;
116 n = e->node;
117 while (n && n->startbit <= bit) {
118 if ((n->startbit + MAPSIZE) > bit) {
119 if (value) {
120 n->map |= (MAPBIT << (bit - n->startbit));
121 } else {
122 n->map &= ~(MAPBIT << (bit - n->startbit));
123 if (!n->map) {
124 /* drop this node from the bitmap */
125
126 if (!n->next) {
127 /*
128 * this was the highest map
129 * within the bitmap
130 */
131 if (prev)
132 e->highbit = prev->startbit + MAPSIZE;
133 else
134 e->highbit = 0;
135 }
136 if (prev)
137 prev->next = n->next;
138 else
139 e->node = n->next;
140
141 kfree(n);
142 }
143 }
144 return 0;
145 }
146 prev = n;
147 n = n->next;
148 }
149
150 if (!value)
151 return 0;
152
153 new = kmalloc(sizeof(*new), GFP_ATOMIC);
154 if (!new)
155 return -ENOMEM;
156 memset(new, 0, sizeof(*new));
157
158 new->startbit = bit & ~(MAPSIZE - 1);
159 new->map = (MAPBIT << (bit - new->startbit));
160
161 if (!n)
162 /* this node will be the highest map within the bitmap */
163 e->highbit = new->startbit + MAPSIZE;
164
165 if (prev) {
166 new->next = prev->next;
167 prev->next = new;
168 } else {
169 new->next = e->node;
170 e->node = new;
171 }
172
173 return 0;
174}
175
176void ebitmap_destroy(struct ebitmap *e)
177{
178 struct ebitmap_node *n, *temp;
179
180 if (!e)
181 return;
182
183 n = e->node;
184 while (n) {
185 temp = n;
186 n = n->next;
187 kfree(temp);
188 }
189
190 e->highbit = 0;
191 e->node = NULL;
192 return;
193}
194
195int ebitmap_read(struct ebitmap *e, void *fp)
196{
197 int rc;
198 struct ebitmap_node *n, *l;
199 u32 buf[3], mapsize, count, i;
200 u64 map;
201
202 ebitmap_init(e);
203
204 rc = next_entry(buf, fp, sizeof buf);
205 if (rc < 0)
206 goto out;
207
208 mapsize = le32_to_cpu(buf[0]);
209 e->highbit = le32_to_cpu(buf[1]);
210 count = le32_to_cpu(buf[2]);
211
212 if (mapsize != MAPSIZE) {
213 printk(KERN_ERR "security: ebitmap: map size %u does not "
214 "match my size %Zd (high bit was %d)\n", mapsize,
215 MAPSIZE, e->highbit);
216 goto bad;
217 }
218 if (!e->highbit) {
219 e->node = NULL;
220 goto ok;
221 }
222 if (e->highbit & (MAPSIZE - 1)) {
223 printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
224 "multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
225 goto bad;
226 }
227 l = NULL;
228 for (i = 0; i < count; i++) {
229 rc = next_entry(buf, fp, sizeof(u32));
230 if (rc < 0) {
231 printk(KERN_ERR "security: ebitmap: truncated map\n");
232 goto bad;
233 }
234 n = kmalloc(sizeof(*n), GFP_KERNEL);
235 if (!n) {
236 printk(KERN_ERR "security: ebitmap: out of memory\n");
237 rc = -ENOMEM;
238 goto bad;
239 }
240 memset(n, 0, sizeof(*n));
241
242 n->startbit = le32_to_cpu(buf[0]);
243
244 if (n->startbit & (MAPSIZE - 1)) {
245 printk(KERN_ERR "security: ebitmap start bit (%d) is "
246 "not a multiple of the map size (%Zd)\n",
247 n->startbit, MAPSIZE);
248 goto bad_free;
249 }
250 if (n->startbit > (e->highbit - MAPSIZE)) {
251 printk(KERN_ERR "security: ebitmap start bit (%d) is "
252 "beyond the end of the bitmap (%Zd)\n",
253 n->startbit, (e->highbit - MAPSIZE));
254 goto bad_free;
255 }
256 rc = next_entry(&map, fp, sizeof(u64));
257 if (rc < 0) {
258 printk(KERN_ERR "security: ebitmap: truncated map\n");
259 goto bad_free;
260 }
261 n->map = le64_to_cpu(map);
262
263 if (!n->map) {
264 printk(KERN_ERR "security: ebitmap: null map in "
265 "ebitmap (startbit %d)\n", n->startbit);
266 goto bad_free;
267 }
268 if (l) {
269 if (n->startbit <= l->startbit) {
270 printk(KERN_ERR "security: ebitmap: start "
271 "bit %d comes after start bit %d\n",
272 n->startbit, l->startbit);
273 goto bad_free;
274 }
275 l->next = n;
276 } else
277 e->node = n;
278
279 l = n;
280 }
281
282ok:
283 rc = 0;
284out:
285 return rc;
286bad_free:
287 kfree(n);
288bad:
289 if (!rc)
290 rc = -EINVAL;
291 ebitmap_destroy(e);
292 goto out;
293}
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
new file mode 100644
index 000000000000..471370233fd9
--- /dev/null
+++ b/security/selinux/ss/ebitmap.h
@@ -0,0 +1,48 @@
1/*
2 * An extensible bitmap is a bitmap that supports an
3 * arbitrary number of bits. Extensible bitmaps are
4 * used to represent sets of values, such as types,
5 * roles, categories, and classes.
6 *
7 * Each extensible bitmap is implemented as a linked
8 * list of bitmap nodes, where each bitmap node has
9 * an explicitly specified starting bit position within
10 * the total bitmap.
11 *
12 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
13 */
14#ifndef _SS_EBITMAP_H_
15#define _SS_EBITMAP_H_
16
17#define MAPTYPE u64 /* portion of bitmap in each node */
18#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
19#define MAPBIT 1ULL /* a bit in the node bitmap */
20
21struct ebitmap_node {
22 u32 startbit; /* starting position in the total bitmap */
23 MAPTYPE map; /* this node's portion of the bitmap */
24 struct ebitmap_node *next;
25};
26
27struct ebitmap {
28 struct ebitmap_node *node; /* first node in the bitmap */
29 u32 highbit; /* highest position in the total bitmap */
30};
31
32#define ebitmap_length(e) ((e)->highbit)
33#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
34
35static inline void ebitmap_init(struct ebitmap *e)
36{
37 memset(e, 0, sizeof(*e));
38}
39
40int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
41int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
42int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
43int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
44int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
45void ebitmap_destroy(struct ebitmap *e);
46int ebitmap_read(struct ebitmap *e, void *fp);
47
48#endif /* _SS_EBITMAP_H_ */
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
new file mode 100644
index 000000000000..26661fcc00ce
--- /dev/null
+++ b/security/selinux/ss/hashtab.c
@@ -0,0 +1,167 @@
1/*
2 * Implementation of the hash table type.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6#include <linux/kernel.h>
7#include <linux/slab.h>
8#include <linux/errno.h>
9#include "hashtab.h"
10
11struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
12 int (*keycmp)(struct hashtab *h, void *key1, void *key2),
13 u32 size)
14{
15 struct hashtab *p;
16 u32 i;
17
18 p = kmalloc(sizeof(*p), GFP_KERNEL);
19 if (p == NULL)
20 return p;
21
22 memset(p, 0, sizeof(*p));
23 p->size = size;
24 p->nel = 0;
25 p->hash_value = hash_value;
26 p->keycmp = keycmp;
27 p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL);
28 if (p->htable == NULL) {
29 kfree(p);
30 return NULL;
31 }
32
33 for (i = 0; i < size; i++)
34 p->htable[i] = NULL;
35
36 return p;
37}
38
39int hashtab_insert(struct hashtab *h, void *key, void *datum)
40{
41 u32 hvalue;
42 struct hashtab_node *prev, *cur, *newnode;
43
44 if (!h || h->nel == HASHTAB_MAX_NODES)
45 return -EINVAL;
46
47 hvalue = h->hash_value(h, key);
48 prev = NULL;
49 cur = h->htable[hvalue];
50 while (cur && h->keycmp(h, key, cur->key) > 0) {
51 prev = cur;
52 cur = cur->next;
53 }
54
55 if (cur && (h->keycmp(h, key, cur->key) == 0))
56 return -EEXIST;
57
58 newnode = kmalloc(sizeof(*newnode), GFP_KERNEL);
59 if (newnode == NULL)
60 return -ENOMEM;
61 memset(newnode, 0, sizeof(*newnode));
62 newnode->key = key;
63 newnode->datum = datum;
64 if (prev) {
65 newnode->next = prev->next;
66 prev->next = newnode;
67 } else {
68 newnode->next = h->htable[hvalue];
69 h->htable[hvalue] = newnode;
70 }
71
72 h->nel++;
73 return 0;
74}
75
76void *hashtab_search(struct hashtab *h, void *key)
77{
78 u32 hvalue;
79 struct hashtab_node *cur;
80
81 if (!h)
82 return NULL;
83
84 hvalue = h->hash_value(h, key);
85 cur = h->htable[hvalue];
86 while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
87 cur = cur->next;
88
89 if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
90 return NULL;
91
92 return cur->datum;
93}
94
95void hashtab_destroy(struct hashtab *h)
96{
97 u32 i;
98 struct hashtab_node *cur, *temp;
99
100 if (!h)
101 return;
102
103 for (i = 0; i < h->size; i++) {
104 cur = h->htable[i];
105 while (cur != NULL) {
106 temp = cur;
107 cur = cur->next;
108 kfree(temp);
109 }
110 h->htable[i] = NULL;
111 }
112
113 kfree(h->htable);
114 h->htable = NULL;
115
116 kfree(h);
117}
118
119int hashtab_map(struct hashtab *h,
120 int (*apply)(void *k, void *d, void *args),
121 void *args)
122{
123 u32 i;
124 int ret;
125 struct hashtab_node *cur;
126
127 if (!h)
128 return 0;
129
130 for (i = 0; i < h->size; i++) {
131 cur = h->htable[i];
132 while (cur != NULL) {
133 ret = apply(cur->key, cur->datum, args);
134 if (ret)
135 return ret;
136 cur = cur->next;
137 }
138 }
139 return 0;
140}
141
142
143void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
144{
145 u32 i, chain_len, slots_used, max_chain_len;
146 struct hashtab_node *cur;
147
148 slots_used = 0;
149 max_chain_len = 0;
150 for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
151 cur = h->htable[i];
152 if (cur) {
153 slots_used++;
154 chain_len = 0;
155 while (cur) {
156 chain_len++;
157 cur = cur->next;
158 }
159
160 if (chain_len > max_chain_len)
161 max_chain_len = chain_len;
162 }
163 }
164
165 info->slots_used = slots_used;
166 info->max_chain_len = max_chain_len;
167}
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h
new file mode 100644
index 000000000000..4cc85816a718
--- /dev/null
+++ b/security/selinux/ss/hashtab.h
@@ -0,0 +1,87 @@
1/*
2 * A hash table (hashtab) maintains associations between
3 * key values and datum values. The type of the key values
4 * and the type of the datum values is arbitrary. The
5 * functions for hash computation and key comparison are
6 * provided by the creator of the table.
7 *
8 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
9 */
10#ifndef _SS_HASHTAB_H_
11#define _SS_HASHTAB_H_
12
13#define HASHTAB_MAX_NODES 0xffffffff
14
15struct hashtab_node {
16 void *key;
17 void *datum;
18 struct hashtab_node *next;
19};
20
21struct hashtab {
22 struct hashtab_node **htable; /* hash table */
23 u32 size; /* number of slots in hash table */
24 u32 nel; /* number of elements in hash table */
25 u32 (*hash_value)(struct hashtab *h, void *key);
26 /* hash function */
27 int (*keycmp)(struct hashtab *h, void *key1, void *key2);
28 /* key comparison function */
29};
30
31struct hashtab_info {
32 u32 slots_used;
33 u32 max_chain_len;
34};
35
36/*
37 * Creates a new hash table with the specified characteristics.
38 *
39 * Returns NULL if insufficent space is available or
40 * the new hash table otherwise.
41 */
42struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
43 int (*keycmp)(struct hashtab *h, void *key1, void *key2),
44 u32 size);
45
46/*
47 * Inserts the specified (key, datum) pair into the specified hash table.
48 *
49 * Returns -ENOMEM on memory allocation error,
50 * -EEXIST if there is already an entry with the same key,
51 * -EINVAL for general errors or
52 * 0 otherwise.
53 */
54int hashtab_insert(struct hashtab *h, void *k, void *d);
55
56/*
57 * Searches for the entry with the specified key in the hash table.
58 *
59 * Returns NULL if no entry has the specified key or
60 * the datum of the entry otherwise.
61 */
62void *hashtab_search(struct hashtab *h, void *k);
63
64/*
65 * Destroys the specified hash table.
66 */
67void hashtab_destroy(struct hashtab *h);
68
69/*
70 * Applies the specified apply function to (key,datum,args)
71 * for each entry in the specified hash table.
72 *
73 * The order in which the function is applied to the entries
74 * is dependent upon the internal structure of the hash table.
75 *
76 * If apply returns a non-zero status, then hashtab_map will cease
77 * iterating through the hash table and will propagate the error
78 * return to its caller.
79 */
80int hashtab_map(struct hashtab *h,
81 int (*apply)(void *k, void *d, void *args),
82 void *args);
83
84/* Fill info with some hash table statistics */
85void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
86
87#endif /* _SS_HASHTAB_H */
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
new file mode 100644
index 000000000000..756036bcc243
--- /dev/null
+++ b/security/selinux/ss/mls.c
@@ -0,0 +1,527 @@
1/*
2 * Implementation of the multi-level security (MLS) policy.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6/*
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * Support for enhanced MLS infrastructure.
10 *
11 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
12 */
13
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/string.h>
17#include <linux/errno.h>
18#include "mls.h"
19#include "policydb.h"
20#include "services.h"
21
22/*
23 * Return the length in bytes for the MLS fields of the
24 * security context string representation of `context'.
25 */
26int mls_compute_context_len(struct context * context)
27{
28 int i, l, len, range;
29
30 if (!selinux_mls_enabled)
31 return 0;
32
33 len = 1; /* for the beginning ":" */
34 for (l = 0; l < 2; l++) {
35 range = 0;
36 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
37
38 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
39 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
40 if (range) {
41 range++;
42 continue;
43 }
44
45 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
46 range++;
47 } else {
48 if (range > 1)
49 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
50 range = 0;
51 }
52 }
53 /* Handle case where last category is the end of range */
54 if (range > 1)
55 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
56
57 if (l == 0) {
58 if (mls_level_eq(&context->range.level[0],
59 &context->range.level[1]))
60 break;
61 else
62 len++;
63 }
64 }
65
66 return len;
67}
68
69/*
70 * Write the security context string representation of
71 * the MLS fields of `context' into the string `*scontext'.
72 * Update `*scontext' to point to the end of the MLS fields.
73 */
74void mls_sid_to_context(struct context *context,
75 char **scontext)
76{
77 char *scontextp;
78 int i, l, range, wrote_sep;
79
80 if (!selinux_mls_enabled)
81 return;
82
83 scontextp = *scontext;
84
85 *scontextp = ':';
86 scontextp++;
87
88 for (l = 0; l < 2; l++) {
89 range = 0;
90 wrote_sep = 0;
91 strcpy(scontextp,
92 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
93 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
94
95 /* categories */
96 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
97 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
98 if (range) {
99 range++;
100 continue;
101 }
102
103 if (!wrote_sep) {
104 *scontextp++ = ':';
105 wrote_sep = 1;
106 } else
107 *scontextp++ = ',';
108 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
109 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
110 range++;
111 } else {
112 if (range > 1) {
113 if (range > 2)
114 *scontextp++ = '.';
115 else
116 *scontextp++ = ',';
117
118 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
119 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
120 }
121 range = 0;
122 }
123 }
124
125 /* Handle case where last category is the end of range */
126 if (range > 1) {
127 if (range > 2)
128 *scontextp++ = '.';
129 else
130 *scontextp++ = ',';
131
132 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
133 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
134 }
135
136 if (l == 0) {
137 if (mls_level_eq(&context->range.level[0],
138 &context->range.level[1]))
139 break;
140 else {
141 *scontextp = '-';
142 scontextp++;
143 }
144 }
145 }
146
147 *scontext = scontextp;
148 return;
149}
150
151/*
152 * Return 1 if the MLS fields in the security context
153 * structure `c' are valid. Return 0 otherwise.
154 */
155int mls_context_isvalid(struct policydb *p, struct context *c)
156{
157 struct level_datum *levdatum;
158 struct user_datum *usrdatum;
159 int i, l;
160
161 if (!selinux_mls_enabled)
162 return 1;
163
164 /*
165 * MLS range validity checks: high must dominate low, low level must
166 * be valid (category set <-> sensitivity check), and high level must
167 * be valid (category set <-> sensitivity check)
168 */
169 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
170 /* High does not dominate low. */
171 return 0;
172
173 for (l = 0; l < 2; l++) {
174 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
175 return 0;
176 levdatum = hashtab_search(p->p_levels.table,
177 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
178 if (!levdatum)
179 return 0;
180
181 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
182 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
183 if (i > p->p_cats.nprim)
184 return 0;
185 if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
186 /*
187 * Category may not be associated with
188 * sensitivity in low level.
189 */
190 return 0;
191 }
192 }
193 }
194
195 if (c->role == OBJECT_R_VAL)
196 return 1;
197
198 /*
199 * User must be authorized for the MLS range.
200 */
201 if (!c->user || c->user > p->p_users.nprim)
202 return 0;
203 usrdatum = p->user_val_to_struct[c->user - 1];
204 if (!mls_range_contains(usrdatum->range, c->range))
205 return 0; /* user may not be associated with range */
206
207 return 1;
208}
209
210/*
211 * Set the MLS fields in the security context structure
212 * `context' based on the string representation in
213 * the string `*scontext'. Update `*scontext' to
214 * point to the end of the string representation of
215 * the MLS fields.
216 *
217 * This function modifies the string in place, inserting
218 * NULL characters to terminate the MLS fields.
219 */
220int mls_context_to_sid(char oldc,
221 char **scontext,
222 struct context *context)
223{
224
225 char delim;
226 char *scontextp, *p, *rngptr;
227 struct level_datum *levdatum;
228 struct cat_datum *catdatum, *rngdatum;
229 int l, rc = -EINVAL;
230
231 if (!selinux_mls_enabled)
232 return 0;
233
234 /* No MLS component to the security context. */
235 if (!oldc)
236 goto out;
237
238 /* Extract low sensitivity. */
239 scontextp = p = *scontext;
240 while (*p && *p != ':' && *p != '-')
241 p++;
242
243 delim = *p;
244 if (delim != 0)
245 *p++ = 0;
246
247 for (l = 0; l < 2; l++) {
248 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
249 if (!levdatum) {
250 rc = -EINVAL;
251 goto out;
252 }
253
254 context->range.level[l].sens = levdatum->level->sens;
255
256 if (delim == ':') {
257 /* Extract category set. */
258 while (1) {
259 scontextp = p;
260 while (*p && *p != ',' && *p != '-')
261 p++;
262 delim = *p;
263 if (delim != 0)
264 *p++ = 0;
265
266 /* Separate into range if exists */
267 if ((rngptr = strchr(scontextp, '.')) != NULL) {
268 /* Remove '.' */
269 *rngptr++ = 0;
270 }
271
272 catdatum = hashtab_search(policydb.p_cats.table,
273 scontextp);
274 if (!catdatum) {
275 rc = -EINVAL;
276 goto out;
277 }
278
279 rc = ebitmap_set_bit(&context->range.level[l].cat,
280 catdatum->value - 1, 1);
281 if (rc)
282 goto out;
283
284 /* If range, set all categories in range */
285 if (rngptr) {
286 int i;
287
288 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
289 if (!rngdatum) {
290 rc = -EINVAL;
291 goto out;
292 }
293
294 if (catdatum->value >= rngdatum->value) {
295 rc = -EINVAL;
296 goto out;
297 }
298
299 for (i = catdatum->value; i < rngdatum->value; i++) {
300 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
301 if (rc)
302 goto out;
303 }
304 }
305
306 if (delim != ',')
307 break;
308 }
309 }
310 if (delim == '-') {
311 /* Extract high sensitivity. */
312 scontextp = p;
313 while (*p && *p != ':')
314 p++;
315
316 delim = *p;
317 if (delim != 0)
318 *p++ = 0;
319 } else
320 break;
321 }
322
323 if (l == 0) {
324 context->range.level[1].sens = context->range.level[0].sens;
325 rc = ebitmap_cpy(&context->range.level[1].cat,
326 &context->range.level[0].cat);
327 if (rc)
328 goto out;
329 }
330 *scontext = ++p;
331 rc = 0;
332out:
333 return rc;
334}
335
336/*
337 * Copies the MLS range from `src' into `dst'.
338 */
339static inline int mls_copy_context(struct context *dst,
340 struct context *src)
341{
342 int l, rc = 0;
343
344 /* Copy the MLS range from the source context */
345 for (l = 0; l < 2; l++) {
346 dst->range.level[l].sens = src->range.level[l].sens;
347 rc = ebitmap_cpy(&dst->range.level[l].cat,
348 &src->range.level[l].cat);
349 if (rc)
350 break;
351 }
352
353 return rc;
354}
355
356/*
357 * Copies the effective MLS range from `src' into `dst'.
358 */
359static inline int mls_scopy_context(struct context *dst,
360 struct context *src)
361{
362 int l, rc = 0;
363
364 /* Copy the MLS range from the source context */
365 for (l = 0; l < 2; l++) {
366 dst->range.level[l].sens = src->range.level[0].sens;
367 rc = ebitmap_cpy(&dst->range.level[l].cat,
368 &src->range.level[0].cat);
369 if (rc)
370 break;
371 }
372
373 return rc;
374}
375
376/*
377 * Copies the MLS range `range' into `context'.
378 */
379static inline int mls_range_set(struct context *context,
380 struct mls_range *range)
381{
382 int l, rc = 0;
383
384 /* Copy the MLS range into the context */
385 for (l = 0; l < 2; l++) {
386 context->range.level[l].sens = range->level[l].sens;
387 rc = ebitmap_cpy(&context->range.level[l].cat,
388 &range->level[l].cat);
389 if (rc)
390 break;
391 }
392
393 return rc;
394}
395
396int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
397 struct context *usercon)
398{
399 if (selinux_mls_enabled) {
400 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
401 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
402 struct mls_level *user_low = &(user->range.level[0]);
403 struct mls_level *user_clr = &(user->range.level[1]);
404 struct mls_level *user_def = &(user->dfltlevel);
405 struct mls_level *usercon_sen = &(usercon->range.level[0]);
406 struct mls_level *usercon_clr = &(usercon->range.level[1]);
407
408 /* Honor the user's default level if we can */
409 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
410 *usercon_sen = *user_def;
411 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
412 *usercon_sen = *fromcon_sen;
413 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
414 *usercon_sen = *user_low;
415 } else
416 return -EINVAL;
417
418 /* Lower the clearance of available contexts
419 if the clearance of "fromcon" is lower than
420 that of the user's default clearance (but
421 only if the "fromcon" clearance dominates
422 the user's computed sensitivity level) */
423 if (mls_level_dom(user_clr, fromcon_clr)) {
424 *usercon_clr = *fromcon_clr;
425 } else if (mls_level_dom(fromcon_clr, user_clr)) {
426 *usercon_clr = *user_clr;
427 } else
428 return -EINVAL;
429 }
430
431 return 0;
432}
433
434/*
435 * Convert the MLS fields in the security context
436 * structure `c' from the values specified in the
437 * policy `oldp' to the values specified in the policy `newp'.
438 */
439int mls_convert_context(struct policydb *oldp,
440 struct policydb *newp,
441 struct context *c)
442{
443 struct level_datum *levdatum;
444 struct cat_datum *catdatum;
445 struct ebitmap bitmap;
446 int l, i;
447
448 if (!selinux_mls_enabled)
449 return 0;
450
451 for (l = 0; l < 2; l++) {
452 levdatum = hashtab_search(newp->p_levels.table,
453 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
454
455 if (!levdatum)
456 return -EINVAL;
457 c->range.level[l].sens = levdatum->level->sens;
458
459 ebitmap_init(&bitmap);
460 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
461 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
462 int rc;
463
464 catdatum = hashtab_search(newp->p_cats.table,
465 oldp->p_cat_val_to_name[i - 1]);
466 if (!catdatum)
467 return -EINVAL;
468 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
469 if (rc)
470 return rc;
471 }
472 }
473 ebitmap_destroy(&c->range.level[l].cat);
474 c->range.level[l].cat = bitmap;
475 }
476
477 return 0;
478}
479
480int mls_compute_sid(struct context *scontext,
481 struct context *tcontext,
482 u16 tclass,
483 u32 specified,
484 struct context *newcontext)
485{
486 if (!selinux_mls_enabled)
487 return 0;
488
489 switch (specified) {
490 case AVTAB_TRANSITION:
491 if (tclass == SECCLASS_PROCESS) {
492 struct range_trans *rangetr;
493 /* Look for a range transition rule. */
494 for (rangetr = policydb.range_tr; rangetr;
495 rangetr = rangetr->next) {
496 if (rangetr->dom == scontext->type &&
497 rangetr->type == tcontext->type) {
498 /* Set the range from the rule */
499 return mls_range_set(newcontext,
500 &rangetr->range);
501 }
502 }
503 }
504 /* Fallthrough */
505 case AVTAB_CHANGE:
506 if (tclass == SECCLASS_PROCESS)
507 /* Use the process MLS attributes. */
508 return mls_copy_context(newcontext, scontext);
509 else
510 /* Use the process effective MLS attributes. */
511 return mls_scopy_context(newcontext, scontext);
512 case AVTAB_MEMBER:
513 /* Only polyinstantiate the MLS attributes if
514 the type is being polyinstantiated */
515 if (newcontext->type != tcontext->type) {
516 /* Use the process effective MLS attributes. */
517 return mls_scopy_context(newcontext, scontext);
518 } else {
519 /* Use the related object MLS attributes. */
520 return mls_copy_context(newcontext, tcontext);
521 }
522 default:
523 return -EINVAL;
524 }
525 return -EINVAL;
526}
527
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
new file mode 100644
index 000000000000..0d37beaa85e2
--- /dev/null
+++ b/security/selinux/ss/mls.h
@@ -0,0 +1,42 @@
1/*
2 * Multi-level security (MLS) policy operations.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6/*
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * Support for enhanced MLS infrastructure.
10 *
11 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
12 */
13
14#ifndef _SS_MLS_H_
15#define _SS_MLS_H_
16
17#include "context.h"
18#include "policydb.h"
19
20int mls_compute_context_len(struct context *context);
21void mls_sid_to_context(struct context *context, char **scontext);
22int mls_context_isvalid(struct policydb *p, struct context *c);
23
24int mls_context_to_sid(char oldc,
25 char **scontext,
26 struct context *context);
27
28int mls_convert_context(struct policydb *oldp,
29 struct policydb *newp,
30 struct context *context);
31
32int mls_compute_sid(struct context *scontext,
33 struct context *tcontext,
34 u16 tclass,
35 u32 specified,
36 struct context *newcontext);
37
38int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
39 struct context *usercon);
40
41#endif /* _SS_MLS_H */
42
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h
new file mode 100644
index 000000000000..0c692d58d489
--- /dev/null
+++ b/security/selinux/ss/mls_types.h
@@ -0,0 +1,56 @@
1/*
2 * Type definitions for the multi-level security (MLS) policy.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6/*
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * Support for enhanced MLS infrastructure.
10 *
11 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
12 */
13
14#ifndef _SS_MLS_TYPES_H_
15#define _SS_MLS_TYPES_H_
16
17#include "security.h"
18
19struct mls_level {
20 u32 sens; /* sensitivity */
21 struct ebitmap cat; /* category set */
22};
23
24struct mls_range {
25 struct mls_level level[2]; /* low == level[0], high == level[1] */
26};
27
28static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
29{
30 if (!selinux_mls_enabled)
31 return 1;
32
33 return ((l1->sens == l2->sens) &&
34 ebitmap_cmp(&l1->cat, &l2->cat));
35}
36
37static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
38{
39 if (!selinux_mls_enabled)
40 return 1;
41
42 return ((l1->sens >= l2->sens) &&
43 ebitmap_contains(&l1->cat, &l2->cat));
44}
45
46#define mls_level_incomp(l1, l2) \
47(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
48
49#define mls_level_between(l1, l2, l3) \
50(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
51
52#define mls_range_contains(r1, r2) \
53(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
54 mls_level_dom(&(r1).level[1], &(r2).level[1]))
55
56#endif /* _SS_MLS_TYPES_H_ */
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
new file mode 100644
index 000000000000..14190efbf333
--- /dev/null
+++ b/security/selinux/ss/policydb.c
@@ -0,0 +1,1843 @@
1/*
2 * Implementation of the policy database.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6
7/*
8 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
9 *
10 * Support for enhanced MLS infrastructure.
11 *
12 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
13 *
14 * Added conditional policy language extensions
15 *
16 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
17 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, version 2.
21 */
22
23#include <linux/kernel.h>
24#include <linux/slab.h>
25#include <linux/string.h>
26#include <linux/errno.h>
27#include "security.h"
28
29#include "policydb.h"
30#include "conditional.h"
31#include "mls.h"
32
33#define _DEBUG_HASHES
34
35#ifdef DEBUG_HASHES
36static char *symtab_name[SYM_NUM] = {
37 "common prefixes",
38 "classes",
39 "roles",
40 "types",
41 "users",
42 "bools",
43 "levels",
44 "categories",
45};
46#endif
47
48int selinux_mls_enabled = 0;
49
50static unsigned int symtab_sizes[SYM_NUM] = {
51 2,
52 32,
53 16,
54 512,
55 128,
56 16,
57 16,
58 16,
59};
60
61struct policydb_compat_info {
62 int version;
63 int sym_num;
64 int ocon_num;
65};
66
67/* These need to be updated if SYM_NUM or OCON_NUM changes */
68static struct policydb_compat_info policydb_compat[] = {
69 {
70 .version = POLICYDB_VERSION_BASE,
71 .sym_num = SYM_NUM - 3,
72 .ocon_num = OCON_NUM - 1,
73 },
74 {
75 .version = POLICYDB_VERSION_BOOL,
76 .sym_num = SYM_NUM - 2,
77 .ocon_num = OCON_NUM - 1,
78 },
79 {
80 .version = POLICYDB_VERSION_IPV6,
81 .sym_num = SYM_NUM - 2,
82 .ocon_num = OCON_NUM,
83 },
84 {
85 .version = POLICYDB_VERSION_NLCLASS,
86 .sym_num = SYM_NUM - 2,
87 .ocon_num = OCON_NUM,
88 },
89 {
90 .version = POLICYDB_VERSION_MLS,
91 .sym_num = SYM_NUM,
92 .ocon_num = OCON_NUM,
93 },
94};
95
96static struct policydb_compat_info *policydb_lookup_compat(int version)
97{
98 int i;
99 struct policydb_compat_info *info = NULL;
100
101 for (i = 0; i < sizeof(policydb_compat)/sizeof(*info); i++) {
102 if (policydb_compat[i].version == version) {
103 info = &policydb_compat[i];
104 break;
105 }
106 }
107 return info;
108}
109
110/*
111 * Initialize the role table.
112 */
113static int roles_init(struct policydb *p)
114{
115 char *key = NULL;
116 int rc;
117 struct role_datum *role;
118
119 role = kmalloc(sizeof(*role), GFP_KERNEL);
120 if (!role) {
121 rc = -ENOMEM;
122 goto out;
123 }
124 memset(role, 0, sizeof(*role));
125 role->value = ++p->p_roles.nprim;
126 if (role->value != OBJECT_R_VAL) {
127 rc = -EINVAL;
128 goto out_free_role;
129 }
130 key = kmalloc(strlen(OBJECT_R)+1,GFP_KERNEL);
131 if (!key) {
132 rc = -ENOMEM;
133 goto out_free_role;
134 }
135 strcpy(key, OBJECT_R);
136 rc = hashtab_insert(p->p_roles.table, key, role);
137 if (rc)
138 goto out_free_key;
139out:
140 return rc;
141
142out_free_key:
143 kfree(key);
144out_free_role:
145 kfree(role);
146 goto out;
147}
148
149/*
150 * Initialize a policy database structure.
151 */
152static int policydb_init(struct policydb *p)
153{
154 int i, rc;
155
156 memset(p, 0, sizeof(*p));
157
158 for (i = 0; i < SYM_NUM; i++) {
159 rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
160 if (rc)
161 goto out_free_symtab;
162 }
163
164 rc = avtab_init(&p->te_avtab);
165 if (rc)
166 goto out_free_symtab;
167
168 rc = roles_init(p);
169 if (rc)
170 goto out_free_avtab;
171
172 rc = cond_policydb_init(p);
173 if (rc)
174 goto out_free_avtab;
175
176out:
177 return rc;
178
179out_free_avtab:
180 avtab_destroy(&p->te_avtab);
181
182out_free_symtab:
183 for (i = 0; i < SYM_NUM; i++)
184 hashtab_destroy(p->symtab[i].table);
185 goto out;
186}
187
188/*
189 * The following *_index functions are used to
190 * define the val_to_name and val_to_struct arrays
191 * in a policy database structure. The val_to_name
192 * arrays are used when converting security context
193 * structures into string representations. The
194 * val_to_struct arrays are used when the attributes
195 * of a class, role, or user are needed.
196 */
197
198static int common_index(void *key, void *datum, void *datap)
199{
200 struct policydb *p;
201 struct common_datum *comdatum;
202
203 comdatum = datum;
204 p = datap;
205 if (!comdatum->value || comdatum->value > p->p_commons.nprim)
206 return -EINVAL;
207 p->p_common_val_to_name[comdatum->value - 1] = key;
208 return 0;
209}
210
211static int class_index(void *key, void *datum, void *datap)
212{
213 struct policydb *p;
214 struct class_datum *cladatum;
215
216 cladatum = datum;
217 p = datap;
218 if (!cladatum->value || cladatum->value > p->p_classes.nprim)
219 return -EINVAL;
220 p->p_class_val_to_name[cladatum->value - 1] = key;
221 p->class_val_to_struct[cladatum->value - 1] = cladatum;
222 return 0;
223}
224
225static int role_index(void *key, void *datum, void *datap)
226{
227 struct policydb *p;
228 struct role_datum *role;
229
230 role = datum;
231 p = datap;
232 if (!role->value || role->value > p->p_roles.nprim)
233 return -EINVAL;
234 p->p_role_val_to_name[role->value - 1] = key;
235 p->role_val_to_struct[role->value - 1] = role;
236 return 0;
237}
238
239static int type_index(void *key, void *datum, void *datap)
240{
241 struct policydb *p;
242 struct type_datum *typdatum;
243
244 typdatum = datum;
245 p = datap;
246
247 if (typdatum->primary) {
248 if (!typdatum->value || typdatum->value > p->p_types.nprim)
249 return -EINVAL;
250 p->p_type_val_to_name[typdatum->value - 1] = key;
251 }
252
253 return 0;
254}
255
256static int user_index(void *key, void *datum, void *datap)
257{
258 struct policydb *p;
259 struct user_datum *usrdatum;
260
261 usrdatum = datum;
262 p = datap;
263 if (!usrdatum->value || usrdatum->value > p->p_users.nprim)
264 return -EINVAL;
265 p->p_user_val_to_name[usrdatum->value - 1] = key;
266 p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
267 return 0;
268}
269
270static int sens_index(void *key, void *datum, void *datap)
271{
272 struct policydb *p;
273 struct level_datum *levdatum;
274
275 levdatum = datum;
276 p = datap;
277
278 if (!levdatum->isalias) {
279 if (!levdatum->level->sens ||
280 levdatum->level->sens > p->p_levels.nprim)
281 return -EINVAL;
282 p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
283 }
284
285 return 0;
286}
287
288static int cat_index(void *key, void *datum, void *datap)
289{
290 struct policydb *p;
291 struct cat_datum *catdatum;
292
293 catdatum = datum;
294 p = datap;
295
296 if (!catdatum->isalias) {
297 if (!catdatum->value || catdatum->value > p->p_cats.nprim)
298 return -EINVAL;
299 p->p_cat_val_to_name[catdatum->value - 1] = key;
300 }
301
302 return 0;
303}
304
305static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
306{
307 common_index,
308 class_index,
309 role_index,
310 type_index,
311 user_index,
312 cond_index_bool,
313 sens_index,
314 cat_index,
315};
316
317/*
318 * Define the common val_to_name array and the class
319 * val_to_name and val_to_struct arrays in a policy
320 * database structure.
321 *
322 * Caller must clean up upon failure.
323 */
324static int policydb_index_classes(struct policydb *p)
325{
326 int rc;
327
328 p->p_common_val_to_name =
329 kmalloc(p->p_commons.nprim * sizeof(char *), GFP_KERNEL);
330 if (!p->p_common_val_to_name) {
331 rc = -ENOMEM;
332 goto out;
333 }
334
335 rc = hashtab_map(p->p_commons.table, common_index, p);
336 if (rc)
337 goto out;
338
339 p->class_val_to_struct =
340 kmalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)), GFP_KERNEL);
341 if (!p->class_val_to_struct) {
342 rc = -ENOMEM;
343 goto out;
344 }
345
346 p->p_class_val_to_name =
347 kmalloc(p->p_classes.nprim * sizeof(char *), GFP_KERNEL);
348 if (!p->p_class_val_to_name) {
349 rc = -ENOMEM;
350 goto out;
351 }
352
353 rc = hashtab_map(p->p_classes.table, class_index, p);
354out:
355 return rc;
356}
357
358#ifdef DEBUG_HASHES
359static void symtab_hash_eval(struct symtab *s)
360{
361 int i;
362
363 for (i = 0; i < SYM_NUM; i++) {
364 struct hashtab *h = s[i].table;
365 struct hashtab_info info;
366
367 hashtab_stat(h, &info);
368 printk(KERN_INFO "%s: %d entries and %d/%d buckets used, "
369 "longest chain length %d\n", symtab_name[i], h->nel,
370 info.slots_used, h->size, info.max_chain_len);
371 }
372}
373#endif
374
375/*
376 * Define the other val_to_name and val_to_struct arrays
377 * in a policy database structure.
378 *
379 * Caller must clean up on failure.
380 */
381static int policydb_index_others(struct policydb *p)
382{
383 int i, rc = 0;
384
385 printk(KERN_INFO "security: %d users, %d roles, %d types, %d bools",
386 p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
387 if (selinux_mls_enabled)
388 printk(", %d sens, %d cats", p->p_levels.nprim,
389 p->p_cats.nprim);
390 printk("\n");
391
392 printk(KERN_INFO "security: %d classes, %d rules\n",
393 p->p_classes.nprim, p->te_avtab.nel);
394
395#ifdef DEBUG_HASHES
396 avtab_hash_eval(&p->te_avtab, "rules");
397 symtab_hash_eval(p->symtab);
398#endif
399
400 p->role_val_to_struct =
401 kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)),
402 GFP_KERNEL);
403 if (!p->role_val_to_struct) {
404 rc = -ENOMEM;
405 goto out;
406 }
407
408 p->user_val_to_struct =
409 kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)),
410 GFP_KERNEL);
411 if (!p->user_val_to_struct) {
412 rc = -ENOMEM;
413 goto out;
414 }
415
416 if (cond_init_bool_indexes(p)) {
417 rc = -ENOMEM;
418 goto out;
419 }
420
421 for (i = SYM_ROLES; i < SYM_NUM; i++) {
422 p->sym_val_to_name[i] =
423 kmalloc(p->symtab[i].nprim * sizeof(char *), GFP_KERNEL);
424 if (!p->sym_val_to_name[i]) {
425 rc = -ENOMEM;
426 goto out;
427 }
428 rc = hashtab_map(p->symtab[i].table, index_f[i], p);
429 if (rc)
430 goto out;
431 }
432
433out:
434 return rc;
435}
436
437/*
438 * The following *_destroy functions are used to
439 * free any memory allocated for each kind of
440 * symbol data in the policy database.
441 */
442
443static int perm_destroy(void *key, void *datum, void *p)
444{
445 kfree(key);
446 kfree(datum);
447 return 0;
448}
449
450static int common_destroy(void *key, void *datum, void *p)
451{
452 struct common_datum *comdatum;
453
454 kfree(key);
455 comdatum = datum;
456 hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
457 hashtab_destroy(comdatum->permissions.table);
458 kfree(datum);
459 return 0;
460}
461
462static int class_destroy(void *key, void *datum, void *p)
463{
464 struct class_datum *cladatum;
465 struct constraint_node *constraint, *ctemp;
466 struct constraint_expr *e, *etmp;
467
468 kfree(key);
469 cladatum = datum;
470 hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
471 hashtab_destroy(cladatum->permissions.table);
472 constraint = cladatum->constraints;
473 while (constraint) {
474 e = constraint->expr;
475 while (e) {
476 ebitmap_destroy(&e->names);
477 etmp = e;
478 e = e->next;
479 kfree(etmp);
480 }
481 ctemp = constraint;
482 constraint = constraint->next;
483 kfree(ctemp);
484 }
485
486 constraint = cladatum->validatetrans;
487 while (constraint) {
488 e = constraint->expr;
489 while (e) {
490 ebitmap_destroy(&e->names);
491 etmp = e;
492 e = e->next;
493 kfree(etmp);
494 }
495 ctemp = constraint;
496 constraint = constraint->next;
497 kfree(ctemp);
498 }
499
500 kfree(cladatum->comkey);
501 kfree(datum);
502 return 0;
503}
504
505static int role_destroy(void *key, void *datum, void *p)
506{
507 struct role_datum *role;
508
509 kfree(key);
510 role = datum;
511 ebitmap_destroy(&role->dominates);
512 ebitmap_destroy(&role->types);
513 kfree(datum);
514 return 0;
515}
516
517static int type_destroy(void *key, void *datum, void *p)
518{
519 kfree(key);
520 kfree(datum);
521 return 0;
522}
523
524static int user_destroy(void *key, void *datum, void *p)
525{
526 struct user_datum *usrdatum;
527
528 kfree(key);
529 usrdatum = datum;
530 ebitmap_destroy(&usrdatum->roles);
531 ebitmap_destroy(&usrdatum->range.level[0].cat);
532 ebitmap_destroy(&usrdatum->range.level[1].cat);
533 ebitmap_destroy(&usrdatum->dfltlevel.cat);
534 kfree(datum);
535 return 0;
536}
537
538static int sens_destroy(void *key, void *datum, void *p)
539{
540 struct level_datum *levdatum;
541
542 kfree(key);
543 levdatum = datum;
544 ebitmap_destroy(&levdatum->level->cat);
545 kfree(levdatum->level);
546 kfree(datum);
547 return 0;
548}
549
550static int cat_destroy(void *key, void *datum, void *p)
551{
552 kfree(key);
553 kfree(datum);
554 return 0;
555}
556
557static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
558{
559 common_destroy,
560 class_destroy,
561 role_destroy,
562 type_destroy,
563 user_destroy,
564 cond_destroy_bool,
565 sens_destroy,
566 cat_destroy,
567};
568
569static void ocontext_destroy(struct ocontext *c, int i)
570{
571 context_destroy(&c->context[0]);
572 context_destroy(&c->context[1]);
573 if (i == OCON_ISID || i == OCON_FS ||
574 i == OCON_NETIF || i == OCON_FSUSE)
575 kfree(c->u.name);
576 kfree(c);
577}
578
579/*
580 * Free any memory allocated by a policy database structure.
581 */
582void policydb_destroy(struct policydb *p)
583{
584 struct ocontext *c, *ctmp;
585 struct genfs *g, *gtmp;
586 int i;
587
588 for (i = 0; i < SYM_NUM; i++) {
589 hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
590 hashtab_destroy(p->symtab[i].table);
591 }
592
593 for (i = 0; i < SYM_NUM; i++) {
594 if (p->sym_val_to_name[i])
595 kfree(p->sym_val_to_name[i]);
596 }
597
598 if (p->class_val_to_struct)
599 kfree(p->class_val_to_struct);
600 if (p->role_val_to_struct)
601 kfree(p->role_val_to_struct);
602 if (p->user_val_to_struct)
603 kfree(p->user_val_to_struct);
604
605 avtab_destroy(&p->te_avtab);
606
607 for (i = 0; i < OCON_NUM; i++) {
608 c = p->ocontexts[i];
609 while (c) {
610 ctmp = c;
611 c = c->next;
612 ocontext_destroy(ctmp,i);
613 }
614 }
615
616 g = p->genfs;
617 while (g) {
618 kfree(g->fstype);
619 c = g->head;
620 while (c) {
621 ctmp = c;
622 c = c->next;
623 ocontext_destroy(ctmp,OCON_FSUSE);
624 }
625 gtmp = g;
626 g = g->next;
627 kfree(gtmp);
628 }
629
630 cond_policydb_destroy(p);
631
632 return;
633}
634
635/*
636 * Load the initial SIDs specified in a policy database
637 * structure into a SID table.
638 */
639int policydb_load_isids(struct policydb *p, struct sidtab *s)
640{
641 struct ocontext *head, *c;
642 int rc;
643
644 rc = sidtab_init(s);
645 if (rc) {
646 printk(KERN_ERR "security: out of memory on SID table init\n");
647 goto out;
648 }
649
650 head = p->ocontexts[OCON_ISID];
651 for (c = head; c; c = c->next) {
652 if (!c->context[0].user) {
653 printk(KERN_ERR "security: SID %s was never "
654 "defined.\n", c->u.name);
655 rc = -EINVAL;
656 goto out;
657 }
658 if (sidtab_insert(s, c->sid[0], &c->context[0])) {
659 printk(KERN_ERR "security: unable to load initial "
660 "SID %s.\n", c->u.name);
661 rc = -EINVAL;
662 goto out;
663 }
664 }
665out:
666 return rc;
667}
668
669/*
670 * Return 1 if the fields in the security context
671 * structure `c' are valid. Return 0 otherwise.
672 */
673int policydb_context_isvalid(struct policydb *p, struct context *c)
674{
675 struct role_datum *role;
676 struct user_datum *usrdatum;
677
678 if (!c->role || c->role > p->p_roles.nprim)
679 return 0;
680
681 if (!c->user || c->user > p->p_users.nprim)
682 return 0;
683
684 if (!c->type || c->type > p->p_types.nprim)
685 return 0;
686
687 if (c->role != OBJECT_R_VAL) {
688 /*
689 * Role must be authorized for the type.
690 */
691 role = p->role_val_to_struct[c->role - 1];
692 if (!ebitmap_get_bit(&role->types,
693 c->type - 1))
694 /* role may not be associated with type */
695 return 0;
696
697 /*
698 * User must be authorized for the role.
699 */
700 usrdatum = p->user_val_to_struct[c->user - 1];
701 if (!usrdatum)
702 return 0;
703
704 if (!ebitmap_get_bit(&usrdatum->roles,
705 c->role - 1))
706 /* user may not be associated with role */
707 return 0;
708 }
709
710 if (!mls_context_isvalid(p, c))
711 return 0;
712
713 return 1;
714}
715
716/*
717 * Read a MLS range structure from a policydb binary
718 * representation file.
719 */
720static int mls_read_range_helper(struct mls_range *r, void *fp)
721{
722 u32 buf[2], items;
723 int rc;
724
725 rc = next_entry(buf, fp, sizeof(u32));
726 if (rc < 0)
727 goto out;
728
729 items = le32_to_cpu(buf[0]);
730 if (items > ARRAY_SIZE(buf)) {
731 printk(KERN_ERR "security: mls: range overflow\n");
732 rc = -EINVAL;
733 goto out;
734 }
735 rc = next_entry(buf, fp, sizeof(u32) * items);
736 if (rc < 0) {
737 printk(KERN_ERR "security: mls: truncated range\n");
738 goto out;
739 }
740 r->level[0].sens = le32_to_cpu(buf[0]);
741 if (items > 1)
742 r->level[1].sens = le32_to_cpu(buf[1]);
743 else
744 r->level[1].sens = r->level[0].sens;
745
746 rc = ebitmap_read(&r->level[0].cat, fp);
747 if (rc) {
748 printk(KERN_ERR "security: mls: error reading low "
749 "categories\n");
750 goto out;
751 }
752 if (items > 1) {
753 rc = ebitmap_read(&r->level[1].cat, fp);
754 if (rc) {
755 printk(KERN_ERR "security: mls: error reading high "
756 "categories\n");
757 goto bad_high;
758 }
759 } else {
760 rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
761 if (rc) {
762 printk(KERN_ERR "security: mls: out of memory\n");
763 goto bad_high;
764 }
765 }
766
767 rc = 0;
768out:
769 return rc;
770bad_high:
771 ebitmap_destroy(&r->level[0].cat);
772 goto out;
773}
774
775/*
776 * Read and validate a security context structure
777 * from a policydb binary representation file.
778 */
779static int context_read_and_validate(struct context *c,
780 struct policydb *p,
781 void *fp)
782{
783 u32 buf[3];
784 int rc;
785
786 rc = next_entry(buf, fp, sizeof buf);
787 if (rc < 0) {
788 printk(KERN_ERR "security: context truncated\n");
789 goto out;
790 }
791 c->user = le32_to_cpu(buf[0]);
792 c->role = le32_to_cpu(buf[1]);
793 c->type = le32_to_cpu(buf[2]);
794 if (p->policyvers >= POLICYDB_VERSION_MLS) {
795 if (mls_read_range_helper(&c->range, fp)) {
796 printk(KERN_ERR "security: error reading MLS range of "
797 "context\n");
798 rc = -EINVAL;
799 goto out;
800 }
801 }
802
803 if (!policydb_context_isvalid(p, c)) {
804 printk(KERN_ERR "security: invalid security context\n");
805 context_destroy(c);
806 rc = -EINVAL;
807 }
808out:
809 return rc;
810}
811
812/*
813 * The following *_read functions are used to
814 * read the symbol data from a policy database
815 * binary representation file.
816 */
817
818static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
819{
820 char *key = NULL;
821 struct perm_datum *perdatum;
822 int rc;
823 u32 buf[2], len;
824
825 perdatum = kmalloc(sizeof(*perdatum), GFP_KERNEL);
826 if (!perdatum) {
827 rc = -ENOMEM;
828 goto out;
829 }
830 memset(perdatum, 0, sizeof(*perdatum));
831
832 rc = next_entry(buf, fp, sizeof buf);
833 if (rc < 0)
834 goto bad;
835
836 len = le32_to_cpu(buf[0]);
837 perdatum->value = le32_to_cpu(buf[1]);
838
839 key = kmalloc(len + 1,GFP_KERNEL);
840 if (!key) {
841 rc = -ENOMEM;
842 goto bad;
843 }
844 rc = next_entry(key, fp, len);
845 if (rc < 0)
846 goto bad;
847 key[len] = 0;
848
849 rc = hashtab_insert(h, key, perdatum);
850 if (rc)
851 goto bad;
852out:
853 return rc;
854bad:
855 perm_destroy(key, perdatum, NULL);
856 goto out;
857}
858
859static int common_read(struct policydb *p, struct hashtab *h, void *fp)
860{
861 char *key = NULL;
862 struct common_datum *comdatum;
863 u32 buf[4], len, nel;
864 int i, rc;
865
866 comdatum = kmalloc(sizeof(*comdatum), GFP_KERNEL);
867 if (!comdatum) {
868 rc = -ENOMEM;
869 goto out;
870 }
871 memset(comdatum, 0, sizeof(*comdatum));
872
873 rc = next_entry(buf, fp, sizeof buf);
874 if (rc < 0)
875 goto bad;
876
877 len = le32_to_cpu(buf[0]);
878 comdatum->value = le32_to_cpu(buf[1]);
879
880 rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
881 if (rc)
882 goto bad;
883 comdatum->permissions.nprim = le32_to_cpu(buf[2]);
884 nel = le32_to_cpu(buf[3]);
885
886 key = kmalloc(len + 1,GFP_KERNEL);
887 if (!key) {
888 rc = -ENOMEM;
889 goto bad;
890 }
891 rc = next_entry(key, fp, len);
892 if (rc < 0)
893 goto bad;
894 key[len] = 0;
895
896 for (i = 0; i < nel; i++) {
897 rc = perm_read(p, comdatum->permissions.table, fp);
898 if (rc)
899 goto bad;
900 }
901
902 rc = hashtab_insert(h, key, comdatum);
903 if (rc)
904 goto bad;
905out:
906 return rc;
907bad:
908 common_destroy(key, comdatum, NULL);
909 goto out;
910}
911
912static int read_cons_helper(struct constraint_node **nodep, int ncons,
913 int allowxtarget, void *fp)
914{
915 struct constraint_node *c, *lc;
916 struct constraint_expr *e, *le;
917 u32 buf[3], nexpr;
918 int rc, i, j, depth;
919
920 lc = NULL;
921 for (i = 0; i < ncons; i++) {
922 c = kmalloc(sizeof(*c), GFP_KERNEL);
923 if (!c)
924 return -ENOMEM;
925 memset(c, 0, sizeof(*c));
926
927 if (lc) {
928 lc->next = c;
929 } else {
930 *nodep = c;
931 }
932
933 rc = next_entry(buf, fp, (sizeof(u32) * 2));
934 if (rc < 0)
935 return rc;
936 c->permissions = le32_to_cpu(buf[0]);
937 nexpr = le32_to_cpu(buf[1]);
938 le = NULL;
939 depth = -1;
940 for (j = 0; j < nexpr; j++) {
941 e = kmalloc(sizeof(*e), GFP_KERNEL);
942 if (!e)
943 return -ENOMEM;
944 memset(e, 0, sizeof(*e));
945
946 if (le) {
947 le->next = e;
948 } else {
949 c->expr = e;
950 }
951
952 rc = next_entry(buf, fp, (sizeof(u32) * 3));
953 if (rc < 0)
954 return rc;
955 e->expr_type = le32_to_cpu(buf[0]);
956 e->attr = le32_to_cpu(buf[1]);
957 e->op = le32_to_cpu(buf[2]);
958
959 switch (e->expr_type) {
960 case CEXPR_NOT:
961 if (depth < 0)
962 return -EINVAL;
963 break;
964 case CEXPR_AND:
965 case CEXPR_OR:
966 if (depth < 1)
967 return -EINVAL;
968 depth--;
969 break;
970 case CEXPR_ATTR:
971 if (depth == (CEXPR_MAXDEPTH - 1))
972 return -EINVAL;
973 depth++;
974 break;
975 case CEXPR_NAMES:
976 if (!allowxtarget && (e->attr & CEXPR_XTARGET))
977 return -EINVAL;
978 if (depth == (CEXPR_MAXDEPTH - 1))
979 return -EINVAL;
980 depth++;
981 if (ebitmap_read(&e->names, fp))
982 return -EINVAL;
983 break;
984 default:
985 return -EINVAL;
986 }
987 le = e;
988 }
989 if (depth != 0)
990 return -EINVAL;
991 lc = c;
992 }
993
994 return 0;
995}
996
997static int class_read(struct policydb *p, struct hashtab *h, void *fp)
998{
999 char *key = NULL;
1000 struct class_datum *cladatum;
1001 u32 buf[6], len, len2, ncons, nel;
1002 int i, rc;
1003
1004 cladatum = kmalloc(sizeof(*cladatum), GFP_KERNEL);
1005 if (!cladatum) {
1006 rc = -ENOMEM;
1007 goto out;
1008 }
1009 memset(cladatum, 0, sizeof(*cladatum));
1010
1011 rc = next_entry(buf, fp, sizeof(u32)*6);
1012 if (rc < 0)
1013 goto bad;
1014
1015 len = le32_to_cpu(buf[0]);
1016 len2 = le32_to_cpu(buf[1]);
1017 cladatum->value = le32_to_cpu(buf[2]);
1018
1019 rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
1020 if (rc)
1021 goto bad;
1022 cladatum->permissions.nprim = le32_to_cpu(buf[3]);
1023 nel = le32_to_cpu(buf[4]);
1024
1025 ncons = le32_to_cpu(buf[5]);
1026
1027 key = kmalloc(len + 1,GFP_KERNEL);
1028 if (!key) {
1029 rc = -ENOMEM;
1030 goto bad;
1031 }
1032 rc = next_entry(key, fp, len);
1033 if (rc < 0)
1034 goto bad;
1035 key[len] = 0;
1036
1037 if (len2) {
1038 cladatum->comkey = kmalloc(len2 + 1,GFP_KERNEL);
1039 if (!cladatum->comkey) {
1040 rc = -ENOMEM;
1041 goto bad;
1042 }
1043 rc = next_entry(cladatum->comkey, fp, len2);
1044 if (rc < 0)
1045 goto bad;
1046 cladatum->comkey[len2] = 0;
1047
1048 cladatum->comdatum = hashtab_search(p->p_commons.table,
1049 cladatum->comkey);
1050 if (!cladatum->comdatum) {
1051 printk(KERN_ERR "security: unknown common %s\n",
1052 cladatum->comkey);
1053 rc = -EINVAL;
1054 goto bad;
1055 }
1056 }
1057 for (i = 0; i < nel; i++) {
1058 rc = perm_read(p, cladatum->permissions.table, fp);
1059 if (rc)
1060 goto bad;
1061 }
1062
1063 rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
1064 if (rc)
1065 goto bad;
1066
1067 if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {
1068 /* grab the validatetrans rules */
1069 rc = next_entry(buf, fp, sizeof(u32));
1070 if (rc < 0)
1071 goto bad;
1072 ncons = le32_to_cpu(buf[0]);
1073 rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
1074 if (rc)
1075 goto bad;
1076 }
1077
1078 rc = hashtab_insert(h, key, cladatum);
1079 if (rc)
1080 goto bad;
1081
1082 rc = 0;
1083out:
1084 return rc;
1085bad:
1086 class_destroy(key, cladatum, NULL);
1087 goto out;
1088}
1089
1090static int role_read(struct policydb *p, struct hashtab *h, void *fp)
1091{
1092 char *key = NULL;
1093 struct role_datum *role;
1094 int rc;
1095 u32 buf[2], len;
1096
1097 role = kmalloc(sizeof(*role), GFP_KERNEL);
1098 if (!role) {
1099 rc = -ENOMEM;
1100 goto out;
1101 }
1102 memset(role, 0, sizeof(*role));
1103
1104 rc = next_entry(buf, fp, sizeof buf);
1105 if (rc < 0)
1106 goto bad;
1107
1108 len = le32_to_cpu(buf[0]);
1109 role->value = le32_to_cpu(buf[1]);
1110
1111 key = kmalloc(len + 1,GFP_KERNEL);
1112 if (!key) {
1113 rc = -ENOMEM;
1114 goto bad;
1115 }
1116 rc = next_entry(key, fp, len);
1117 if (rc < 0)
1118 goto bad;
1119 key[len] = 0;
1120
1121 rc = ebitmap_read(&role->dominates, fp);
1122 if (rc)
1123 goto bad;
1124
1125 rc = ebitmap_read(&role->types, fp);
1126 if (rc)
1127 goto bad;
1128
1129 if (strcmp(key, OBJECT_R) == 0) {
1130 if (role->value != OBJECT_R_VAL) {
1131 printk(KERN_ERR "Role %s has wrong value %d\n",
1132 OBJECT_R, role->value);
1133 rc = -EINVAL;
1134 goto bad;
1135 }
1136 rc = 0;
1137 goto bad;
1138 }
1139
1140 rc = hashtab_insert(h, key, role);
1141 if (rc)
1142 goto bad;
1143out:
1144 return rc;
1145bad:
1146 role_destroy(key, role, NULL);
1147 goto out;
1148}
1149
1150static int type_read(struct policydb *p, struct hashtab *h, void *fp)
1151{
1152 char *key = NULL;
1153 struct type_datum *typdatum;
1154 int rc;
1155 u32 buf[3], len;
1156
1157 typdatum = kmalloc(sizeof(*typdatum),GFP_KERNEL);
1158 if (!typdatum) {
1159 rc = -ENOMEM;
1160 return rc;
1161 }
1162 memset(typdatum, 0, sizeof(*typdatum));
1163
1164 rc = next_entry(buf, fp, sizeof buf);
1165 if (rc < 0)
1166 goto bad;
1167
1168 len = le32_to_cpu(buf[0]);
1169 typdatum->value = le32_to_cpu(buf[1]);
1170 typdatum->primary = le32_to_cpu(buf[2]);
1171
1172 key = kmalloc(len + 1,GFP_KERNEL);
1173 if (!key) {
1174 rc = -ENOMEM;
1175 goto bad;
1176 }
1177 rc = next_entry(key, fp, len);
1178 if (rc < 0)
1179 goto bad;
1180 key[len] = 0;
1181
1182 rc = hashtab_insert(h, key, typdatum);
1183 if (rc)
1184 goto bad;
1185out:
1186 return rc;
1187bad:
1188 type_destroy(key, typdatum, NULL);
1189 goto out;
1190}
1191
1192
1193/*
1194 * Read a MLS level structure from a policydb binary
1195 * representation file.
1196 */
1197static int mls_read_level(struct mls_level *lp, void *fp)
1198{
1199 u32 buf[1];
1200 int rc;
1201
1202 memset(lp, 0, sizeof(*lp));
1203
1204 rc = next_entry(buf, fp, sizeof buf);
1205 if (rc < 0) {
1206 printk(KERN_ERR "security: mls: truncated level\n");
1207 goto bad;
1208 }
1209 lp->sens = le32_to_cpu(buf[0]);
1210
1211 if (ebitmap_read(&lp->cat, fp)) {
1212 printk(KERN_ERR "security: mls: error reading level "
1213 "categories\n");
1214 goto bad;
1215 }
1216 return 0;
1217
1218bad:
1219 return -EINVAL;
1220}
1221
1222static int user_read(struct policydb *p, struct hashtab *h, void *fp)
1223{
1224 char *key = NULL;
1225 struct user_datum *usrdatum;
1226 int rc;
1227 u32 buf[2], len;
1228
1229 usrdatum = kmalloc(sizeof(*usrdatum), GFP_KERNEL);
1230 if (!usrdatum) {
1231 rc = -ENOMEM;
1232 goto out;
1233 }
1234 memset(usrdatum, 0, sizeof(*usrdatum));
1235
1236 rc = next_entry(buf, fp, sizeof buf);
1237 if (rc < 0)
1238 goto bad;
1239
1240 len = le32_to_cpu(buf[0]);
1241 usrdatum->value = le32_to_cpu(buf[1]);
1242
1243 key = kmalloc(len + 1,GFP_KERNEL);
1244 if (!key) {
1245 rc = -ENOMEM;
1246 goto bad;
1247 }
1248 rc = next_entry(key, fp, len);
1249 if (rc < 0)
1250 goto bad;
1251 key[len] = 0;
1252
1253 rc = ebitmap_read(&usrdatum->roles, fp);
1254 if (rc)
1255 goto bad;
1256
1257 if (p->policyvers >= POLICYDB_VERSION_MLS) {
1258 rc = mls_read_range_helper(&usrdatum->range, fp);
1259 if (rc)
1260 goto bad;
1261 rc = mls_read_level(&usrdatum->dfltlevel, fp);
1262 if (rc)
1263 goto bad;
1264 }
1265
1266 rc = hashtab_insert(h, key, usrdatum);
1267 if (rc)
1268 goto bad;
1269out:
1270 return rc;
1271bad:
1272 user_destroy(key, usrdatum, NULL);
1273 goto out;
1274}
1275
1276static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
1277{
1278 char *key = NULL;
1279 struct level_datum *levdatum;
1280 int rc;
1281 u32 buf[2], len;
1282
1283 levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
1284 if (!levdatum) {
1285 rc = -ENOMEM;
1286 goto out;
1287 }
1288 memset(levdatum, 0, sizeof(*levdatum));
1289
1290 rc = next_entry(buf, fp, sizeof buf);
1291 if (rc < 0)
1292 goto bad;
1293
1294 len = le32_to_cpu(buf[0]);
1295 levdatum->isalias = le32_to_cpu(buf[1]);
1296
1297 key = kmalloc(len + 1,GFP_ATOMIC);
1298 if (!key) {
1299 rc = -ENOMEM;
1300 goto bad;
1301 }
1302 rc = next_entry(key, fp, len);
1303 if (rc < 0)
1304 goto bad;
1305 key[len] = 0;
1306
1307 levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC);
1308 if (!levdatum->level) {
1309 rc = -ENOMEM;
1310 goto bad;
1311 }
1312 if (mls_read_level(levdatum->level, fp)) {
1313 rc = -EINVAL;
1314 goto bad;
1315 }
1316
1317 rc = hashtab_insert(h, key, levdatum);
1318 if (rc)
1319 goto bad;
1320out:
1321 return rc;
1322bad:
1323 sens_destroy(key, levdatum, NULL);
1324 goto out;
1325}
1326
1327static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
1328{
1329 char *key = NULL;
1330 struct cat_datum *catdatum;
1331 int rc;
1332 u32 buf[3], len;
1333
1334 catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
1335 if (!catdatum) {
1336 rc = -ENOMEM;
1337 goto out;
1338 }
1339 memset(catdatum, 0, sizeof(*catdatum));
1340
1341 rc = next_entry(buf, fp, sizeof buf);
1342 if (rc < 0)
1343 goto bad;
1344
1345 len = le32_to_cpu(buf[0]);
1346 catdatum->value = le32_to_cpu(buf[1]);
1347 catdatum->isalias = le32_to_cpu(buf[2]);
1348
1349 key = kmalloc(len + 1,GFP_ATOMIC);
1350 if (!key) {
1351 rc = -ENOMEM;
1352 goto bad;
1353 }
1354 rc = next_entry(key, fp, len);
1355 if (rc < 0)
1356 goto bad;
1357 key[len] = 0;
1358
1359 rc = hashtab_insert(h, key, catdatum);
1360 if (rc)
1361 goto bad;
1362out:
1363 return rc;
1364
1365bad:
1366 cat_destroy(key, catdatum, NULL);
1367 goto out;
1368}
1369
1370static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
1371{
1372 common_read,
1373 class_read,
1374 role_read,
1375 type_read,
1376 user_read,
1377 cond_read_bool,
1378 sens_read,
1379 cat_read,
1380};
1381
1382extern int ss_initialized;
1383
1384/*
1385 * Read the configuration data from a policy database binary
1386 * representation file into a policy database structure.
1387 */
1388int policydb_read(struct policydb *p, void *fp)
1389{
1390 struct role_allow *ra, *lra;
1391 struct role_trans *tr, *ltr;
1392 struct ocontext *l, *c, *newc;
1393 struct genfs *genfs_p, *genfs, *newgenfs;
1394 int i, j, rc;
1395 u32 buf[8], len, len2, config, nprim, nel, nel2;
1396 char *policydb_str;
1397 struct policydb_compat_info *info;
1398 struct range_trans *rt, *lrt;
1399
1400 config = 0;
1401
1402 rc = policydb_init(p);
1403 if (rc)
1404 goto out;
1405
1406 /* Read the magic number and string length. */
1407 rc = next_entry(buf, fp, sizeof(u32)* 2);
1408 if (rc < 0)
1409 goto bad;
1410
1411 for (i = 0; i < 2; i++)
1412 buf[i] = le32_to_cpu(buf[i]);
1413
1414 if (buf[0] != POLICYDB_MAGIC) {
1415 printk(KERN_ERR "security: policydb magic number 0x%x does "
1416 "not match expected magic number 0x%x\n",
1417 buf[0], POLICYDB_MAGIC);
1418 goto bad;
1419 }
1420
1421 len = buf[1];
1422 if (len != strlen(POLICYDB_STRING)) {
1423 printk(KERN_ERR "security: policydb string length %d does not "
1424 "match expected length %Zu\n",
1425 len, strlen(POLICYDB_STRING));
1426 goto bad;
1427 }
1428 policydb_str = kmalloc(len + 1,GFP_KERNEL);
1429 if (!policydb_str) {
1430 printk(KERN_ERR "security: unable to allocate memory for policydb "
1431 "string of length %d\n", len);
1432 rc = -ENOMEM;
1433 goto bad;
1434 }
1435 rc = next_entry(policydb_str, fp, len);
1436 if (rc < 0) {
1437 printk(KERN_ERR "security: truncated policydb string identifier\n");
1438 kfree(policydb_str);
1439 goto bad;
1440 }
1441 policydb_str[len] = 0;
1442 if (strcmp(policydb_str, POLICYDB_STRING)) {
1443 printk(KERN_ERR "security: policydb string %s does not match "
1444 "my string %s\n", policydb_str, POLICYDB_STRING);
1445 kfree(policydb_str);
1446 goto bad;
1447 }
1448 /* Done with policydb_str. */
1449 kfree(policydb_str);
1450 policydb_str = NULL;
1451
1452 /* Read the version, config, and table sizes. */
1453 rc = next_entry(buf, fp, sizeof(u32)*4);
1454 if (rc < 0)
1455 goto bad;
1456 for (i = 0; i < 4; i++)
1457 buf[i] = le32_to_cpu(buf[i]);
1458
1459 p->policyvers = buf[0];
1460 if (p->policyvers < POLICYDB_VERSION_MIN ||
1461 p->policyvers > POLICYDB_VERSION_MAX) {
1462 printk(KERN_ERR "security: policydb version %d does not match "
1463 "my version range %d-%d\n",
1464 buf[0], POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
1465 goto bad;
1466 }
1467
1468 if ((buf[1] & POLICYDB_CONFIG_MLS)) {
1469 if (ss_initialized && !selinux_mls_enabled) {
1470 printk(KERN_ERR "Cannot switch between non-MLS and MLS "
1471 "policies\n");
1472 goto bad;
1473 }
1474 selinux_mls_enabled = 1;
1475 config |= POLICYDB_CONFIG_MLS;
1476
1477 if (p->policyvers < POLICYDB_VERSION_MLS) {
1478 printk(KERN_ERR "security policydb version %d (MLS) "
1479 "not backwards compatible\n", p->policyvers);
1480 goto bad;
1481 }
1482 } else {
1483 if (ss_initialized && selinux_mls_enabled) {
1484 printk(KERN_ERR "Cannot switch between MLS and non-MLS "
1485 "policies\n");
1486 goto bad;
1487 }
1488 }
1489
1490 info = policydb_lookup_compat(p->policyvers);
1491 if (!info) {
1492 printk(KERN_ERR "security: unable to find policy compat info "
1493 "for version %d\n", p->policyvers);
1494 goto bad;
1495 }
1496
1497 if (buf[2] != info->sym_num || buf[3] != info->ocon_num) {
1498 printk(KERN_ERR "security: policydb table sizes (%d,%d) do "
1499 "not match mine (%d,%d)\n", buf[2], buf[3],
1500 info->sym_num, info->ocon_num);
1501 goto bad;
1502 }
1503
1504 for (i = 0; i < info->sym_num; i++) {
1505 rc = next_entry(buf, fp, sizeof(u32)*2);
1506 if (rc < 0)
1507 goto bad;
1508 nprim = le32_to_cpu(buf[0]);
1509 nel = le32_to_cpu(buf[1]);
1510 for (j = 0; j < nel; j++) {
1511 rc = read_f[i](p, p->symtab[i].table, fp);
1512 if (rc)
1513 goto bad;
1514 }
1515
1516 p->symtab[i].nprim = nprim;
1517 }
1518
1519 rc = avtab_read(&p->te_avtab, fp, config);
1520 if (rc)
1521 goto bad;
1522
1523 if (p->policyvers >= POLICYDB_VERSION_BOOL) {
1524 rc = cond_read_list(p, fp);
1525 if (rc)
1526 goto bad;
1527 }
1528
1529 rc = next_entry(buf, fp, sizeof(u32));
1530 if (rc < 0)
1531 goto bad;
1532 nel = le32_to_cpu(buf[0]);
1533 ltr = NULL;
1534 for (i = 0; i < nel; i++) {
1535 tr = kmalloc(sizeof(*tr), GFP_KERNEL);
1536 if (!tr) {
1537 rc = -ENOMEM;
1538 goto bad;
1539 }
1540 memset(tr, 0, sizeof(*tr));
1541 if (ltr) {
1542 ltr->next = tr;
1543 } else {
1544 p->role_tr = tr;
1545 }
1546 rc = next_entry(buf, fp, sizeof(u32)*3);
1547 if (rc < 0)
1548 goto bad;
1549 tr->role = le32_to_cpu(buf[0]);
1550 tr->type = le32_to_cpu(buf[1]);
1551 tr->new_role = le32_to_cpu(buf[2]);
1552 ltr = tr;
1553 }
1554
1555 rc = next_entry(buf, fp, sizeof(u32));
1556 if (rc < 0)
1557 goto bad;
1558 nel = le32_to_cpu(buf[0]);
1559 lra = NULL;
1560 for (i = 0; i < nel; i++) {
1561 ra = kmalloc(sizeof(*ra), GFP_KERNEL);
1562 if (!ra) {
1563 rc = -ENOMEM;
1564 goto bad;
1565 }
1566 memset(ra, 0, sizeof(*ra));
1567 if (lra) {
1568 lra->next = ra;
1569 } else {
1570 p->role_allow = ra;
1571 }
1572 rc = next_entry(buf, fp, sizeof(u32)*2);
1573 if (rc < 0)
1574 goto bad;
1575 ra->role = le32_to_cpu(buf[0]);
1576 ra->new_role = le32_to_cpu(buf[1]);
1577 lra = ra;
1578 }
1579
1580 rc = policydb_index_classes(p);
1581 if (rc)
1582 goto bad;
1583
1584 rc = policydb_index_others(p);
1585 if (rc)
1586 goto bad;
1587
1588 for (i = 0; i < info->ocon_num; i++) {
1589 rc = next_entry(buf, fp, sizeof(u32));
1590 if (rc < 0)
1591 goto bad;
1592 nel = le32_to_cpu(buf[0]);
1593 l = NULL;
1594 for (j = 0; j < nel; j++) {
1595 c = kmalloc(sizeof(*c), GFP_KERNEL);
1596 if (!c) {
1597 rc = -ENOMEM;
1598 goto bad;
1599 }
1600 memset(c, 0, sizeof(*c));
1601 if (l) {
1602 l->next = c;
1603 } else {
1604 p->ocontexts[i] = c;
1605 }
1606 l = c;
1607 rc = -EINVAL;
1608 switch (i) {
1609 case OCON_ISID:
1610 rc = next_entry(buf, fp, sizeof(u32));
1611 if (rc < 0)
1612 goto bad;
1613 c->sid[0] = le32_to_cpu(buf[0]);
1614 rc = context_read_and_validate(&c->context[0], p, fp);
1615 if (rc)
1616 goto bad;
1617 break;
1618 case OCON_FS:
1619 case OCON_NETIF:
1620 rc = next_entry(buf, fp, sizeof(u32));
1621 if (rc < 0)
1622 goto bad;
1623 len = le32_to_cpu(buf[0]);
1624 c->u.name = kmalloc(len + 1,GFP_KERNEL);
1625 if (!c->u.name) {
1626 rc = -ENOMEM;
1627 goto bad;
1628 }
1629 rc = next_entry(c->u.name, fp, len);
1630 if (rc < 0)
1631 goto bad;
1632 c->u.name[len] = 0;
1633 rc = context_read_and_validate(&c->context[0], p, fp);
1634 if (rc)
1635 goto bad;
1636 rc = context_read_and_validate(&c->context[1], p, fp);
1637 if (rc)
1638 goto bad;
1639 break;
1640 case OCON_PORT:
1641 rc = next_entry(buf, fp, sizeof(u32)*3);
1642 if (rc < 0)
1643 goto bad;
1644 c->u.port.protocol = le32_to_cpu(buf[0]);
1645 c->u.port.low_port = le32_to_cpu(buf[1]);
1646 c->u.port.high_port = le32_to_cpu(buf[2]);
1647 rc = context_read_and_validate(&c->context[0], p, fp);
1648 if (rc)
1649 goto bad;
1650 break;
1651 case OCON_NODE:
1652 rc = next_entry(buf, fp, sizeof(u32)* 2);
1653 if (rc < 0)
1654 goto bad;
1655 c->u.node.addr = le32_to_cpu(buf[0]);
1656 c->u.node.mask = le32_to_cpu(buf[1]);
1657 rc = context_read_and_validate(&c->context[0], p, fp);
1658 if (rc)
1659 goto bad;
1660 break;
1661 case OCON_FSUSE:
1662 rc = next_entry(buf, fp, sizeof(u32)*2);
1663 if (rc < 0)
1664 goto bad;
1665 c->v.behavior = le32_to_cpu(buf[0]);
1666 if (c->v.behavior > SECURITY_FS_USE_NONE)
1667 goto bad;
1668 len = le32_to_cpu(buf[1]);
1669 c->u.name = kmalloc(len + 1,GFP_KERNEL);
1670 if (!c->u.name) {
1671 rc = -ENOMEM;
1672 goto bad;
1673 }
1674 rc = next_entry(c->u.name, fp, len);
1675 if (rc < 0)
1676 goto bad;
1677 c->u.name[len] = 0;
1678 rc = context_read_and_validate(&c->context[0], p, fp);
1679 if (rc)
1680 goto bad;
1681 break;
1682 case OCON_NODE6: {
1683 int k;
1684
1685 rc = next_entry(buf, fp, sizeof(u32) * 8);
1686 if (rc < 0)
1687 goto bad;
1688 for (k = 0; k < 4; k++)
1689 c->u.node6.addr[k] = le32_to_cpu(buf[k]);
1690 for (k = 0; k < 4; k++)
1691 c->u.node6.mask[k] = le32_to_cpu(buf[k+4]);
1692 if (context_read_and_validate(&c->context[0], p, fp))
1693 goto bad;
1694 break;
1695 }
1696 }
1697 }
1698 }
1699
1700 rc = next_entry(buf, fp, sizeof(u32));
1701 if (rc < 0)
1702 goto bad;
1703 nel = le32_to_cpu(buf[0]);
1704 genfs_p = NULL;
1705 rc = -EINVAL;
1706 for (i = 0; i < nel; i++) {
1707 rc = next_entry(buf, fp, sizeof(u32));
1708 if (rc < 0)
1709 goto bad;
1710 len = le32_to_cpu(buf[0]);
1711 newgenfs = kmalloc(sizeof(*newgenfs), GFP_KERNEL);
1712 if (!newgenfs) {
1713 rc = -ENOMEM;
1714 goto bad;
1715 }
1716 memset(newgenfs, 0, sizeof(*newgenfs));
1717
1718 newgenfs->fstype = kmalloc(len + 1,GFP_KERNEL);
1719 if (!newgenfs->fstype) {
1720 rc = -ENOMEM;
1721 kfree(newgenfs);
1722 goto bad;
1723 }
1724 rc = next_entry(newgenfs->fstype, fp, len);
1725 if (rc < 0) {
1726 kfree(newgenfs->fstype);
1727 kfree(newgenfs);
1728 goto bad;
1729 }
1730 newgenfs->fstype[len] = 0;
1731 for (genfs_p = NULL, genfs = p->genfs; genfs;
1732 genfs_p = genfs, genfs = genfs->next) {
1733 if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
1734 printk(KERN_ERR "security: dup genfs "
1735 "fstype %s\n", newgenfs->fstype);
1736 kfree(newgenfs->fstype);
1737 kfree(newgenfs);
1738 goto bad;
1739 }
1740 if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
1741 break;
1742 }
1743 newgenfs->next = genfs;
1744 if (genfs_p)
1745 genfs_p->next = newgenfs;
1746 else
1747 p->genfs = newgenfs;
1748 rc = next_entry(buf, fp, sizeof(u32));
1749 if (rc < 0)
1750 goto bad;
1751 nel2 = le32_to_cpu(buf[0]);
1752 for (j = 0; j < nel2; j++) {
1753 rc = next_entry(buf, fp, sizeof(u32));
1754 if (rc < 0)
1755 goto bad;
1756 len = le32_to_cpu(buf[0]);
1757
1758 newc = kmalloc(sizeof(*newc), GFP_KERNEL);
1759 if (!newc) {
1760 rc = -ENOMEM;
1761 goto bad;
1762 }
1763 memset(newc, 0, sizeof(*newc));
1764
1765 newc->u.name = kmalloc(len + 1,GFP_KERNEL);
1766 if (!newc->u.name) {
1767 rc = -ENOMEM;
1768 goto bad_newc;
1769 }
1770 rc = next_entry(newc->u.name, fp, len);
1771 if (rc < 0)
1772 goto bad_newc;
1773 newc->u.name[len] = 0;
1774 rc = next_entry(buf, fp, sizeof(u32));
1775 if (rc < 0)
1776 goto bad_newc;
1777 newc->v.sclass = le32_to_cpu(buf[0]);
1778 if (context_read_and_validate(&newc->context[0], p, fp))
1779 goto bad_newc;
1780 for (l = NULL, c = newgenfs->head; c;
1781 l = c, c = c->next) {
1782 if (!strcmp(newc->u.name, c->u.name) &&
1783 (!c->v.sclass || !newc->v.sclass ||
1784 newc->v.sclass == c->v.sclass)) {
1785 printk(KERN_ERR "security: dup genfs "
1786 "entry (%s,%s)\n",
1787 newgenfs->fstype, c->u.name);
1788 goto bad_newc;
1789 }
1790 len = strlen(newc->u.name);
1791 len2 = strlen(c->u.name);
1792 if (len > len2)
1793 break;
1794 }
1795
1796 newc->next = c;
1797 if (l)
1798 l->next = newc;
1799 else
1800 newgenfs->head = newc;
1801 }
1802 }
1803
1804 if (p->policyvers >= POLICYDB_VERSION_MLS) {
1805 rc = next_entry(buf, fp, sizeof(u32));
1806 if (rc < 0)
1807 goto bad;
1808 nel = le32_to_cpu(buf[0]);
1809 lrt = NULL;
1810 for (i = 0; i < nel; i++) {
1811 rt = kmalloc(sizeof(*rt), GFP_KERNEL);
1812 if (!rt) {
1813 rc = -ENOMEM;
1814 goto bad;
1815 }
1816 memset(rt, 0, sizeof(*rt));
1817 if (lrt)
1818 lrt->next = rt;
1819 else
1820 p->range_tr = rt;
1821 rc = next_entry(buf, fp, (sizeof(u32) * 2));
1822 if (rc < 0)
1823 goto bad;
1824 rt->dom = le32_to_cpu(buf[0]);
1825 rt->type = le32_to_cpu(buf[1]);
1826 rc = mls_read_range_helper(&rt->range, fp);
1827 if (rc)
1828 goto bad;
1829 lrt = rt;
1830 }
1831 }
1832
1833 rc = 0;
1834out:
1835 return rc;
1836bad_newc:
1837 ocontext_destroy(newc,OCON_FSUSE);
1838bad:
1839 if (!rc)
1840 rc = -EINVAL;
1841 policydb_destroy(p);
1842 goto out;
1843}
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
new file mode 100644
index 000000000000..2470e2a1a1c3
--- /dev/null
+++ b/security/selinux/ss/policydb.h
@@ -0,0 +1,275 @@
1/*
2 * A policy database (policydb) specifies the
3 * configuration data for the security policy.
4 *
5 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
6 */
7
8/*
9 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
10 *
11 * Support for enhanced MLS infrastructure.
12 *
13 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
14 *
15 * Added conditional policy language extensions
16 *
17 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
18 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation, version 2.
22 */
23
24#ifndef _SS_POLICYDB_H_
25#define _SS_POLICYDB_H_
26
27#include "symtab.h"
28#include "avtab.h"
29#include "sidtab.h"
30#include "context.h"
31#include "constraint.h"
32
33/*
34 * A datum type is defined for each kind of symbol
35 * in the configuration data: individual permissions,
36 * common prefixes for access vectors, classes,
37 * users, roles, types, sensitivities, categories, etc.
38 */
39
40/* Permission attributes */
41struct perm_datum {
42 u32 value; /* permission bit + 1 */
43};
44
45/* Attributes of a common prefix for access vectors */
46struct common_datum {
47 u32 value; /* internal common value */
48 struct symtab permissions; /* common permissions */
49};
50
51/* Class attributes */
52struct class_datum {
53 u32 value; /* class value */
54 char *comkey; /* common name */
55 struct common_datum *comdatum; /* common datum */
56 struct symtab permissions; /* class-specific permission symbol table */
57 struct constraint_node *constraints; /* constraints on class permissions */
58 struct constraint_node *validatetrans; /* special transition rules */
59};
60
61/* Role attributes */
62struct role_datum {
63 u32 value; /* internal role value */
64 struct ebitmap dominates; /* set of roles dominated by this role */
65 struct ebitmap types; /* set of authorized types for role */
66};
67
68struct role_trans {
69 u32 role; /* current role */
70 u32 type; /* program executable type */
71 u32 new_role; /* new role */
72 struct role_trans *next;
73};
74
75struct role_allow {
76 u32 role; /* current role */
77 u32 new_role; /* new role */
78 struct role_allow *next;
79};
80
81/* Type attributes */
82struct type_datum {
83 u32 value; /* internal type value */
84 unsigned char primary; /* primary name? */
85};
86
87/* User attributes */
88struct user_datum {
89 u32 value; /* internal user value */
90 struct ebitmap roles; /* set of authorized roles for user */
91 struct mls_range range; /* MLS range (min - max) for user */
92 struct mls_level dfltlevel; /* default login MLS level for user */
93};
94
95
96/* Sensitivity attributes */
97struct level_datum {
98 struct mls_level *level; /* sensitivity and associated categories */
99 unsigned char isalias; /* is this sensitivity an alias for another? */
100};
101
102/* Category attributes */
103struct cat_datum {
104 u32 value; /* internal category bit + 1 */
105 unsigned char isalias; /* is this category an alias for another? */
106};
107
108struct range_trans {
109 u32 dom; /* current process domain */
110 u32 type; /* program executable type */
111 struct mls_range range; /* new range */
112 struct range_trans *next;
113};
114
115/* Boolean data type */
116struct cond_bool_datum {
117 __u32 value; /* internal type value */
118 int state;
119};
120
121struct cond_node;
122
123/*
124 * The configuration data includes security contexts for
125 * initial SIDs, unlabeled file systems, TCP and UDP port numbers,
126 * network interfaces, and nodes. This structure stores the
127 * relevant data for one such entry. Entries of the same kind
128 * (e.g. all initial SIDs) are linked together into a list.
129 */
130struct ocontext {
131 union {
132 char *name; /* name of initial SID, fs, netif, fstype, path */
133 struct {
134 u8 protocol;
135 u16 low_port;
136 u16 high_port;
137 } port; /* TCP or UDP port information */
138 struct {
139 u32 addr;
140 u32 mask;
141 } node; /* node information */
142 struct {
143 u32 addr[4];
144 u32 mask[4];
145 } node6; /* IPv6 node information */
146 } u;
147 union {
148 u32 sclass; /* security class for genfs */
149 u32 behavior; /* labeling behavior for fs_use */
150 } v;
151 struct context context[2]; /* security context(s) */
152 u32 sid[2]; /* SID(s) */
153 struct ocontext *next;
154};
155
156struct genfs {
157 char *fstype;
158 struct ocontext *head;
159 struct genfs *next;
160};
161
162/* symbol table array indices */
163#define SYM_COMMONS 0
164#define SYM_CLASSES 1
165#define SYM_ROLES 2
166#define SYM_TYPES 3
167#define SYM_USERS 4
168#define SYM_BOOLS 5
169#define SYM_LEVELS 6
170#define SYM_CATS 7
171#define SYM_NUM 8
172
173/* object context array indices */
174#define OCON_ISID 0 /* initial SIDs */
175#define OCON_FS 1 /* unlabeled file systems */
176#define OCON_PORT 2 /* TCP and UDP port numbers */
177#define OCON_NETIF 3 /* network interfaces */
178#define OCON_NODE 4 /* nodes */
179#define OCON_FSUSE 5 /* fs_use */
180#define OCON_NODE6 6 /* IPv6 nodes */
181#define OCON_NUM 7
182
183/* The policy database */
184struct policydb {
185 /* symbol tables */
186 struct symtab symtab[SYM_NUM];
187#define p_commons symtab[SYM_COMMONS]
188#define p_classes symtab[SYM_CLASSES]
189#define p_roles symtab[SYM_ROLES]
190#define p_types symtab[SYM_TYPES]
191#define p_users symtab[SYM_USERS]
192#define p_bools symtab[SYM_BOOLS]
193#define p_levels symtab[SYM_LEVELS]
194#define p_cats symtab[SYM_CATS]
195
196 /* symbol names indexed by (value - 1) */
197 char **sym_val_to_name[SYM_NUM];
198#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
199#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
200#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
201#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
202#define p_user_val_to_name sym_val_to_name[SYM_USERS]
203#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
204#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
205#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
206
207 /* class, role, and user attributes indexed by (value - 1) */
208 struct class_datum **class_val_to_struct;
209 struct role_datum **role_val_to_struct;
210 struct user_datum **user_val_to_struct;
211
212 /* type enforcement access vectors and transitions */
213 struct avtab te_avtab;
214
215 /* role transitions */
216 struct role_trans *role_tr;
217
218 /* bools indexed by (value - 1) */
219 struct cond_bool_datum **bool_val_to_struct;
220 /* type enforcement conditional access vectors and transitions */
221 struct avtab te_cond_avtab;
222 /* linked list indexing te_cond_avtab by conditional */
223 struct cond_node* cond_list;
224
225 /* role allows */
226 struct role_allow *role_allow;
227
228 /* security contexts of initial SIDs, unlabeled file systems,
229 TCP or UDP port numbers, network interfaces and nodes */
230 struct ocontext *ocontexts[OCON_NUM];
231
232 /* security contexts for files in filesystems that cannot support
233 a persistent label mapping or use another
234 fixed labeling behavior. */
235 struct genfs *genfs;
236
237 /* range transitions */
238 struct range_trans *range_tr;
239
240 unsigned int policyvers;
241};
242
243extern void policydb_destroy(struct policydb *p);
244extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
245extern int policydb_context_isvalid(struct policydb *p, struct context *c);
246extern int policydb_read(struct policydb *p, void *fp);
247
248#define PERM_SYMTAB_SIZE 32
249
250#define POLICYDB_CONFIG_MLS 1
251
252#define OBJECT_R "object_r"
253#define OBJECT_R_VAL 1
254
255#define POLICYDB_MAGIC SELINUX_MAGIC
256#define POLICYDB_STRING "SE Linux"
257
258struct policy_file {
259 char *data;
260 size_t len;
261};
262
263static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
264{
265 if (bytes > fp->len)
266 return -EINVAL;
267
268 memcpy(buf, fp->data, bytes);
269 fp->data += bytes;
270 fp->len -= bytes;
271 return 0;
272}
273
274#endif /* _SS_POLICYDB_H_ */
275
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
new file mode 100644
index 000000000000..5a820cf88c9c
--- /dev/null
+++ b/security/selinux/ss/services.c
@@ -0,0 +1,1777 @@
1/*
2 * Implementation of the security services.
3 *
4 * Authors : Stephen Smalley, <sds@epoch.ncsc.mil>
5 * James Morris <jmorris@redhat.com>
6 *
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * Support for enhanced MLS infrastructure.
10 *
11 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
12 *
13 * Added conditional policy language extensions
14 *
15 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
16 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
17 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, version 2.
21 */
22#include <linux/kernel.h>
23#include <linux/slab.h>
24#include <linux/string.h>
25#include <linux/spinlock.h>
26#include <linux/errno.h>
27#include <linux/in.h>
28#include <linux/sched.h>
29#include <linux/audit.h>
30#include <asm/semaphore.h>
31#include "flask.h"
32#include "avc.h"
33#include "avc_ss.h"
34#include "security.h"
35#include "context.h"
36#include "policydb.h"
37#include "sidtab.h"
38#include "services.h"
39#include "conditional.h"
40#include "mls.h"
41
42extern void selnl_notify_policyload(u32 seqno);
43unsigned int policydb_loaded_version;
44
45static DEFINE_RWLOCK(policy_rwlock);
46#define POLICY_RDLOCK read_lock(&policy_rwlock)
47#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
48#define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
49#define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
50
51static DECLARE_MUTEX(load_sem);
52#define LOAD_LOCK down(&load_sem)
53#define LOAD_UNLOCK up(&load_sem)
54
55static struct sidtab sidtab;
56struct policydb policydb;
57int ss_initialized = 0;
58
59/*
60 * The largest sequence number that has been used when
61 * providing an access decision to the access vector cache.
62 * The sequence number only changes when a policy change
63 * occurs.
64 */
65static u32 latest_granting = 0;
66
67/* Forward declaration. */
68static int context_struct_to_string(struct context *context, char **scontext,
69 u32 *scontext_len);
70
71/*
72 * Return the boolean value of a constraint expression
73 * when it is applied to the specified source and target
74 * security contexts.
75 *
76 * xcontext is a special beast... It is used by the validatetrans rules
77 * only. For these rules, scontext is the context before the transition,
78 * tcontext is the context after the transition, and xcontext is the context
79 * of the process performing the transition. All other callers of
80 * constraint_expr_eval should pass in NULL for xcontext.
81 */
82static int constraint_expr_eval(struct context *scontext,
83 struct context *tcontext,
84 struct context *xcontext,
85 struct constraint_expr *cexpr)
86{
87 u32 val1, val2;
88 struct context *c;
89 struct role_datum *r1, *r2;
90 struct mls_level *l1, *l2;
91 struct constraint_expr *e;
92 int s[CEXPR_MAXDEPTH];
93 int sp = -1;
94
95 for (e = cexpr; e; e = e->next) {
96 switch (e->expr_type) {
97 case CEXPR_NOT:
98 BUG_ON(sp < 0);
99 s[sp] = !s[sp];
100 break;
101 case CEXPR_AND:
102 BUG_ON(sp < 1);
103 sp--;
104 s[sp] &= s[sp+1];
105 break;
106 case CEXPR_OR:
107 BUG_ON(sp < 1);
108 sp--;
109 s[sp] |= s[sp+1];
110 break;
111 case CEXPR_ATTR:
112 if (sp == (CEXPR_MAXDEPTH-1))
113 return 0;
114 switch (e->attr) {
115 case CEXPR_USER:
116 val1 = scontext->user;
117 val2 = tcontext->user;
118 break;
119 case CEXPR_TYPE:
120 val1 = scontext->type;
121 val2 = tcontext->type;
122 break;
123 case CEXPR_ROLE:
124 val1 = scontext->role;
125 val2 = tcontext->role;
126 r1 = policydb.role_val_to_struct[val1 - 1];
127 r2 = policydb.role_val_to_struct[val2 - 1];
128 switch (e->op) {
129 case CEXPR_DOM:
130 s[++sp] = ebitmap_get_bit(&r1->dominates,
131 val2 - 1);
132 continue;
133 case CEXPR_DOMBY:
134 s[++sp] = ebitmap_get_bit(&r2->dominates,
135 val1 - 1);
136 continue;
137 case CEXPR_INCOMP:
138 s[++sp] = ( !ebitmap_get_bit(&r1->dominates,
139 val2 - 1) &&
140 !ebitmap_get_bit(&r2->dominates,
141 val1 - 1) );
142 continue;
143 default:
144 break;
145 }
146 break;
147 case CEXPR_L1L2:
148 l1 = &(scontext->range.level[0]);
149 l2 = &(tcontext->range.level[0]);
150 goto mls_ops;
151 case CEXPR_L1H2:
152 l1 = &(scontext->range.level[0]);
153 l2 = &(tcontext->range.level[1]);
154 goto mls_ops;
155 case CEXPR_H1L2:
156 l1 = &(scontext->range.level[1]);
157 l2 = &(tcontext->range.level[0]);
158 goto mls_ops;
159 case CEXPR_H1H2:
160 l1 = &(scontext->range.level[1]);
161 l2 = &(tcontext->range.level[1]);
162 goto mls_ops;
163 case CEXPR_L1H1:
164 l1 = &(scontext->range.level[0]);
165 l2 = &(scontext->range.level[1]);
166 goto mls_ops;
167 case CEXPR_L2H2:
168 l1 = &(tcontext->range.level[0]);
169 l2 = &(tcontext->range.level[1]);
170 goto mls_ops;
171mls_ops:
172 switch (e->op) {
173 case CEXPR_EQ:
174 s[++sp] = mls_level_eq(l1, l2);
175 continue;
176 case CEXPR_NEQ:
177 s[++sp] = !mls_level_eq(l1, l2);
178 continue;
179 case CEXPR_DOM:
180 s[++sp] = mls_level_dom(l1, l2);
181 continue;
182 case CEXPR_DOMBY:
183 s[++sp] = mls_level_dom(l2, l1);
184 continue;
185 case CEXPR_INCOMP:
186 s[++sp] = mls_level_incomp(l2, l1);
187 continue;
188 default:
189 BUG();
190 return 0;
191 }
192 break;
193 default:
194 BUG();
195 return 0;
196 }
197
198 switch (e->op) {
199 case CEXPR_EQ:
200 s[++sp] = (val1 == val2);
201 break;
202 case CEXPR_NEQ:
203 s[++sp] = (val1 != val2);
204 break;
205 default:
206 BUG();
207 return 0;
208 }
209 break;
210 case CEXPR_NAMES:
211 if (sp == (CEXPR_MAXDEPTH-1))
212 return 0;
213 c = scontext;
214 if (e->attr & CEXPR_TARGET)
215 c = tcontext;
216 else if (e->attr & CEXPR_XTARGET) {
217 c = xcontext;
218 if (!c) {
219 BUG();
220 return 0;
221 }
222 }
223 if (e->attr & CEXPR_USER)
224 val1 = c->user;
225 else if (e->attr & CEXPR_ROLE)
226 val1 = c->role;
227 else if (e->attr & CEXPR_TYPE)
228 val1 = c->type;
229 else {
230 BUG();
231 return 0;
232 }
233
234 switch (e->op) {
235 case CEXPR_EQ:
236 s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
237 break;
238 case CEXPR_NEQ:
239 s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
240 break;
241 default:
242 BUG();
243 return 0;
244 }
245 break;
246 default:
247 BUG();
248 return 0;
249 }
250 }
251
252 BUG_ON(sp != 0);
253 return s[0];
254}
255
256/*
257 * Compute access vectors based on a context structure pair for
258 * the permissions in a particular class.
259 */
260static int context_struct_compute_av(struct context *scontext,
261 struct context *tcontext,
262 u16 tclass,
263 u32 requested,
264 struct av_decision *avd)
265{
266 struct constraint_node *constraint;
267 struct role_allow *ra;
268 struct avtab_key avkey;
269 struct avtab_datum *avdatum;
270 struct class_datum *tclass_datum;
271
272 /*
273 * Remap extended Netlink classes for old policy versions.
274 * Do this here rather than socket_type_to_security_class()
275 * in case a newer policy version is loaded, allowing sockets
276 * to remain in the correct class.
277 */
278 if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
279 if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
280 tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
281 tclass = SECCLASS_NETLINK_SOCKET;
282
283 if (!tclass || tclass > policydb.p_classes.nprim) {
284 printk(KERN_ERR "security_compute_av: unrecognized class %d\n",
285 tclass);
286 return -EINVAL;
287 }
288 tclass_datum = policydb.class_val_to_struct[tclass - 1];
289
290 /*
291 * Initialize the access vectors to the default values.
292 */
293 avd->allowed = 0;
294 avd->decided = 0xffffffff;
295 avd->auditallow = 0;
296 avd->auditdeny = 0xffffffff;
297 avd->seqno = latest_granting;
298
299 /*
300 * If a specific type enforcement rule was defined for
301 * this permission check, then use it.
302 */
303 avkey.source_type = scontext->type;
304 avkey.target_type = tcontext->type;
305 avkey.target_class = tclass;
306 avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_AV);
307 if (avdatum) {
308 if (avdatum->specified & AVTAB_ALLOWED)
309 avd->allowed = avtab_allowed(avdatum);
310 if (avdatum->specified & AVTAB_AUDITDENY)
311 avd->auditdeny = avtab_auditdeny(avdatum);
312 if (avdatum->specified & AVTAB_AUDITALLOW)
313 avd->auditallow = avtab_auditallow(avdatum);
314 }
315
316 /* Check conditional av table for additional permissions */
317 cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
318
319 /*
320 * Remove any permissions prohibited by a constraint (this includes
321 * the MLS policy).
322 */
323 constraint = tclass_datum->constraints;
324 while (constraint) {
325 if ((constraint->permissions & (avd->allowed)) &&
326 !constraint_expr_eval(scontext, tcontext, NULL,
327 constraint->expr)) {
328 avd->allowed = (avd->allowed) & ~(constraint->permissions);
329 }
330 constraint = constraint->next;
331 }
332
333 /*
334 * If checking process transition permission and the
335 * role is changing, then check the (current_role, new_role)
336 * pair.
337 */
338 if (tclass == SECCLASS_PROCESS &&
339 (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) &&
340 scontext->role != tcontext->role) {
341 for (ra = policydb.role_allow; ra; ra = ra->next) {
342 if (scontext->role == ra->role &&
343 tcontext->role == ra->new_role)
344 break;
345 }
346 if (!ra)
347 avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
348 PROCESS__DYNTRANSITION);
349 }
350
351 return 0;
352}
353
354static int security_validtrans_handle_fail(struct context *ocontext,
355 struct context *ncontext,
356 struct context *tcontext,
357 u16 tclass)
358{
359 char *o = NULL, *n = NULL, *t = NULL;
360 u32 olen, nlen, tlen;
361
362 if (context_struct_to_string(ocontext, &o, &olen) < 0)
363 goto out;
364 if (context_struct_to_string(ncontext, &n, &nlen) < 0)
365 goto out;
366 if (context_struct_to_string(tcontext, &t, &tlen) < 0)
367 goto out;
368 audit_log(current->audit_context,
369 "security_validate_transition: denied for"
370 " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
371 o, n, t, policydb.p_class_val_to_name[tclass-1]);
372out:
373 kfree(o);
374 kfree(n);
375 kfree(t);
376
377 if (!selinux_enforcing)
378 return 0;
379 return -EPERM;
380}
381
382int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
383 u16 tclass)
384{
385 struct context *ocontext;
386 struct context *ncontext;
387 struct context *tcontext;
388 struct class_datum *tclass_datum;
389 struct constraint_node *constraint;
390 int rc = 0;
391
392 if (!ss_initialized)
393 return 0;
394
395 POLICY_RDLOCK;
396
397 /*
398 * Remap extended Netlink classes for old policy versions.
399 * Do this here rather than socket_type_to_security_class()
400 * in case a newer policy version is loaded, allowing sockets
401 * to remain in the correct class.
402 */
403 if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS)
404 if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET &&
405 tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
406 tclass = SECCLASS_NETLINK_SOCKET;
407
408 if (!tclass || tclass > policydb.p_classes.nprim) {
409 printk(KERN_ERR "security_validate_transition: "
410 "unrecognized class %d\n", tclass);
411 rc = -EINVAL;
412 goto out;
413 }
414 tclass_datum = policydb.class_val_to_struct[tclass - 1];
415
416 ocontext = sidtab_search(&sidtab, oldsid);
417 if (!ocontext) {
418 printk(KERN_ERR "security_validate_transition: "
419 " unrecognized SID %d\n", oldsid);
420 rc = -EINVAL;
421 goto out;
422 }
423
424 ncontext = sidtab_search(&sidtab, newsid);
425 if (!ncontext) {
426 printk(KERN_ERR "security_validate_transition: "
427 " unrecognized SID %d\n", newsid);
428 rc = -EINVAL;
429 goto out;
430 }
431
432 tcontext = sidtab_search(&sidtab, tasksid);
433 if (!tcontext) {
434 printk(KERN_ERR "security_validate_transition: "
435 " unrecognized SID %d\n", tasksid);
436 rc = -EINVAL;
437 goto out;
438 }
439
440 constraint = tclass_datum->validatetrans;
441 while (constraint) {
442 if (!constraint_expr_eval(ocontext, ncontext, tcontext,
443 constraint->expr)) {
444 rc = security_validtrans_handle_fail(ocontext, ncontext,
445 tcontext, tclass);
446 goto out;
447 }
448 constraint = constraint->next;
449 }
450
451out:
452 POLICY_RDUNLOCK;
453 return rc;
454}
455
456/**
457 * security_compute_av - Compute access vector decisions.
458 * @ssid: source security identifier
459 * @tsid: target security identifier
460 * @tclass: target security class
461 * @requested: requested permissions
462 * @avd: access vector decisions
463 *
464 * Compute a set of access vector decisions based on the
465 * SID pair (@ssid, @tsid) for the permissions in @tclass.
466 * Return -%EINVAL if any of the parameters are invalid or %0
467 * if the access vector decisions were computed successfully.
468 */
469int security_compute_av(u32 ssid,
470 u32 tsid,
471 u16 tclass,
472 u32 requested,
473 struct av_decision *avd)
474{
475 struct context *scontext = NULL, *tcontext = NULL;
476 int rc = 0;
477
478 if (!ss_initialized) {
479 avd->allowed = requested;
480 avd->decided = requested;
481 avd->auditallow = 0;
482 avd->auditdeny = 0xffffffff;
483 avd->seqno = latest_granting;
484 return 0;
485 }
486
487 POLICY_RDLOCK;
488
489 scontext = sidtab_search(&sidtab, ssid);
490 if (!scontext) {
491 printk(KERN_ERR "security_compute_av: unrecognized SID %d\n",
492 ssid);
493 rc = -EINVAL;
494 goto out;
495 }
496 tcontext = sidtab_search(&sidtab, tsid);
497 if (!tcontext) {
498 printk(KERN_ERR "security_compute_av: unrecognized SID %d\n",
499 tsid);
500 rc = -EINVAL;
501 goto out;
502 }
503
504 rc = context_struct_compute_av(scontext, tcontext, tclass,
505 requested, avd);
506out:
507 POLICY_RDUNLOCK;
508 return rc;
509}
510
511/*
512 * Write the security context string representation of
513 * the context structure `context' into a dynamically
514 * allocated string of the correct size. Set `*scontext'
515 * to point to this string and set `*scontext_len' to
516 * the length of the string.
517 */
518static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
519{
520 char *scontextp;
521
522 *scontext = NULL;
523 *scontext_len = 0;
524
525 /* Compute the size of the context. */
526 *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
527 *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
528 *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
529 *scontext_len += mls_compute_context_len(context);
530
531 /* Allocate space for the context; caller must free this space. */
532 scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
533 if (!scontextp) {
534 return -ENOMEM;
535 }
536 *scontext = scontextp;
537
538 /*
539 * Copy the user name, role name and type name into the context.
540 */
541 sprintf(scontextp, "%s:%s:%s",
542 policydb.p_user_val_to_name[context->user - 1],
543 policydb.p_role_val_to_name[context->role - 1],
544 policydb.p_type_val_to_name[context->type - 1]);
545 scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
546 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
547 1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
548
549 mls_sid_to_context(context, &scontextp);
550
551 *scontextp = 0;
552
553 return 0;
554}
555
556#include "initial_sid_to_string.h"
557
558/**
559 * security_sid_to_context - Obtain a context for a given SID.
560 * @sid: security identifier, SID
561 * @scontext: security context
562 * @scontext_len: length in bytes
563 *
564 * Write the string representation of the context associated with @sid
565 * into a dynamically allocated string of the correct size. Set @scontext
566 * to point to this string and set @scontext_len to the length of the string.
567 */
568int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
569{
570 struct context *context;
571 int rc = 0;
572
573 if (!ss_initialized) {
574 if (sid <= SECINITSID_NUM) {
575 char *scontextp;
576
577 *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
578 scontextp = kmalloc(*scontext_len,GFP_ATOMIC);
579 strcpy(scontextp, initial_sid_to_string[sid]);
580 *scontext = scontextp;
581 goto out;
582 }
583 printk(KERN_ERR "security_sid_to_context: called before initial "
584 "load_policy on unknown SID %d\n", sid);
585 rc = -EINVAL;
586 goto out;
587 }
588 POLICY_RDLOCK;
589 context = sidtab_search(&sidtab, sid);
590 if (!context) {
591 printk(KERN_ERR "security_sid_to_context: unrecognized SID "
592 "%d\n", sid);
593 rc = -EINVAL;
594 goto out_unlock;
595 }
596 rc = context_struct_to_string(context, scontext, scontext_len);
597out_unlock:
598 POLICY_RDUNLOCK;
599out:
600 return rc;
601
602}
603
604/**
605 * security_context_to_sid - Obtain a SID for a given security context.
606 * @scontext: security context
607 * @scontext_len: length in bytes
608 * @sid: security identifier, SID
609 *
610 * Obtains a SID associated with the security context that
611 * has the string representation specified by @scontext.
612 * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
613 * memory is available, or 0 on success.
614 */
615int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
616{
617 char *scontext2;
618 struct context context;
619 struct role_datum *role;
620 struct type_datum *typdatum;
621 struct user_datum *usrdatum;
622 char *scontextp, *p, oldc;
623 int rc = 0;
624
625 if (!ss_initialized) {
626 int i;
627
628 for (i = 1; i < SECINITSID_NUM; i++) {
629 if (!strcmp(initial_sid_to_string[i], scontext)) {
630 *sid = i;
631 goto out;
632 }
633 }
634 *sid = SECINITSID_KERNEL;
635 goto out;
636 }
637 *sid = SECSID_NULL;
638
639 /* Copy the string so that we can modify the copy as we parse it.
640 The string should already by null terminated, but we append a
641 null suffix to the copy to avoid problems with the existing
642 attr package, which doesn't view the null terminator as part
643 of the attribute value. */
644 scontext2 = kmalloc(scontext_len+1,GFP_KERNEL);
645 if (!scontext2) {
646 rc = -ENOMEM;
647 goto out;
648 }
649 memcpy(scontext2, scontext, scontext_len);
650 scontext2[scontext_len] = 0;
651
652 context_init(&context);
653 *sid = SECSID_NULL;
654
655 POLICY_RDLOCK;
656
657 /* Parse the security context. */
658
659 rc = -EINVAL;
660 scontextp = (char *) scontext2;
661
662 /* Extract the user. */
663 p = scontextp;
664 while (*p && *p != ':')
665 p++;
666
667 if (*p == 0)
668 goto out_unlock;
669
670 *p++ = 0;
671
672 usrdatum = hashtab_search(policydb.p_users.table, scontextp);
673 if (!usrdatum)
674 goto out_unlock;
675
676 context.user = usrdatum->value;
677
678 /* Extract role. */
679 scontextp = p;
680 while (*p && *p != ':')
681 p++;
682
683 if (*p == 0)
684 goto out_unlock;
685
686 *p++ = 0;
687
688 role = hashtab_search(policydb.p_roles.table, scontextp);
689 if (!role)
690 goto out_unlock;
691 context.role = role->value;
692
693 /* Extract type. */
694 scontextp = p;
695 while (*p && *p != ':')
696 p++;
697 oldc = *p;
698 *p++ = 0;
699
700 typdatum = hashtab_search(policydb.p_types.table, scontextp);
701 if (!typdatum)
702 goto out_unlock;
703
704 context.type = typdatum->value;
705
706 rc = mls_context_to_sid(oldc, &p, &context);
707 if (rc)
708 goto out_unlock;
709
710 if ((p - scontext2) < scontext_len) {
711 rc = -EINVAL;
712 goto out_unlock;
713 }
714
715 /* Check the validity of the new context. */
716 if (!policydb_context_isvalid(&policydb, &context)) {
717 rc = -EINVAL;
718 goto out_unlock;
719 }
720 /* Obtain the new sid. */
721 rc = sidtab_context_to_sid(&sidtab, &context, sid);
722out_unlock:
723 POLICY_RDUNLOCK;
724 context_destroy(&context);
725 kfree(scontext2);
726out:
727 return rc;
728}
729
730static int compute_sid_handle_invalid_context(
731 struct context *scontext,
732 struct context *tcontext,
733 u16 tclass,
734 struct context *newcontext)
735{
736 char *s = NULL, *t = NULL, *n = NULL;
737 u32 slen, tlen, nlen;
738
739 if (context_struct_to_string(scontext, &s, &slen) < 0)
740 goto out;
741 if (context_struct_to_string(tcontext, &t, &tlen) < 0)
742 goto out;
743 if (context_struct_to_string(newcontext, &n, &nlen) < 0)
744 goto out;
745 audit_log(current->audit_context,
746 "security_compute_sid: invalid context %s"
747 " for scontext=%s"
748 " tcontext=%s"
749 " tclass=%s",
750 n, s, t, policydb.p_class_val_to_name[tclass-1]);
751out:
752 kfree(s);
753 kfree(t);
754 kfree(n);
755 if (!selinux_enforcing)
756 return 0;
757 return -EACCES;
758}
759
760static int security_compute_sid(u32 ssid,
761 u32 tsid,
762 u16 tclass,
763 u32 specified,
764 u32 *out_sid)
765{
766 struct context *scontext = NULL, *tcontext = NULL, newcontext;
767 struct role_trans *roletr = NULL;
768 struct avtab_key avkey;
769 struct avtab_datum *avdatum;
770 struct avtab_node *node;
771 unsigned int type_change = 0;
772 int rc = 0;
773
774 if (!ss_initialized) {
775 switch (tclass) {
776 case SECCLASS_PROCESS:
777 *out_sid = ssid;
778 break;
779 default:
780 *out_sid = tsid;
781 break;
782 }
783 goto out;
784 }
785
786 POLICY_RDLOCK;
787
788 scontext = sidtab_search(&sidtab, ssid);
789 if (!scontext) {
790 printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n",
791 ssid);
792 rc = -EINVAL;
793 goto out_unlock;
794 }
795 tcontext = sidtab_search(&sidtab, tsid);
796 if (!tcontext) {
797 printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n",
798 tsid);
799 rc = -EINVAL;
800 goto out_unlock;
801 }
802
803 context_init(&newcontext);
804
805 /* Set the user identity. */
806 switch (specified) {
807 case AVTAB_TRANSITION:
808 case AVTAB_CHANGE:
809 /* Use the process user identity. */
810 newcontext.user = scontext->user;
811 break;
812 case AVTAB_MEMBER:
813 /* Use the related object owner. */
814 newcontext.user = tcontext->user;
815 break;
816 }
817
818 /* Set the role and type to default values. */
819 switch (tclass) {
820 case SECCLASS_PROCESS:
821 /* Use the current role and type of process. */
822 newcontext.role = scontext->role;
823 newcontext.type = scontext->type;
824 break;
825 default:
826 /* Use the well-defined object role. */
827 newcontext.role = OBJECT_R_VAL;
828 /* Use the type of the related object. */
829 newcontext.type = tcontext->type;
830 }
831
832 /* Look for a type transition/member/change rule. */
833 avkey.source_type = scontext->type;
834 avkey.target_type = tcontext->type;
835 avkey.target_class = tclass;
836 avdatum = avtab_search(&policydb.te_avtab, &avkey, AVTAB_TYPE);
837
838 /* If no permanent rule, also check for enabled conditional rules */
839 if(!avdatum) {
840 node = avtab_search_node(&policydb.te_cond_avtab, &avkey, specified);
841 for (; node != NULL; node = avtab_search_node_next(node, specified)) {
842 if (node->datum.specified & AVTAB_ENABLED) {
843 avdatum = &node->datum;
844 break;
845 }
846 }
847 }
848
849 type_change = (avdatum && (avdatum->specified & specified));
850 if (type_change) {
851 /* Use the type from the type transition/member/change rule. */
852 switch (specified) {
853 case AVTAB_TRANSITION:
854 newcontext.type = avtab_transition(avdatum);
855 break;
856 case AVTAB_MEMBER:
857 newcontext.type = avtab_member(avdatum);
858 break;
859 case AVTAB_CHANGE:
860 newcontext.type = avtab_change(avdatum);
861 break;
862 }
863 }
864
865 /* Check for class-specific changes. */
866 switch (tclass) {
867 case SECCLASS_PROCESS:
868 if (specified & AVTAB_TRANSITION) {
869 /* Look for a role transition rule. */
870 for (roletr = policydb.role_tr; roletr;
871 roletr = roletr->next) {
872 if (roletr->role == scontext->role &&
873 roletr->type == tcontext->type) {
874 /* Use the role transition rule. */
875 newcontext.role = roletr->new_role;
876 break;
877 }
878 }
879 }
880 break;
881 default:
882 break;
883 }
884
885 /* Set the MLS attributes.
886 This is done last because it may allocate memory. */
887 rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext);
888 if (rc)
889 goto out_unlock;
890
891 /* Check the validity of the context. */
892 if (!policydb_context_isvalid(&policydb, &newcontext)) {
893 rc = compute_sid_handle_invalid_context(scontext,
894 tcontext,
895 tclass,
896 &newcontext);
897 if (rc)
898 goto out_unlock;
899 }
900 /* Obtain the sid for the context. */
901 rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
902out_unlock:
903 POLICY_RDUNLOCK;
904 context_destroy(&newcontext);
905out:
906 return rc;
907}
908
909/**
910 * security_transition_sid - Compute the SID for a new subject/object.
911 * @ssid: source security identifier
912 * @tsid: target security identifier
913 * @tclass: target security class
914 * @out_sid: security identifier for new subject/object
915 *
916 * Compute a SID to use for labeling a new subject or object in the
917 * class @tclass based on a SID pair (@ssid, @tsid).
918 * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
919 * if insufficient memory is available, or %0 if the new SID was
920 * computed successfully.
921 */
922int security_transition_sid(u32 ssid,
923 u32 tsid,
924 u16 tclass,
925 u32 *out_sid)
926{
927 return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
928}
929
930/**
931 * security_member_sid - Compute the SID for member selection.
932 * @ssid: source security identifier
933 * @tsid: target security identifier
934 * @tclass: target security class
935 * @out_sid: security identifier for selected member
936 *
937 * Compute a SID to use when selecting a member of a polyinstantiated
938 * object of class @tclass based on a SID pair (@ssid, @tsid).
939 * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
940 * if insufficient memory is available, or %0 if the SID was
941 * computed successfully.
942 */
943int security_member_sid(u32 ssid,
944 u32 tsid,
945 u16 tclass,
946 u32 *out_sid)
947{
948 return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
949}
950
951/**
952 * security_change_sid - Compute the SID for object relabeling.
953 * @ssid: source security identifier
954 * @tsid: target security identifier
955 * @tclass: target security class
956 * @out_sid: security identifier for selected member
957 *
958 * Compute a SID to use for relabeling an object of class @tclass
959 * based on a SID pair (@ssid, @tsid).
960 * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
961 * if insufficient memory is available, or %0 if the SID was
962 * computed successfully.
963 */
964int security_change_sid(u32 ssid,
965 u32 tsid,
966 u16 tclass,
967 u32 *out_sid)
968{
969 return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
970}
971
972/*
973 * Verify that each permission that is defined under the
974 * existing policy is still defined with the same value
975 * in the new policy.
976 */
977static int validate_perm(void *key, void *datum, void *p)
978{
979 struct hashtab *h;
980 struct perm_datum *perdatum, *perdatum2;
981 int rc = 0;
982
983
984 h = p;
985 perdatum = datum;
986
987 perdatum2 = hashtab_search(h, key);
988 if (!perdatum2) {
989 printk(KERN_ERR "security: permission %s disappeared",
990 (char *)key);
991 rc = -ENOENT;
992 goto out;
993 }
994 if (perdatum->value != perdatum2->value) {
995 printk(KERN_ERR "security: the value of permission %s changed",
996 (char *)key);
997 rc = -EINVAL;
998 }
999out:
1000 return rc;
1001}
1002
1003/*
1004 * Verify that each class that is defined under the
1005 * existing policy is still defined with the same
1006 * attributes in the new policy.
1007 */
1008static int validate_class(void *key, void *datum, void *p)
1009{
1010 struct policydb *newp;
1011 struct class_datum *cladatum, *cladatum2;
1012 int rc;
1013
1014 newp = p;
1015 cladatum = datum;
1016
1017 cladatum2 = hashtab_search(newp->p_classes.table, key);
1018 if (!cladatum2) {
1019 printk(KERN_ERR "security: class %s disappeared\n",
1020 (char *)key);
1021 rc = -ENOENT;
1022 goto out;
1023 }
1024 if (cladatum->value != cladatum2->value) {
1025 printk(KERN_ERR "security: the value of class %s changed\n",
1026 (char *)key);
1027 rc = -EINVAL;
1028 goto out;
1029 }
1030 if ((cladatum->comdatum && !cladatum2->comdatum) ||
1031 (!cladatum->comdatum && cladatum2->comdatum)) {
1032 printk(KERN_ERR "security: the inherits clause for the access "
1033 "vector definition for class %s changed\n", (char *)key);
1034 rc = -EINVAL;
1035 goto out;
1036 }
1037 if (cladatum->comdatum) {
1038 rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm,
1039 cladatum2->comdatum->permissions.table);
1040 if (rc) {
1041 printk(" in the access vector definition for class "
1042 "%s\n", (char *)key);
1043 goto out;
1044 }
1045 }
1046 rc = hashtab_map(cladatum->permissions.table, validate_perm,
1047 cladatum2->permissions.table);
1048 if (rc)
1049 printk(" in access vector definition for class %s\n",
1050 (char *)key);
1051out:
1052 return rc;
1053}
1054
1055/* Clone the SID into the new SID table. */
1056static int clone_sid(u32 sid,
1057 struct context *context,
1058 void *arg)
1059{
1060 struct sidtab *s = arg;
1061
1062 return sidtab_insert(s, sid, context);
1063}
1064
1065static inline int convert_context_handle_invalid_context(struct context *context)
1066{
1067 int rc = 0;
1068
1069 if (selinux_enforcing) {
1070 rc = -EINVAL;
1071 } else {
1072 char *s;
1073 u32 len;
1074
1075 context_struct_to_string(context, &s, &len);
1076 printk(KERN_ERR "security: context %s is invalid\n", s);
1077 kfree(s);
1078 }
1079 return rc;
1080}
1081
1082struct convert_context_args {
1083 struct policydb *oldp;
1084 struct policydb *newp;
1085};
1086
1087/*
1088 * Convert the values in the security context
1089 * structure `c' from the values specified
1090 * in the policy `p->oldp' to the values specified
1091 * in the policy `p->newp'. Verify that the
1092 * context is valid under the new policy.
1093 */
1094static int convert_context(u32 key,
1095 struct context *c,
1096 void *p)
1097{
1098 struct convert_context_args *args;
1099 struct context oldc;
1100 struct role_datum *role;
1101 struct type_datum *typdatum;
1102 struct user_datum *usrdatum;
1103 char *s;
1104 u32 len;
1105 int rc;
1106
1107 args = p;
1108
1109 rc = context_cpy(&oldc, c);
1110 if (rc)
1111 goto out;
1112
1113 rc = -EINVAL;
1114
1115 /* Convert the user. */
1116 usrdatum = hashtab_search(args->newp->p_users.table,
1117 args->oldp->p_user_val_to_name[c->user - 1]);
1118 if (!usrdatum) {
1119 goto bad;
1120 }
1121 c->user = usrdatum->value;
1122
1123 /* Convert the role. */
1124 role = hashtab_search(args->newp->p_roles.table,
1125 args->oldp->p_role_val_to_name[c->role - 1]);
1126 if (!role) {
1127 goto bad;
1128 }
1129 c->role = role->value;
1130
1131 /* Convert the type. */
1132 typdatum = hashtab_search(args->newp->p_types.table,
1133 args->oldp->p_type_val_to_name[c->type - 1]);
1134 if (!typdatum) {
1135 goto bad;
1136 }
1137 c->type = typdatum->value;
1138
1139 rc = mls_convert_context(args->oldp, args->newp, c);
1140 if (rc)
1141 goto bad;
1142
1143 /* Check the validity of the new context. */
1144 if (!policydb_context_isvalid(args->newp, c)) {
1145 rc = convert_context_handle_invalid_context(&oldc);
1146 if (rc)
1147 goto bad;
1148 }
1149
1150 context_destroy(&oldc);
1151out:
1152 return rc;
1153bad:
1154 context_struct_to_string(&oldc, &s, &len);
1155 context_destroy(&oldc);
1156 printk(KERN_ERR "security: invalidating context %s\n", s);
1157 kfree(s);
1158 goto out;
1159}
1160
1161extern void selinux_complete_init(void);
1162
1163/**
1164 * security_load_policy - Load a security policy configuration.
1165 * @data: binary policy data
1166 * @len: length of data in bytes
1167 *
1168 * Load a new set of security policy configuration data,
1169 * validate it and convert the SID table as necessary.
1170 * This function will flush the access vector cache after
1171 * loading the new policy.
1172 */
1173int security_load_policy(void *data, size_t len)
1174{
1175 struct policydb oldpolicydb, newpolicydb;
1176 struct sidtab oldsidtab, newsidtab;
1177 struct convert_context_args args;
1178 u32 seqno;
1179 int rc = 0;
1180 struct policy_file file = { data, len }, *fp = &file;
1181
1182 LOAD_LOCK;
1183
1184 if (!ss_initialized) {
1185 avtab_cache_init();
1186 if (policydb_read(&policydb, fp)) {
1187 LOAD_UNLOCK;
1188 avtab_cache_destroy();
1189 return -EINVAL;
1190 }
1191 if (policydb_load_isids(&policydb, &sidtab)) {
1192 LOAD_UNLOCK;
1193 policydb_destroy(&policydb);
1194 avtab_cache_destroy();
1195 return -EINVAL;
1196 }
1197 policydb_loaded_version = policydb.policyvers;
1198 ss_initialized = 1;
1199
1200 LOAD_UNLOCK;
1201 selinux_complete_init();
1202 return 0;
1203 }
1204
1205#if 0
1206 sidtab_hash_eval(&sidtab, "sids");
1207#endif
1208
1209 if (policydb_read(&newpolicydb, fp)) {
1210 LOAD_UNLOCK;
1211 return -EINVAL;
1212 }
1213
1214 sidtab_init(&newsidtab);
1215
1216 /* Verify that the existing classes did not change. */
1217 if (hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb)) {
1218 printk(KERN_ERR "security: the definition of an existing "
1219 "class changed\n");
1220 rc = -EINVAL;
1221 goto err;
1222 }
1223
1224 /* Clone the SID table. */
1225 sidtab_shutdown(&sidtab);
1226 if (sidtab_map(&sidtab, clone_sid, &newsidtab)) {
1227 rc = -ENOMEM;
1228 goto err;
1229 }
1230
1231 /* Convert the internal representations of contexts
1232 in the new SID table and remove invalid SIDs. */
1233 args.oldp = &policydb;
1234 args.newp = &newpolicydb;
1235 sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
1236
1237 /* Save the old policydb and SID table to free later. */
1238 memcpy(&oldpolicydb, &policydb, sizeof policydb);
1239 sidtab_set(&oldsidtab, &sidtab);
1240
1241 /* Install the new policydb and SID table. */
1242 POLICY_WRLOCK;
1243 memcpy(&policydb, &newpolicydb, sizeof policydb);
1244 sidtab_set(&sidtab, &newsidtab);
1245 seqno = ++latest_granting;
1246 policydb_loaded_version = policydb.policyvers;
1247 POLICY_WRUNLOCK;
1248 LOAD_UNLOCK;
1249
1250 /* Free the old policydb and SID table. */
1251 policydb_destroy(&oldpolicydb);
1252 sidtab_destroy(&oldsidtab);
1253
1254 avc_ss_reset(seqno);
1255 selnl_notify_policyload(seqno);
1256
1257 return 0;
1258
1259err:
1260 LOAD_UNLOCK;
1261 sidtab_destroy(&newsidtab);
1262 policydb_destroy(&newpolicydb);
1263 return rc;
1264
1265}
1266
1267/**
1268 * security_port_sid - Obtain the SID for a port.
1269 * @domain: communication domain aka address family
1270 * @type: socket type
1271 * @protocol: protocol number
1272 * @port: port number
1273 * @out_sid: security identifier
1274 */
1275int security_port_sid(u16 domain,
1276 u16 type,
1277 u8 protocol,
1278 u16 port,
1279 u32 *out_sid)
1280{
1281 struct ocontext *c;
1282 int rc = 0;
1283
1284 POLICY_RDLOCK;
1285
1286 c = policydb.ocontexts[OCON_PORT];
1287 while (c) {
1288 if (c->u.port.protocol == protocol &&
1289 c->u.port.low_port <= port &&
1290 c->u.port.high_port >= port)
1291 break;
1292 c = c->next;
1293 }
1294
1295 if (c) {
1296 if (!c->sid[0]) {
1297 rc = sidtab_context_to_sid(&sidtab,
1298 &c->context[0],
1299 &c->sid[0]);
1300 if (rc)
1301 goto out;
1302 }
1303 *out_sid = c->sid[0];
1304 } else {
1305 *out_sid = SECINITSID_PORT;
1306 }
1307
1308out:
1309 POLICY_RDUNLOCK;
1310 return rc;
1311}
1312
1313/**
1314 * security_netif_sid - Obtain the SID for a network interface.
1315 * @name: interface name
1316 * @if_sid: interface SID
1317 * @msg_sid: default SID for received packets
1318 */
1319int security_netif_sid(char *name,
1320 u32 *if_sid,
1321 u32 *msg_sid)
1322{
1323 int rc = 0;
1324 struct ocontext *c;
1325
1326 POLICY_RDLOCK;
1327
1328 c = policydb.ocontexts[OCON_NETIF];
1329 while (c) {
1330 if (strcmp(name, c->u.name) == 0)
1331 break;
1332 c = c->next;
1333 }
1334
1335 if (c) {
1336 if (!c->sid[0] || !c->sid[1]) {
1337 rc = sidtab_context_to_sid(&sidtab,
1338 &c->context[0],
1339 &c->sid[0]);
1340 if (rc)
1341 goto out;
1342 rc = sidtab_context_to_sid(&sidtab,
1343 &c->context[1],
1344 &c->sid[1]);
1345 if (rc)
1346 goto out;
1347 }
1348 *if_sid = c->sid[0];
1349 *msg_sid = c->sid[1];
1350 } else {
1351 *if_sid = SECINITSID_NETIF;
1352 *msg_sid = SECINITSID_NETMSG;
1353 }
1354
1355out:
1356 POLICY_RDUNLOCK;
1357 return rc;
1358}
1359
1360static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
1361{
1362 int i, fail = 0;
1363
1364 for(i = 0; i < 4; i++)
1365 if(addr[i] != (input[i] & mask[i])) {
1366 fail = 1;
1367 break;
1368 }
1369
1370 return !fail;
1371}
1372
1373/**
1374 * security_node_sid - Obtain the SID for a node (host).
1375 * @domain: communication domain aka address family
1376 * @addrp: address
1377 * @addrlen: address length in bytes
1378 * @out_sid: security identifier
1379 */
1380int security_node_sid(u16 domain,
1381 void *addrp,
1382 u32 addrlen,
1383 u32 *out_sid)
1384{
1385 int rc = 0;
1386 struct ocontext *c;
1387
1388 POLICY_RDLOCK;
1389
1390 switch (domain) {
1391 case AF_INET: {
1392 u32 addr;
1393
1394 if (addrlen != sizeof(u32)) {
1395 rc = -EINVAL;
1396 goto out;
1397 }
1398
1399 addr = *((u32 *)addrp);
1400
1401 c = policydb.ocontexts[OCON_NODE];
1402 while (c) {
1403 if (c->u.node.addr == (addr & c->u.node.mask))
1404 break;
1405 c = c->next;
1406 }
1407 break;
1408 }
1409
1410 case AF_INET6:
1411 if (addrlen != sizeof(u64) * 2) {
1412 rc = -EINVAL;
1413 goto out;
1414 }
1415 c = policydb.ocontexts[OCON_NODE6];
1416 while (c) {
1417 if (match_ipv6_addrmask(addrp, c->u.node6.addr,
1418 c->u.node6.mask))
1419 break;
1420 c = c->next;
1421 }
1422 break;
1423
1424 default:
1425 *out_sid = SECINITSID_NODE;
1426 goto out;
1427 }
1428
1429 if (c) {
1430 if (!c->sid[0]) {
1431 rc = sidtab_context_to_sid(&sidtab,
1432 &c->context[0],
1433 &c->sid[0]);
1434 if (rc)
1435 goto out;
1436 }
1437 *out_sid = c->sid[0];
1438 } else {
1439 *out_sid = SECINITSID_NODE;
1440 }
1441
1442out:
1443 POLICY_RDUNLOCK;
1444 return rc;
1445}
1446
1447#define SIDS_NEL 25
1448
1449/**
1450 * security_get_user_sids - Obtain reachable SIDs for a user.
1451 * @fromsid: starting SID
1452 * @username: username
1453 * @sids: array of reachable SIDs for user
1454 * @nel: number of elements in @sids
1455 *
1456 * Generate the set of SIDs for legal security contexts
1457 * for a given user that can be reached by @fromsid.
1458 * Set *@sids to point to a dynamically allocated
1459 * array containing the set of SIDs. Set *@nel to the
1460 * number of elements in the array.
1461 */
1462
1463int security_get_user_sids(u32 fromsid,
1464 char *username,
1465 u32 **sids,
1466 u32 *nel)
1467{
1468 struct context *fromcon, usercon;
1469 u32 *mysids, *mysids2, sid;
1470 u32 mynel = 0, maxnel = SIDS_NEL;
1471 struct user_datum *user;
1472 struct role_datum *role;
1473 struct av_decision avd;
1474 int rc = 0, i, j;
1475
1476 if (!ss_initialized) {
1477 *sids = NULL;
1478 *nel = 0;
1479 goto out;
1480 }
1481
1482 POLICY_RDLOCK;
1483
1484 fromcon = sidtab_search(&sidtab, fromsid);
1485 if (!fromcon) {
1486 rc = -EINVAL;
1487 goto out_unlock;
1488 }
1489
1490 user = hashtab_search(policydb.p_users.table, username);
1491 if (!user) {
1492 rc = -EINVAL;
1493 goto out_unlock;
1494 }
1495 usercon.user = user->value;
1496
1497 mysids = kmalloc(maxnel*sizeof(*mysids), GFP_ATOMIC);
1498 if (!mysids) {
1499 rc = -ENOMEM;
1500 goto out_unlock;
1501 }
1502 memset(mysids, 0, maxnel*sizeof(*mysids));
1503
1504 for (i = ebitmap_startbit(&user->roles); i < ebitmap_length(&user->roles); i++) {
1505 if (!ebitmap_get_bit(&user->roles, i))
1506 continue;
1507 role = policydb.role_val_to_struct[i];
1508 usercon.role = i+1;
1509 for (j = ebitmap_startbit(&role->types); j < ebitmap_length(&role->types); j++) {
1510 if (!ebitmap_get_bit(&role->types, j))
1511 continue;
1512 usercon.type = j+1;
1513
1514 if (mls_setup_user_range(fromcon, user, &usercon))
1515 continue;
1516
1517 rc = context_struct_compute_av(fromcon, &usercon,
1518 SECCLASS_PROCESS,
1519 PROCESS__TRANSITION,
1520 &avd);
1521 if (rc || !(avd.allowed & PROCESS__TRANSITION))
1522 continue;
1523 rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
1524 if (rc) {
1525 kfree(mysids);
1526 goto out_unlock;
1527 }
1528 if (mynel < maxnel) {
1529 mysids[mynel++] = sid;
1530 } else {
1531 maxnel += SIDS_NEL;
1532 mysids2 = kmalloc(maxnel*sizeof(*mysids2), GFP_ATOMIC);
1533 if (!mysids2) {
1534 rc = -ENOMEM;
1535 kfree(mysids);
1536 goto out_unlock;
1537 }
1538 memset(mysids2, 0, maxnel*sizeof(*mysids2));
1539 memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
1540 kfree(mysids);
1541 mysids = mysids2;
1542 mysids[mynel++] = sid;
1543 }
1544 }
1545 }
1546
1547 *sids = mysids;
1548 *nel = mynel;
1549
1550out_unlock:
1551 POLICY_RDUNLOCK;
1552out:
1553 return rc;
1554}
1555
1556/**
1557 * security_genfs_sid - Obtain a SID for a file in a filesystem
1558 * @fstype: filesystem type
1559 * @path: path from root of mount
1560 * @sclass: file security class
1561 * @sid: SID for path
1562 *
1563 * Obtain a SID to use for a file in a filesystem that
1564 * cannot support xattr or use a fixed labeling behavior like
1565 * transition SIDs or task SIDs.
1566 */
1567int security_genfs_sid(const char *fstype,
1568 char *path,
1569 u16 sclass,
1570 u32 *sid)
1571{
1572 int len;
1573 struct genfs *genfs;
1574 struct ocontext *c;
1575 int rc = 0, cmp = 0;
1576
1577 POLICY_RDLOCK;
1578
1579 for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
1580 cmp = strcmp(fstype, genfs->fstype);
1581 if (cmp <= 0)
1582 break;
1583 }
1584
1585 if (!genfs || cmp) {
1586 *sid = SECINITSID_UNLABELED;
1587 rc = -ENOENT;
1588 goto out;
1589 }
1590
1591 for (c = genfs->head; c; c = c->next) {
1592 len = strlen(c->u.name);
1593 if ((!c->v.sclass || sclass == c->v.sclass) &&
1594 (strncmp(c->u.name, path, len) == 0))
1595 break;
1596 }
1597
1598 if (!c) {
1599 *sid = SECINITSID_UNLABELED;
1600 rc = -ENOENT;
1601 goto out;
1602 }
1603
1604 if (!c->sid[0]) {
1605 rc = sidtab_context_to_sid(&sidtab,
1606 &c->context[0],
1607 &c->sid[0]);
1608 if (rc)
1609 goto out;
1610 }
1611
1612 *sid = c->sid[0];
1613out:
1614 POLICY_RDUNLOCK;
1615 return rc;
1616}
1617
1618/**
1619 * security_fs_use - Determine how to handle labeling for a filesystem.
1620 * @fstype: filesystem type
1621 * @behavior: labeling behavior
1622 * @sid: SID for filesystem (superblock)
1623 */
1624int security_fs_use(
1625 const char *fstype,
1626 unsigned int *behavior,
1627 u32 *sid)
1628{
1629 int rc = 0;
1630 struct ocontext *c;
1631
1632 POLICY_RDLOCK;
1633
1634 c = policydb.ocontexts[OCON_FSUSE];
1635 while (c) {
1636 if (strcmp(fstype, c->u.name) == 0)
1637 break;
1638 c = c->next;
1639 }
1640
1641 if (c) {
1642 *behavior = c->v.behavior;
1643 if (!c->sid[0]) {
1644 rc = sidtab_context_to_sid(&sidtab,
1645 &c->context[0],
1646 &c->sid[0]);
1647 if (rc)
1648 goto out;
1649 }
1650 *sid = c->sid[0];
1651 } else {
1652 rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
1653 if (rc) {
1654 *behavior = SECURITY_FS_USE_NONE;
1655 rc = 0;
1656 } else {
1657 *behavior = SECURITY_FS_USE_GENFS;
1658 }
1659 }
1660
1661out:
1662 POLICY_RDUNLOCK;
1663 return rc;
1664}
1665
1666int security_get_bools(int *len, char ***names, int **values)
1667{
1668 int i, rc = -ENOMEM;
1669
1670 POLICY_RDLOCK;
1671 *names = NULL;
1672 *values = NULL;
1673
1674 *len = policydb.p_bools.nprim;
1675 if (!*len) {
1676 rc = 0;
1677 goto out;
1678 }
1679
1680 *names = (char**)kmalloc(sizeof(char*) * *len, GFP_ATOMIC);
1681 if (!*names)
1682 goto err;
1683 memset(*names, 0, sizeof(char*) * *len);
1684
1685 *values = (int*)kmalloc(sizeof(int) * *len, GFP_ATOMIC);
1686 if (!*values)
1687 goto err;
1688
1689 for (i = 0; i < *len; i++) {
1690 size_t name_len;
1691 (*values)[i] = policydb.bool_val_to_struct[i]->state;
1692 name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
1693 (*names)[i] = (char*)kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
1694 if (!(*names)[i])
1695 goto err;
1696 strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
1697 (*names)[i][name_len - 1] = 0;
1698 }
1699 rc = 0;
1700out:
1701 POLICY_RDUNLOCK;
1702 return rc;
1703err:
1704 if (*names) {
1705 for (i = 0; i < *len; i++)
1706 if ((*names)[i])
1707 kfree((*names)[i]);
1708 }
1709 if (*values)
1710 kfree(*values);
1711 goto out;
1712}
1713
1714
1715int security_set_bools(int len, int *values)
1716{
1717 int i, rc = 0;
1718 int lenp, seqno = 0;
1719 struct cond_node *cur;
1720
1721 POLICY_WRLOCK;
1722
1723 lenp = policydb.p_bools.nprim;
1724 if (len != lenp) {
1725 rc = -EFAULT;
1726 goto out;
1727 }
1728
1729 printk(KERN_INFO "security: committed booleans { ");
1730 for (i = 0; i < len; i++) {
1731 if (values[i]) {
1732 policydb.bool_val_to_struct[i]->state = 1;
1733 } else {
1734 policydb.bool_val_to_struct[i]->state = 0;
1735 }
1736 if (i != 0)
1737 printk(", ");
1738 printk("%s:%d", policydb.p_bool_val_to_name[i],
1739 policydb.bool_val_to_struct[i]->state);
1740 }
1741 printk(" }\n");
1742
1743 for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
1744 rc = evaluate_cond_node(&policydb, cur);
1745 if (rc)
1746 goto out;
1747 }
1748
1749 seqno = ++latest_granting;
1750
1751out:
1752 POLICY_WRUNLOCK;
1753 if (!rc) {
1754 avc_ss_reset(seqno);
1755 selnl_notify_policyload(seqno);
1756 }
1757 return rc;
1758}
1759
1760int security_get_bool_value(int bool)
1761{
1762 int rc = 0;
1763 int len;
1764
1765 POLICY_RDLOCK;
1766
1767 len = policydb.p_bools.nprim;
1768 if (bool >= len) {
1769 rc = -EFAULT;
1770 goto out;
1771 }
1772
1773 rc = policydb.bool_val_to_struct[bool]->state;
1774out:
1775 POLICY_RDUNLOCK;
1776 return rc;
1777}
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
new file mode 100644
index 000000000000..e8d907e903cd
--- /dev/null
+++ b/security/selinux/ss/services.h
@@ -0,0 +1,15 @@
1/*
2 * Implementation of the security services.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6#ifndef _SS_SERVICES_H_
7#define _SS_SERVICES_H_
8
9#include "policydb.h"
10#include "sidtab.h"
11
12extern struct policydb policydb;
13
14#endif /* _SS_SERVICES_H_ */
15
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
new file mode 100644
index 000000000000..871c33bd0741
--- /dev/null
+++ b/security/selinux/ss/sidtab.c
@@ -0,0 +1,305 @@
1/*
2 * Implementation of the SID table type.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6#include <linux/kernel.h>
7#include <linux/slab.h>
8#include <linux/spinlock.h>
9#include <linux/errno.h>
10#include <linux/sched.h>
11#include "flask.h"
12#include "security.h"
13#include "sidtab.h"
14
15#define SIDTAB_HASH(sid) \
16(sid & SIDTAB_HASH_MASK)
17
18#define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
19#define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
20#define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
21
22int sidtab_init(struct sidtab *s)
23{
24 int i;
25
26 s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC);
27 if (!s->htable)
28 return -ENOMEM;
29 for (i = 0; i < SIDTAB_SIZE; i++)
30 s->htable[i] = NULL;
31 s->nel = 0;
32 s->next_sid = 1;
33 s->shutdown = 0;
34 INIT_SIDTAB_LOCK(s);
35 return 0;
36}
37
38int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
39{
40 int hvalue, rc = 0;
41 struct sidtab_node *prev, *cur, *newnode;
42
43 if (!s) {
44 rc = -ENOMEM;
45 goto out;
46 }
47
48 hvalue = SIDTAB_HASH(sid);
49 prev = NULL;
50 cur = s->htable[hvalue];
51 while (cur != NULL && sid > cur->sid) {
52 prev = cur;
53 cur = cur->next;
54 }
55
56 if (cur && sid == cur->sid) {
57 rc = -EEXIST;
58 goto out;
59 }
60
61 newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC);
62 if (newnode == NULL) {
63 rc = -ENOMEM;
64 goto out;
65 }
66 newnode->sid = sid;
67 if (context_cpy(&newnode->context, context)) {
68 kfree(newnode);
69 rc = -ENOMEM;
70 goto out;
71 }
72
73 if (prev) {
74 newnode->next = prev->next;
75 wmb();
76 prev->next = newnode;
77 } else {
78 newnode->next = s->htable[hvalue];
79 wmb();
80 s->htable[hvalue] = newnode;
81 }
82
83 s->nel++;
84 if (sid >= s->next_sid)
85 s->next_sid = sid + 1;
86out:
87 return rc;
88}
89
90struct context *sidtab_search(struct sidtab *s, u32 sid)
91{
92 int hvalue;
93 struct sidtab_node *cur;
94
95 if (!s)
96 return NULL;
97
98 hvalue = SIDTAB_HASH(sid);
99 cur = s->htable[hvalue];
100 while (cur != NULL && sid > cur->sid)
101 cur = cur->next;
102
103 if (cur == NULL || sid != cur->sid) {
104 /* Remap invalid SIDs to the unlabeled SID. */
105 sid = SECINITSID_UNLABELED;
106 hvalue = SIDTAB_HASH(sid);
107 cur = s->htable[hvalue];
108 while (cur != NULL && sid > cur->sid)
109 cur = cur->next;
110 if (!cur || sid != cur->sid)
111 return NULL;
112 }
113
114 return &cur->context;
115}
116
117int sidtab_map(struct sidtab *s,
118 int (*apply) (u32 sid,
119 struct context *context,
120 void *args),
121 void *args)
122{
123 int i, rc = 0;
124 struct sidtab_node *cur;
125
126 if (!s)
127 goto out;
128
129 for (i = 0; i < SIDTAB_SIZE; i++) {
130 cur = s->htable[i];
131 while (cur != NULL) {
132 rc = apply(cur->sid, &cur->context, args);
133 if (rc)
134 goto out;
135 cur = cur->next;
136 }
137 }
138out:
139 return rc;
140}
141
142void sidtab_map_remove_on_error(struct sidtab *s,
143 int (*apply) (u32 sid,
144 struct context *context,
145 void *args),
146 void *args)
147{
148 int i, ret;
149 struct sidtab_node *last, *cur, *temp;
150
151 if (!s)
152 return;
153
154 for (i = 0; i < SIDTAB_SIZE; i++) {
155 last = NULL;
156 cur = s->htable[i];
157 while (cur != NULL) {
158 ret = apply(cur->sid, &cur->context, args);
159 if (ret) {
160 if (last) {
161 last->next = cur->next;
162 } else {
163 s->htable[i] = cur->next;
164 }
165
166 temp = cur;
167 cur = cur->next;
168 context_destroy(&temp->context);
169 kfree(temp);
170 s->nel--;
171 } else {
172 last = cur;
173 cur = cur->next;
174 }
175 }
176 }
177
178 return;
179}
180
181static inline u32 sidtab_search_context(struct sidtab *s,
182 struct context *context)
183{
184 int i;
185 struct sidtab_node *cur;
186
187 for (i = 0; i < SIDTAB_SIZE; i++) {
188 cur = s->htable[i];
189 while (cur != NULL) {
190 if (context_cmp(&cur->context, context))
191 return cur->sid;
192 cur = cur->next;
193 }
194 }
195 return 0;
196}
197
198int sidtab_context_to_sid(struct sidtab *s,
199 struct context *context,
200 u32 *out_sid)
201{
202 u32 sid;
203 int ret = 0;
204 unsigned long flags;
205
206 *out_sid = SECSID_NULL;
207
208 sid = sidtab_search_context(s, context);
209 if (!sid) {
210 SIDTAB_LOCK(s, flags);
211 /* Rescan now that we hold the lock. */
212 sid = sidtab_search_context(s, context);
213 if (sid)
214 goto unlock_out;
215 /* No SID exists for the context. Allocate a new one. */
216 if (s->next_sid == UINT_MAX || s->shutdown) {
217 ret = -ENOMEM;
218 goto unlock_out;
219 }
220 sid = s->next_sid++;
221 ret = sidtab_insert(s, sid, context);
222 if (ret)
223 s->next_sid--;
224unlock_out:
225 SIDTAB_UNLOCK(s, flags);
226 }
227
228 if (ret)
229 return ret;
230
231 *out_sid = sid;
232 return 0;
233}
234
235void sidtab_hash_eval(struct sidtab *h, char *tag)
236{
237 int i, chain_len, slots_used, max_chain_len;
238 struct sidtab_node *cur;
239
240 slots_used = 0;
241 max_chain_len = 0;
242 for (i = 0; i < SIDTAB_SIZE; i++) {
243 cur = h->htable[i];
244 if (cur) {
245 slots_used++;
246 chain_len = 0;
247 while (cur) {
248 chain_len++;
249 cur = cur->next;
250 }
251
252 if (chain_len > max_chain_len)
253 max_chain_len = chain_len;
254 }
255 }
256
257 printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
258 "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
259 max_chain_len);
260}
261
262void sidtab_destroy(struct sidtab *s)
263{
264 int i;
265 struct sidtab_node *cur, *temp;
266
267 if (!s)
268 return;
269
270 for (i = 0; i < SIDTAB_SIZE; i++) {
271 cur = s->htable[i];
272 while (cur != NULL) {
273 temp = cur;
274 cur = cur->next;
275 context_destroy(&temp->context);
276 kfree(temp);
277 }
278 s->htable[i] = NULL;
279 }
280 kfree(s->htable);
281 s->htable = NULL;
282 s->nel = 0;
283 s->next_sid = 1;
284}
285
286void sidtab_set(struct sidtab *dst, struct sidtab *src)
287{
288 unsigned long flags;
289
290 SIDTAB_LOCK(src, flags);
291 dst->htable = src->htable;
292 dst->nel = src->nel;
293 dst->next_sid = src->next_sid;
294 dst->shutdown = 0;
295 SIDTAB_UNLOCK(src, flags);
296}
297
298void sidtab_shutdown(struct sidtab *s)
299{
300 unsigned long flags;
301
302 SIDTAB_LOCK(s, flags);
303 s->shutdown = 1;
304 SIDTAB_UNLOCK(s, flags);
305}
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
new file mode 100644
index 000000000000..2fe9dfa3eb3a
--- /dev/null
+++ b/security/selinux/ss/sidtab.h
@@ -0,0 +1,59 @@
1/*
2 * A security identifier table (sidtab) is a hash table
3 * of security context structures indexed by SID value.
4 *
5 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
6 */
7#ifndef _SS_SIDTAB_H_
8#define _SS_SIDTAB_H_
9
10#include "context.h"
11
12struct sidtab_node {
13 u32 sid; /* security identifier */
14 struct context context; /* security context structure */
15 struct sidtab_node *next;
16};
17
18#define SIDTAB_HASH_BITS 7
19#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
20#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
21
22#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
23
24struct sidtab {
25 struct sidtab_node **htable;
26 unsigned int nel; /* number of elements */
27 unsigned int next_sid; /* next SID to allocate */
28 unsigned char shutdown;
29 spinlock_t lock;
30};
31
32int sidtab_init(struct sidtab *s);
33int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
34struct context *sidtab_search(struct sidtab *s, u32 sid);
35
36int sidtab_map(struct sidtab *s,
37 int (*apply) (u32 sid,
38 struct context *context,
39 void *args),
40 void *args);
41
42void sidtab_map_remove_on_error(struct sidtab *s,
43 int (*apply) (u32 sid,
44 struct context *context,
45 void *args),
46 void *args);
47
48int sidtab_context_to_sid(struct sidtab *s,
49 struct context *context,
50 u32 *sid);
51
52void sidtab_hash_eval(struct sidtab *h, char *tag);
53void sidtab_destroy(struct sidtab *s);
54void sidtab_set(struct sidtab *dst, struct sidtab *src);
55void sidtab_shutdown(struct sidtab *s);
56
57#endif /* _SS_SIDTAB_H_ */
58
59
diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c
new file mode 100644
index 000000000000..24a10d36d3b6
--- /dev/null
+++ b/security/selinux/ss/symtab.c
@@ -0,0 +1,44 @@
1/*
2 * Implementation of the symbol table type.
3 *
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
5 */
6#include <linux/kernel.h>
7#include <linux/slab.h>
8#include <linux/string.h>
9#include <linux/errno.h>
10#include "symtab.h"
11
12static unsigned int symhash(struct hashtab *h, void *key)
13{
14 char *p, *keyp;
15 unsigned int size;
16 unsigned int val;
17
18 val = 0;
19 keyp = key;
20 size = strlen(keyp);
21 for (p = keyp; (p - keyp) < size; p++)
22 val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
23 return val & (h->size - 1);
24}
25
26static int symcmp(struct hashtab *h, void *key1, void *key2)
27{
28 char *keyp1, *keyp2;
29
30 keyp1 = key1;
31 keyp2 = key2;
32 return strcmp(keyp1, keyp2);
33}
34
35
36int symtab_init(struct symtab *s, unsigned int size)
37{
38 s->table = hashtab_create(symhash, symcmp, size);
39 if (!s->table)
40 return -1;
41 s->nprim = 0;
42 return 0;
43}
44
diff --git a/security/selinux/ss/symtab.h b/security/selinux/ss/symtab.h
new file mode 100644
index 000000000000..ca422b42fbc0
--- /dev/null
+++ b/security/selinux/ss/symtab.h
@@ -0,0 +1,23 @@
1/*
2 * A symbol table (symtab) maintains associations between symbol
3 * strings and datum values. The type of the datum values
4 * is arbitrary. The symbol table type is implemented
5 * using the hash table type (hashtab).
6 *
7 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
8 */
9#ifndef _SS_SYMTAB_H_
10#define _SS_SYMTAB_H_
11
12#include "hashtab.h"
13
14struct symtab {
15 struct hashtab *table; /* hash table (keyed on a string) */
16 u32 nprim; /* number of primary names in table */
17};
18
19int symtab_init(struct symtab *s, unsigned int size);
20
21#endif /* _SS_SYMTAB_H_ */
22
23