[NetLabel]: SELinux support
[deliverable/linux.git] / security / selinux / ss / mls.c
CommitLineData
1da177e4
LT
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 *
376bd9cb 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
1da177e4 12 */
7420ed23
VY
13/*
14 * Updated: Hewlett-Packard <paul.moore@hp.com>
15 *
16 * Added support to import/export the MLS label
17 *
18 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
19 */
1da177e4
LT
20
21#include <linux/kernel.h>
22#include <linux/slab.h>
23#include <linux/string.h>
24#include <linux/errno.h>
f5c1d5b2 25#include "sidtab.h"
1da177e4
LT
26#include "mls.h"
27#include "policydb.h"
28#include "services.h"
29
30/*
31 * Return the length in bytes for the MLS fields of the
32 * security context string representation of `context'.
33 */
34int mls_compute_context_len(struct context * context)
35{
36 int i, l, len, range;
782ebb99 37 struct ebitmap_node *node;
1da177e4
LT
38
39 if (!selinux_mls_enabled)
40 return 0;
41
42 len = 1; /* for the beginning ":" */
43 for (l = 0; l < 2; l++) {
44 range = 0;
45 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
46
782ebb99
SS
47 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
48 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
49 if (range) {
50 range++;
51 continue;
52 }
53
782ebb99 54 len += strlen(policydb.p_cat_val_to_name[i]) + 1;
1da177e4
LT
55 range++;
56 } else {
57 if (range > 1)
782ebb99 58 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
1da177e4
LT
59 range = 0;
60 }
61 }
62 /* Handle case where last category is the end of range */
63 if (range > 1)
782ebb99 64 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
1da177e4
LT
65
66 if (l == 0) {
67 if (mls_level_eq(&context->range.level[0],
68 &context->range.level[1]))
69 break;
70 else
71 len++;
72 }
73 }
74
75 return len;
76}
77
78/*
79 * Write the security context string representation of
80 * the MLS fields of `context' into the string `*scontext'.
81 * Update `*scontext' to point to the end of the MLS fields.
82 */
83void mls_sid_to_context(struct context *context,
84 char **scontext)
85{
86 char *scontextp;
87 int i, l, range, wrote_sep;
782ebb99 88 struct ebitmap_node *node;
1da177e4
LT
89
90 if (!selinux_mls_enabled)
91 return;
92
93 scontextp = *scontext;
94
95 *scontextp = ':';
96 scontextp++;
97
98 for (l = 0; l < 2; l++) {
99 range = 0;
100 wrote_sep = 0;
101 strcpy(scontextp,
102 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
103 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
104
105 /* categories */
782ebb99
SS
106 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
107 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
108 if (range) {
109 range++;
110 continue;
111 }
112
113 if (!wrote_sep) {
114 *scontextp++ = ':';
115 wrote_sep = 1;
116 } else
117 *scontextp++ = ',';
782ebb99
SS
118 strcpy(scontextp, policydb.p_cat_val_to_name[i]);
119 scontextp += strlen(policydb.p_cat_val_to_name[i]);
1da177e4
LT
120 range++;
121 } else {
122 if (range > 1) {
123 if (range > 2)
124 *scontextp++ = '.';
125 else
126 *scontextp++ = ',';
127
782ebb99
SS
128 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
129 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
1da177e4
LT
130 }
131 range = 0;
132 }
133 }
134
135 /* Handle case where last category is the end of range */
136 if (range > 1) {
137 if (range > 2)
138 *scontextp++ = '.';
139 else
140 *scontextp++ = ',';
141
782ebb99
SS
142 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
143 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
1da177e4
LT
144 }
145
146 if (l == 0) {
147 if (mls_level_eq(&context->range.level[0],
148 &context->range.level[1]))
149 break;
150 else {
151 *scontextp = '-';
152 scontextp++;
153 }
154 }
155 }
156
157 *scontext = scontextp;
158 return;
159}
160
161/*
162 * Return 1 if the MLS fields in the security context
163 * structure `c' are valid. Return 0 otherwise.
164 */
165int mls_context_isvalid(struct policydb *p, struct context *c)
166{
167 struct level_datum *levdatum;
168 struct user_datum *usrdatum;
782ebb99 169 struct ebitmap_node *node;
1da177e4
LT
170 int i, l;
171
172 if (!selinux_mls_enabled)
173 return 1;
174
175 /*
176 * MLS range validity checks: high must dominate low, low level must
177 * be valid (category set <-> sensitivity check), and high level must
178 * be valid (category set <-> sensitivity check)
179 */
180 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
181 /* High does not dominate low. */
182 return 0;
183
184 for (l = 0; l < 2; l++) {
185 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
186 return 0;
187 levdatum = hashtab_search(p->p_levels.table,
188 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
189 if (!levdatum)
190 return 0;
191
782ebb99
SS
192 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
193 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
194 if (i > p->p_cats.nprim)
195 return 0;
782ebb99 196 if (!ebitmap_get_bit(&levdatum->level->cat, i))
1da177e4
LT
197 /*
198 * Category may not be associated with
199 * sensitivity in low level.
200 */
201 return 0;
202 }
203 }
204 }
205
206 if (c->role == OBJECT_R_VAL)
207 return 1;
208
209 /*
210 * User must be authorized for the MLS range.
211 */
212 if (!c->user || c->user > p->p_users.nprim)
213 return 0;
214 usrdatum = p->user_val_to_struct[c->user - 1];
215 if (!mls_range_contains(usrdatum->range, c->range))
216 return 0; /* user may not be associated with range */
217
218 return 1;
219}
220
221/*
222 * Set the MLS fields in the security context structure
223 * `context' based on the string representation in
224 * the string `*scontext'. Update `*scontext' to
225 * point to the end of the string representation of
226 * the MLS fields.
227 *
228 * This function modifies the string in place, inserting
229 * NULL characters to terminate the MLS fields.
f5c1d5b2
JM
230 *
231 * If a def_sid is provided and no MLS field is present,
232 * copy the MLS field of the associated default context.
233 * Used for upgraded to MLS systems where objects may lack
234 * MLS fields.
235 *
236 * Policy read-lock must be held for sidtab lookup.
237 *
1da177e4
LT
238 */
239int mls_context_to_sid(char oldc,
240 char **scontext,
f5c1d5b2
JM
241 struct context *context,
242 struct sidtab *s,
243 u32 def_sid)
1da177e4
LT
244{
245
246 char delim;
247 char *scontextp, *p, *rngptr;
248 struct level_datum *levdatum;
249 struct cat_datum *catdatum, *rngdatum;
250 int l, rc = -EINVAL;
251
e517a0cd
SS
252 if (!selinux_mls_enabled) {
253 if (def_sid != SECSID_NULL && oldc)
ab5703b3 254 *scontext += strlen(*scontext)+1;
1da177e4 255 return 0;
e517a0cd 256 }
1da177e4 257
f5c1d5b2
JM
258 /*
259 * No MLS component to the security context, try and map to
260 * default if provided.
261 */
262 if (!oldc) {
263 struct context *defcon;
264
265 if (def_sid == SECSID_NULL)
266 goto out;
267
268 defcon = sidtab_search(s, def_sid);
269 if (!defcon)
270 goto out;
271
272 rc = mls_copy_context(context, defcon);
1da177e4 273 goto out;
f5c1d5b2 274 }
1da177e4
LT
275
276 /* Extract low sensitivity. */
277 scontextp = p = *scontext;
278 while (*p && *p != ':' && *p != '-')
279 p++;
280
281 delim = *p;
282 if (delim != 0)
283 *p++ = 0;
284
285 for (l = 0; l < 2; l++) {
286 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
287 if (!levdatum) {
288 rc = -EINVAL;
289 goto out;
290 }
291
292 context->range.level[l].sens = levdatum->level->sens;
293
294 if (delim == ':') {
295 /* Extract category set. */
296 while (1) {
297 scontextp = p;
298 while (*p && *p != ',' && *p != '-')
299 p++;
300 delim = *p;
301 if (delim != 0)
302 *p++ = 0;
303
304 /* Separate into range if exists */
305 if ((rngptr = strchr(scontextp, '.')) != NULL) {
306 /* Remove '.' */
307 *rngptr++ = 0;
308 }
309
310 catdatum = hashtab_search(policydb.p_cats.table,
311 scontextp);
312 if (!catdatum) {
313 rc = -EINVAL;
314 goto out;
315 }
316
317 rc = ebitmap_set_bit(&context->range.level[l].cat,
318 catdatum->value - 1, 1);
319 if (rc)
320 goto out;
321
322 /* If range, set all categories in range */
323 if (rngptr) {
324 int i;
325
326 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
327 if (!rngdatum) {
328 rc = -EINVAL;
329 goto out;
330 }
331
332 if (catdatum->value >= rngdatum->value) {
333 rc = -EINVAL;
334 goto out;
335 }
336
337 for (i = catdatum->value; i < rngdatum->value; i++) {
338 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
339 if (rc)
340 goto out;
341 }
342 }
343
344 if (delim != ',')
345 break;
346 }
347 }
348 if (delim == '-') {
349 /* Extract high sensitivity. */
350 scontextp = p;
351 while (*p && *p != ':')
352 p++;
353
354 delim = *p;
355 if (delim != 0)
356 *p++ = 0;
357 } else
358 break;
359 }
360
361 if (l == 0) {
362 context->range.level[1].sens = context->range.level[0].sens;
363 rc = ebitmap_cpy(&context->range.level[1].cat,
364 &context->range.level[0].cat);
365 if (rc)
366 goto out;
367 }
368 *scontext = ++p;
369 rc = 0;
370out:
371 return rc;
372}
373
376bd9cb
DG
374/*
375 * Set the MLS fields in the security context structure
376 * `context' based on the string representation in
377 * the string `str'. This function will allocate temporary memory with the
378 * given constraints of gfp_mask.
379 */
380int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
381{
382 char *tmpstr, *freestr;
383 int rc;
384
385 if (!selinux_mls_enabled)
386 return -EINVAL;
387
388 /* we need freestr because mls_context_to_sid will change
389 the value of tmpstr */
390 tmpstr = freestr = kstrdup(str, gfp_mask);
391 if (!tmpstr) {
392 rc = -ENOMEM;
393 } else {
394 rc = mls_context_to_sid(':', &tmpstr, context,
395 NULL, SECSID_NULL);
396 kfree(freestr);
397 }
398
399 return rc;
400}
401
1da177e4
LT
402/*
403 * Copies the effective MLS range from `src' into `dst'.
404 */
405static inline int mls_scopy_context(struct context *dst,
406 struct context *src)
407{
408 int l, rc = 0;
409
410 /* Copy the MLS range from the source context */
411 for (l = 0; l < 2; l++) {
412 dst->range.level[l].sens = src->range.level[0].sens;
413 rc = ebitmap_cpy(&dst->range.level[l].cat,
414 &src->range.level[0].cat);
415 if (rc)
416 break;
417 }
418
419 return rc;
420}
421
422/*
423 * Copies the MLS range `range' into `context'.
424 */
425static inline int mls_range_set(struct context *context,
426 struct mls_range *range)
427{
428 int l, rc = 0;
429
430 /* Copy the MLS range into the context */
431 for (l = 0; l < 2; l++) {
432 context->range.level[l].sens = range->level[l].sens;
433 rc = ebitmap_cpy(&context->range.level[l].cat,
434 &range->level[l].cat);
435 if (rc)
436 break;
437 }
438
439 return rc;
440}
441
442int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
443 struct context *usercon)
444{
445 if (selinux_mls_enabled) {
446 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
447 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
448 struct mls_level *user_low = &(user->range.level[0]);
449 struct mls_level *user_clr = &(user->range.level[1]);
450 struct mls_level *user_def = &(user->dfltlevel);
451 struct mls_level *usercon_sen = &(usercon->range.level[0]);
452 struct mls_level *usercon_clr = &(usercon->range.level[1]);
453
454 /* Honor the user's default level if we can */
455 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
456 *usercon_sen = *user_def;
457 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
458 *usercon_sen = *fromcon_sen;
459 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
460 *usercon_sen = *user_low;
461 } else
462 return -EINVAL;
463
464 /* Lower the clearance of available contexts
465 if the clearance of "fromcon" is lower than
466 that of the user's default clearance (but
467 only if the "fromcon" clearance dominates
468 the user's computed sensitivity level) */
469 if (mls_level_dom(user_clr, fromcon_clr)) {
470 *usercon_clr = *fromcon_clr;
471 } else if (mls_level_dom(fromcon_clr, user_clr)) {
472 *usercon_clr = *user_clr;
473 } else
474 return -EINVAL;
475 }
476
477 return 0;
478}
479
480/*
481 * Convert the MLS fields in the security context
482 * structure `c' from the values specified in the
483 * policy `oldp' to the values specified in the policy `newp'.
484 */
485int mls_convert_context(struct policydb *oldp,
486 struct policydb *newp,
487 struct context *c)
488{
489 struct level_datum *levdatum;
490 struct cat_datum *catdatum;
491 struct ebitmap bitmap;
782ebb99 492 struct ebitmap_node *node;
1da177e4
LT
493 int l, i;
494
495 if (!selinux_mls_enabled)
496 return 0;
497
498 for (l = 0; l < 2; l++) {
499 levdatum = hashtab_search(newp->p_levels.table,
500 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
501
502 if (!levdatum)
503 return -EINVAL;
504 c->range.level[l].sens = levdatum->level->sens;
505
506 ebitmap_init(&bitmap);
782ebb99
SS
507 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
508 if (ebitmap_node_get_bit(node, i)) {
1da177e4
LT
509 int rc;
510
511 catdatum = hashtab_search(newp->p_cats.table,
782ebb99 512 oldp->p_cat_val_to_name[i]);
1da177e4
LT
513 if (!catdatum)
514 return -EINVAL;
515 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
516 if (rc)
517 return rc;
518 }
519 }
520 ebitmap_destroy(&c->range.level[l].cat);
521 c->range.level[l].cat = bitmap;
522 }
523
524 return 0;
525}
526
527int mls_compute_sid(struct context *scontext,
528 struct context *tcontext,
529 u16 tclass,
530 u32 specified,
531 struct context *newcontext)
532{
533 if (!selinux_mls_enabled)
534 return 0;
535
536 switch (specified) {
537 case AVTAB_TRANSITION:
538 if (tclass == SECCLASS_PROCESS) {
539 struct range_trans *rangetr;
540 /* Look for a range transition rule. */
541 for (rangetr = policydb.range_tr; rangetr;
542 rangetr = rangetr->next) {
543 if (rangetr->dom == scontext->type &&
544 rangetr->type == tcontext->type) {
545 /* Set the range from the rule */
546 return mls_range_set(newcontext,
547 &rangetr->range);
548 }
549 }
550 }
551 /* Fallthrough */
552 case AVTAB_CHANGE:
553 if (tclass == SECCLASS_PROCESS)
554 /* Use the process MLS attributes. */
555 return mls_copy_context(newcontext, scontext);
556 else
557 /* Use the process effective MLS attributes. */
558 return mls_scopy_context(newcontext, scontext);
559 case AVTAB_MEMBER:
560 /* Only polyinstantiate the MLS attributes if
561 the type is being polyinstantiated */
562 if (newcontext->type != tcontext->type) {
563 /* Use the process effective MLS attributes. */
564 return mls_scopy_context(newcontext, scontext);
565 } else {
566 /* Use the related object MLS attributes. */
567 return mls_copy_context(newcontext, tcontext);
568 }
569 default:
570 return -EINVAL;
571 }
572 return -EINVAL;
573}
574
7420ed23
VY
575/**
576 * mls_export_lvl - Export the MLS sensitivity levels
577 * @context: the security context
578 * @low: the low sensitivity level
579 * @high: the high sensitivity level
580 *
581 * Description:
582 * Given the security context copy the low MLS sensitivity level into lvl_low
583 * and the high sensitivity level in lvl_high. The MLS levels are only
584 * exported if the pointers are not NULL, if they are NULL then that level is
585 * not exported.
586 *
587 */
588void mls_export_lvl(const struct context *context, u32 *low, u32 *high)
589{
590 if (!selinux_mls_enabled)
591 return;
592
593 if (low != NULL)
594 *low = context->range.level[0].sens - 1;
595 if (high != NULL)
596 *high = context->range.level[1].sens - 1;
597}
598
599/**
600 * mls_import_lvl - Import the MLS sensitivity levels
601 * @context: the security context
602 * @low: the low sensitivity level
603 * @high: the high sensitivity level
604 *
605 * Description:
606 * Given the security context and the two sensitivty levels, set the MLS levels
607 * in the context according the two given as parameters. Returns zero on
608 * success, negative values on failure.
609 *
610 */
611void mls_import_lvl(struct context *context, u32 low, u32 high)
612{
613 if (!selinux_mls_enabled)
614 return;
615
616 context->range.level[0].sens = low + 1;
617 context->range.level[1].sens = high + 1;
618}
619
620/**
621 * mls_export_cat - Export the MLS categories
622 * @context: the security context
623 * @low: the low category
624 * @low_len: length of the cat_low bitmap in bytes
625 * @high: the high category
626 * @high_len: length of the cat_high bitmap in bytes
627 *
628 * Description:
629 * Given the security context export the low MLS category bitmap into cat_low
630 * and the high category bitmap into cat_high. The MLS categories are only
631 * exported if the pointers are not NULL, if they are NULL then that level is
632 * not exported. The caller is responsibile for freeing the memory when
633 * finished. Returns zero on success, negative values on failure.
634 *
635 */
636int mls_export_cat(const struct context *context,
637 unsigned char **low,
638 size_t *low_len,
639 unsigned char **high,
640 size_t *high_len)
641{
642 int rc = -EPERM;
643
644 if (!selinux_mls_enabled)
645 return 0;
646
647 if (low != NULL) {
648 rc = ebitmap_export(&context->range.level[0].cat,
649 low,
650 low_len);
651 if (rc != 0)
652 goto export_cat_failure;
653 }
654 if (high != NULL) {
655 rc = ebitmap_export(&context->range.level[1].cat,
656 high,
657 high_len);
658 if (rc != 0)
659 goto export_cat_failure;
660 }
661
662 return 0;
663
664export_cat_failure:
665 if (low != NULL)
666 kfree(*low);
667 if (high != NULL)
668 kfree(*high);
669 return rc;
670}
671
672/**
673 * mls_import_cat - Import the MLS categories
674 * @context: the security context
675 * @low: the low category
676 * @low_len: length of the cat_low bitmap in bytes
677 * @high: the high category
678 * @high_len: length of the cat_high bitmap in bytes
679 *
680 * Description:
681 * Given the security context and the two category bitmap strings import the
682 * categories into the security context. The MLS categories are only imported
683 * if the pointers are not NULL, if they are NULL they are skipped. Returns
684 * zero on success, negative values on failure.
685 *
686 */
687int mls_import_cat(struct context *context,
688 const unsigned char *low,
689 size_t low_len,
690 const unsigned char *high,
691 size_t high_len)
692{
693 int rc = -EPERM;
694
695 if (!selinux_mls_enabled)
696 return 0;
697
698 if (low != NULL) {
699 rc = ebitmap_import(low,
700 low_len,
701 &context->range.level[0].cat);
702 if (rc != 0)
703 goto import_cat_failure;
704 }
705 if (high != NULL) {
706 if (high == low)
707 rc = ebitmap_cpy(&context->range.level[1].cat,
708 &context->range.level[0].cat);
709 else
710 rc = ebitmap_import(high,
711 high_len,
712 &context->range.level[1].cat);
713 if (rc != 0)
714 goto import_cat_failure;
715 }
716
717 return 0;
718
719import_cat_failure:
720 ebitmap_destroy(&context->range.level[0].cat);
721 ebitmap_destroy(&context->range.level[1].cat);
722 return rc;
723}
This page took 0.166238 seconds and 5 git commands to generate.