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 */ 137420ed23SVenkat Yekkirala /* 147420ed23SVenkat Yekkirala * Updated: Hewlett-Packard <paul.moore@hp.com> 157420ed23SVenkat Yekkirala * 1602752760SPaul Moore * Added support to import/export the MLS label from NetLabel 177420ed23SVenkat Yekkirala * 187420ed23SVenkat Yekkirala * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 197420ed23SVenkat 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> 2502752760SPaul Moore #include <net/netlabel.h> 26f5c1d5b2SJames Morris #include "sidtab.h" 271da177e4SLinus Torvalds #include "mls.h" 281da177e4SLinus Torvalds #include "policydb.h" 291da177e4SLinus Torvalds #include "services.h" 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* 321da177e4SLinus Torvalds * Return the length in bytes for the MLS fields of the 331da177e4SLinus Torvalds * security context string representation of `context'. 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds int mls_compute_context_len(struct context *context) 361da177e4SLinus Torvalds { 379fe79ad1SKaiGai Kohei int i, l, len, head, prev; 389fe79ad1SKaiGai Kohei char *nm; 399fe79ad1SKaiGai Kohei struct ebitmap *e; 40782ebb99SStephen Smalley struct ebitmap_node *node; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds if (!selinux_mls_enabled) 431da177e4SLinus Torvalds return 0; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds len = 1; /* for the beginning ":" */ 461da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 479fe79ad1SKaiGai Kohei int index_sens = context->range.level[l].sens; 489fe79ad1SKaiGai Kohei len += strlen(policydb.p_sens_val_to_name[index_sens - 1]); 491da177e4SLinus Torvalds 509fe79ad1SKaiGai Kohei /* categories */ 519fe79ad1SKaiGai Kohei head = -2; 529fe79ad1SKaiGai Kohei prev = -2; 539fe79ad1SKaiGai Kohei e = &context->range.level[l].cat; 549fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(e, node, i) { 559fe79ad1SKaiGai Kohei if (i - prev > 1) { 569fe79ad1SKaiGai Kohei /* one or more negative bits are skipped */ 579fe79ad1SKaiGai Kohei if (head != prev) { 589fe79ad1SKaiGai Kohei nm = policydb.p_cat_val_to_name[prev]; 599fe79ad1SKaiGai Kohei len += strlen(nm) + 1; 601da177e4SLinus Torvalds } 619fe79ad1SKaiGai Kohei nm = policydb.p_cat_val_to_name[i]; 629fe79ad1SKaiGai Kohei len += strlen(nm) + 1; 639fe79ad1SKaiGai Kohei head = i; 641da177e4SLinus Torvalds } 659fe79ad1SKaiGai Kohei prev = i; 661da177e4SLinus Torvalds } 679fe79ad1SKaiGai Kohei if (prev != head) { 689fe79ad1SKaiGai Kohei nm = policydb.p_cat_val_to_name[prev]; 699fe79ad1SKaiGai Kohei len += strlen(nm) + 1; 709fe79ad1SKaiGai Kohei } 711da177e4SLinus Torvalds if (l == 0) { 721da177e4SLinus Torvalds if (mls_level_eq(&context->range.level[0], 731da177e4SLinus Torvalds &context->range.level[1])) 741da177e4SLinus Torvalds break; 751da177e4SLinus Torvalds else 761da177e4SLinus Torvalds len++; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds return len; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* 841da177e4SLinus Torvalds * Write the security context string representation of 851da177e4SLinus Torvalds * the MLS fields of `context' into the string `*scontext'. 861da177e4SLinus Torvalds * Update `*scontext' to point to the end of the MLS fields. 871da177e4SLinus Torvalds */ 881da177e4SLinus Torvalds void mls_sid_to_context(struct context *context, 891da177e4SLinus Torvalds char **scontext) 901da177e4SLinus Torvalds { 919fe79ad1SKaiGai Kohei char *scontextp, *nm; 929fe79ad1SKaiGai Kohei int i, l, head, prev; 939fe79ad1SKaiGai Kohei struct ebitmap *e; 94782ebb99SStephen Smalley struct ebitmap_node *node; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds if (!selinux_mls_enabled) 971da177e4SLinus Torvalds return; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds scontextp = *scontext; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds *scontextp = ':'; 1021da177e4SLinus Torvalds scontextp++; 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 1051da177e4SLinus Torvalds strcpy(scontextp, 1061da177e4SLinus Torvalds policydb.p_sens_val_to_name[context->range.level[l].sens - 1]); 1079fe79ad1SKaiGai Kohei scontextp += strlen(scontextp); 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds /* categories */ 1109fe79ad1SKaiGai Kohei head = -2; 1119fe79ad1SKaiGai Kohei prev = -2; 1129fe79ad1SKaiGai Kohei e = &context->range.level[l].cat; 1139fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(e, node, i) { 1149fe79ad1SKaiGai Kohei if (i - prev > 1) { 1159fe79ad1SKaiGai Kohei /* one or more negative bits are skipped */ 1169fe79ad1SKaiGai Kohei if (prev != head) { 1179fe79ad1SKaiGai Kohei if (prev - head > 1) 1189fe79ad1SKaiGai Kohei *scontextp++ = '.'; 1199fe79ad1SKaiGai Kohei else 1209fe79ad1SKaiGai Kohei *scontextp++ = ','; 1219fe79ad1SKaiGai Kohei nm = policydb.p_cat_val_to_name[prev]; 1229fe79ad1SKaiGai Kohei strcpy(scontextp, nm); 1239fe79ad1SKaiGai Kohei scontextp += strlen(nm); 1241da177e4SLinus Torvalds } 1259fe79ad1SKaiGai Kohei if (prev < 0) 1261da177e4SLinus Torvalds *scontextp++ = ':'; 1279fe79ad1SKaiGai Kohei else 1281da177e4SLinus Torvalds *scontextp++ = ','; 1299fe79ad1SKaiGai Kohei nm = policydb.p_cat_val_to_name[i]; 1309fe79ad1SKaiGai Kohei strcpy(scontextp, nm); 1319fe79ad1SKaiGai Kohei scontextp += strlen(nm); 1329fe79ad1SKaiGai Kohei head = i; 1339fe79ad1SKaiGai Kohei } 1349fe79ad1SKaiGai Kohei prev = i; 1359fe79ad1SKaiGai Kohei } 1369fe79ad1SKaiGai Kohei 1379fe79ad1SKaiGai Kohei if (prev != head) { 1389fe79ad1SKaiGai Kohei if (prev - head > 1) 1391da177e4SLinus Torvalds *scontextp++ = '.'; 1401da177e4SLinus Torvalds else 1411da177e4SLinus Torvalds *scontextp++ = ','; 1429fe79ad1SKaiGai Kohei nm = policydb.p_cat_val_to_name[prev]; 1439fe79ad1SKaiGai Kohei strcpy(scontextp, nm); 1449fe79ad1SKaiGai Kohei scontextp += strlen(nm); 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds if (l == 0) { 1481da177e4SLinus Torvalds if (mls_level_eq(&context->range.level[0], 1491da177e4SLinus Torvalds &context->range.level[1])) 1501da177e4SLinus Torvalds break; 1519fe79ad1SKaiGai Kohei else 1529fe79ad1SKaiGai Kohei *scontextp++ = '-'; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds *scontext = scontextp; 1571da177e4SLinus Torvalds return; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 16045e5421eSStephen Smalley int mls_level_isvalid(struct policydb *p, struct mls_level *l) 16145e5421eSStephen Smalley { 16245e5421eSStephen Smalley struct level_datum *levdatum; 16345e5421eSStephen Smalley struct ebitmap_node *node; 16445e5421eSStephen Smalley int i; 16545e5421eSStephen Smalley 16645e5421eSStephen Smalley if (!l->sens || l->sens > p->p_levels.nprim) 16745e5421eSStephen Smalley return 0; 16845e5421eSStephen Smalley levdatum = hashtab_search(p->p_levels.table, 16945e5421eSStephen Smalley p->p_sens_val_to_name[l->sens - 1]); 17045e5421eSStephen Smalley if (!levdatum) 17145e5421eSStephen Smalley return 0; 17245e5421eSStephen Smalley 17345e5421eSStephen Smalley ebitmap_for_each_positive_bit(&l->cat, node, i) { 17445e5421eSStephen Smalley if (i > p->p_cats.nprim) 17545e5421eSStephen Smalley return 0; 17645e5421eSStephen Smalley if (!ebitmap_get_bit(&levdatum->level->cat, i)) { 17745e5421eSStephen Smalley /* 17845e5421eSStephen Smalley * Category may not be associated with 17945e5421eSStephen Smalley * sensitivity. 18045e5421eSStephen Smalley */ 18145e5421eSStephen Smalley return 0; 18245e5421eSStephen Smalley } 18345e5421eSStephen Smalley } 18445e5421eSStephen Smalley 18545e5421eSStephen Smalley return 1; 18645e5421eSStephen Smalley } 18745e5421eSStephen Smalley 18845e5421eSStephen Smalley int mls_range_isvalid(struct policydb *p, struct mls_range *r) 18945e5421eSStephen Smalley { 19045e5421eSStephen Smalley return (mls_level_isvalid(p, &r->level[0]) && 19145e5421eSStephen Smalley mls_level_isvalid(p, &r->level[1]) && 19245e5421eSStephen Smalley mls_level_dom(&r->level[1], &r->level[0])); 19345e5421eSStephen Smalley } 19445e5421eSStephen Smalley 1951da177e4SLinus Torvalds /* 1961da177e4SLinus Torvalds * Return 1 if the MLS fields in the security context 1971da177e4SLinus Torvalds * structure `c' are valid. Return 0 otherwise. 1981da177e4SLinus Torvalds */ 1991da177e4SLinus Torvalds int mls_context_isvalid(struct policydb *p, struct context *c) 2001da177e4SLinus Torvalds { 2011da177e4SLinus Torvalds struct user_datum *usrdatum; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds if (!selinux_mls_enabled) 2041da177e4SLinus Torvalds return 1; 2051da177e4SLinus Torvalds 20645e5421eSStephen Smalley if (!mls_range_isvalid(p, &c->range)) 2071da177e4SLinus Torvalds return 0; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds if (c->role == OBJECT_R_VAL) 2101da177e4SLinus Torvalds return 1; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* 2131da177e4SLinus Torvalds * User must be authorized for the MLS range. 2141da177e4SLinus Torvalds */ 2151da177e4SLinus Torvalds if (!c->user || c->user > p->p_users.nprim) 2161da177e4SLinus Torvalds return 0; 2171da177e4SLinus Torvalds usrdatum = p->user_val_to_struct[c->user - 1]; 2181da177e4SLinus Torvalds if (!mls_range_contains(usrdatum->range, c->range)) 2191da177e4SLinus Torvalds return 0; /* user may not be associated with range */ 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds return 1; 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds /* 2251da177e4SLinus Torvalds * Set the MLS fields in the security context structure 2261da177e4SLinus Torvalds * `context' based on the string representation in 2271da177e4SLinus Torvalds * the string `*scontext'. Update `*scontext' to 2281da177e4SLinus Torvalds * point to the end of the string representation of 2291da177e4SLinus Torvalds * the MLS fields. 2301da177e4SLinus Torvalds * 2311da177e4SLinus Torvalds * This function modifies the string in place, inserting 2321da177e4SLinus Torvalds * NULL characters to terminate the MLS fields. 233f5c1d5b2SJames Morris * 234f5c1d5b2SJames Morris * If a def_sid is provided and no MLS field is present, 235f5c1d5b2SJames Morris * copy the MLS field of the associated default context. 236f5c1d5b2SJames Morris * Used for upgraded to MLS systems where objects may lack 237f5c1d5b2SJames Morris * MLS fields. 238f5c1d5b2SJames Morris * 239f5c1d5b2SJames Morris * Policy read-lock must be held for sidtab lookup. 240f5c1d5b2SJames Morris * 2411da177e4SLinus Torvalds */ 24212b29f34SStephen Smalley int mls_context_to_sid(struct policydb *pol, 24312b29f34SStephen Smalley char oldc, 2441da177e4SLinus Torvalds char **scontext, 245f5c1d5b2SJames Morris struct context *context, 246f5c1d5b2SJames Morris struct sidtab *s, 247f5c1d5b2SJames Morris u32 def_sid) 2481da177e4SLinus Torvalds { 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds char delim; 2511da177e4SLinus Torvalds char *scontextp, *p, *rngptr; 2521da177e4SLinus Torvalds struct level_datum *levdatum; 2531da177e4SLinus Torvalds struct cat_datum *catdatum, *rngdatum; 2541da177e4SLinus Torvalds int l, rc = -EINVAL; 2551da177e4SLinus Torvalds 256e517a0cdSStephen Smalley if (!selinux_mls_enabled) { 257e517a0cdSStephen Smalley if (def_sid != SECSID_NULL && oldc) 258ab5703b3SRon Yorston *scontext += strlen(*scontext)+1; 2591da177e4SLinus Torvalds return 0; 260e517a0cdSStephen Smalley } 2611da177e4SLinus Torvalds 262f5c1d5b2SJames Morris /* 263f5c1d5b2SJames Morris * No MLS component to the security context, try and map to 264f5c1d5b2SJames Morris * default if provided. 265f5c1d5b2SJames Morris */ 266f5c1d5b2SJames Morris if (!oldc) { 267f5c1d5b2SJames Morris struct context *defcon; 268f5c1d5b2SJames Morris 269f5c1d5b2SJames Morris if (def_sid == SECSID_NULL) 2701da177e4SLinus Torvalds goto out; 2711da177e4SLinus Torvalds 272f5c1d5b2SJames Morris defcon = sidtab_search(s, def_sid); 273f5c1d5b2SJames Morris if (!defcon) 274f5c1d5b2SJames Morris goto out; 275f5c1d5b2SJames Morris 2760efc61eaSVenkat Yekkirala rc = mls_context_cpy(context, defcon); 277f5c1d5b2SJames Morris goto out; 278f5c1d5b2SJames Morris } 279f5c1d5b2SJames Morris 2801da177e4SLinus Torvalds /* Extract low sensitivity. */ 2811da177e4SLinus Torvalds scontextp = p = *scontext; 2821da177e4SLinus Torvalds while (*p && *p != ':' && *p != '-') 2831da177e4SLinus Torvalds p++; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds delim = *p; 2861da177e4SLinus Torvalds if (delim != 0) 2871da177e4SLinus Torvalds *p++ = 0; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 29012b29f34SStephen Smalley levdatum = hashtab_search(pol->p_levels.table, scontextp); 2911da177e4SLinus Torvalds if (!levdatum) { 2921da177e4SLinus Torvalds rc = -EINVAL; 2931da177e4SLinus Torvalds goto out; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds context->range.level[l].sens = levdatum->level->sens; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds if (delim == ':') { 2991da177e4SLinus Torvalds /* Extract category set. */ 3001da177e4SLinus Torvalds while (1) { 3011da177e4SLinus Torvalds scontextp = p; 3021da177e4SLinus Torvalds while (*p && *p != ',' && *p != '-') 3031da177e4SLinus Torvalds p++; 3041da177e4SLinus Torvalds delim = *p; 3051da177e4SLinus Torvalds if (delim != 0) 3061da177e4SLinus Torvalds *p++ = 0; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds /* Separate into range if exists */ 3091a5e6f87SEric Paris rngptr = strchr(scontextp, '.'); 3101a5e6f87SEric Paris if (rngptr != NULL) { 3111da177e4SLinus Torvalds /* Remove '.' */ 3121da177e4SLinus Torvalds *rngptr++ = 0; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 31512b29f34SStephen Smalley catdatum = hashtab_search(pol->p_cats.table, 3161da177e4SLinus Torvalds scontextp); 3171da177e4SLinus Torvalds if (!catdatum) { 3181da177e4SLinus Torvalds rc = -EINVAL; 3191da177e4SLinus Torvalds goto out; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds rc = ebitmap_set_bit(&context->range.level[l].cat, 3231da177e4SLinus Torvalds catdatum->value - 1, 1); 3241da177e4SLinus Torvalds if (rc) 3251da177e4SLinus Torvalds goto out; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* If range, set all categories in range */ 3281da177e4SLinus Torvalds if (rngptr) { 3291da177e4SLinus Torvalds int i; 3301da177e4SLinus Torvalds 33112b29f34SStephen Smalley rngdatum = hashtab_search(pol->p_cats.table, rngptr); 3321da177e4SLinus Torvalds if (!rngdatum) { 3331da177e4SLinus Torvalds rc = -EINVAL; 3341da177e4SLinus Torvalds goto out; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds if (catdatum->value >= rngdatum->value) { 3381da177e4SLinus Torvalds rc = -EINVAL; 3391da177e4SLinus Torvalds goto out; 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds for (i = catdatum->value; i < rngdatum->value; i++) { 3431da177e4SLinus Torvalds rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); 3441da177e4SLinus Torvalds if (rc) 3451da177e4SLinus Torvalds goto out; 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds if (delim != ',') 3501da177e4SLinus Torvalds break; 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds if (delim == '-') { 3541da177e4SLinus Torvalds /* Extract high sensitivity. */ 3551da177e4SLinus Torvalds scontextp = p; 3561da177e4SLinus Torvalds while (*p && *p != ':') 3571da177e4SLinus Torvalds p++; 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds delim = *p; 3601da177e4SLinus Torvalds if (delim != 0) 3611da177e4SLinus Torvalds *p++ = 0; 3621da177e4SLinus Torvalds } else 3631da177e4SLinus Torvalds break; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds if (l == 0) { 3671da177e4SLinus Torvalds context->range.level[1].sens = context->range.level[0].sens; 3681da177e4SLinus Torvalds rc = ebitmap_cpy(&context->range.level[1].cat, 3691da177e4SLinus Torvalds &context->range.level[0].cat); 3701da177e4SLinus Torvalds if (rc) 3711da177e4SLinus Torvalds goto out; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds *scontext = ++p; 3741da177e4SLinus Torvalds rc = 0; 3751da177e4SLinus Torvalds out: 3761da177e4SLinus Torvalds return rc; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds /* 380376bd9cbSDarrel Goeddel * Set the MLS fields in the security context structure 381376bd9cbSDarrel Goeddel * `context' based on the string representation in 382376bd9cbSDarrel Goeddel * the string `str'. This function will allocate temporary memory with the 383376bd9cbSDarrel Goeddel * given constraints of gfp_mask. 384376bd9cbSDarrel Goeddel */ 385376bd9cbSDarrel Goeddel int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) 386376bd9cbSDarrel Goeddel { 387376bd9cbSDarrel Goeddel char *tmpstr, *freestr; 388376bd9cbSDarrel Goeddel int rc; 389376bd9cbSDarrel Goeddel 390376bd9cbSDarrel Goeddel if (!selinux_mls_enabled) 391376bd9cbSDarrel Goeddel return -EINVAL; 392376bd9cbSDarrel Goeddel 393376bd9cbSDarrel Goeddel /* we need freestr because mls_context_to_sid will change 394376bd9cbSDarrel Goeddel the value of tmpstr */ 395376bd9cbSDarrel Goeddel tmpstr = freestr = kstrdup(str, gfp_mask); 396376bd9cbSDarrel Goeddel if (!tmpstr) { 397376bd9cbSDarrel Goeddel rc = -ENOMEM; 398376bd9cbSDarrel Goeddel } else { 39912b29f34SStephen Smalley rc = mls_context_to_sid(&policydb, ':', &tmpstr, context, 400376bd9cbSDarrel Goeddel NULL, SECSID_NULL); 401376bd9cbSDarrel Goeddel kfree(freestr); 402376bd9cbSDarrel Goeddel } 403376bd9cbSDarrel Goeddel 404376bd9cbSDarrel Goeddel return rc; 405376bd9cbSDarrel Goeddel } 406376bd9cbSDarrel Goeddel 407376bd9cbSDarrel Goeddel /* 4081da177e4SLinus Torvalds * Copies the MLS range `range' into `context'. 4091da177e4SLinus Torvalds */ 4101da177e4SLinus Torvalds static inline int mls_range_set(struct context *context, 4111da177e4SLinus Torvalds struct mls_range *range) 4121da177e4SLinus Torvalds { 4131da177e4SLinus Torvalds int l, rc = 0; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* Copy the MLS range into the context */ 4161da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 4171da177e4SLinus Torvalds context->range.level[l].sens = range->level[l].sens; 4181da177e4SLinus Torvalds rc = ebitmap_cpy(&context->range.level[l].cat, 4191da177e4SLinus Torvalds &range->level[l].cat); 4201da177e4SLinus Torvalds if (rc) 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds return rc; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds int mls_setup_user_range(struct context *fromcon, struct user_datum *user, 4281da177e4SLinus Torvalds struct context *usercon) 4291da177e4SLinus Torvalds { 4301da177e4SLinus Torvalds if (selinux_mls_enabled) { 4311da177e4SLinus Torvalds struct mls_level *fromcon_sen = &(fromcon->range.level[0]); 4321da177e4SLinus Torvalds struct mls_level *fromcon_clr = &(fromcon->range.level[1]); 4331da177e4SLinus Torvalds struct mls_level *user_low = &(user->range.level[0]); 4341da177e4SLinus Torvalds struct mls_level *user_clr = &(user->range.level[1]); 4351da177e4SLinus Torvalds struct mls_level *user_def = &(user->dfltlevel); 4361da177e4SLinus Torvalds struct mls_level *usercon_sen = &(usercon->range.level[0]); 4371da177e4SLinus Torvalds struct mls_level *usercon_clr = &(usercon->range.level[1]); 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds /* Honor the user's default level if we can */ 440*f5269710SEric Paris if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) 4411da177e4SLinus Torvalds *usercon_sen = *user_def; 442*f5269710SEric Paris else if (mls_level_between(fromcon_sen, user_def, user_clr)) 4431da177e4SLinus Torvalds *usercon_sen = *fromcon_sen; 444*f5269710SEric Paris else if (mls_level_between(fromcon_clr, user_low, user_def)) 4451da177e4SLinus Torvalds *usercon_sen = *user_low; 446*f5269710SEric Paris else 4471da177e4SLinus Torvalds return -EINVAL; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /* Lower the clearance of available contexts 4501da177e4SLinus Torvalds if the clearance of "fromcon" is lower than 4511da177e4SLinus Torvalds that of the user's default clearance (but 4521da177e4SLinus Torvalds only if the "fromcon" clearance dominates 4531da177e4SLinus Torvalds the user's computed sensitivity level) */ 4541a5e6f87SEric Paris if (mls_level_dom(user_clr, fromcon_clr)) 4551da177e4SLinus Torvalds *usercon_clr = *fromcon_clr; 4561a5e6f87SEric Paris else if (mls_level_dom(fromcon_clr, user_clr)) 4571da177e4SLinus Torvalds *usercon_clr = *user_clr; 4581a5e6f87SEric Paris else 4591da177e4SLinus Torvalds return -EINVAL; 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds return 0; 4631da177e4SLinus Torvalds } 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds /* 4661da177e4SLinus Torvalds * Convert the MLS fields in the security context 4671da177e4SLinus Torvalds * structure `c' from the values specified in the 4681da177e4SLinus Torvalds * policy `oldp' to the values specified in the policy `newp'. 4691da177e4SLinus Torvalds */ 4701da177e4SLinus Torvalds int mls_convert_context(struct policydb *oldp, 4711da177e4SLinus Torvalds struct policydb *newp, 4721da177e4SLinus Torvalds struct context *c) 4731da177e4SLinus Torvalds { 4741da177e4SLinus Torvalds struct level_datum *levdatum; 4751da177e4SLinus Torvalds struct cat_datum *catdatum; 4761da177e4SLinus Torvalds struct ebitmap bitmap; 477782ebb99SStephen Smalley struct ebitmap_node *node; 4781da177e4SLinus Torvalds int l, i; 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds if (!selinux_mls_enabled) 4811da177e4SLinus Torvalds return 0; 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds for (l = 0; l < 2; l++) { 4841da177e4SLinus Torvalds levdatum = hashtab_search(newp->p_levels.table, 4851da177e4SLinus Torvalds oldp->p_sens_val_to_name[c->range.level[l].sens - 1]); 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds if (!levdatum) 4881da177e4SLinus Torvalds return -EINVAL; 4891da177e4SLinus Torvalds c->range.level[l].sens = levdatum->level->sens; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds ebitmap_init(&bitmap); 4929fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) { 4931da177e4SLinus Torvalds int rc; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds catdatum = hashtab_search(newp->p_cats.table, 496782ebb99SStephen Smalley oldp->p_cat_val_to_name[i]); 4971da177e4SLinus Torvalds if (!catdatum) 4981da177e4SLinus Torvalds return -EINVAL; 4991da177e4SLinus Torvalds rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); 5001da177e4SLinus Torvalds if (rc) 5011da177e4SLinus Torvalds return rc; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds ebitmap_destroy(&c->range.level[l].cat); 5041da177e4SLinus Torvalds c->range.level[l].cat = bitmap; 5051da177e4SLinus Torvalds } 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds return 0; 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds int mls_compute_sid(struct context *scontext, 5111da177e4SLinus Torvalds struct context *tcontext, 5121da177e4SLinus Torvalds u16 tclass, 5131da177e4SLinus Torvalds u32 specified, 5141da177e4SLinus Torvalds struct context *newcontext) 5151da177e4SLinus Torvalds { 516f3f87714SDarrel Goeddel struct range_trans *rtr; 517f3f87714SDarrel Goeddel 5181da177e4SLinus Torvalds if (!selinux_mls_enabled) 5191da177e4SLinus Torvalds return 0; 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds switch (specified) { 5221da177e4SLinus Torvalds case AVTAB_TRANSITION: 5231da177e4SLinus Torvalds /* Look for a range transition rule. */ 524f3f87714SDarrel Goeddel for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { 525f3f87714SDarrel Goeddel if (rtr->source_type == scontext->type && 526f3f87714SDarrel Goeddel rtr->target_type == tcontext->type && 527f3f87714SDarrel Goeddel rtr->target_class == tclass) { 5281da177e4SLinus Torvalds /* Set the range from the rule */ 5291da177e4SLinus Torvalds return mls_range_set(newcontext, 530f3f87714SDarrel Goeddel &rtr->target_range); 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds /* Fallthrough */ 5341da177e4SLinus Torvalds case AVTAB_CHANGE: 5351da177e4SLinus Torvalds if (tclass == SECCLASS_PROCESS) 5361da177e4SLinus Torvalds /* Use the process MLS attributes. */ 5370efc61eaSVenkat Yekkirala return mls_context_cpy(newcontext, scontext); 5381da177e4SLinus Torvalds else 5391da177e4SLinus Torvalds /* Use the process effective MLS attributes. */ 5400efc61eaSVenkat Yekkirala return mls_context_cpy_low(newcontext, scontext); 5411da177e4SLinus Torvalds case AVTAB_MEMBER: 5421da177e4SLinus Torvalds /* Use the process effective MLS attributes. */ 5430efc61eaSVenkat Yekkirala return mls_context_cpy_low(newcontext, scontext); 5441da177e4SLinus Torvalds default: 5451da177e4SLinus Torvalds return -EINVAL; 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds return -EINVAL; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 55002752760SPaul Moore #ifdef CONFIG_NETLABEL 5517420ed23SVenkat Yekkirala /** 55202752760SPaul Moore * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel 5537420ed23SVenkat Yekkirala * @context: the security context 55402752760SPaul Moore * @secattr: the NetLabel security attributes 5557420ed23SVenkat Yekkirala * 5567420ed23SVenkat Yekkirala * Description: 55702752760SPaul Moore * Given the security context copy the low MLS sensitivity level into the 55802752760SPaul Moore * NetLabel MLS sensitivity level field. 5597420ed23SVenkat Yekkirala * 5607420ed23SVenkat Yekkirala */ 56102752760SPaul Moore void mls_export_netlbl_lvl(struct context *context, 56202752760SPaul Moore struct netlbl_lsm_secattr *secattr) 5637420ed23SVenkat Yekkirala { 5647420ed23SVenkat Yekkirala if (!selinux_mls_enabled) 5657420ed23SVenkat Yekkirala return; 5667420ed23SVenkat Yekkirala 56716efd454SPaul Moore secattr->attr.mls.lvl = context->range.level[0].sens - 1; 56802752760SPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_LVL; 5697420ed23SVenkat Yekkirala } 5707420ed23SVenkat Yekkirala 5717420ed23SVenkat Yekkirala /** 57202752760SPaul Moore * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels 5737420ed23SVenkat Yekkirala * @context: the security context 57402752760SPaul Moore * @secattr: the NetLabel security attributes 5757420ed23SVenkat Yekkirala * 5767420ed23SVenkat Yekkirala * Description: 57702752760SPaul Moore * Given the security context and the NetLabel security attributes, copy the 57802752760SPaul Moore * NetLabel MLS sensitivity level into the context. 5797420ed23SVenkat Yekkirala * 5807420ed23SVenkat Yekkirala */ 58102752760SPaul Moore void mls_import_netlbl_lvl(struct context *context, 58202752760SPaul Moore struct netlbl_lsm_secattr *secattr) 5837420ed23SVenkat Yekkirala { 5847420ed23SVenkat Yekkirala if (!selinux_mls_enabled) 5857420ed23SVenkat Yekkirala return; 5867420ed23SVenkat Yekkirala 58716efd454SPaul Moore context->range.level[0].sens = secattr->attr.mls.lvl + 1; 58802752760SPaul Moore context->range.level[1].sens = context->range.level[0].sens; 5897420ed23SVenkat Yekkirala } 5907420ed23SVenkat Yekkirala 5917420ed23SVenkat Yekkirala /** 59202752760SPaul Moore * mls_export_netlbl_cat - Export the MLS categories to NetLabel 5937420ed23SVenkat Yekkirala * @context: the security context 59402752760SPaul Moore * @secattr: the NetLabel security attributes 5957420ed23SVenkat Yekkirala * 5967420ed23SVenkat Yekkirala * Description: 59702752760SPaul Moore * Given the security context copy the low MLS categories into the NetLabel 59802752760SPaul Moore * MLS category field. Returns zero on success, negative values on failure. 5997420ed23SVenkat Yekkirala * 6007420ed23SVenkat Yekkirala */ 60102752760SPaul Moore int mls_export_netlbl_cat(struct context *context, 60202752760SPaul Moore struct netlbl_lsm_secattr *secattr) 6037420ed23SVenkat Yekkirala { 60402752760SPaul Moore int rc; 6057420ed23SVenkat Yekkirala 60602752760SPaul Moore if (!selinux_mls_enabled) 6077420ed23SVenkat Yekkirala return 0; 6087420ed23SVenkat Yekkirala 60902752760SPaul Moore rc = ebitmap_netlbl_export(&context->range.level[0].cat, 61016efd454SPaul Moore &secattr->attr.mls.cat); 61116efd454SPaul Moore if (rc == 0 && secattr->attr.mls.cat != NULL) 61202752760SPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_CAT; 61302752760SPaul Moore 6147420ed23SVenkat Yekkirala return rc; 6157420ed23SVenkat Yekkirala } 6167420ed23SVenkat Yekkirala 6177420ed23SVenkat Yekkirala /** 61802752760SPaul Moore * mls_import_netlbl_cat - Import the MLS categories from NetLabel 6197420ed23SVenkat Yekkirala * @context: the security context 62002752760SPaul Moore * @secattr: the NetLabel security attributes 6217420ed23SVenkat Yekkirala * 6227420ed23SVenkat Yekkirala * Description: 62302752760SPaul Moore * Copy the NetLabel security attributes into the SELinux context; since the 62402752760SPaul Moore * NetLabel security attribute only contains a single MLS category use it for 62502752760SPaul Moore * both the low and high categories of the context. Returns zero on success, 62602752760SPaul Moore * negative values on failure. 6277420ed23SVenkat Yekkirala * 6287420ed23SVenkat Yekkirala */ 62902752760SPaul Moore int mls_import_netlbl_cat(struct context *context, 63002752760SPaul Moore struct netlbl_lsm_secattr *secattr) 6317420ed23SVenkat Yekkirala { 63202752760SPaul Moore int rc; 6337420ed23SVenkat Yekkirala 6347420ed23SVenkat Yekkirala if (!selinux_mls_enabled) 6357420ed23SVenkat Yekkirala return 0; 6367420ed23SVenkat Yekkirala 63702752760SPaul Moore rc = ebitmap_netlbl_import(&context->range.level[0].cat, 63816efd454SPaul Moore secattr->attr.mls.cat); 6397420ed23SVenkat Yekkirala if (rc != 0) 64002752760SPaul Moore goto import_netlbl_cat_failure; 64102752760SPaul Moore 6427420ed23SVenkat Yekkirala rc = ebitmap_cpy(&context->range.level[1].cat, 6437420ed23SVenkat Yekkirala &context->range.level[0].cat); 6447420ed23SVenkat Yekkirala if (rc != 0) 64502752760SPaul Moore goto import_netlbl_cat_failure; 6467420ed23SVenkat Yekkirala 6477420ed23SVenkat Yekkirala return 0; 6487420ed23SVenkat Yekkirala 64902752760SPaul Moore import_netlbl_cat_failure: 6507420ed23SVenkat Yekkirala ebitmap_destroy(&context->range.level[0].cat); 6517420ed23SVenkat Yekkirala ebitmap_destroy(&context->range.level[1].cat); 6527420ed23SVenkat Yekkirala return rc; 6537420ed23SVenkat Yekkirala } 65402752760SPaul Moore #endif /* CONFIG_NETLABEL */ 655