18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Implementation of the multi-level security (MLS) policy. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author : Stephen Smalley, <sds@tycho.nsa.gov> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Support for enhanced MLS infrastructure. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Updated: Hewlett-Packard <paul@paul-moore.com> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Added support to import/export the MLS label from NetLabel 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/kernel.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/string.h> 258c2ecf20Sopenharmony_ci#include <linux/errno.h> 268c2ecf20Sopenharmony_ci#include <net/netlabel.h> 278c2ecf20Sopenharmony_ci#include "sidtab.h" 288c2ecf20Sopenharmony_ci#include "mls.h" 298c2ecf20Sopenharmony_ci#include "policydb.h" 308c2ecf20Sopenharmony_ci#include "services.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Return the length in bytes for the MLS fields of the 348c2ecf20Sopenharmony_ci * security context string representation of `context'. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ciint mls_compute_context_len(struct policydb *p, struct context *context) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci int i, l, len, head, prev; 398c2ecf20Sopenharmony_ci char *nm; 408c2ecf20Sopenharmony_ci struct ebitmap *e; 418c2ecf20Sopenharmony_ci struct ebitmap_node *node; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!p->mls_enabled) 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci len = 1; /* for the beginning ":" */ 478c2ecf20Sopenharmony_ci for (l = 0; l < 2; l++) { 488c2ecf20Sopenharmony_ci int index_sens = context->range.level[l].sens; 498c2ecf20Sopenharmony_ci len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1)); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* categories */ 528c2ecf20Sopenharmony_ci head = -2; 538c2ecf20Sopenharmony_ci prev = -2; 548c2ecf20Sopenharmony_ci e = &context->range.level[l].cat; 558c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(e, node, i) { 568c2ecf20Sopenharmony_ci if (i - prev > 1) { 578c2ecf20Sopenharmony_ci /* one or more negative bits are skipped */ 588c2ecf20Sopenharmony_ci if (head != prev) { 598c2ecf20Sopenharmony_ci nm = sym_name(p, SYM_CATS, prev); 608c2ecf20Sopenharmony_ci len += strlen(nm) + 1; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci nm = sym_name(p, SYM_CATS, i); 638c2ecf20Sopenharmony_ci len += strlen(nm) + 1; 648c2ecf20Sopenharmony_ci head = i; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci prev = i; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci if (prev != head) { 698c2ecf20Sopenharmony_ci nm = sym_name(p, SYM_CATS, prev); 708c2ecf20Sopenharmony_ci len += strlen(nm) + 1; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci if (l == 0) { 738c2ecf20Sopenharmony_ci if (mls_level_eq(&context->range.level[0], 748c2ecf20Sopenharmony_ci &context->range.level[1])) 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci else 778c2ecf20Sopenharmony_ci len++; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return len; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * Write the security context string representation of 868c2ecf20Sopenharmony_ci * the MLS fields of `context' into the string `*scontext'. 878c2ecf20Sopenharmony_ci * Update `*scontext' to point to the end of the MLS fields. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_civoid mls_sid_to_context(struct policydb *p, 908c2ecf20Sopenharmony_ci struct context *context, 918c2ecf20Sopenharmony_ci char **scontext) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci char *scontextp, *nm; 948c2ecf20Sopenharmony_ci int i, l, head, prev; 958c2ecf20Sopenharmony_ci struct ebitmap *e; 968c2ecf20Sopenharmony_ci struct ebitmap_node *node; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!p->mls_enabled) 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci scontextp = *scontext; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci *scontextp = ':'; 1048c2ecf20Sopenharmony_ci scontextp++; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci for (l = 0; l < 2; l++) { 1078c2ecf20Sopenharmony_ci strcpy(scontextp, sym_name(p, SYM_LEVELS, 1088c2ecf20Sopenharmony_ci context->range.level[l].sens - 1)); 1098c2ecf20Sopenharmony_ci scontextp += strlen(scontextp); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* categories */ 1128c2ecf20Sopenharmony_ci head = -2; 1138c2ecf20Sopenharmony_ci prev = -2; 1148c2ecf20Sopenharmony_ci e = &context->range.level[l].cat; 1158c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(e, node, i) { 1168c2ecf20Sopenharmony_ci if (i - prev > 1) { 1178c2ecf20Sopenharmony_ci /* one or more negative bits are skipped */ 1188c2ecf20Sopenharmony_ci if (prev != head) { 1198c2ecf20Sopenharmony_ci if (prev - head > 1) 1208c2ecf20Sopenharmony_ci *scontextp++ = '.'; 1218c2ecf20Sopenharmony_ci else 1228c2ecf20Sopenharmony_ci *scontextp++ = ','; 1238c2ecf20Sopenharmony_ci nm = sym_name(p, SYM_CATS, prev); 1248c2ecf20Sopenharmony_ci strcpy(scontextp, nm); 1258c2ecf20Sopenharmony_ci scontextp += strlen(nm); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci if (prev < 0) 1288c2ecf20Sopenharmony_ci *scontextp++ = ':'; 1298c2ecf20Sopenharmony_ci else 1308c2ecf20Sopenharmony_ci *scontextp++ = ','; 1318c2ecf20Sopenharmony_ci nm = sym_name(p, SYM_CATS, i); 1328c2ecf20Sopenharmony_ci strcpy(scontextp, nm); 1338c2ecf20Sopenharmony_ci scontextp += strlen(nm); 1348c2ecf20Sopenharmony_ci head = i; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci prev = i; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (prev != head) { 1408c2ecf20Sopenharmony_ci if (prev - head > 1) 1418c2ecf20Sopenharmony_ci *scontextp++ = '.'; 1428c2ecf20Sopenharmony_ci else 1438c2ecf20Sopenharmony_ci *scontextp++ = ','; 1448c2ecf20Sopenharmony_ci nm = sym_name(p, SYM_CATS, prev); 1458c2ecf20Sopenharmony_ci strcpy(scontextp, nm); 1468c2ecf20Sopenharmony_ci scontextp += strlen(nm); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (l == 0) { 1508c2ecf20Sopenharmony_ci if (mls_level_eq(&context->range.level[0], 1518c2ecf20Sopenharmony_ci &context->range.level[1])) 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci else 1548c2ecf20Sopenharmony_ci *scontextp++ = '-'; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci *scontext = scontextp; 1598c2ecf20Sopenharmony_ci return; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciint mls_level_isvalid(struct policydb *p, struct mls_level *l) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct level_datum *levdatum; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!l->sens || l->sens > p->p_levels.nprim) 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci levdatum = symtab_search(&p->p_levels, 1698c2ecf20Sopenharmony_ci sym_name(p, SYM_LEVELS, l->sens - 1)); 1708c2ecf20Sopenharmony_ci if (!levdatum) 1718c2ecf20Sopenharmony_ci return 0; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* 1748c2ecf20Sopenharmony_ci * Return 1 iff all the bits set in l->cat are also be set in 1758c2ecf20Sopenharmony_ci * levdatum->level->cat and no bit in l->cat is larger than 1768c2ecf20Sopenharmony_ci * p->p_cats.nprim. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci return ebitmap_contains(&levdatum->level->cat, &l->cat, 1798c2ecf20Sopenharmony_ci p->p_cats.nprim); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciint mls_range_isvalid(struct policydb *p, struct mls_range *r) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci return (mls_level_isvalid(p, &r->level[0]) && 1858c2ecf20Sopenharmony_ci mls_level_isvalid(p, &r->level[1]) && 1868c2ecf20Sopenharmony_ci mls_level_dom(&r->level[1], &r->level[0])); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* 1908c2ecf20Sopenharmony_ci * Return 1 if the MLS fields in the security context 1918c2ecf20Sopenharmony_ci * structure `c' are valid. Return 0 otherwise. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ciint mls_context_isvalid(struct policydb *p, struct context *c) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct user_datum *usrdatum; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (!p->mls_enabled) 1988c2ecf20Sopenharmony_ci return 1; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (!mls_range_isvalid(p, &c->range)) 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (c->role == OBJECT_R_VAL) 2048c2ecf20Sopenharmony_ci return 1; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * User must be authorized for the MLS range. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci if (!c->user || c->user > p->p_users.nprim) 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci usrdatum = p->user_val_to_struct[c->user - 1]; 2128c2ecf20Sopenharmony_ci if (!mls_range_contains(usrdatum->range, c->range)) 2138c2ecf20Sopenharmony_ci return 0; /* user may not be associated with range */ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return 1; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* 2198c2ecf20Sopenharmony_ci * Set the MLS fields in the security context structure 2208c2ecf20Sopenharmony_ci * `context' based on the string representation in 2218c2ecf20Sopenharmony_ci * the string `scontext'. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * This function modifies the string in place, inserting 2248c2ecf20Sopenharmony_ci * NULL characters to terminate the MLS fields. 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * If a def_sid is provided and no MLS field is present, 2278c2ecf20Sopenharmony_ci * copy the MLS field of the associated default context. 2288c2ecf20Sopenharmony_ci * Used for upgraded to MLS systems where objects may lack 2298c2ecf20Sopenharmony_ci * MLS fields. 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Policy read-lock must be held for sidtab lookup. 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ciint mls_context_to_sid(struct policydb *pol, 2358c2ecf20Sopenharmony_ci char oldc, 2368c2ecf20Sopenharmony_ci char *scontext, 2378c2ecf20Sopenharmony_ci struct context *context, 2388c2ecf20Sopenharmony_ci struct sidtab *s, 2398c2ecf20Sopenharmony_ci u32 def_sid) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci char *sensitivity, *cur_cat, *next_cat, *rngptr; 2428c2ecf20Sopenharmony_ci struct level_datum *levdatum; 2438c2ecf20Sopenharmony_ci struct cat_datum *catdatum, *rngdatum; 2448c2ecf20Sopenharmony_ci int l, rc, i; 2458c2ecf20Sopenharmony_ci char *rangep[2]; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (!pol->mls_enabled) { 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * With no MLS, only return -EINVAL if there is a MLS field 2508c2ecf20Sopenharmony_ci * and it did not come from an xattr. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci if (oldc && def_sid == SECSID_NULL) 2538c2ecf20Sopenharmony_ci return -EINVAL; 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * No MLS component to the security context, try and map to 2598c2ecf20Sopenharmony_ci * default if provided. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci if (!oldc) { 2628c2ecf20Sopenharmony_ci struct context *defcon; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (def_sid == SECSID_NULL) 2658c2ecf20Sopenharmony_ci return -EINVAL; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci defcon = sidtab_search(s, def_sid); 2688c2ecf20Sopenharmony_ci if (!defcon) 2698c2ecf20Sopenharmony_ci return -EINVAL; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return mls_context_cpy(context, defcon); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* 2758c2ecf20Sopenharmony_ci * If we're dealing with a range, figure out where the two parts 2768c2ecf20Sopenharmony_ci * of the range begin. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci rangep[0] = scontext; 2798c2ecf20Sopenharmony_ci rangep[1] = strchr(scontext, '-'); 2808c2ecf20Sopenharmony_ci if (rangep[1]) { 2818c2ecf20Sopenharmony_ci rangep[1][0] = '\0'; 2828c2ecf20Sopenharmony_ci rangep[1]++; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* For each part of the range: */ 2868c2ecf20Sopenharmony_ci for (l = 0; l < 2; l++) { 2878c2ecf20Sopenharmony_ci /* Split sensitivity and category set. */ 2888c2ecf20Sopenharmony_ci sensitivity = rangep[l]; 2898c2ecf20Sopenharmony_ci if (sensitivity == NULL) 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci next_cat = strchr(sensitivity, ':'); 2928c2ecf20Sopenharmony_ci if (next_cat) 2938c2ecf20Sopenharmony_ci *(next_cat++) = '\0'; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Parse sensitivity. */ 2968c2ecf20Sopenharmony_ci levdatum = symtab_search(&pol->p_levels, sensitivity); 2978c2ecf20Sopenharmony_ci if (!levdatum) 2988c2ecf20Sopenharmony_ci return -EINVAL; 2998c2ecf20Sopenharmony_ci context->range.level[l].sens = levdatum->level->sens; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Extract category set. */ 3028c2ecf20Sopenharmony_ci while (next_cat != NULL) { 3038c2ecf20Sopenharmony_ci cur_cat = next_cat; 3048c2ecf20Sopenharmony_ci next_cat = strchr(next_cat, ','); 3058c2ecf20Sopenharmony_ci if (next_cat != NULL) 3068c2ecf20Sopenharmony_ci *(next_cat++) = '\0'; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Separate into range if exists */ 3098c2ecf20Sopenharmony_ci rngptr = strchr(cur_cat, '.'); 3108c2ecf20Sopenharmony_ci if (rngptr != NULL) { 3118c2ecf20Sopenharmony_ci /* Remove '.' */ 3128c2ecf20Sopenharmony_ci *rngptr++ = '\0'; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci catdatum = symtab_search(&pol->p_cats, cur_cat); 3168c2ecf20Sopenharmony_ci if (!catdatum) 3178c2ecf20Sopenharmony_ci return -EINVAL; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci rc = ebitmap_set_bit(&context->range.level[l].cat, 3208c2ecf20Sopenharmony_ci catdatum->value - 1, 1); 3218c2ecf20Sopenharmony_ci if (rc) 3228c2ecf20Sopenharmony_ci return rc; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* If range, set all categories in range */ 3258c2ecf20Sopenharmony_ci if (rngptr == NULL) 3268c2ecf20Sopenharmony_ci continue; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci rngdatum = symtab_search(&pol->p_cats, rngptr); 3298c2ecf20Sopenharmony_ci if (!rngdatum) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (catdatum->value >= rngdatum->value) 3338c2ecf20Sopenharmony_ci return -EINVAL; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci for (i = catdatum->value; i < rngdatum->value; i++) { 3368c2ecf20Sopenharmony_ci rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1); 3378c2ecf20Sopenharmony_ci if (rc) 3388c2ecf20Sopenharmony_ci return rc; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* If we didn't see a '-', the range start is also the range end. */ 3448c2ecf20Sopenharmony_ci if (rangep[1] == NULL) { 3458c2ecf20Sopenharmony_ci context->range.level[1].sens = context->range.level[0].sens; 3468c2ecf20Sopenharmony_ci rc = ebitmap_cpy(&context->range.level[1].cat, 3478c2ecf20Sopenharmony_ci &context->range.level[0].cat); 3488c2ecf20Sopenharmony_ci if (rc) 3498c2ecf20Sopenharmony_ci return rc; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/* 3568c2ecf20Sopenharmony_ci * Set the MLS fields in the security context structure 3578c2ecf20Sopenharmony_ci * `context' based on the string representation in 3588c2ecf20Sopenharmony_ci * the string `str'. This function will allocate temporary memory with the 3598c2ecf20Sopenharmony_ci * given constraints of gfp_mask. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ciint mls_from_string(struct policydb *p, char *str, struct context *context, 3628c2ecf20Sopenharmony_ci gfp_t gfp_mask) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci char *tmpstr; 3658c2ecf20Sopenharmony_ci int rc; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (!p->mls_enabled) 3688c2ecf20Sopenharmony_ci return -EINVAL; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci tmpstr = kstrdup(str, gfp_mask); 3718c2ecf20Sopenharmony_ci if (!tmpstr) { 3728c2ecf20Sopenharmony_ci rc = -ENOMEM; 3738c2ecf20Sopenharmony_ci } else { 3748c2ecf20Sopenharmony_ci rc = mls_context_to_sid(p, ':', tmpstr, context, 3758c2ecf20Sopenharmony_ci NULL, SECSID_NULL); 3768c2ecf20Sopenharmony_ci kfree(tmpstr); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return rc; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci/* 3838c2ecf20Sopenharmony_ci * Copies the MLS range `range' into `context'. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ciint mls_range_set(struct context *context, 3868c2ecf20Sopenharmony_ci struct mls_range *range) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci int l, rc = 0; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Copy the MLS range into the context */ 3918c2ecf20Sopenharmony_ci for (l = 0; l < 2; l++) { 3928c2ecf20Sopenharmony_ci context->range.level[l].sens = range->level[l].sens; 3938c2ecf20Sopenharmony_ci rc = ebitmap_cpy(&context->range.level[l].cat, 3948c2ecf20Sopenharmony_ci &range->level[l].cat); 3958c2ecf20Sopenharmony_ci if (rc) 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return rc; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ciint mls_setup_user_range(struct policydb *p, 4038c2ecf20Sopenharmony_ci struct context *fromcon, struct user_datum *user, 4048c2ecf20Sopenharmony_ci struct context *usercon) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci if (p->mls_enabled) { 4078c2ecf20Sopenharmony_ci struct mls_level *fromcon_sen = &(fromcon->range.level[0]); 4088c2ecf20Sopenharmony_ci struct mls_level *fromcon_clr = &(fromcon->range.level[1]); 4098c2ecf20Sopenharmony_ci struct mls_level *user_low = &(user->range.level[0]); 4108c2ecf20Sopenharmony_ci struct mls_level *user_clr = &(user->range.level[1]); 4118c2ecf20Sopenharmony_ci struct mls_level *user_def = &(user->dfltlevel); 4128c2ecf20Sopenharmony_ci struct mls_level *usercon_sen = &(usercon->range.level[0]); 4138c2ecf20Sopenharmony_ci struct mls_level *usercon_clr = &(usercon->range.level[1]); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Honor the user's default level if we can */ 4168c2ecf20Sopenharmony_ci if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) 4178c2ecf20Sopenharmony_ci *usercon_sen = *user_def; 4188c2ecf20Sopenharmony_ci else if (mls_level_between(fromcon_sen, user_def, user_clr)) 4198c2ecf20Sopenharmony_ci *usercon_sen = *fromcon_sen; 4208c2ecf20Sopenharmony_ci else if (mls_level_between(fromcon_clr, user_low, user_def)) 4218c2ecf20Sopenharmony_ci *usercon_sen = *user_low; 4228c2ecf20Sopenharmony_ci else 4238c2ecf20Sopenharmony_ci return -EINVAL; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Lower the clearance of available contexts 4268c2ecf20Sopenharmony_ci if the clearance of "fromcon" is lower than 4278c2ecf20Sopenharmony_ci that of the user's default clearance (but 4288c2ecf20Sopenharmony_ci only if the "fromcon" clearance dominates 4298c2ecf20Sopenharmony_ci the user's computed sensitivity level) */ 4308c2ecf20Sopenharmony_ci if (mls_level_dom(user_clr, fromcon_clr)) 4318c2ecf20Sopenharmony_ci *usercon_clr = *fromcon_clr; 4328c2ecf20Sopenharmony_ci else if (mls_level_dom(fromcon_clr, user_clr)) 4338c2ecf20Sopenharmony_ci *usercon_clr = *user_clr; 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci return -EINVAL; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/* 4428c2ecf20Sopenharmony_ci * Convert the MLS fields in the security context 4438c2ecf20Sopenharmony_ci * structure `oldc' from the values specified in the 4448c2ecf20Sopenharmony_ci * policy `oldp' to the values specified in the policy `newp', 4458c2ecf20Sopenharmony_ci * storing the resulting context in `newc'. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_ciint mls_convert_context(struct policydb *oldp, 4488c2ecf20Sopenharmony_ci struct policydb *newp, 4498c2ecf20Sopenharmony_ci struct context *oldc, 4508c2ecf20Sopenharmony_ci struct context *newc) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct level_datum *levdatum; 4538c2ecf20Sopenharmony_ci struct cat_datum *catdatum; 4548c2ecf20Sopenharmony_ci struct ebitmap_node *node; 4558c2ecf20Sopenharmony_ci int l, i; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (!oldp->mls_enabled || !newp->mls_enabled) 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci for (l = 0; l < 2; l++) { 4618c2ecf20Sopenharmony_ci char *name = sym_name(oldp, SYM_LEVELS, 4628c2ecf20Sopenharmony_ci oldc->range.level[l].sens - 1); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci levdatum = symtab_search(&newp->p_levels, name); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!levdatum) 4678c2ecf20Sopenharmony_ci return -EINVAL; 4688c2ecf20Sopenharmony_ci newc->range.level[l].sens = levdatum->level->sens; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, 4718c2ecf20Sopenharmony_ci node, i) { 4728c2ecf20Sopenharmony_ci int rc; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci catdatum = symtab_search(&newp->p_cats, 4758c2ecf20Sopenharmony_ci sym_name(oldp, SYM_CATS, i)); 4768c2ecf20Sopenharmony_ci if (!catdatum) 4778c2ecf20Sopenharmony_ci return -EINVAL; 4788c2ecf20Sopenharmony_ci rc = ebitmap_set_bit(&newc->range.level[l].cat, 4798c2ecf20Sopenharmony_ci catdatum->value - 1, 1); 4808c2ecf20Sopenharmony_ci if (rc) 4818c2ecf20Sopenharmony_ci return rc; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciint mls_compute_sid(struct policydb *p, 4898c2ecf20Sopenharmony_ci struct context *scontext, 4908c2ecf20Sopenharmony_ci struct context *tcontext, 4918c2ecf20Sopenharmony_ci u16 tclass, 4928c2ecf20Sopenharmony_ci u32 specified, 4938c2ecf20Sopenharmony_ci struct context *newcontext, 4948c2ecf20Sopenharmony_ci bool sock) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct range_trans rtr; 4978c2ecf20Sopenharmony_ci struct mls_range *r; 4988c2ecf20Sopenharmony_ci struct class_datum *cladatum; 4998c2ecf20Sopenharmony_ci int default_range = 0; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (!p->mls_enabled) 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci switch (specified) { 5058c2ecf20Sopenharmony_ci case AVTAB_TRANSITION: 5068c2ecf20Sopenharmony_ci /* Look for a range transition rule. */ 5078c2ecf20Sopenharmony_ci rtr.source_type = scontext->type; 5088c2ecf20Sopenharmony_ci rtr.target_type = tcontext->type; 5098c2ecf20Sopenharmony_ci rtr.target_class = tclass; 5108c2ecf20Sopenharmony_ci r = policydb_rangetr_search(p, &rtr); 5118c2ecf20Sopenharmony_ci if (r) 5128c2ecf20Sopenharmony_ci return mls_range_set(newcontext, r); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (tclass && tclass <= p->p_classes.nprim) { 5158c2ecf20Sopenharmony_ci cladatum = p->class_val_to_struct[tclass - 1]; 5168c2ecf20Sopenharmony_ci if (cladatum) 5178c2ecf20Sopenharmony_ci default_range = cladatum->default_range; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci switch (default_range) { 5218c2ecf20Sopenharmony_ci case DEFAULT_SOURCE_LOW: 5228c2ecf20Sopenharmony_ci return mls_context_cpy_low(newcontext, scontext); 5238c2ecf20Sopenharmony_ci case DEFAULT_SOURCE_HIGH: 5248c2ecf20Sopenharmony_ci return mls_context_cpy_high(newcontext, scontext); 5258c2ecf20Sopenharmony_ci case DEFAULT_SOURCE_LOW_HIGH: 5268c2ecf20Sopenharmony_ci return mls_context_cpy(newcontext, scontext); 5278c2ecf20Sopenharmony_ci case DEFAULT_TARGET_LOW: 5288c2ecf20Sopenharmony_ci return mls_context_cpy_low(newcontext, tcontext); 5298c2ecf20Sopenharmony_ci case DEFAULT_TARGET_HIGH: 5308c2ecf20Sopenharmony_ci return mls_context_cpy_high(newcontext, tcontext); 5318c2ecf20Sopenharmony_ci case DEFAULT_TARGET_LOW_HIGH: 5328c2ecf20Sopenharmony_ci return mls_context_cpy(newcontext, tcontext); 5338c2ecf20Sopenharmony_ci case DEFAULT_GLBLUB: 5348c2ecf20Sopenharmony_ci return mls_context_glblub(newcontext, 5358c2ecf20Sopenharmony_ci scontext, tcontext); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci fallthrough; 5398c2ecf20Sopenharmony_ci case AVTAB_CHANGE: 5408c2ecf20Sopenharmony_ci if ((tclass == p->process_class) || sock) 5418c2ecf20Sopenharmony_ci /* Use the process MLS attributes. */ 5428c2ecf20Sopenharmony_ci return mls_context_cpy(newcontext, scontext); 5438c2ecf20Sopenharmony_ci else 5448c2ecf20Sopenharmony_ci /* Use the process effective MLS attributes. */ 5458c2ecf20Sopenharmony_ci return mls_context_cpy_low(newcontext, scontext); 5468c2ecf20Sopenharmony_ci case AVTAB_MEMBER: 5478c2ecf20Sopenharmony_ci /* Use the process effective MLS attributes. */ 5488c2ecf20Sopenharmony_ci return mls_context_cpy_low(newcontext, scontext); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci return -EINVAL; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci#ifdef CONFIG_NETLABEL 5548c2ecf20Sopenharmony_ci/** 5558c2ecf20Sopenharmony_ci * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel 5568c2ecf20Sopenharmony_ci * @context: the security context 5578c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * Description: 5608c2ecf20Sopenharmony_ci * Given the security context copy the low MLS sensitivity level into the 5618c2ecf20Sopenharmony_ci * NetLabel MLS sensitivity level field. 5628c2ecf20Sopenharmony_ci * 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_civoid mls_export_netlbl_lvl(struct policydb *p, 5658c2ecf20Sopenharmony_ci struct context *context, 5668c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci if (!p->mls_enabled) 5698c2ecf20Sopenharmony_ci return; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci secattr->attr.mls.lvl = context->range.level[0].sens - 1; 5728c2ecf20Sopenharmony_ci secattr->flags |= NETLBL_SECATTR_MLS_LVL; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/** 5768c2ecf20Sopenharmony_ci * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels 5778c2ecf20Sopenharmony_ci * @context: the security context 5788c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes 5798c2ecf20Sopenharmony_ci * 5808c2ecf20Sopenharmony_ci * Description: 5818c2ecf20Sopenharmony_ci * Given the security context and the NetLabel security attributes, copy the 5828c2ecf20Sopenharmony_ci * NetLabel MLS sensitivity level into the context. 5838c2ecf20Sopenharmony_ci * 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_civoid mls_import_netlbl_lvl(struct policydb *p, 5868c2ecf20Sopenharmony_ci struct context *context, 5878c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci if (!p->mls_enabled) 5908c2ecf20Sopenharmony_ci return; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci context->range.level[0].sens = secattr->attr.mls.lvl + 1; 5938c2ecf20Sopenharmony_ci context->range.level[1].sens = context->range.level[0].sens; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci/** 5978c2ecf20Sopenharmony_ci * mls_export_netlbl_cat - Export the MLS categories to NetLabel 5988c2ecf20Sopenharmony_ci * @context: the security context 5998c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes 6008c2ecf20Sopenharmony_ci * 6018c2ecf20Sopenharmony_ci * Description: 6028c2ecf20Sopenharmony_ci * Given the security context copy the low MLS categories into the NetLabel 6038c2ecf20Sopenharmony_ci * MLS category field. Returns zero on success, negative values on failure. 6048c2ecf20Sopenharmony_ci * 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ciint mls_export_netlbl_cat(struct policydb *p, 6078c2ecf20Sopenharmony_ci struct context *context, 6088c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci int rc; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (!p->mls_enabled) 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci rc = ebitmap_netlbl_export(&context->range.level[0].cat, 6168c2ecf20Sopenharmony_ci &secattr->attr.mls.cat); 6178c2ecf20Sopenharmony_ci if (rc == 0 && secattr->attr.mls.cat != NULL) 6188c2ecf20Sopenharmony_ci secattr->flags |= NETLBL_SECATTR_MLS_CAT; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return rc; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/** 6248c2ecf20Sopenharmony_ci * mls_import_netlbl_cat - Import the MLS categories from NetLabel 6258c2ecf20Sopenharmony_ci * @context: the security context 6268c2ecf20Sopenharmony_ci * @secattr: the NetLabel security attributes 6278c2ecf20Sopenharmony_ci * 6288c2ecf20Sopenharmony_ci * Description: 6298c2ecf20Sopenharmony_ci * Copy the NetLabel security attributes into the SELinux context; since the 6308c2ecf20Sopenharmony_ci * NetLabel security attribute only contains a single MLS category use it for 6318c2ecf20Sopenharmony_ci * both the low and high categories of the context. Returns zero on success, 6328c2ecf20Sopenharmony_ci * negative values on failure. 6338c2ecf20Sopenharmony_ci * 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ciint mls_import_netlbl_cat(struct policydb *p, 6368c2ecf20Sopenharmony_ci struct context *context, 6378c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci int rc; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!p->mls_enabled) 6428c2ecf20Sopenharmony_ci return 0; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci rc = ebitmap_netlbl_import(&context->range.level[0].cat, 6458c2ecf20Sopenharmony_ci secattr->attr.mls.cat); 6468c2ecf20Sopenharmony_ci if (rc) 6478c2ecf20Sopenharmony_ci goto import_netlbl_cat_failure; 6488c2ecf20Sopenharmony_ci memcpy(&context->range.level[1].cat, &context->range.level[0].cat, 6498c2ecf20Sopenharmony_ci sizeof(context->range.level[0].cat)); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci return 0; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ciimport_netlbl_cat_failure: 6548c2ecf20Sopenharmony_ci ebitmap_destroy(&context->range.level[0].cat); 6558c2ecf20Sopenharmony_ci return rc; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci#endif /* CONFIG_NETLABEL */ 658