/* * Implementation of the multi-level security (MLS) policy. * * Author : Stephen Smalley, */ /* * Updated: Trusted Computer Solutions, Inc. * * Support for enhanced MLS infrastructure. * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. */ /* Ported to Xen 3.0, George Coker, */ #include #include #include #include #include "sidtab.h" #include "mls.h" #include "policydb.h" #include "services.h" /* * Return the length in bytes for the MLS fields of the * security context string representation of `context'. */ int mls_compute_context_len(struct context * context) { int i, l, len, head, prev; char *nm; struct ebitmap *e; struct ebitmap_node *node; if ( !flask_mls_enabled ) return 0; len = 1; /* for the beginning ":" */ for ( l = 0; l < 2; l++ ) { int index_sens = context->range.level[l].sens; len += strlen(policydb.p_sens_val_to_name[index_sens - 1]); /* categories */ head = -2; prev = -2; e = &context->range.level[l].cat; ebitmap_for_each_positive_bit(e, node, i) { if ( i - prev > 1 ) { /* one or more negative bits are skipped */ if ( head != prev ) { nm = policydb.p_cat_val_to_name[prev]; len += strlen(nm) + 1; } nm = policydb.p_cat_val_to_name[i]; len += strlen(nm) + 1; head = i; } prev = i; } if ( prev != head ) { nm = policydb.p_cat_val_to_name[prev]; len += strlen(nm) + 1; } if ( l == 0 ) { if ( mls_level_eq(&context->range.level[0], &context->range.level[1]) ) break; else len++; } } return len; } /* * Write the security context string representation of * the MLS fields of `context' into the string `*scontext'. * Update `*scontext' to point to the end of the MLS fields. */ void mls_sid_to_context(struct context *context, char **scontext) { char *scontextp, *nm; int i, l, head, prev; struct ebitmap *e; struct ebitmap_node *node; if ( !flask_mls_enabled ) return; scontextp = *scontext; *scontextp = ':'; scontextp++; for ( l = 0; l < 2; l++ ) { memcpy(scontextp, policydb.p_sens_val_to_name[context->range.level[l].sens - 1], strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1])+1); scontextp += strlen(scontextp); /* categories */ head = -2; prev = -2; e = &context->range.level[l].cat; ebitmap_for_each_positive_bit(e, node, i) { if ( i - prev > 1 ) { /* one or more negative bits are skipped */ if ( prev != head ) { if ( prev - head > 1 ) *scontextp++ = '.'; else *scontextp++ = ','; nm = policydb.p_cat_val_to_name[prev]; memcpy(scontextp, nm, strlen(nm)+1); scontextp += strlen(nm); } if ( prev < 0 ) *scontextp++ = ':'; else *scontextp++ = ','; nm = policydb.p_cat_val_to_name[i]; memcpy(scontextp, nm, strlen(nm)+1); scontextp += strlen(nm); head = i; } prev = i; } if ( prev != head ) { if ( prev - head > 1 ) *scontextp++ = '.'; else *scontextp++ = ','; nm = policydb.p_cat_val_to_name[prev]; memcpy(scontextp, nm, strlen(nm)+1); scontextp += strlen(nm); } if ( l == 0 ) { if ( mls_level_eq(&context->range.level[0], &context->range.level[1]) ) break; else { *scontextp = '-'; scontextp++; } } } *scontext = scontextp; return; } int mls_level_isvalid(struct policydb *p, struct mls_level *l) { struct level_datum *levdatum; struct ebitmap_node *node; int i; if ( !l->sens || l->sens > p->p_levels.nprim ) return 0; levdatum = hashtab_search(p->p_levels.table, p->p_sens_val_to_name[l->sens - 1]); if ( !levdatum ) return 0; ebitmap_for_each_positive_bit(&l->cat, node, i) { if ( i > p->p_cats.nprim ) return 0; if ( !ebitmap_get_bit(&levdatum->level->cat, i) ) { /* * Category may not be associated with * sensitivity. */ return 0; } } return 1; } int mls_range_isvalid(struct policydb *p, struct mls_range *r) { return ( mls_level_isvalid(p, &r->level[0]) && mls_level_isvalid(p, &r->level[1]) && mls_level_dom(&r->level[1], &r->level[0])); } /* * Return 1 if the MLS fields in the security context * structure `c' are valid. Return 0 otherwise. */ int mls_context_isvalid(struct policydb *p, struct context *c) { struct user_datum *usrdatum; if ( !flask_mls_enabled ) return 1; if ( !mls_range_isvalid(p, &c->range) ) return 0; if ( c->role == OBJECT_R_VAL ) return 1; /* * User must be authorized for the MLS range. */ if ( !c->user || c->user > p->p_users.nprim ) return 0; usrdatum = p->user_val_to_struct[c->user - 1]; if ( !mls_range_contains(usrdatum->range, c->range) ) return 0; /* user may not be associated with range */ return 1; } /* * Set the MLS fields in the security context structure * `context' based on the string representation in * the string `*scontext'. Update `*scontext' to * point to the end of the string representation of * the MLS fields. * * This function modifies the string in place, inserting * NULL characters to terminate the MLS fields. * * Policy read-lock must be held for sidtab lookup. * */ int mls_context_to_sid(char oldc, char **scontext, struct context *context, struct sidtab *s) { char delim; char *scontextp, *p, *rngptr; struct level_datum *levdatum; struct cat_datum *catdatum, *rngdatum; int l, rc = -EINVAL; if ( !flask_mls_enabled ) return 0; /* * No MLS component to the security context -> error. */ if ( !oldc ) goto out; /* Extract low sensitivity. */ scontextp = p = *scontext; while ( *p && *p != ':' && *p != '-' ) p++; delim = *p; if ( delim != 0 ) *p++ = 0; for ( l = 0; l < 2; l++ ) { levdatum = hashtab_search(policydb.p_levels.table, scontextp); if ( !levdatum ) { rc = -EINVAL; goto out; } context->range.level[l].sens = levdatum->level->sens; if ( delim == ':' ) { /* Extract category set. */ while ( 1 ) { scontextp = p; while ( *p && *p != ',' && *p != '-' ) p++; delim = *p; if ( delim != 0 ) *p++ = 0; /* Separate into range if exists */ if ( (rngptr = strchr(scontextp, '.')) != NULL ) { /* Remove '.' */ *rngptr++ = 0; } catdatum = hashtab_search(policydb.p_cats.table, scontextp); if ( !catdatum ) { rc = -EINVAL; goto out; } rc = ebitmap_set_bit(&context->range.level[l].cat, catdatum->value - 1, 1); if ( rc ) goto out; /* If range, set all categories in range */ if ( rngptr ) { int i; rngdatum = hashtab_search(policydb.p_cats.table, rngptr); if ( !rngdatum ) { rc = -EINVAL; goto out; } if ( catdatum->value >= rngdatum->value ) { rc = -EINVAL; goto out; } for ( i = catdatum->value; i < rngdatum->value; i++ ) { rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); if ( rc ) goto out; } } if ( delim != ',' ) break; } } if ( delim == '-' ) { /* Extract high sensitivity. */ scontextp = p; while ( *p && *p != ':' ) p++; delim = *p; if ( delim != 0 ) *p++ = 0; } else break; } if ( l == 0 ) { context->range.level[1].sens = context->range.level[0].sens; rc = ebitmap_cpy(&context->range.level[1].cat, &context->range.level[0].cat); if ( rc ) goto out; } *scontext = ++p; rc = 0; out: return rc; } /* * Copies the MLS range `range' into `context'. */ static inline int mls_range_set(struct context *context, struct mls_range *range) { int l, rc = 0; /* Copy the MLS range into the context */ for ( l = 0; l < 2; l++ ) { context->range.level[l].sens = range->level[l].sens; rc = ebitmap_cpy(&context->range.level[l].cat, &range->level[l].cat); if ( rc ) break; } return rc; } /* * Convert the MLS fields in the security context * structure `c' from the values specified in the * policy `oldp' to the values specified in the policy `newp'. */ int mls_convert_context(struct policydb *oldp, struct policydb *newp, struct context *c) { struct level_datum *levdatum; struct cat_datum *catdatum; struct ebitmap bitmap; struct ebitmap_node *node; int l, i; if ( !flask_mls_enabled ) return 0; for ( l = 0; l < 2; l++ ) { levdatum = hashtab_search(newp->p_levels.table, oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); if ( !levdatum ) return -EINVAL; c->range.level[l].sens = levdatum->level->sens; ebitmap_init(&bitmap); ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) { int rc; catdatum = hashtab_search(newp->p_cats.table, oldp->p_cat_val_to_name[i]); if ( !catdatum ) return -EINVAL; rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); if ( rc ) return rc; } ebitmap_destroy(&c->range.level[l].cat); c->range.level[l].cat = bitmap; } return 0; } int mls_compute_sid(struct context *scontext, struct context *tcontext, u16 tclass, u32 specified, struct context *newcontext) { struct range_trans *rtr; if ( !flask_mls_enabled ) return 0; switch ( specified ) { case AVTAB_TRANSITION: /* Look for a range transition rule. */ for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { if (rtr->source_type == scontext->type && rtr->target_type == tcontext->type && rtr->target_class == tclass) { /* Set the range from the rule */ return mls_range_set(newcontext, &rtr->target_range); } } /* Fallthrough */ case AVTAB_CHANGE: if ( tclass == SECCLASS_DOMAIN ) /* Use the process MLS attributes. */ return mls_context_cpy(newcontext, scontext); else /* Use the process effective MLS attributes. */ return mls_context_cpy_low(newcontext, scontext); case AVTAB_MEMBER: /* Use the process effective MLS attributes. */ return mls_context_cpy_low(newcontext, scontext); default: return -EINVAL; } return -EINVAL; }