2 * Implementation of the multi-level security (MLS) policy.
4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
9 * Support for enhanced MLS infrastructure.
11 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/string.h>
17 #include <linux/errno.h>
23 * Return the length in bytes for the MLS fields of the
24 * security context string representation of `context'.
26 int mls_compute_context_len(struct context
* context
)
30 if (!selinux_mls_enabled
)
33 len
= 1; /* for the beginning ":" */
34 for (l
= 0; l
< 2; l
++) {
36 len
+= strlen(policydb
.p_sens_val_to_name
[context
->range
.level
[l
].sens
- 1]);
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)) {
45 len
+= strlen(policydb
.p_cat_val_to_name
[i
- 1]) + 1;
49 len
+= strlen(policydb
.p_cat_val_to_name
[i
- 2]) + 1;
53 /* Handle case where last category is the end of range */
55 len
+= strlen(policydb
.p_cat_val_to_name
[i
- 2]) + 1;
58 if (mls_level_eq(&context
->range
.level
[0],
59 &context
->range
.level
[1]))
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.
74 void mls_sid_to_context(struct context
*context
,
78 int i
, l
, range
, wrote_sep
;
80 if (!selinux_mls_enabled
)
83 scontextp
= *scontext
;
88 for (l
= 0; l
< 2; l
++) {
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]);
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)) {
108 strcpy(scontextp
, policydb
.p_cat_val_to_name
[i
- 1]);
109 scontextp
+= strlen(policydb
.p_cat_val_to_name
[i
- 1]);
118 strcpy(scontextp
, policydb
.p_cat_val_to_name
[i
- 2]);
119 scontextp
+= strlen(policydb
.p_cat_val_to_name
[i
- 2]);
125 /* Handle case where last category is the end of range */
132 strcpy(scontextp
, policydb
.p_cat_val_to_name
[i
- 2]);
133 scontextp
+= strlen(policydb
.p_cat_val_to_name
[i
- 2]);
137 if (mls_level_eq(&context
->range
.level
[0],
138 &context
->range
.level
[1]))
147 *scontext
= scontextp
;
152 * Return 1 if the MLS fields in the security context
153 * structure `c' are valid. Return 0 otherwise.
155 int mls_context_isvalid(struct policydb
*p
, struct context
*c
)
157 struct level_datum
*levdatum
;
158 struct user_datum
*usrdatum
;
161 if (!selinux_mls_enabled
)
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)
169 if (!mls_level_dom(&c
->range
.level
[1], &c
->range
.level
[0]))
170 /* High does not dominate low. */
173 for (l
= 0; l
< 2; l
++) {
174 if (!c
->range
.level
[l
].sens
|| c
->range
.level
[l
].sens
> p
->p_levels
.nprim
)
176 levdatum
= hashtab_search(p
->p_levels
.table
,
177 p
->p_sens_val_to_name
[c
->range
.level
[l
].sens
- 1]);
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
)
185 if (!ebitmap_get_bit(&levdatum
->level
->cat
, i
- 1))
187 * Category may not be associated with
188 * sensitivity in low level.
195 if (c
->role
== OBJECT_R_VAL
)
199 * User must be authorized for the MLS range.
201 if (!c
->user
|| c
->user
> p
->p_users
.nprim
)
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 */
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
217 * This function modifies the string in place, inserting
218 * NULL characters to terminate the MLS fields.
220 int mls_context_to_sid(char oldc
,
222 struct context
*context
)
226 char *scontextp
, *p
, *rngptr
;
227 struct level_datum
*levdatum
;
228 struct cat_datum
*catdatum
, *rngdatum
;
231 if (!selinux_mls_enabled
)
234 /* No MLS component to the security context. */
238 /* Extract low sensitivity. */
239 scontextp
= p
= *scontext
;
240 while (*p
&& *p
!= ':' && *p
!= '-')
247 for (l
= 0; l
< 2; l
++) {
248 levdatum
= hashtab_search(policydb
.p_levels
.table
, scontextp
);
254 context
->range
.level
[l
].sens
= levdatum
->level
->sens
;
257 /* Extract category set. */
260 while (*p
&& *p
!= ',' && *p
!= '-')
266 /* Separate into range if exists */
267 if ((rngptr
= strchr(scontextp
, '.')) != NULL
) {
272 catdatum
= hashtab_search(policydb
.p_cats
.table
,
279 rc
= ebitmap_set_bit(&context
->range
.level
[l
].cat
,
280 catdatum
->value
- 1, 1);
284 /* If range, set all categories in range */
288 rngdatum
= hashtab_search(policydb
.p_cats
.table
, rngptr
);
294 if (catdatum
->value
>= rngdatum
->value
) {
299 for (i
= catdatum
->value
; i
< rngdatum
->value
; i
++) {
300 rc
= ebitmap_set_bit(&context
->range
.level
[l
].cat
, i
, 1);
311 /* Extract high sensitivity. */
313 while (*p
&& *p
!= ':')
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
);
337 * Copies the MLS range from `src' into `dst'.
339 static inline int mls_copy_context(struct context
*dst
,
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
);
357 * Copies the effective MLS range from `src' into `dst'.
359 static inline int mls_scopy_context(struct context
*dst
,
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
);
377 * Copies the MLS range `range' into `context'.
379 static inline int mls_range_set(struct context
*context
,
380 struct mls_range
*range
)
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
);
396 int mls_setup_user_range(struct context
*fromcon
, struct user_datum
*user
,
397 struct context
*usercon
)
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]);
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
;
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
;
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'.
439 int mls_convert_context(struct policydb
*oldp
,
440 struct policydb
*newp
,
443 struct level_datum
*levdatum
;
444 struct cat_datum
*catdatum
;
445 struct ebitmap bitmap
;
448 if (!selinux_mls_enabled
)
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]);
457 c
->range
.level
[l
].sens
= levdatum
->level
->sens
;
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)) {
464 catdatum
= hashtab_search(newp
->p_cats
.table
,
465 oldp
->p_cat_val_to_name
[i
- 1]);
468 rc
= ebitmap_set_bit(&bitmap
, catdatum
->value
- 1, 1);
473 ebitmap_destroy(&c
->range
.level
[l
].cat
);
474 c
->range
.level
[l
].cat
= bitmap
;
480 int mls_compute_sid(struct context
*scontext
,
481 struct context
*tcontext
,
484 struct context
*newcontext
)
486 if (!selinux_mls_enabled
)
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
,
506 if (tclass
== SECCLASS_PROCESS
)
507 /* Use the process MLS attributes. */
508 return mls_copy_context(newcontext
, scontext
);
510 /* Use the process effective MLS attributes. */
511 return mls_scopy_context(newcontext
, scontext
);
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
);
519 /* Use the related object MLS attributes. */
520 return mls_copy_context(newcontext
, tcontext
);