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>
24 * Return the length in bytes for the MLS fields of the
25 * security context string representation of `context'.
27 int mls_compute_context_len(struct context * context)
31 if (!selinux_mls_enabled)
34 len = 1; /* for the beginning ":" */
35 for (l = 0; l < 2; l++) {
37 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
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)) {
46 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
50 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
54 /* Handle case where last category is the end of range */
56 len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
59 if (mls_level_eq(&context->range.level[0],
60 &context->range.level[1]))
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.
75 void mls_sid_to_context(struct context *context,
79 int i, l, range, wrote_sep;
81 if (!selinux_mls_enabled)
84 scontextp = *scontext;
89 for (l = 0; l < 2; l++) {
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]);
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)) {
109 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
110 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
119 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
120 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
126 /* Handle case where last category is the end of range */
133 strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
134 scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
138 if (mls_level_eq(&context->range.level[0],
139 &context->range.level[1]))
148 *scontext = scontextp;
153 * Return 1 if the MLS fields in the security context
154 * structure `c' are valid. Return 0 otherwise.
156 int mls_context_isvalid(struct policydb *p, struct context *c)
158 struct level_datum *levdatum;
159 struct user_datum *usrdatum;
162 if (!selinux_mls_enabled)
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)
170 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
171 /* High does not dominate low. */
174 for (l = 0; l < 2; l++) {
175 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
177 levdatum = hashtab_search(p->p_levels.table,
178 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
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)
186 if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
188 * Category may not be associated with
189 * sensitivity in low level.
196 if (c->role == OBJECT_R_VAL)
200 * User must be authorized for the MLS range.
202 if (!c->user || c->user > p->p_users.nprim)
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 */
212 * Copies the MLS range from `src' into `dst'.
214 static inline int mls_copy_context(struct context *dst,
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);
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
238 * This function modifies the string in place, inserting
239 * NULL characters to terminate the MLS fields.
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
246 * Policy read-lock must be held for sidtab lookup.
249 int mls_context_to_sid(char oldc,
251 struct context *context,
257 char *scontextp, *p, *rngptr;
258 struct level_datum *levdatum;
259 struct cat_datum *catdatum, *rngdatum;
262 if (!selinux_mls_enabled)
266 * No MLS component to the security context, try and map to
267 * default if provided.
270 struct context *defcon;
272 if (def_sid == SECSID_NULL)
275 defcon = sidtab_search(s, def_sid);
279 rc = mls_copy_context(context, defcon);
283 /* Extract low sensitivity. */
284 scontextp = p = *scontext;
285 while (*p && *p != ':' && *p != '-')
292 for (l = 0; l < 2; l++) {
293 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
299 context->range.level[l].sens = levdatum->level->sens;
302 /* Extract category set. */
305 while (*p && *p != ',' && *p != '-')
311 /* Separate into range if exists */
312 if ((rngptr = strchr(scontextp, '.')) != NULL) {
317 catdatum = hashtab_search(policydb.p_cats.table,
324 rc = ebitmap_set_bit(&context->range.level[l].cat,
325 catdatum->value - 1, 1);
329 /* If range, set all categories in range */
333 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
339 if (catdatum->value >= rngdatum->value) {
344 for (i = catdatum->value; i < rngdatum->value; i++) {
345 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
356 /* Extract high sensitivity. */
358 while (*p && *p != ':')
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);
382 * Copies the effective MLS range from `src' into `dst'.
384 static inline int mls_scopy_context(struct context *dst,
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);
402 * Copies the MLS range `range' into `context'.
404 static inline int mls_range_set(struct context *context,
405 struct mls_range *range)
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);
421 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
422 struct context *usercon)
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]);
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;
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;
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'.
464 int mls_convert_context(struct policydb *oldp,
465 struct policydb *newp,
468 struct level_datum *levdatum;
469 struct cat_datum *catdatum;
470 struct ebitmap bitmap;
473 if (!selinux_mls_enabled)
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]);
482 c->range.level[l].sens = levdatum->level->sens;
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)) {
489 catdatum = hashtab_search(newp->p_cats.table,
490 oldp->p_cat_val_to_name[i - 1]);
493 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
498 ebitmap_destroy(&c->range.level[l].cat);
499 c->range.level[l].cat = bitmap;
505 int mls_compute_sid(struct context *scontext,
506 struct context *tcontext,
509 struct context *newcontext)
511 if (!selinux_mls_enabled)
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,
531 if (tclass == SECCLASS_PROCESS)
532 /* Use the process MLS attributes. */
533 return mls_copy_context(newcontext, scontext);
535 /* Use the process effective MLS attributes. */
536 return mls_scopy_context(newcontext, scontext);
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);
544 /* Use the related object MLS attributes. */
545 return mls_copy_context(newcontext, tcontext);