1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Implementation of the multi-level security (MLS) policy.
41da177e4SLinus Torvalds *
50fe53224SStephen Smalley * Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
61da177e4SLinus Torvalds */
7*4afec360SPaul Moore
81da177e4SLinus Torvalds /*
91da177e4SLinus Torvalds * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
101da177e4SLinus Torvalds * Support for enhanced MLS infrastructure.
11376bd9cbSDarrel Goeddel * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12*4afec360SPaul Moore *
1382c21bfaSPaul Moore * Updated: Hewlett-Packard <paul@paul-moore.com>
1402752760SPaul Moore * Added support to import/export the MLS label from NetLabel
15*4afec360SPaul Moore * Copyright (C) Hewlett-Packard Development Company, L.P., 2006
167420ed23SVenkat Yekkirala */
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #include <linux/kernel.h>
191da177e4SLinus Torvalds #include <linux/slab.h>
201da177e4SLinus Torvalds #include <linux/string.h>
211da177e4SLinus Torvalds #include <linux/errno.h>
2202752760SPaul Moore #include <net/netlabel.h>
23f5c1d5b2SJames Morris #include "sidtab.h"
241da177e4SLinus Torvalds #include "mls.h"
251da177e4SLinus Torvalds #include "policydb.h"
261da177e4SLinus Torvalds #include "services.h"
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds /*
291da177e4SLinus Torvalds * Return the length in bytes for the MLS fields of the
301da177e4SLinus Torvalds * security context string representation of `context'.
311da177e4SLinus Torvalds */
mls_compute_context_len(struct policydb * p,struct context * context)32aa8e712cSStephen Smalley int mls_compute_context_len(struct policydb *p, struct context *context)
331da177e4SLinus Torvalds {
349fe79ad1SKaiGai Kohei int i, l, len, head, prev;
359fe79ad1SKaiGai Kohei char *nm;
369fe79ad1SKaiGai Kohei struct ebitmap *e;
37782ebb99SStephen Smalley struct ebitmap_node *node;
381da177e4SLinus Torvalds
39aa8e712cSStephen Smalley if (!p->mls_enabled)
401da177e4SLinus Torvalds return 0;
411da177e4SLinus Torvalds
421da177e4SLinus Torvalds len = 1; /* for the beginning ":" */
431da177e4SLinus Torvalds for (l = 0; l < 2; l++) {
44fd5a90ffSChristian Göttsche u32 index_sens = context->range.level[l].sens;
45aa8e712cSStephen Smalley len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
461da177e4SLinus Torvalds
479fe79ad1SKaiGai Kohei /* categories */
489fe79ad1SKaiGai Kohei head = -2;
499fe79ad1SKaiGai Kohei prev = -2;
509fe79ad1SKaiGai Kohei e = &context->range.level[l].cat;
51*4afec360SPaul Moore ebitmap_for_each_positive_bit(e, node, i)
52*4afec360SPaul Moore {
539fe79ad1SKaiGai Kohei if (i - prev > 1) {
549fe79ad1SKaiGai Kohei /* one or more negative bits are skipped */
559fe79ad1SKaiGai Kohei if (head != prev) {
56aa8e712cSStephen Smalley nm = sym_name(p, SYM_CATS, prev);
579fe79ad1SKaiGai Kohei len += strlen(nm) + 1;
581da177e4SLinus Torvalds }
59aa8e712cSStephen Smalley nm = sym_name(p, SYM_CATS, i);
609fe79ad1SKaiGai Kohei len += strlen(nm) + 1;
619fe79ad1SKaiGai Kohei head = i;
621da177e4SLinus Torvalds }
639fe79ad1SKaiGai Kohei prev = i;
641da177e4SLinus Torvalds }
659fe79ad1SKaiGai Kohei if (prev != head) {
66aa8e712cSStephen Smalley nm = sym_name(p, SYM_CATS, prev);
679fe79ad1SKaiGai Kohei len += strlen(nm) + 1;
689fe79ad1SKaiGai Kohei }
691da177e4SLinus Torvalds if (l == 0) {
701da177e4SLinus Torvalds if (mls_level_eq(&context->range.level[0],
711da177e4SLinus Torvalds &context->range.level[1]))
721da177e4SLinus Torvalds break;
731da177e4SLinus Torvalds else
741da177e4SLinus Torvalds len++;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds return len;
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds
811da177e4SLinus Torvalds /*
821da177e4SLinus Torvalds * Write the security context string representation of
831da177e4SLinus Torvalds * the MLS fields of `context' into the string `*scontext'.
841da177e4SLinus Torvalds * Update `*scontext' to point to the end of the MLS fields.
851da177e4SLinus Torvalds */
mls_sid_to_context(struct policydb * p,struct context * context,char ** scontext)86*4afec360SPaul Moore void mls_sid_to_context(struct policydb *p, struct context *context,
871da177e4SLinus Torvalds char **scontext)
881da177e4SLinus Torvalds {
899fe79ad1SKaiGai Kohei char *scontextp, *nm;
909fe79ad1SKaiGai Kohei int i, l, head, prev;
919fe79ad1SKaiGai Kohei struct ebitmap *e;
92782ebb99SStephen Smalley struct ebitmap_node *node;
931da177e4SLinus Torvalds
94aa8e712cSStephen Smalley if (!p->mls_enabled)
951da177e4SLinus Torvalds return;
961da177e4SLinus Torvalds
971da177e4SLinus Torvalds scontextp = *scontext;
981da177e4SLinus Torvalds
991da177e4SLinus Torvalds *scontextp = ':';
1001da177e4SLinus Torvalds scontextp++;
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds for (l = 0; l < 2; l++) {
103aa8e712cSStephen Smalley strcpy(scontextp, sym_name(p, SYM_LEVELS,
104ac76c05bSEric Paris context->range.level[l].sens - 1));
1059fe79ad1SKaiGai Kohei scontextp += strlen(scontextp);
1061da177e4SLinus Torvalds
1071da177e4SLinus Torvalds /* categories */
1089fe79ad1SKaiGai Kohei head = -2;
1099fe79ad1SKaiGai Kohei prev = -2;
1109fe79ad1SKaiGai Kohei e = &context->range.level[l].cat;
111*4afec360SPaul Moore ebitmap_for_each_positive_bit(e, node, i)
112*4afec360SPaul Moore {
1139fe79ad1SKaiGai Kohei if (i - prev > 1) {
1149fe79ad1SKaiGai Kohei /* one or more negative bits are skipped */
1159fe79ad1SKaiGai Kohei if (prev != head) {
1169fe79ad1SKaiGai Kohei if (prev - head > 1)
1179fe79ad1SKaiGai Kohei *scontextp++ = '.';
1189fe79ad1SKaiGai Kohei else
1199fe79ad1SKaiGai Kohei *scontextp++ = ',';
120aa8e712cSStephen Smalley nm = sym_name(p, SYM_CATS, prev);
1219fe79ad1SKaiGai Kohei strcpy(scontextp, nm);
1229fe79ad1SKaiGai Kohei scontextp += strlen(nm);
1231da177e4SLinus Torvalds }
1249fe79ad1SKaiGai Kohei if (prev < 0)
1251da177e4SLinus Torvalds *scontextp++ = ':';
1269fe79ad1SKaiGai Kohei else
1271da177e4SLinus Torvalds *scontextp++ = ',';
128aa8e712cSStephen Smalley nm = sym_name(p, SYM_CATS, i);
1299fe79ad1SKaiGai Kohei strcpy(scontextp, nm);
1309fe79ad1SKaiGai Kohei scontextp += strlen(nm);
1319fe79ad1SKaiGai Kohei head = i;
1329fe79ad1SKaiGai Kohei }
1339fe79ad1SKaiGai Kohei prev = i;
1349fe79ad1SKaiGai Kohei }
1359fe79ad1SKaiGai Kohei
1369fe79ad1SKaiGai Kohei if (prev != head) {
1379fe79ad1SKaiGai Kohei if (prev - head > 1)
1381da177e4SLinus Torvalds *scontextp++ = '.';
1391da177e4SLinus Torvalds else
1401da177e4SLinus Torvalds *scontextp++ = ',';
141aa8e712cSStephen Smalley nm = sym_name(p, SYM_CATS, prev);
1429fe79ad1SKaiGai Kohei strcpy(scontextp, nm);
1439fe79ad1SKaiGai Kohei scontextp += strlen(nm);
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;
1509fe79ad1SKaiGai Kohei else
1519fe79ad1SKaiGai Kohei *scontextp++ = '-';
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds }
1541da177e4SLinus Torvalds
1551da177e4SLinus Torvalds *scontext = scontextp;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds
mls_level_isvalid(struct policydb * p,struct mls_level * l)15845e5421eSStephen Smalley int mls_level_isvalid(struct policydb *p, struct mls_level *l)
15945e5421eSStephen Smalley {
16045e5421eSStephen Smalley struct level_datum *levdatum;
16145e5421eSStephen Smalley
16245e5421eSStephen Smalley if (!l->sens || l->sens > p->p_levels.nprim)
16345e5421eSStephen Smalley return 0;
164237389e3SOndrej Mosnacek levdatum = symtab_search(&p->p_levels,
165ac76c05bSEric Paris sym_name(p, SYM_LEVELS, l->sens - 1));
16645e5421eSStephen Smalley if (!levdatum)
16745e5421eSStephen Smalley return 0;
16845e5421eSStephen Smalley
16945e5421eSStephen Smalley /*
170fee71142SWaiman Long * Return 1 iff all the bits set in l->cat are also be set in
171fee71142SWaiman Long * levdatum->level->cat and no bit in l->cat is larger than
172fee71142SWaiman Long * p->p_cats.nprim.
17345e5421eSStephen Smalley */
174fee71142SWaiman Long return ebitmap_contains(&levdatum->level->cat, &l->cat,
175fee71142SWaiman Long p->p_cats.nprim);
17645e5421eSStephen Smalley }
17745e5421eSStephen Smalley
mls_range_isvalid(struct policydb * p,struct mls_range * r)17845e5421eSStephen Smalley int mls_range_isvalid(struct policydb *p, struct mls_range *r)
17945e5421eSStephen Smalley {
18045e5421eSStephen Smalley return (mls_level_isvalid(p, &r->level[0]) &&
18145e5421eSStephen Smalley mls_level_isvalid(p, &r->level[1]) &&
18245e5421eSStephen Smalley mls_level_dom(&r->level[1], &r->level[0]));
18345e5421eSStephen Smalley }
18445e5421eSStephen Smalley
1851da177e4SLinus Torvalds /*
1861da177e4SLinus Torvalds * Return 1 if the MLS fields in the security context
1871da177e4SLinus Torvalds * structure `c' are valid. Return 0 otherwise.
1881da177e4SLinus Torvalds */
mls_context_isvalid(struct policydb * p,struct context * c)1891da177e4SLinus Torvalds int mls_context_isvalid(struct policydb *p, struct context *c)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds struct user_datum *usrdatum;
1921da177e4SLinus Torvalds
1930719aaf5SGuido Trentalancia if (!p->mls_enabled)
1941da177e4SLinus Torvalds return 1;
1951da177e4SLinus Torvalds
19645e5421eSStephen Smalley if (!mls_range_isvalid(p, &c->range))
1971da177e4SLinus Torvalds return 0;
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds if (c->role == OBJECT_R_VAL)
2001da177e4SLinus Torvalds return 1;
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds /*
2031da177e4SLinus Torvalds * User must be authorized for the MLS range.
2041da177e4SLinus Torvalds */
2051da177e4SLinus Torvalds if (!c->user || c->user > p->p_users.nprim)
2061da177e4SLinus Torvalds return 0;
2071da177e4SLinus Torvalds usrdatum = p->user_val_to_struct[c->user - 1];
2081da177e4SLinus Torvalds if (!mls_range_contains(usrdatum->range, c->range))
2091da177e4SLinus Torvalds return 0; /* user may not be associated with range */
2101da177e4SLinus Torvalds
2111da177e4SLinus Torvalds return 1;
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds
2141da177e4SLinus Torvalds /*
2151da177e4SLinus Torvalds * Set the MLS fields in the security context structure
2161da177e4SLinus Torvalds * `context' based on the string representation in
21795ffe194SJann Horn * the string `scontext'.
2181da177e4SLinus Torvalds *
2191da177e4SLinus Torvalds * This function modifies the string in place, inserting
2201da177e4SLinus Torvalds * NULL characters to terminate the MLS fields.
221f5c1d5b2SJames Morris *
222f5c1d5b2SJames Morris * If a def_sid is provided and no MLS field is present,
223f5c1d5b2SJames Morris * copy the MLS field of the associated default context.
224f5c1d5b2SJames Morris * Used for upgraded to MLS systems where objects may lack
225f5c1d5b2SJames Morris * MLS fields.
226f5c1d5b2SJames Morris *
227f5c1d5b2SJames Morris * Policy read-lock must be held for sidtab lookup.
228f5c1d5b2SJames Morris *
2291da177e4SLinus Torvalds */
mls_context_to_sid(struct policydb * pol,char oldc,char * scontext,struct context * context,struct sidtab * s,u32 def_sid)230*4afec360SPaul Moore int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext,
231*4afec360SPaul Moore struct context *context, struct sidtab *s, u32 def_sid)
2321da177e4SLinus Torvalds {
23395ffe194SJann Horn char *sensitivity, *cur_cat, *next_cat, *rngptr;
2341da177e4SLinus Torvalds struct level_datum *levdatum;
2351da177e4SLinus Torvalds struct cat_datum *catdatum, *rngdatum;
236fd5a90ffSChristian Göttsche u32 i;
237fd5a90ffSChristian Göttsche int l, rc;
23895ffe194SJann Horn char *rangep[2];
2391da177e4SLinus Torvalds
2400719aaf5SGuido Trentalancia if (!pol->mls_enabled) {
241877181a8SPaul Moore /*
242877181a8SPaul Moore * With no MLS, only return -EINVAL if there is a MLS field
243877181a8SPaul Moore * and it did not come from an xattr.
244877181a8SPaul Moore */
245877181a8SPaul Moore if (oldc && def_sid == SECSID_NULL)
24695ffe194SJann Horn return -EINVAL;
247877181a8SPaul Moore return 0;
248e517a0cdSStephen Smalley }
2491da177e4SLinus Torvalds
250f5c1d5b2SJames Morris /*
251f5c1d5b2SJames Morris * No MLS component to the security context, try and map to
252f5c1d5b2SJames Morris * default if provided.
253f5c1d5b2SJames Morris */
254f5c1d5b2SJames Morris if (!oldc) {
255f5c1d5b2SJames Morris struct context *defcon;
256f5c1d5b2SJames Morris
257f5c1d5b2SJames Morris if (def_sid == SECSID_NULL)
25895ffe194SJann Horn return -EINVAL;
2591da177e4SLinus Torvalds
260f5c1d5b2SJames Morris defcon = sidtab_search(s, def_sid);
261f5c1d5b2SJames Morris if (!defcon)
26295ffe194SJann Horn return -EINVAL;
263f5c1d5b2SJames Morris
26495ffe194SJann Horn return mls_context_cpy(context, defcon);
265f5c1d5b2SJames Morris }
266f5c1d5b2SJames Morris
26795ffe194SJann Horn /*
26895ffe194SJann Horn * If we're dealing with a range, figure out where the two parts
26995ffe194SJann Horn * of the range begin.
27095ffe194SJann Horn */
27195ffe194SJann Horn rangep[0] = scontext;
27295ffe194SJann Horn rangep[1] = strchr(scontext, '-');
27395ffe194SJann Horn if (rangep[1]) {
27495ffe194SJann Horn rangep[1][0] = '\0';
27595ffe194SJann Horn rangep[1]++;
27695ffe194SJann Horn }
2771da177e4SLinus Torvalds
27895ffe194SJann Horn /* For each part of the range: */
2791da177e4SLinus Torvalds for (l = 0; l < 2; l++) {
28095ffe194SJann Horn /* Split sensitivity and category set. */
28195ffe194SJann Horn sensitivity = rangep[l];
28295ffe194SJann Horn if (sensitivity == NULL)
28395ffe194SJann Horn break;
28495ffe194SJann Horn next_cat = strchr(sensitivity, ':');
28595ffe194SJann Horn if (next_cat)
28695ffe194SJann Horn *(next_cat++) = '\0';
2871da177e4SLinus Torvalds
28895ffe194SJann Horn /* Parse sensitivity. */
289237389e3SOndrej Mosnacek levdatum = symtab_search(&pol->p_levels, sensitivity);
29095ffe194SJann Horn if (!levdatum)
29195ffe194SJann Horn return -EINVAL;
2921da177e4SLinus Torvalds context->range.level[l].sens = levdatum->level->sens;
2931da177e4SLinus Torvalds
2941da177e4SLinus Torvalds /* Extract category set. */
29595ffe194SJann Horn while (next_cat != NULL) {
29695ffe194SJann Horn cur_cat = next_cat;
29795ffe194SJann Horn next_cat = strchr(next_cat, ',');
29895ffe194SJann Horn if (next_cat != NULL)
29995ffe194SJann Horn *(next_cat++) = '\0';
3001da177e4SLinus Torvalds
3011da177e4SLinus Torvalds /* Separate into range if exists */
30295ffe194SJann Horn rngptr = strchr(cur_cat, '.');
3031a5e6f87SEric Paris if (rngptr != NULL) {
3041da177e4SLinus Torvalds /* Remove '.' */
305df4ea865SVesa-Matti J Kari *rngptr++ = '\0';
3061da177e4SLinus Torvalds }
3071da177e4SLinus Torvalds
308237389e3SOndrej Mosnacek catdatum = symtab_search(&pol->p_cats, cur_cat);
30995ffe194SJann Horn if (!catdatum)
31095ffe194SJann Horn return -EINVAL;
3111da177e4SLinus Torvalds
3121da177e4SLinus Torvalds rc = ebitmap_set_bit(&context->range.level[l].cat,
3131da177e4SLinus Torvalds catdatum->value - 1, 1);
3141da177e4SLinus Torvalds if (rc)
31595ffe194SJann Horn return rc;
3161da177e4SLinus Torvalds
3171da177e4SLinus Torvalds /* If range, set all categories in range */
31895ffe194SJann Horn if (rngptr == NULL)
31995ffe194SJann Horn continue;
3201da177e4SLinus Torvalds
321237389e3SOndrej Mosnacek rngdatum = symtab_search(&pol->p_cats, rngptr);
32295ffe194SJann Horn if (!rngdatum)
32395ffe194SJann Horn return -EINVAL;
3241da177e4SLinus Torvalds
32595ffe194SJann Horn if (catdatum->value >= rngdatum->value)
32695ffe194SJann Horn return -EINVAL;
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds for (i = catdatum->value; i < rngdatum->value; i++) {
329*4afec360SPaul Moore rc = ebitmap_set_bit(
330*4afec360SPaul Moore &context->range.level[l].cat, i, 1);
3311da177e4SLinus Torvalds if (rc)
33295ffe194SJann Horn return rc;
33395ffe194SJann Horn }
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds }
3361da177e4SLinus Torvalds
33795ffe194SJann Horn /* If we didn't see a '-', the range start is also the range end. */
33895ffe194SJann Horn if (rangep[1] == NULL) {
3391da177e4SLinus Torvalds context->range.level[1].sens = context->range.level[0].sens;
3401da177e4SLinus Torvalds rc = ebitmap_cpy(&context->range.level[1].cat,
3411da177e4SLinus Torvalds &context->range.level[0].cat);
3421da177e4SLinus Torvalds if (rc)
3431da177e4SLinus Torvalds return rc;
3441da177e4SLinus Torvalds }
3451da177e4SLinus Torvalds
34695ffe194SJann Horn return 0;
34795ffe194SJann Horn }
34895ffe194SJann Horn
3491da177e4SLinus Torvalds /*
350376bd9cbSDarrel Goeddel * Set the MLS fields in the security context structure
351376bd9cbSDarrel Goeddel * `context' based on the string representation in
352376bd9cbSDarrel Goeddel * the string `str'. This function will allocate temporary memory with the
353376bd9cbSDarrel Goeddel * given constraints of gfp_mask.
354376bd9cbSDarrel Goeddel */
mls_from_string(struct policydb * p,char * str,struct context * context,gfp_t gfp_mask)355aa8e712cSStephen Smalley int mls_from_string(struct policydb *p, char *str, struct context *context,
356aa8e712cSStephen Smalley gfp_t gfp_mask)
357376bd9cbSDarrel Goeddel {
35895ffe194SJann Horn char *tmpstr;
359376bd9cbSDarrel Goeddel int rc;
360376bd9cbSDarrel Goeddel
361aa8e712cSStephen Smalley if (!p->mls_enabled)
362376bd9cbSDarrel Goeddel return -EINVAL;
363376bd9cbSDarrel Goeddel
36495ffe194SJann Horn tmpstr = kstrdup(str, gfp_mask);
365376bd9cbSDarrel Goeddel if (!tmpstr) {
366376bd9cbSDarrel Goeddel rc = -ENOMEM;
367376bd9cbSDarrel Goeddel } else {
368*4afec360SPaul Moore rc = mls_context_to_sid(p, ':', tmpstr, context, NULL,
369*4afec360SPaul Moore SECSID_NULL);
37095ffe194SJann Horn kfree(tmpstr);
371376bd9cbSDarrel Goeddel }
372376bd9cbSDarrel Goeddel
373376bd9cbSDarrel Goeddel return rc;
374376bd9cbSDarrel Goeddel }
375376bd9cbSDarrel Goeddel
376376bd9cbSDarrel Goeddel /*
3771da177e4SLinus Torvalds * Copies the MLS range `range' into `context'.
3781da177e4SLinus Torvalds */
mls_range_set(struct context * context,struct mls_range * range)379*4afec360SPaul Moore int mls_range_set(struct context *context, struct mls_range *range)
3801da177e4SLinus Torvalds {
3811da177e4SLinus Torvalds int l, rc = 0;
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds /* Copy the MLS range into the context */
3841da177e4SLinus Torvalds for (l = 0; l < 2; l++) {
3851da177e4SLinus Torvalds context->range.level[l].sens = range->level[l].sens;
3861da177e4SLinus Torvalds rc = ebitmap_cpy(&context->range.level[l].cat,
3871da177e4SLinus Torvalds &range->level[l].cat);
3881da177e4SLinus Torvalds if (rc)
3891da177e4SLinus Torvalds break;
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds return rc;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds
mls_setup_user_range(struct policydb * p,struct context * fromcon,struct user_datum * user,struct context * usercon)395*4afec360SPaul Moore int mls_setup_user_range(struct policydb *p, struct context *fromcon,
396*4afec360SPaul Moore struct user_datum *user, struct context *usercon)
3971da177e4SLinus Torvalds {
398aa8e712cSStephen Smalley if (p->mls_enabled) {
3991da177e4SLinus Torvalds struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
4001da177e4SLinus Torvalds struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
4011da177e4SLinus Torvalds struct mls_level *user_low = &(user->range.level[0]);
4021da177e4SLinus Torvalds struct mls_level *user_clr = &(user->range.level[1]);
4031da177e4SLinus Torvalds struct mls_level *user_def = &(user->dfltlevel);
4041da177e4SLinus Torvalds struct mls_level *usercon_sen = &(usercon->range.level[0]);
4051da177e4SLinus Torvalds struct mls_level *usercon_clr = &(usercon->range.level[1]);
4061da177e4SLinus Torvalds
4071da177e4SLinus Torvalds /* Honor the user's default level if we can */
408f5269710SEric Paris if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
4091da177e4SLinus Torvalds *usercon_sen = *user_def;
410f5269710SEric Paris else if (mls_level_between(fromcon_sen, user_def, user_clr))
4111da177e4SLinus Torvalds *usercon_sen = *fromcon_sen;
412f5269710SEric Paris else if (mls_level_between(fromcon_clr, user_low, user_def))
4131da177e4SLinus Torvalds *usercon_sen = *user_low;
414f5269710SEric Paris else
4151da177e4SLinus Torvalds return -EINVAL;
4161da177e4SLinus Torvalds
4171da177e4SLinus Torvalds /* Lower the clearance of available contexts
4181da177e4SLinus Torvalds if the clearance of "fromcon" is lower than
4191da177e4SLinus Torvalds that of the user's default clearance (but
4201da177e4SLinus Torvalds only if the "fromcon" clearance dominates
4211da177e4SLinus Torvalds the user's computed sensitivity level) */
4221a5e6f87SEric Paris if (mls_level_dom(user_clr, fromcon_clr))
4231da177e4SLinus Torvalds *usercon_clr = *fromcon_clr;
4241a5e6f87SEric Paris else if (mls_level_dom(fromcon_clr, user_clr))
4251da177e4SLinus Torvalds *usercon_clr = *user_clr;
4261a5e6f87SEric Paris else
4271da177e4SLinus Torvalds return -EINVAL;
4281da177e4SLinus Torvalds }
4291da177e4SLinus Torvalds
4301da177e4SLinus Torvalds return 0;
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds
4331da177e4SLinus Torvalds /*
4341da177e4SLinus Torvalds * Convert the MLS fields in the security context
435ee1a84fdSOndrej Mosnacek * structure `oldc' from the values specified in the
436ee1a84fdSOndrej Mosnacek * policy `oldp' to the values specified in the policy `newp',
437ee1a84fdSOndrej Mosnacek * storing the resulting context in `newc'.
4381da177e4SLinus Torvalds */
mls_convert_context(struct policydb * oldp,struct policydb * newp,struct context * oldc,struct context * newc)439*4afec360SPaul Moore int mls_convert_context(struct policydb *oldp, struct policydb *newp,
440*4afec360SPaul Moore struct context *oldc, struct context *newc)
4411da177e4SLinus Torvalds {
4421da177e4SLinus Torvalds struct level_datum *levdatum;
4431da177e4SLinus Torvalds struct cat_datum *catdatum;
444782ebb99SStephen Smalley struct ebitmap_node *node;
445fd5a90ffSChristian Göttsche u32 i;
446fd5a90ffSChristian Göttsche int l;
4471da177e4SLinus Torvalds
448aa8e712cSStephen Smalley if (!oldp->mls_enabled || !newp->mls_enabled)
4491da177e4SLinus Torvalds return 0;
4501da177e4SLinus Torvalds
4511da177e4SLinus Torvalds for (l = 0; l < 2; l++) {
452237389e3SOndrej Mosnacek char *name = sym_name(oldp, SYM_LEVELS,
453237389e3SOndrej Mosnacek oldc->range.level[l].sens - 1);
454237389e3SOndrej Mosnacek
455237389e3SOndrej Mosnacek levdatum = symtab_search(&newp->p_levels, name);
4561da177e4SLinus Torvalds
4571da177e4SLinus Torvalds if (!levdatum)
4581da177e4SLinus Torvalds return -EINVAL;
459ee1a84fdSOndrej Mosnacek newc->range.level[l].sens = levdatum->level->sens;
4601da177e4SLinus Torvalds
461*4afec360SPaul Moore ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node,
462*4afec360SPaul Moore i)
463*4afec360SPaul Moore {
4641da177e4SLinus Torvalds int rc;
4651da177e4SLinus Torvalds
466237389e3SOndrej Mosnacek catdatum = symtab_search(&newp->p_cats,
467ac76c05bSEric Paris sym_name(oldp, SYM_CATS, i));
4681da177e4SLinus Torvalds if (!catdatum)
4691da177e4SLinus Torvalds return -EINVAL;
470ee1a84fdSOndrej Mosnacek rc = ebitmap_set_bit(&newc->range.level[l].cat,
471ee1a84fdSOndrej Mosnacek catdatum->value - 1, 1);
4721da177e4SLinus Torvalds if (rc)
4731da177e4SLinus Torvalds return rc;
4741da177e4SLinus Torvalds }
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds
4771da177e4SLinus Torvalds return 0;
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds
mls_compute_sid(struct policydb * p,struct context * scontext,struct context * tcontext,u16 tclass,u32 specified,struct context * newcontext,bool sock)480*4afec360SPaul Moore int mls_compute_sid(struct policydb *p, struct context *scontext,
481*4afec360SPaul Moore struct context *tcontext, u16 tclass, u32 specified,
482*4afec360SPaul Moore struct context *newcontext, bool sock)
4831da177e4SLinus Torvalds {
4842f3e82d6SStephen Smalley struct range_trans rtr;
4852f3e82d6SStephen Smalley struct mls_range *r;
486aa893269SEric Paris struct class_datum *cladatum;
487fd5a90ffSChristian Göttsche char default_range = 0;
488f3f87714SDarrel Goeddel
489aa8e712cSStephen Smalley if (!p->mls_enabled)
4901da177e4SLinus Torvalds return 0;
4911da177e4SLinus Torvalds
4921da177e4SLinus Torvalds switch (specified) {
4931da177e4SLinus Torvalds case AVTAB_TRANSITION:
4941da177e4SLinus Torvalds /* Look for a range transition rule. */
4952f3e82d6SStephen Smalley rtr.source_type = scontext->type;
4962f3e82d6SStephen Smalley rtr.target_type = tcontext->type;
4972f3e82d6SStephen Smalley rtr.target_class = tclass;
49824def7bbSOndrej Mosnacek r = policydb_rangetr_search(p, &rtr);
4992f3e82d6SStephen Smalley if (r)
5002f3e82d6SStephen Smalley return mls_range_set(newcontext, r);
501aa893269SEric Paris
502aa8e712cSStephen Smalley if (tclass && tclass <= p->p_classes.nprim) {
503aa8e712cSStephen Smalley cladatum = p->class_val_to_struct[tclass - 1];
504aa893269SEric Paris if (cladatum)
505aa893269SEric Paris default_range = cladatum->default_range;
506aa893269SEric Paris }
507aa893269SEric Paris
508aa893269SEric Paris switch (default_range) {
509aa893269SEric Paris case DEFAULT_SOURCE_LOW:
510aa893269SEric Paris return mls_context_cpy_low(newcontext, scontext);
511aa893269SEric Paris case DEFAULT_SOURCE_HIGH:
512aa893269SEric Paris return mls_context_cpy_high(newcontext, scontext);
513aa893269SEric Paris case DEFAULT_SOURCE_LOW_HIGH:
514aa893269SEric Paris return mls_context_cpy(newcontext, scontext);
515aa893269SEric Paris case DEFAULT_TARGET_LOW:
516aa893269SEric Paris return mls_context_cpy_low(newcontext, tcontext);
517aa893269SEric Paris case DEFAULT_TARGET_HIGH:
518aa893269SEric Paris return mls_context_cpy_high(newcontext, tcontext);
519aa893269SEric Paris case DEFAULT_TARGET_LOW_HIGH:
520aa893269SEric Paris return mls_context_cpy(newcontext, tcontext);
52142345b68SJoshua Brindle case DEFAULT_GLBLUB:
522*4afec360SPaul Moore return mls_context_glblub(newcontext, scontext,
523*4afec360SPaul Moore tcontext);
524aa893269SEric Paris }
525aa893269SEric Paris
526df561f66SGustavo A. R. Silva fallthrough;
5271da177e4SLinus Torvalds case AVTAB_CHANGE:
5284b850396SZou Wei if ((tclass == p->process_class) || sock)
5291da177e4SLinus Torvalds /* Use the process MLS attributes. */
5300efc61eaSVenkat Yekkirala return mls_context_cpy(newcontext, scontext);
5311da177e4SLinus Torvalds else
5321da177e4SLinus Torvalds /* Use the process effective MLS attributes. */
5330efc61eaSVenkat Yekkirala return mls_context_cpy_low(newcontext, scontext);
5341da177e4SLinus Torvalds case AVTAB_MEMBER:
5351da177e4SLinus Torvalds /* Use the process effective MLS attributes. */
5360efc61eaSVenkat Yekkirala return mls_context_cpy_low(newcontext, scontext);
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds return -EINVAL;
5391da177e4SLinus Torvalds }
5401da177e4SLinus Torvalds
54102752760SPaul Moore #ifdef CONFIG_NETLABEL
5427420ed23SVenkat Yekkirala /**
54302752760SPaul Moore * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
544e9fd7292SPaul Moore * @p: the policy
5457420ed23SVenkat Yekkirala * @context: the security context
54602752760SPaul Moore * @secattr: the NetLabel security attributes
5477420ed23SVenkat Yekkirala *
5487420ed23SVenkat Yekkirala * Description:
54902752760SPaul Moore * Given the security context copy the low MLS sensitivity level into the
55002752760SPaul Moore * NetLabel MLS sensitivity level field.
5517420ed23SVenkat Yekkirala *
5527420ed23SVenkat Yekkirala */
mls_export_netlbl_lvl(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)553*4afec360SPaul Moore void mls_export_netlbl_lvl(struct policydb *p, struct context *context,
55402752760SPaul Moore struct netlbl_lsm_secattr *secattr)
5557420ed23SVenkat Yekkirala {
556aa8e712cSStephen Smalley if (!p->mls_enabled)
5577420ed23SVenkat Yekkirala return;
5587420ed23SVenkat Yekkirala
55916efd454SPaul Moore secattr->attr.mls.lvl = context->range.level[0].sens - 1;
56002752760SPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_LVL;
5617420ed23SVenkat Yekkirala }
5627420ed23SVenkat Yekkirala
5637420ed23SVenkat Yekkirala /**
56402752760SPaul Moore * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
565e9fd7292SPaul Moore * @p: the policy
5667420ed23SVenkat Yekkirala * @context: the security context
56702752760SPaul Moore * @secattr: the NetLabel security attributes
5687420ed23SVenkat Yekkirala *
5697420ed23SVenkat Yekkirala * Description:
57002752760SPaul Moore * Given the security context and the NetLabel security attributes, copy the
57102752760SPaul Moore * NetLabel MLS sensitivity level into the context.
5727420ed23SVenkat Yekkirala *
5737420ed23SVenkat Yekkirala */
mls_import_netlbl_lvl(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)574*4afec360SPaul Moore void mls_import_netlbl_lvl(struct policydb *p, struct context *context,
57502752760SPaul Moore struct netlbl_lsm_secattr *secattr)
5767420ed23SVenkat Yekkirala {
577aa8e712cSStephen Smalley if (!p->mls_enabled)
5787420ed23SVenkat Yekkirala return;
5797420ed23SVenkat Yekkirala
58016efd454SPaul Moore context->range.level[0].sens = secattr->attr.mls.lvl + 1;
58102752760SPaul Moore context->range.level[1].sens = context->range.level[0].sens;
5827420ed23SVenkat Yekkirala }
5837420ed23SVenkat Yekkirala
5847420ed23SVenkat Yekkirala /**
58502752760SPaul Moore * mls_export_netlbl_cat - Export the MLS categories to NetLabel
586e9fd7292SPaul Moore * @p: the policy
5877420ed23SVenkat Yekkirala * @context: the security context
58802752760SPaul Moore * @secattr: the NetLabel security attributes
5897420ed23SVenkat Yekkirala *
5907420ed23SVenkat Yekkirala * Description:
59102752760SPaul Moore * Given the security context copy the low MLS categories into the NetLabel
59202752760SPaul Moore * MLS category field. Returns zero on success, negative values on failure.
5937420ed23SVenkat Yekkirala *
5947420ed23SVenkat Yekkirala */
mls_export_netlbl_cat(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)595*4afec360SPaul Moore int mls_export_netlbl_cat(struct policydb *p, struct context *context,
59602752760SPaul Moore struct netlbl_lsm_secattr *secattr)
5977420ed23SVenkat Yekkirala {
59802752760SPaul Moore int rc;
5997420ed23SVenkat Yekkirala
600aa8e712cSStephen Smalley if (!p->mls_enabled)
6017420ed23SVenkat Yekkirala return 0;
6027420ed23SVenkat Yekkirala
60302752760SPaul Moore rc = ebitmap_netlbl_export(&context->range.level[0].cat,
60416efd454SPaul Moore &secattr->attr.mls.cat);
60516efd454SPaul Moore if (rc == 0 && secattr->attr.mls.cat != NULL)
60602752760SPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_CAT;
60702752760SPaul Moore
6087420ed23SVenkat Yekkirala return rc;
6097420ed23SVenkat Yekkirala }
6107420ed23SVenkat Yekkirala
6117420ed23SVenkat Yekkirala /**
61202752760SPaul Moore * mls_import_netlbl_cat - Import the MLS categories from NetLabel
613e9fd7292SPaul Moore * @p: the policy
6147420ed23SVenkat Yekkirala * @context: the security context
61502752760SPaul Moore * @secattr: the NetLabel security attributes
6167420ed23SVenkat Yekkirala *
6177420ed23SVenkat Yekkirala * Description:
61802752760SPaul Moore * Copy the NetLabel security attributes into the SELinux context; since the
61902752760SPaul Moore * NetLabel security attribute only contains a single MLS category use it for
62002752760SPaul Moore * both the low and high categories of the context. Returns zero on success,
62102752760SPaul Moore * negative values on failure.
6227420ed23SVenkat Yekkirala *
6237420ed23SVenkat Yekkirala */
mls_import_netlbl_cat(struct policydb * p,struct context * context,struct netlbl_lsm_secattr * secattr)624*4afec360SPaul Moore int mls_import_netlbl_cat(struct policydb *p, struct context *context,
62502752760SPaul Moore struct netlbl_lsm_secattr *secattr)
6267420ed23SVenkat Yekkirala {
62702752760SPaul Moore int rc;
6287420ed23SVenkat Yekkirala
629aa8e712cSStephen Smalley if (!p->mls_enabled)
6307420ed23SVenkat Yekkirala return 0;
6317420ed23SVenkat Yekkirala
63202752760SPaul Moore rc = ebitmap_netlbl_import(&context->range.level[0].cat,
63316efd454SPaul Moore secattr->attr.mls.cat);
634da8026faSPaul Moore if (rc)
63502752760SPaul Moore goto import_netlbl_cat_failure;
636da8026faSPaul Moore memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
637da8026faSPaul Moore sizeof(context->range.level[0].cat));
6387420ed23SVenkat Yekkirala
6397420ed23SVenkat Yekkirala return 0;
6407420ed23SVenkat Yekkirala
64102752760SPaul Moore import_netlbl_cat_failure:
6427420ed23SVenkat Yekkirala ebitmap_destroy(&context->range.level[0].cat);
6437420ed23SVenkat Yekkirala return rc;
6447420ed23SVenkat Yekkirala }
64502752760SPaul Moore #endif /* CONFIG_NETLABEL */
646