11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Implementation of the multi-level security (MLS) policy. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Author : Stephen Smalley, <sds@epoch.ncsc.mil> 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds /* 71da177e4SLinus Torvalds * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Support for enhanced MLS infrastructure. 101da177e4SLinus Torvalds * 11376bd9cbSDarrel Goeddel * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 121da177e4SLinus Torvalds */ 13*7420ed23SVenkat Yekkirala /* 14*7420ed23SVenkat Yekkirala * Updated: Hewlett-Packard <paul.moore@hp.com> 15*7420ed23SVenkat Yekkirala * 16*7420ed23SVenkat Yekkirala * Added support to import/export the MLS label 17*7420ed23SVenkat Yekkirala * 18*7420ed23SVenkat Yekkirala * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 19*7420ed23SVenkat Yekkirala */ 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include <linux/kernel.h> 221da177e4SLinus Torvalds #include <linux/slab.h> 231da177e4SLinus Torvalds #include <linux/string.h> 241da177e4SLinus Torvalds #include <linux/errno.h> 25f5c1d5b2SJames Morris #include "sidtab.h" 261da177e4SLinus Torvalds #include "mls.h" 271da177e4SLinus Torvalds #include "policydb.h" 281da177e4SLinus Torvalds #include "services.h" 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* 311da177e4SLinus Torvalds * Return the length in bytes for the MLS fields of the 321da177e4SLinus Torvalds * security context string representation of `context'. 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds int mls_compute_context_len(struct context * context) 351da177e4SLinus Torvalds { 361da177e4SLinus Torvalds int i, l, len, range; 37782ebb99SStephen Smalley struct ebitmap_node *node; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds if (!selinux_mls_enabled) 401da177e4SLinus Torvalds return 0; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds len = 1; /* for the beginning ":" */ 431da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 441da177e4SLinus Torvalds range = 0; 451da177e4SLinus Torvalds len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 461da177e4SLinus Torvalds 47782ebb99SStephen Smalley ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { 48782ebb99SStephen Smalley if (ebitmap_node_get_bit(node, i)) { 491da177e4SLinus Torvalds if (range) { 501da177e4SLinus Torvalds range++; 511da177e4SLinus Torvalds continue; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 54782ebb99SStephen Smalley len += strlen(policydb.p_cat_val_to_name[i]) + 1; 551da177e4SLinus Torvalds range++; 561da177e4SLinus Torvalds } else { 571da177e4SLinus Torvalds if (range > 1) 58782ebb99SStephen Smalley len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; 591da177e4SLinus Torvalds range = 0; 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds /* Handle case where last category is the end of range */ 631da177e4SLinus Torvalds if (range > 1) 64782ebb99SStephen Smalley len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds if (l == 0) { 671da177e4SLinus Torvalds if (mls_level_eq(&context->range.level[0], 681da177e4SLinus Torvalds &context->range.level[1])) 691da177e4SLinus Torvalds break; 701da177e4SLinus Torvalds else 711da177e4SLinus Torvalds len++; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds return len; 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* 791da177e4SLinus Torvalds * Write the security context string representation of 801da177e4SLinus Torvalds * the MLS fields of `context' into the string `*scontext'. 811da177e4SLinus Torvalds * Update `*scontext' to point to the end of the MLS fields. 821da177e4SLinus Torvalds */ 831da177e4SLinus Torvalds void mls_sid_to_context(struct context *context, 841da177e4SLinus Torvalds char **scontext) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds char *scontextp; 871da177e4SLinus Torvalds int i, l, range, wrote_sep; 88782ebb99SStephen Smalley struct ebitmap_node *node; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds if (!selinux_mls_enabled) 911da177e4SLinus Torvalds return; 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds scontextp = *scontext; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds *scontextp = ':'; 961da177e4SLinus Torvalds scontextp++; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 991da177e4SLinus Torvalds range = 0; 1001da177e4SLinus Torvalds wrote_sep = 0; 1011da177e4SLinus Torvalds strcpy(scontextp, 1021da177e4SLinus Torvalds policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 1031da177e4SLinus Torvalds scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* categories */ 106782ebb99SStephen Smalley ebitmap_for_each_bit(&context->range.level[l].cat, node, i) { 107782ebb99SStephen Smalley if (ebitmap_node_get_bit(node, i)) { 1081da177e4SLinus Torvalds if (range) { 1091da177e4SLinus Torvalds range++; 1101da177e4SLinus Torvalds continue; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds if (!wrote_sep) { 1141da177e4SLinus Torvalds *scontextp++ = ':'; 1151da177e4SLinus Torvalds wrote_sep = 1; 1161da177e4SLinus Torvalds } else 1171da177e4SLinus Torvalds *scontextp++ = ','; 118782ebb99SStephen Smalley strcpy(scontextp, policydb.p_cat_val_to_name[i]); 119782ebb99SStephen Smalley scontextp += strlen(policydb.p_cat_val_to_name[i]); 1201da177e4SLinus Torvalds range++; 1211da177e4SLinus Torvalds } else { 1221da177e4SLinus Torvalds if (range > 1) { 1231da177e4SLinus Torvalds if (range > 2) 1241da177e4SLinus Torvalds *scontextp++ = '.'; 1251da177e4SLinus Torvalds else 1261da177e4SLinus Torvalds *scontextp++ = ','; 1271da177e4SLinus Torvalds 128782ebb99SStephen Smalley strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); 129782ebb99SStephen Smalley scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds range = 0; 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /* Handle case where last category is the end of range */ 1361da177e4SLinus Torvalds if (range > 1) { 1371da177e4SLinus Torvalds if (range > 2) 1381da177e4SLinus Torvalds *scontextp++ = '.'; 1391da177e4SLinus Torvalds else 1401da177e4SLinus Torvalds *scontextp++ = ','; 1411da177e4SLinus Torvalds 142782ebb99SStephen Smalley strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]); 143782ebb99SStephen Smalley scontextp += strlen(policydb.p_cat_val_to_name[i - 1]); 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds if (l == 0) { 1471da177e4SLinus Torvalds if (mls_level_eq(&context->range.level[0], 1481da177e4SLinus Torvalds &context->range.level[1])) 1491da177e4SLinus Torvalds break; 1501da177e4SLinus Torvalds else { 1511da177e4SLinus Torvalds *scontextp = '-'; 1521da177e4SLinus Torvalds scontextp++; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds *scontext = scontextp; 1581da177e4SLinus Torvalds return; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 1621da177e4SLinus Torvalds * Return 1 if the MLS fields in the security context 1631da177e4SLinus Torvalds * structure `c' are valid. Return 0 otherwise. 1641da177e4SLinus Torvalds */ 1651da177e4SLinus Torvalds int mls_context_isvalid(struct policydb *p, struct context *c) 1661da177e4SLinus Torvalds { 1671da177e4SLinus Torvalds struct level_datum *levdatum; 1681da177e4SLinus Torvalds struct user_datum *usrdatum; 169782ebb99SStephen Smalley struct ebitmap_node *node; 1701da177e4SLinus Torvalds int i, l; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds if (!selinux_mls_enabled) 1731da177e4SLinus Torvalds return 1; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /* 1761da177e4SLinus Torvalds * MLS range validity checks: high must dominate low, low level must 1771da177e4SLinus Torvalds * be valid (category set <-> sensitivity check), and high level must 1781da177e4SLinus Torvalds * be valid (category set <-> sensitivity check) 1791da177e4SLinus Torvalds */ 1801da177e4SLinus Torvalds if (!mls_level_dom(&c->range.level[1], &c->range.level[0])) 1811da177e4SLinus Torvalds /* High does not dominate low. */ 1821da177e4SLinus Torvalds return 0; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 1851da177e4SLinus Torvalds if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim) 1861da177e4SLinus Torvalds return 0; 1871da177e4SLinus Torvalds levdatum = hashtab_search(p->p_levels.table, 1881da177e4SLinus Torvalds p->p_sens_val_to_name[c->range.level[l].sens - 1]); 1891da177e4SLinus Torvalds if (!levdatum) 1901da177e4SLinus Torvalds return 0; 1911da177e4SLinus Torvalds 192782ebb99SStephen Smalley ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { 193782ebb99SStephen Smalley if (ebitmap_node_get_bit(node, i)) { 1941da177e4SLinus Torvalds if (i > p->p_cats.nprim) 1951da177e4SLinus Torvalds return 0; 196782ebb99SStephen Smalley if (!ebitmap_get_bit(&levdatum->level->cat, i)) 1971da177e4SLinus Torvalds /* 1981da177e4SLinus Torvalds * Category may not be associated with 1991da177e4SLinus Torvalds * sensitivity in low level. 2001da177e4SLinus Torvalds */ 2011da177e4SLinus Torvalds return 0; 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds if (c->role == OBJECT_R_VAL) 2071da177e4SLinus Torvalds return 1; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* 2101da177e4SLinus Torvalds * User must be authorized for the MLS range. 2111da177e4SLinus Torvalds */ 2121da177e4SLinus Torvalds if (!c->user || c->user > p->p_users.nprim) 2131da177e4SLinus Torvalds return 0; 2141da177e4SLinus Torvalds usrdatum = p->user_val_to_struct[c->user - 1]; 2151da177e4SLinus Torvalds if (!mls_range_contains(usrdatum->range, c->range)) 2161da177e4SLinus Torvalds return 0; /* user may not be associated with range */ 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds return 1; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /* 2221da177e4SLinus Torvalds * Set the MLS fields in the security context structure 2231da177e4SLinus Torvalds * `context' based on the string representation in 2241da177e4SLinus Torvalds * the string `*scontext'. Update `*scontext' to 2251da177e4SLinus Torvalds * point to the end of the string representation of 2261da177e4SLinus Torvalds * the MLS fields. 2271da177e4SLinus Torvalds * 2281da177e4SLinus Torvalds * This function modifies the string in place, inserting 2291da177e4SLinus Torvalds * NULL characters to terminate the MLS fields. 230f5c1d5b2SJames Morris * 231f5c1d5b2SJames Morris * If a def_sid is provided and no MLS field is present, 232f5c1d5b2SJames Morris * copy the MLS field of the associated default context. 233f5c1d5b2SJames Morris * Used for upgraded to MLS systems where objects may lack 234f5c1d5b2SJames Morris * MLS fields. 235f5c1d5b2SJames Morris * 236f5c1d5b2SJames Morris * Policy read-lock must be held for sidtab lookup. 237f5c1d5b2SJames Morris * 2381da177e4SLinus Torvalds */ 2391da177e4SLinus Torvalds int mls_context_to_sid(char oldc, 2401da177e4SLinus Torvalds char **scontext, 241f5c1d5b2SJames Morris struct context *context, 242f5c1d5b2SJames Morris struct sidtab *s, 243f5c1d5b2SJames Morris u32 def_sid) 2441da177e4SLinus Torvalds { 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds char delim; 2471da177e4SLinus Torvalds char *scontextp, *p, *rngptr; 2481da177e4SLinus Torvalds struct level_datum *levdatum; 2491da177e4SLinus Torvalds struct cat_datum *catdatum, *rngdatum; 2501da177e4SLinus Torvalds int l, rc = -EINVAL; 2511da177e4SLinus Torvalds 252e517a0cdSStephen Smalley if (!selinux_mls_enabled) { 253e517a0cdSStephen Smalley if (def_sid != SECSID_NULL && oldc) 254ab5703b3SRon Yorston *scontext += strlen(*scontext)+1; 2551da177e4SLinus Torvalds return 0; 256e517a0cdSStephen Smalley } 2571da177e4SLinus Torvalds 258f5c1d5b2SJames Morris /* 259f5c1d5b2SJames Morris * No MLS component to the security context, try and map to 260f5c1d5b2SJames Morris * default if provided. 261f5c1d5b2SJames Morris */ 262f5c1d5b2SJames Morris if (!oldc) { 263f5c1d5b2SJames Morris struct context *defcon; 264f5c1d5b2SJames Morris 265f5c1d5b2SJames Morris if (def_sid == SECSID_NULL) 2661da177e4SLinus Torvalds goto out; 2671da177e4SLinus Torvalds 268f5c1d5b2SJames Morris defcon = sidtab_search(s, def_sid); 269f5c1d5b2SJames Morris if (!defcon) 270f5c1d5b2SJames Morris goto out; 271f5c1d5b2SJames Morris 272f5c1d5b2SJames Morris rc = mls_copy_context(context, defcon); 273f5c1d5b2SJames Morris goto out; 274f5c1d5b2SJames Morris } 275f5c1d5b2SJames Morris 2761da177e4SLinus Torvalds /* Extract low sensitivity. */ 2771da177e4SLinus Torvalds scontextp = p = *scontext; 2781da177e4SLinus Torvalds while (*p && *p != ':' && *p != '-') 2791da177e4SLinus Torvalds p++; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds delim = *p; 2821da177e4SLinus Torvalds if (delim != 0) 2831da177e4SLinus Torvalds *p++ = 0; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 2861da177e4SLinus Torvalds levdatum = hashtab_search(policydb.p_levels.table, scontextp); 2871da177e4SLinus Torvalds if (!levdatum) { 2881da177e4SLinus Torvalds rc = -EINVAL; 2891da177e4SLinus Torvalds goto out; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds context->range.level[l].sens = levdatum->level->sens; 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds if (delim == ':') { 2951da177e4SLinus Torvalds /* Extract category set. */ 2961da177e4SLinus Torvalds while (1) { 2971da177e4SLinus Torvalds scontextp = p; 2981da177e4SLinus Torvalds while (*p && *p != ',' && *p != '-') 2991da177e4SLinus Torvalds p++; 3001da177e4SLinus Torvalds delim = *p; 3011da177e4SLinus Torvalds if (delim != 0) 3021da177e4SLinus Torvalds *p++ = 0; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds /* Separate into range if exists */ 3051da177e4SLinus Torvalds if ((rngptr = strchr(scontextp, '.')) != NULL) { 3061da177e4SLinus Torvalds /* Remove '.' */ 3071da177e4SLinus Torvalds *rngptr++ = 0; 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds catdatum = hashtab_search(policydb.p_cats.table, 3111da177e4SLinus Torvalds scontextp); 3121da177e4SLinus Torvalds if (!catdatum) { 3131da177e4SLinus Torvalds rc = -EINVAL; 3141da177e4SLinus Torvalds goto out; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds rc = ebitmap_set_bit(&context->range.level[l].cat, 3181da177e4SLinus Torvalds catdatum->value - 1, 1); 3191da177e4SLinus Torvalds if (rc) 3201da177e4SLinus Torvalds goto out; 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds /* If range, set all categories in range */ 3231da177e4SLinus Torvalds if (rngptr) { 3241da177e4SLinus Torvalds int i; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds rngdatum = hashtab_search(policydb.p_cats.table, rngptr); 3271da177e4SLinus Torvalds if (!rngdatum) { 3281da177e4SLinus Torvalds rc = -EINVAL; 3291da177e4SLinus Torvalds goto out; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds if (catdatum->value >= rngdatum->value) { 3331da177e4SLinus Torvalds rc = -EINVAL; 3341da177e4SLinus Torvalds goto out; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds for (i = catdatum->value; i < rngdatum->value; i++) { 3381da177e4SLinus Torvalds rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); 3391da177e4SLinus Torvalds if (rc) 3401da177e4SLinus Torvalds goto out; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds if (delim != ',') 3451da177e4SLinus Torvalds break; 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds if (delim == '-') { 3491da177e4SLinus Torvalds /* Extract high sensitivity. */ 3501da177e4SLinus Torvalds scontextp = p; 3511da177e4SLinus Torvalds while (*p && *p != ':') 3521da177e4SLinus Torvalds p++; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds delim = *p; 3551da177e4SLinus Torvalds if (delim != 0) 3561da177e4SLinus Torvalds *p++ = 0; 3571da177e4SLinus Torvalds } else 3581da177e4SLinus Torvalds break; 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds if (l == 0) { 3621da177e4SLinus Torvalds context->range.level[1].sens = context->range.level[0].sens; 3631da177e4SLinus Torvalds rc = ebitmap_cpy(&context->range.level[1].cat, 3641da177e4SLinus Torvalds &context->range.level[0].cat); 3651da177e4SLinus Torvalds if (rc) 3661da177e4SLinus Torvalds goto out; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds *scontext = ++p; 3691da177e4SLinus Torvalds rc = 0; 3701da177e4SLinus Torvalds out: 3711da177e4SLinus Torvalds return rc; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds /* 375376bd9cbSDarrel Goeddel * Set the MLS fields in the security context structure 376376bd9cbSDarrel Goeddel * `context' based on the string representation in 377376bd9cbSDarrel Goeddel * the string `str'. This function will allocate temporary memory with the 378376bd9cbSDarrel Goeddel * given constraints of gfp_mask. 379376bd9cbSDarrel Goeddel */ 380376bd9cbSDarrel Goeddel int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) 381376bd9cbSDarrel Goeddel { 382376bd9cbSDarrel Goeddel char *tmpstr, *freestr; 383376bd9cbSDarrel Goeddel int rc; 384376bd9cbSDarrel Goeddel 385376bd9cbSDarrel Goeddel if (!selinux_mls_enabled) 386376bd9cbSDarrel Goeddel return -EINVAL; 387376bd9cbSDarrel Goeddel 388376bd9cbSDarrel Goeddel /* we need freestr because mls_context_to_sid will change 389376bd9cbSDarrel Goeddel the value of tmpstr */ 390376bd9cbSDarrel Goeddel tmpstr = freestr = kstrdup(str, gfp_mask); 391376bd9cbSDarrel Goeddel if (!tmpstr) { 392376bd9cbSDarrel Goeddel rc = -ENOMEM; 393376bd9cbSDarrel Goeddel } else { 394376bd9cbSDarrel Goeddel rc = mls_context_to_sid(':', &tmpstr, context, 395376bd9cbSDarrel Goeddel NULL, SECSID_NULL); 396376bd9cbSDarrel Goeddel kfree(freestr); 397376bd9cbSDarrel Goeddel } 398376bd9cbSDarrel Goeddel 399376bd9cbSDarrel Goeddel return rc; 400376bd9cbSDarrel Goeddel } 401376bd9cbSDarrel Goeddel 402376bd9cbSDarrel Goeddel /* 4031da177e4SLinus Torvalds * Copies the effective MLS range from `src' into `dst'. 4041da177e4SLinus Torvalds */ 4051da177e4SLinus Torvalds static inline int mls_scopy_context(struct context *dst, 4061da177e4SLinus Torvalds struct context *src) 4071da177e4SLinus Torvalds { 4081da177e4SLinus Torvalds int l, rc = 0; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds /* Copy the MLS range from the source context */ 4111da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 4121da177e4SLinus Torvalds dst->range.level[l].sens = src->range.level[0].sens; 4131da177e4SLinus Torvalds rc = ebitmap_cpy(&dst->range.level[l].cat, 4141da177e4SLinus Torvalds &src->range.level[0].cat); 4151da177e4SLinus Torvalds if (rc) 4161da177e4SLinus Torvalds break; 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds return rc; 4201da177e4SLinus Torvalds } 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds /* 4231da177e4SLinus Torvalds * Copies the MLS range `range' into `context'. 4241da177e4SLinus Torvalds */ 4251da177e4SLinus Torvalds static inline int mls_range_set(struct context *context, 4261da177e4SLinus Torvalds struct mls_range *range) 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds int l, rc = 0; 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds /* Copy the MLS range into the context */ 4311da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 4321da177e4SLinus Torvalds context->range.level[l].sens = range->level[l].sens; 4331da177e4SLinus Torvalds rc = ebitmap_cpy(&context->range.level[l].cat, 4341da177e4SLinus Torvalds &range->level[l].cat); 4351da177e4SLinus Torvalds if (rc) 4361da177e4SLinus Torvalds break; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds return rc; 4401da177e4SLinus Torvalds } 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds int mls_setup_user_range(struct context *fromcon, struct user_datum *user, 4431da177e4SLinus Torvalds struct context *usercon) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds if (selinux_mls_enabled) { 4461da177e4SLinus Torvalds struct mls_level *fromcon_sen = &(fromcon->range.level[0]); 4471da177e4SLinus Torvalds struct mls_level *fromcon_clr = &(fromcon->range.level[1]); 4481da177e4SLinus Torvalds struct mls_level *user_low = &(user->range.level[0]); 4491da177e4SLinus Torvalds struct mls_level *user_clr = &(user->range.level[1]); 4501da177e4SLinus Torvalds struct mls_level *user_def = &(user->dfltlevel); 4511da177e4SLinus Torvalds struct mls_level *usercon_sen = &(usercon->range.level[0]); 4521da177e4SLinus Torvalds struct mls_level *usercon_clr = &(usercon->range.level[1]); 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds /* Honor the user's default level if we can */ 4551da177e4SLinus Torvalds if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) { 4561da177e4SLinus Torvalds *usercon_sen = *user_def; 4571da177e4SLinus Torvalds } else if (mls_level_between(fromcon_sen, user_def, user_clr)) { 4581da177e4SLinus Torvalds *usercon_sen = *fromcon_sen; 4591da177e4SLinus Torvalds } else if (mls_level_between(fromcon_clr, user_low, user_def)) { 4601da177e4SLinus Torvalds *usercon_sen = *user_low; 4611da177e4SLinus Torvalds } else 4621da177e4SLinus Torvalds return -EINVAL; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds /* Lower the clearance of available contexts 4651da177e4SLinus Torvalds if the clearance of "fromcon" is lower than 4661da177e4SLinus Torvalds that of the user's default clearance (but 4671da177e4SLinus Torvalds only if the "fromcon" clearance dominates 4681da177e4SLinus Torvalds the user's computed sensitivity level) */ 4691da177e4SLinus Torvalds if (mls_level_dom(user_clr, fromcon_clr)) { 4701da177e4SLinus Torvalds *usercon_clr = *fromcon_clr; 4711da177e4SLinus Torvalds } else if (mls_level_dom(fromcon_clr, user_clr)) { 4721da177e4SLinus Torvalds *usercon_clr = *user_clr; 4731da177e4SLinus Torvalds } else 4741da177e4SLinus Torvalds return -EINVAL; 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds return 0; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds /* 4811da177e4SLinus Torvalds * Convert the MLS fields in the security context 4821da177e4SLinus Torvalds * structure `c' from the values specified in the 4831da177e4SLinus Torvalds * policy `oldp' to the values specified in the policy `newp'. 4841da177e4SLinus Torvalds */ 4851da177e4SLinus Torvalds int mls_convert_context(struct policydb *oldp, 4861da177e4SLinus Torvalds struct policydb *newp, 4871da177e4SLinus Torvalds struct context *c) 4881da177e4SLinus Torvalds { 4891da177e4SLinus Torvalds struct level_datum *levdatum; 4901da177e4SLinus Torvalds struct cat_datum *catdatum; 4911da177e4SLinus Torvalds struct ebitmap bitmap; 492782ebb99SStephen Smalley struct ebitmap_node *node; 4931da177e4SLinus Torvalds int l, i; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds if (!selinux_mls_enabled) 4961da177e4SLinus Torvalds return 0; 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 4991da177e4SLinus Torvalds levdatum = hashtab_search(newp->p_levels.table, 5001da177e4SLinus Torvalds oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds if (!levdatum) 5031da177e4SLinus Torvalds return -EINVAL; 5041da177e4SLinus Torvalds c->range.level[l].sens = levdatum->level->sens; 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds ebitmap_init(&bitmap); 507782ebb99SStephen Smalley ebitmap_for_each_bit(&c->range.level[l].cat, node, i) { 508782ebb99SStephen Smalley if (ebitmap_node_get_bit(node, i)) { 5091da177e4SLinus Torvalds int rc; 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds catdatum = hashtab_search(newp->p_cats.table, 512782ebb99SStephen Smalley oldp->p_cat_val_to_name[i]); 5131da177e4SLinus Torvalds if (!catdatum) 5141da177e4SLinus Torvalds return -EINVAL; 5151da177e4SLinus Torvalds rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); 5161da177e4SLinus Torvalds if (rc) 5171da177e4SLinus Torvalds return rc; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds ebitmap_destroy(&c->range.level[l].cat); 5211da177e4SLinus Torvalds c->range.level[l].cat = bitmap; 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds return 0; 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds int mls_compute_sid(struct context *scontext, 5281da177e4SLinus Torvalds struct context *tcontext, 5291da177e4SLinus Torvalds u16 tclass, 5301da177e4SLinus Torvalds u32 specified, 5311da177e4SLinus Torvalds struct context *newcontext) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds if (!selinux_mls_enabled) 5341da177e4SLinus Torvalds return 0; 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds switch (specified) { 5371da177e4SLinus Torvalds case AVTAB_TRANSITION: 5381da177e4SLinus Torvalds if (tclass == SECCLASS_PROCESS) { 5391da177e4SLinus Torvalds struct range_trans *rangetr; 5401da177e4SLinus Torvalds /* Look for a range transition rule. */ 5411da177e4SLinus Torvalds for (rangetr = policydb.range_tr; rangetr; 5421da177e4SLinus Torvalds rangetr = rangetr->next) { 5431da177e4SLinus Torvalds if (rangetr->dom == scontext->type && 5441da177e4SLinus Torvalds rangetr->type == tcontext->type) { 5451da177e4SLinus Torvalds /* Set the range from the rule */ 5461da177e4SLinus Torvalds return mls_range_set(newcontext, 5471da177e4SLinus Torvalds &rangetr->range); 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds } 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds /* Fallthrough */ 5521da177e4SLinus Torvalds case AVTAB_CHANGE: 5531da177e4SLinus Torvalds if (tclass == SECCLASS_PROCESS) 5541da177e4SLinus Torvalds /* Use the process MLS attributes. */ 5551da177e4SLinus Torvalds return mls_copy_context(newcontext, scontext); 5561da177e4SLinus Torvalds else 5571da177e4SLinus Torvalds /* Use the process effective MLS attributes. */ 5581da177e4SLinus Torvalds return mls_scopy_context(newcontext, scontext); 5591da177e4SLinus Torvalds case AVTAB_MEMBER: 5601da177e4SLinus Torvalds /* Only polyinstantiate the MLS attributes if 5611da177e4SLinus Torvalds the type is being polyinstantiated */ 5621da177e4SLinus Torvalds if (newcontext->type != tcontext->type) { 5631da177e4SLinus Torvalds /* Use the process effective MLS attributes. */ 5641da177e4SLinus Torvalds return mls_scopy_context(newcontext, scontext); 5651da177e4SLinus Torvalds } else { 5661da177e4SLinus Torvalds /* Use the related object MLS attributes. */ 5671da177e4SLinus Torvalds return mls_copy_context(newcontext, tcontext); 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds default: 5701da177e4SLinus Torvalds return -EINVAL; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds return -EINVAL; 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 575*7420ed23SVenkat Yekkirala /** 576*7420ed23SVenkat Yekkirala * mls_export_lvl - Export the MLS sensitivity levels 577*7420ed23SVenkat Yekkirala * @context: the security context 578*7420ed23SVenkat Yekkirala * @low: the low sensitivity level 579*7420ed23SVenkat Yekkirala * @high: the high sensitivity level 580*7420ed23SVenkat Yekkirala * 581*7420ed23SVenkat Yekkirala * Description: 582*7420ed23SVenkat Yekkirala * Given the security context copy the low MLS sensitivity level into lvl_low 583*7420ed23SVenkat Yekkirala * and the high sensitivity level in lvl_high. The MLS levels are only 584*7420ed23SVenkat Yekkirala * exported if the pointers are not NULL, if they are NULL then that level is 585*7420ed23SVenkat Yekkirala * not exported. 586*7420ed23SVenkat Yekkirala * 587*7420ed23SVenkat Yekkirala */ 588*7420ed23SVenkat Yekkirala void mls_export_lvl(const struct context *context, u32 *low, u32 *high) 589*7420ed23SVenkat Yekkirala { 590*7420ed23SVenkat Yekkirala if (!selinux_mls_enabled) 591*7420ed23SVenkat Yekkirala return; 592*7420ed23SVenkat Yekkirala 593*7420ed23SVenkat Yekkirala if (low != NULL) 594*7420ed23SVenkat Yekkirala *low = context->range.level[0].sens - 1; 595*7420ed23SVenkat Yekkirala if (high != NULL) 596*7420ed23SVenkat Yekkirala *high = context->range.level[1].sens - 1; 597*7420ed23SVenkat Yekkirala } 598*7420ed23SVenkat Yekkirala 599*7420ed23SVenkat Yekkirala /** 600*7420ed23SVenkat Yekkirala * mls_import_lvl - Import the MLS sensitivity levels 601*7420ed23SVenkat Yekkirala * @context: the security context 602*7420ed23SVenkat Yekkirala * @low: the low sensitivity level 603*7420ed23SVenkat Yekkirala * @high: the high sensitivity level 604*7420ed23SVenkat Yekkirala * 605*7420ed23SVenkat Yekkirala * Description: 606*7420ed23SVenkat Yekkirala * Given the security context and the two sensitivty levels, set the MLS levels 607*7420ed23SVenkat Yekkirala * in the context according the two given as parameters. Returns zero on 608*7420ed23SVenkat Yekkirala * success, negative values on failure. 609*7420ed23SVenkat Yekkirala * 610*7420ed23SVenkat Yekkirala */ 611*7420ed23SVenkat Yekkirala void mls_import_lvl(struct context *context, u32 low, u32 high) 612*7420ed23SVenkat Yekkirala { 613*7420ed23SVenkat Yekkirala if (!selinux_mls_enabled) 614*7420ed23SVenkat Yekkirala return; 615*7420ed23SVenkat Yekkirala 616*7420ed23SVenkat Yekkirala context->range.level[0].sens = low + 1; 617*7420ed23SVenkat Yekkirala context->range.level[1].sens = high + 1; 618*7420ed23SVenkat Yekkirala } 619*7420ed23SVenkat Yekkirala 620*7420ed23SVenkat Yekkirala /** 621*7420ed23SVenkat Yekkirala * mls_export_cat - Export the MLS categories 622*7420ed23SVenkat Yekkirala * @context: the security context 623*7420ed23SVenkat Yekkirala * @low: the low category 624*7420ed23SVenkat Yekkirala * @low_len: length of the cat_low bitmap in bytes 625*7420ed23SVenkat Yekkirala * @high: the high category 626*7420ed23SVenkat Yekkirala * @high_len: length of the cat_high bitmap in bytes 627*7420ed23SVenkat Yekkirala * 628*7420ed23SVenkat Yekkirala * Description: 629*7420ed23SVenkat Yekkirala * Given the security context export the low MLS category bitmap into cat_low 630*7420ed23SVenkat Yekkirala * and the high category bitmap into cat_high. The MLS categories are only 631*7420ed23SVenkat Yekkirala * exported if the pointers are not NULL, if they are NULL then that level is 632*7420ed23SVenkat Yekkirala * not exported. The caller is responsibile for freeing the memory when 633*7420ed23SVenkat Yekkirala * finished. Returns zero on success, negative values on failure. 634*7420ed23SVenkat Yekkirala * 635*7420ed23SVenkat Yekkirala */ 636*7420ed23SVenkat Yekkirala int mls_export_cat(const struct context *context, 637*7420ed23SVenkat Yekkirala unsigned char **low, 638*7420ed23SVenkat Yekkirala size_t *low_len, 639*7420ed23SVenkat Yekkirala unsigned char **high, 640*7420ed23SVenkat Yekkirala size_t *high_len) 641*7420ed23SVenkat Yekkirala { 642*7420ed23SVenkat Yekkirala int rc = -EPERM; 643*7420ed23SVenkat Yekkirala 644*7420ed23SVenkat Yekkirala if (!selinux_mls_enabled) 645*7420ed23SVenkat Yekkirala return 0; 646*7420ed23SVenkat Yekkirala 647*7420ed23SVenkat Yekkirala if (low != NULL) { 648*7420ed23SVenkat Yekkirala rc = ebitmap_export(&context->range.level[0].cat, 649*7420ed23SVenkat Yekkirala low, 650*7420ed23SVenkat Yekkirala low_len); 651*7420ed23SVenkat Yekkirala if (rc != 0) 652*7420ed23SVenkat Yekkirala goto export_cat_failure; 653*7420ed23SVenkat Yekkirala } 654*7420ed23SVenkat Yekkirala if (high != NULL) { 655*7420ed23SVenkat Yekkirala rc = ebitmap_export(&context->range.level[1].cat, 656*7420ed23SVenkat Yekkirala high, 657*7420ed23SVenkat Yekkirala high_len); 658*7420ed23SVenkat Yekkirala if (rc != 0) 659*7420ed23SVenkat Yekkirala goto export_cat_failure; 660*7420ed23SVenkat Yekkirala } 661*7420ed23SVenkat Yekkirala 662*7420ed23SVenkat Yekkirala return 0; 663*7420ed23SVenkat Yekkirala 664*7420ed23SVenkat Yekkirala export_cat_failure: 665*7420ed23SVenkat Yekkirala if (low != NULL) 666*7420ed23SVenkat Yekkirala kfree(*low); 667*7420ed23SVenkat Yekkirala if (high != NULL) 668*7420ed23SVenkat Yekkirala kfree(*high); 669*7420ed23SVenkat Yekkirala return rc; 670*7420ed23SVenkat Yekkirala } 671*7420ed23SVenkat Yekkirala 672*7420ed23SVenkat Yekkirala /** 673*7420ed23SVenkat Yekkirala * mls_import_cat - Import the MLS categories 674*7420ed23SVenkat Yekkirala * @context: the security context 675*7420ed23SVenkat Yekkirala * @low: the low category 676*7420ed23SVenkat Yekkirala * @low_len: length of the cat_low bitmap in bytes 677*7420ed23SVenkat Yekkirala * @high: the high category 678*7420ed23SVenkat Yekkirala * @high_len: length of the cat_high bitmap in bytes 679*7420ed23SVenkat Yekkirala * 680*7420ed23SVenkat Yekkirala * Description: 681*7420ed23SVenkat Yekkirala * Given the security context and the two category bitmap strings import the 682*7420ed23SVenkat Yekkirala * categories into the security context. The MLS categories are only imported 683*7420ed23SVenkat Yekkirala * if the pointers are not NULL, if they are NULL they are skipped. Returns 684*7420ed23SVenkat Yekkirala * zero on success, negative values on failure. 685*7420ed23SVenkat Yekkirala * 686*7420ed23SVenkat Yekkirala */ 687*7420ed23SVenkat Yekkirala int mls_import_cat(struct context *context, 688*7420ed23SVenkat Yekkirala const unsigned char *low, 689*7420ed23SVenkat Yekkirala size_t low_len, 690*7420ed23SVenkat Yekkirala const unsigned char *high, 691*7420ed23SVenkat Yekkirala size_t high_len) 692*7420ed23SVenkat Yekkirala { 693*7420ed23SVenkat Yekkirala int rc = -EPERM; 694*7420ed23SVenkat Yekkirala 695*7420ed23SVenkat Yekkirala if (!selinux_mls_enabled) 696*7420ed23SVenkat Yekkirala return 0; 697*7420ed23SVenkat Yekkirala 698*7420ed23SVenkat Yekkirala if (low != NULL) { 699*7420ed23SVenkat Yekkirala rc = ebitmap_import(low, 700*7420ed23SVenkat Yekkirala low_len, 701*7420ed23SVenkat Yekkirala &context->range.level[0].cat); 702*7420ed23SVenkat Yekkirala if (rc != 0) 703*7420ed23SVenkat Yekkirala goto import_cat_failure; 704*7420ed23SVenkat Yekkirala } 705*7420ed23SVenkat Yekkirala if (high != NULL) { 706*7420ed23SVenkat Yekkirala if (high == low) 707*7420ed23SVenkat Yekkirala rc = ebitmap_cpy(&context->range.level[1].cat, 708*7420ed23SVenkat Yekkirala &context->range.level[0].cat); 709*7420ed23SVenkat Yekkirala else 710*7420ed23SVenkat Yekkirala rc = ebitmap_import(high, 711*7420ed23SVenkat Yekkirala high_len, 712*7420ed23SVenkat Yekkirala &context->range.level[1].cat); 713*7420ed23SVenkat Yekkirala if (rc != 0) 714*7420ed23SVenkat Yekkirala goto import_cat_failure; 715*7420ed23SVenkat Yekkirala } 716*7420ed23SVenkat Yekkirala 717*7420ed23SVenkat Yekkirala return 0; 718*7420ed23SVenkat Yekkirala 719*7420ed23SVenkat Yekkirala import_cat_failure: 720*7420ed23SVenkat Yekkirala ebitmap_destroy(&context->range.level[0].cat); 721*7420ed23SVenkat Yekkirala ebitmap_destroy(&context->range.level[1].cat); 722*7420ed23SVenkat Yekkirala return rc; 723*7420ed23SVenkat Yekkirala } 724