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)
30 struct ebitmap_node *node;
32 if (!selinux_mls_enabled)
35 len = 1; /* for the beginning ":" */
36 for (l = 0; l < 2; l++) {
38 len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
40 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
41 if (ebitmap_node_get_bit(node, i)) {
47 len += strlen(policydb.p_cat_val_to_name[i]) + 1;
51 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
55 /* Handle case where last category is the end of range */
57 len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
60 if (mls_level_eq(&context->range.level[0],
61 &context->range.level[1]))
72 * Write the security context string representation of
73 * the MLS fields of `context' into the string `*scontext'.
74 * Update `*scontext' to point to the end of the MLS fields.
76 void mls_sid_to_context(struct context *context,
80 int i, l, range, wrote_sep;
81 struct ebitmap_node *node;
83 if (!selinux_mls_enabled)
86 scontextp = *scontext;
91 for (l = 0; l < 2; l++) {
95 policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
96 scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
99 ebitmap_for_each_bit(&context->range.level[l].cat, node, i) {
100 if (ebitmap_node_get_bit(node, i)) {
111 strcpy(scontextp, policydb.p_cat_val_to_name[i]);
112 scontextp += strlen(policydb.p_cat_val_to_name[i]);
121 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
122 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
128 /* Handle case where last category is the end of range */
135 strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
136 scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
140 if (mls_level_eq(&context->range.level[0],
141 &context->range.level[1]))
150 *scontext = scontextp;
155 * Return 1 if the MLS fields in the security context
156 * structure `c' are valid. Return 0 otherwise.
158 int mls_context_isvalid(struct policydb *p, struct context *c)
160 struct level_datum *levdatum;
161 struct user_datum *usrdatum;
162 struct ebitmap_node *node;
165 if (!selinux_mls_enabled)
169 * MLS range validity checks: high must dominate low, low level must
170 * be valid (category set <-> sensitivity check), and high level must
171 * be valid (category set <-> sensitivity check)
173 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
174 /* High does not dominate low. */
177 for (l = 0; l < 2; l++) {
178 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
180 levdatum = hashtab_search(p->p_levels.table,
181 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
185 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
186 if (ebitmap_node_get_bit(node, i)) {
187 if (i > p->p_cats.nprim)
189 if (!ebitmap_get_bit(&levdatum->level->cat, i))
191 * Category may not be associated with
192 * sensitivity in low level.
199 if (c->role == OBJECT_R_VAL)
203 * User must be authorized for the MLS range.
205 if (!c->user || c->user > p->p_users.nprim)
207 usrdatum = p->user_val_to_struct[c->user - 1];
208 if (!mls_range_contains(usrdatum->range, c->range))
209 return 0; /* user may not be associated with range */
215 * Copies the MLS range from `src' into `dst'.
217 static inline int mls_copy_context(struct context *dst,
222 /* Copy the MLS range from the source context */
223 for (l = 0; l < 2; l++) {
224 dst->range.level[l].sens = src->range.level[l].sens;
225 rc = ebitmap_cpy(&dst->range.level[l].cat,
226 &src->range.level[l].cat);
235 * Set the MLS fields in the security context structure
236 * `context' based on the string representation in
237 * the string `*scontext'. Update `*scontext' to
238 * point to the end of the string representation of
241 * This function modifies the string in place, inserting
242 * NULL characters to terminate the MLS fields.
244 * If a def_sid is provided and no MLS field is present,
245 * copy the MLS field of the associated default context.
246 * Used for upgraded to MLS systems where objects may lack
249 * Policy read-lock must be held for sidtab lookup.
252 int mls_context_to_sid(char oldc,
254 struct context *context,
260 char *scontextp, *p, *rngptr;
261 struct level_datum *levdatum;
262 struct cat_datum *catdatum, *rngdatum;
265 if (!selinux_mls_enabled)
269 * No MLS component to the security context, try and map to
270 * default if provided.
273 struct context *defcon;
275 if (def_sid == SECSID_NULL)
278 defcon = sidtab_search(s, def_sid);
282 rc = mls_copy_context(context, defcon);
286 /* Extract low sensitivity. */
287 scontextp = p = *scontext;
288 while (*p && *p != ':' && *p != '-')
295 for (l = 0; l < 2; l++) {
296 levdatum = hashtab_search(policydb.p_levels.table, scontextp);
302 context->range.level[l].sens = levdatum->level->sens;
305 /* Extract category set. */
308 while (*p && *p != ',' && *p != '-')
314 /* Separate into range if exists */
315 if ((rngptr = strchr(scontextp, '.')) != NULL) {
320 catdatum = hashtab_search(policydb.p_cats.table,
327 rc = ebitmap_set_bit(&context->range.level[l].cat,
328 catdatum->value - 1, 1);
332 /* If range, set all categories in range */
336 rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
342 if (catdatum->value >= rngdatum->value) {
347 for (i = catdatum->value; i < rngdatum->value; i++) {
348 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
359 /* Extract high sensitivity. */
361 while (*p && *p != ':')
372 context->range.level[1].sens = context->range.level[0].sens;
373 rc = ebitmap_cpy(&context->range.level[1].cat,
374 &context->range.level[0].cat);
385 * Copies the effective MLS range from `src' into `dst'.
387 static inline int mls_scopy_context(struct context *dst,
392 /* Copy the MLS range from the source context */
393 for (l = 0; l < 2; l++) {
394 dst->range.level[l].sens = src->range.level[0].sens;
395 rc = ebitmap_cpy(&dst->range.level[l].cat,
396 &src->range.level[0].cat);
405 * Copies the MLS range `range' into `context'.
407 static inline int mls_range_set(struct context *context,
408 struct mls_range *range)
412 /* Copy the MLS range into the context */
413 for (l = 0; l < 2; l++) {
414 context->range.level[l].sens = range->level[l].sens;
415 rc = ebitmap_cpy(&context->range.level[l].cat,
416 &range->level[l].cat);
424 int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
425 struct context *usercon)
427 if (selinux_mls_enabled) {
428 struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
429 struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
430 struct mls_level *user_low = &(user->range.level[0]);
431 struct mls_level *user_clr = &(user->range.level[1]);
432 struct mls_level *user_def = &(user->dfltlevel);
433 struct mls_level *usercon_sen = &(usercon->range.level[0]);
434 struct mls_level *usercon_clr = &(usercon->range.level[1]);
436 /* Honor the user's default level if we can */
437 if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
438 *usercon_sen = *user_def;
439 } else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
440 *usercon_sen = *fromcon_sen;
441 } else if (mls_level_between(fromcon_clr, user_low, user_def)) {
442 *usercon_sen = *user_low;
446 /* Lower the clearance of available contexts
447 if the clearance of "fromcon" is lower than
448 that of the user's default clearance (but
449 only if the "fromcon" clearance dominates
450 the user's computed sensitivity level) */
451 if (mls_level_dom(user_clr, fromcon_clr)) {
452 *usercon_clr = *fromcon_clr;
453 } else if (mls_level_dom(fromcon_clr, user_clr)) {
454 *usercon_clr = *user_clr;
463 * Convert the MLS fields in the security context
464 * structure `c' from the values specified in the
465 * policy `oldp' to the values specified in the policy `newp'.
467 int mls_convert_context(struct policydb *oldp,
468 struct policydb *newp,
471 struct level_datum *levdatum;
472 struct cat_datum *catdatum;
473 struct ebitmap bitmap;
474 struct ebitmap_node *node;
477 if (!selinux_mls_enabled)
480 for (l = 0; l < 2; l++) {
481 levdatum = hashtab_search(newp->p_levels.table,
482 oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
486 c->range.level[l].sens = levdatum->level->sens;
488 ebitmap_init(&bitmap);
489 ebitmap_for_each_bit(&c->range.level[l].cat, node, i) {
490 if (ebitmap_node_get_bit(node, i)) {
493 catdatum = hashtab_search(newp->p_cats.table,
494 oldp->p_cat_val_to_name[i]);
497 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
502 ebitmap_destroy(&c->range.level[l].cat);
503 c->range.level[l].cat = bitmap;
509 int mls_compute_sid(struct context *scontext,
510 struct context *tcontext,
513 struct context *newcontext)
515 if (!selinux_mls_enabled)
519 case AVTAB_TRANSITION:
520 if (tclass == SECCLASS_PROCESS) {
521 struct range_trans *rangetr;
522 /* Look for a range transition rule. */
523 for (rangetr = policydb.range_tr; rangetr;
524 rangetr = rangetr->next) {
525 if (rangetr->dom == scontext->type &&
526 rangetr->type == tcontext->type) {
527 /* Set the range from the rule */
528 return mls_range_set(newcontext,
535 if (tclass == SECCLASS_PROCESS)
536 /* Use the process MLS attributes. */
537 return mls_copy_context(newcontext, scontext);
539 /* Use the process effective MLS attributes. */
540 return mls_scopy_context(newcontext, scontext);
542 /* Only polyinstantiate the MLS attributes if
543 the type is being polyinstantiated */
544 if (newcontext->type != tcontext->type) {
545 /* Use the process effective MLS attributes. */
546 return mls_scopy_context(newcontext, scontext);
548 /* Use the related object MLS attributes. */
549 return mls_copy_context(newcontext, tcontext);