/spare/repo/netdev-2.6 branch 'master'
[deliverable/linux.git] / security / selinux / ss / mls.c
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 "sidtab.h"
19 #include "mls.h"
20 #include "policydb.h"
21 #include "services.h"
22
23 /*
24 * Return the length in bytes for the MLS fields of the
25 * security context string representation of `context'.
26 */
27 int mls_compute_context_len(struct context * context)
28 {
29 int i, l, len, range;
30
31 if (!selinux_mls_enabled)
32 return 0;
33
34 len = 1; /* for the beginning ":" */
35 for (l = 0; l < 2; l++) {
36 range = 0;
37 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
38
39 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
40 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
41 if (range) {
42 range++;
43 continue;
44 }
45
46 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
47 range++;
48 } else {
49 if (range > 1)
50 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
51 range = 0;
52 }
53 }
54 /* Handle case where last category is the end of range */
55 if (range > 1)
56 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
57
58 if (l == 0) {
59 if (mls_level_eq(&context->range.level[0],
60 &context->range.level[1]))
61 break;
62 else
63 len++;
64 }
65 }
66
67 return len;
68 }
69
70 /*
71 * Write the security context string representation of
72 * the MLS fields of `context' into the string `*scontext'.
73 * Update `*scontext' to point to the end of the MLS fields.
74 */
75 void mls_sid_to_context(struct context *context,
76 char **scontext)
77 {
78 char *scontextp;
79 int i, l, range, wrote_sep;
80
81 if (!selinux_mls_enabled)
82 return;
83
84 scontextp = *scontext;
85
86 *scontextp = ':';
87 scontextp++;
88
89 for (l = 0; l < 2; l++) {
90 range = 0;
91 wrote_sep = 0;
92 strcpy(scontextp,
93 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
94 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
95
96 /* categories */
97 for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
98 if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
99 if (range) {
100 range++;
101 continue;
102 }
103
104 if (!wrote_sep) {
105 *scontextp++ = ':';
106 wrote_sep = 1;
107 } else
108 *scontextp++ = ',';
109 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
110 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
111 range++;
112 } else {
113 if (range > 1) {
114 if (range > 2)
115 *scontextp++ = '.';
116 else
117 *scontextp++ = ',';
118
119 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
120 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
121 }
122 range = 0;
123 }
124 }
125
126 /* Handle case where last category is the end of range */
127 if (range > 1) {
128 if (range > 2)
129 *scontextp++ = '.';
130 else
131 *scontextp++ = ',';
132
133 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
134 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
135 }
136
137 if (l == 0) {
138 if (mls_level_eq(&context->range.level[0],
139 &context->range.level[1]))
140 break;
141 else {
142 *scontextp = '-';
143 scontextp++;
144 }
145 }
146 }
147
148 *scontext = scontextp;
149 return;
150 }
151
152 /*
153 * Return 1 if the MLS fields in the security context
154 * structure `c' are valid. Return 0 otherwise.
155 */
156 int mls_context_isvalid(struct policydb *p, struct context *c)
157 {
158 struct level_datum *levdatum;
159 struct user_datum *usrdatum;
160 int i, l;
161
162 if (!selinux_mls_enabled)
163 return 1;
164
165 /*
166 * MLS range validity checks: high must dominate low, low level must
167 * be valid (category set <-> sensitivity check), and high level must
168 * be valid (category set <-> sensitivity check)
169 */
170 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
171 /* High does not dominate low. */
172 return 0;
173
174 for (l = 0; l < 2; l++) {
175 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
176 return 0;
177 levdatum = hashtab_search(p->p_levels.table,
178 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
179 if (!levdatum)
180 return 0;
181
182 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
183 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
184 if (i > p->p_cats.nprim)
185 return 0;
186 if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
187 /*
188 * Category may not be associated with
189 * sensitivity in low level.
190 */
191 return 0;
192 }
193 }
194 }
195
196 if (c->role == OBJECT_R_VAL)
197 return 1;
198
199 /*
200 * User must be authorized for the MLS range.
201 */
202 if (!c->user || c->user > p->p_users.nprim)
203 return 0;
204 usrdatum = p->user_val_to_struct[c->user - 1];
205 if (!mls_range_contains(usrdatum->range, c->range))
206 return 0; /* user may not be associated with range */
207
208 return 1;
209 }
210
211 /*
212 * Copies the MLS range from `src' into `dst'.
213 */
214 static inline int mls_copy_context(struct context *dst,
215 struct context *src)
216 {
217 int l, rc = 0;
218
219 /* Copy the MLS range from the source context */
220 for (l = 0; l < 2; l++) {
221 dst->range.level[l].sens = src->range.level[l].sens;
222 rc = ebitmap_cpy(&dst->range.level[l].cat,
223 &src->range.level[l].cat);
224 if (rc)
225 break;
226 }
227
228 return rc;
229 }
230
231 /*
232 * Set the MLS fields in the security context structure
233 * `context' based on the string representation in
234 * the string `*scontext'. Update `*scontext' to
235 * point to the end of the string representation of
236 * the MLS fields.
237 *
238 * This function modifies the string in place, inserting
239 * NULL characters to terminate the MLS fields.
240 *
241 * If a def_sid is provided and no MLS field is present,
242 * copy the MLS field of the associated default context.
243 * Used for upgraded to MLS systems where objects may lack
244 * MLS fields.
245 *
246 * Policy read-lock must be held for sidtab lookup.
247 *
248 */
249 int mls_context_to_sid(char oldc,
250 char **scontext,
251 struct context *context,
252 struct sidtab *s,
253 u32 def_sid)
254 {
255
256 char delim;
257 char *scontextp, *p, *rngptr;
258 struct level_datum *levdatum;
259 struct cat_datum *catdatum, *rngdatum;
260 int l, rc = -EINVAL;
261
262 if (!selinux_mls_enabled)
263 return 0;
264
265 /*
266 * No MLS component to the security context, try and map to
267 * default if provided.
268 */
269 if (!oldc) {
270 struct context *defcon;
271
272 if (def_sid == SECSID_NULL)
273 goto out;
274
275 defcon = sidtab_search(s, def_sid);
276 if (!defcon)
277 goto out;
278
279 rc = mls_copy_context(context, defcon);
280 goto out;
281 }
282
283 /* Extract low sensitivity. */
284 scontextp = p = *scontext;
285 while (*p && *p != ':' && *p != '-')
286 p++;
287
288 delim = *p;
289 if (delim != 0)
290 *p++ = 0;
291
292 for (l = 0; l < 2; l++) {
293 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
294 if (!levdatum) {
295 rc = -EINVAL;
296 goto out;
297 }
298
299 context->range.level[l].sens = levdatum->level->sens;
300
301 if (delim == ':') {
302 /* Extract category set. */
303 while (1) {
304 scontextp = p;
305 while (*p && *p != ',' && *p != '-')
306 p++;
307 delim = *p;
308 if (delim != 0)
309 *p++ = 0;
310
311 /* Separate into range if exists */
312 if ((rngptr = strchr(scontextp, '.')) != NULL) {
313 /* Remove '.' */
314 *rngptr++ = 0;
315 }
316
317 catdatum = hashtab_search(policydb.p_cats.table,
318 scontextp);
319 if (!catdatum) {
320 rc = -EINVAL;
321 goto out;
322 }
323
324 rc = ebitmap_set_bit(&context->range.level[l].cat,
325 catdatum->value - 1, 1);
326 if (rc)
327 goto out;
328
329 /* If range, set all categories in range */
330 if (rngptr) {
331 int i;
332
333 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
334 if (!rngdatum) {
335 rc = -EINVAL;
336 goto out;
337 }
338
339 if (catdatum->value >= rngdatum->value) {
340 rc = -EINVAL;
341 goto out;
342 }
343
344 for (i = catdatum->value; i < rngdatum->value; i++) {
345 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
346 if (rc)
347 goto out;
348 }
349 }
350
351 if (delim != ',')
352 break;
353 }
354 }
355 if (delim == '-') {
356 /* Extract high sensitivity. */
357 scontextp = p;
358 while (*p && *p != ':')
359 p++;
360
361 delim = *p;
362 if (delim != 0)
363 *p++ = 0;
364 } else
365 break;
366 }
367
368 if (l == 0) {
369 context->range.level[1].sens = context->range.level[0].sens;
370 rc = ebitmap_cpy(&context->range.level[1].cat,
371 &context->range.level[0].cat);
372 if (rc)
373 goto out;
374 }
375 *scontext = ++p;
376 rc = 0;
377 out:
378 return rc;
379 }
380
381 /*
382 * Copies the effective MLS range from `src' into `dst'.
383 */
384 static inline int mls_scopy_context(struct context *dst,
385 struct context *src)
386 {
387 int l, rc = 0;
388
389 /* Copy the MLS range from the source context */
390 for (l = 0; l < 2; l++) {
391 dst->range.level[l].sens = src->range.level[0].sens;
392 rc = ebitmap_cpy(&dst->range.level[l].cat,
393 &src->range.level[0].cat);
394 if (rc)
395 break;
396 }
397
398 return rc;
399 }
400
401 /*
402 * Copies the MLS range `range' into `context'.
403 */
404 static inline int mls_range_set(struct context *context,
405 struct mls_range *range)
406 {
407 int l, rc = 0;
408
409 /* Copy the MLS range into the context */
410 for (l = 0; l < 2; l++) {
411 context->range.level[l].sens = range->level[l].sens;
412 rc = ebitmap_cpy(&context->range.level[l].cat,
413 &range->level[l].cat);
414 if (rc)
415 break;
416 }
417
418 return rc;
419 }
420
421 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
422 struct context *usercon)
423 {
424 if (selinux_mls_enabled) {
425 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
426 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
427 struct mls_level *user_low = &(user->range.level[0]);
428 struct mls_level *user_clr = &(user->range.level[1]);
429 struct mls_level *user_def = &(user->dfltlevel);
430 struct mls_level *usercon_sen = &(usercon->range.level[0]);
431 struct mls_level *usercon_clr = &(usercon->range.level[1]);
432
433 /* Honor the user's default level if we can */
434 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
435 *usercon_sen = *user_def;
436 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
437 *usercon_sen = *fromcon_sen;
438 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
439 *usercon_sen = *user_low;
440 } else
441 return -EINVAL;
442
443 /* Lower the clearance of available contexts
444 if the clearance of "fromcon" is lower than
445 that of the user's default clearance (but
446 only if the "fromcon" clearance dominates
447 the user's computed sensitivity level) */
448 if (mls_level_dom(user_clr, fromcon_clr)) {
449 *usercon_clr = *fromcon_clr;
450 } else if (mls_level_dom(fromcon_clr, user_clr)) {
451 *usercon_clr = *user_clr;
452 } else
453 return -EINVAL;
454 }
455
456 return 0;
457 }
458
459 /*
460 * Convert the MLS fields in the security context
461 * structure `c' from the values specified in the
462 * policy `oldp' to the values specified in the policy `newp'.
463 */
464 int mls_convert_context(struct policydb *oldp,
465 struct policydb *newp,
466 struct context *c)
467 {
468 struct level_datum *levdatum;
469 struct cat_datum *catdatum;
470 struct ebitmap bitmap;
471 int l, i;
472
473 if (!selinux_mls_enabled)
474 return 0;
475
476 for (l = 0; l < 2; l++) {
477 levdatum = hashtab_search(newp->p_levels.table,
478 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
479
480 if (!levdatum)
481 return -EINVAL;
482 c->range.level[l].sens = levdatum->level->sens;
483
484 ebitmap_init(&bitmap);
485 for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
486 if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
487 int rc;
488
489 catdatum = hashtab_search(newp->p_cats.table,
490 oldp->p_cat_val_to_name[i - 1]);
491 if (!catdatum)
492 return -EINVAL;
493 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
494 if (rc)
495 return rc;
496 }
497 }
498 ebitmap_destroy(&c->range.level[l].cat);
499 c->range.level[l].cat = bitmap;
500 }
501
502 return 0;
503 }
504
505 int mls_compute_sid(struct context *scontext,
506 struct context *tcontext,
507 u16 tclass,
508 u32 specified,
509 struct context *newcontext)
510 {
511 if (!selinux_mls_enabled)
512 return 0;
513
514 switch (specified) {
515 case AVTAB_TRANSITION:
516 if (tclass == SECCLASS_PROCESS) {
517 struct range_trans *rangetr;
518 /* Look for a range transition rule. */
519 for (rangetr = policydb.range_tr; rangetr;
520 rangetr = rangetr->next) {
521 if (rangetr->dom == scontext->type &&
522 rangetr->type == tcontext->type) {
523 /* Set the range from the rule */
524 return mls_range_set(newcontext,
525 &rangetr->range);
526 }
527 }
528 }
529 /* Fallthrough */
530 case AVTAB_CHANGE:
531 if (tclass == SECCLASS_PROCESS)
532 /* Use the process MLS attributes. */
533 return mls_copy_context(newcontext, scontext);
534 else
535 /* Use the process effective MLS attributes. */
536 return mls_scopy_context(newcontext, scontext);
537 case AVTAB_MEMBER:
538 /* Only polyinstantiate the MLS attributes if
539 the type is being polyinstantiated */
540 if (newcontext->type != tcontext->type) {
541 /* Use the process effective MLS attributes. */
542 return mls_scopy_context(newcontext, scontext);
543 } else {
544 /* Use the related object MLS attributes. */
545 return mls_copy_context(newcontext, tcontext);
546 }
547 default:
548 return -EINVAL;
549 }
550 return -EINVAL;
551 }
552
This page took 0.044515 seconds and 5 git commands to generate.