| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* | 
|---|
| 3 | * Implementation of the multi-level security (MLS) policy. | 
|---|
| 4 | * | 
|---|
| 5 | * Author : Stephen Smalley, <stephen.smalley.work@gmail.com> | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | /* | 
|---|
| 9 | * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> | 
|---|
| 10 | *          Support for enhanced MLS infrastructure. | 
|---|
| 11 | *          Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 
|---|
| 12 | * | 
|---|
| 13 | * Updated: Hewlett-Packard <paul@paul-moore.com> | 
|---|
| 14 | *          Added support to import/export the MLS label from NetLabel | 
|---|
| 15 | *          Copyright (C) Hewlett-Packard Development Company, L.P., 2006 | 
|---|
| 16 | */ | 
|---|
| 17 |  | 
|---|
| 18 | #include <linux/kernel.h> | 
|---|
| 19 | #include <linux/slab.h> | 
|---|
| 20 | #include <linux/string.h> | 
|---|
| 21 | #include <linux/errno.h> | 
|---|
| 22 | #include <net/netlabel.h> | 
|---|
| 23 | #include "sidtab.h" | 
|---|
| 24 | #include "mls.h" | 
|---|
| 25 | #include "policydb.h" | 
|---|
| 26 | #include "services.h" | 
|---|
| 27 |  | 
|---|
| 28 | /* | 
|---|
| 29 | * Return the length in bytes for the MLS fields of the | 
|---|
| 30 | * security context string representation of `context'. | 
|---|
| 31 | */ | 
|---|
| 32 | int mls_compute_context_len(struct policydb *p, struct context *context) | 
|---|
| 33 | { | 
|---|
| 34 | int i, l, len, head, prev; | 
|---|
| 35 | char *nm; | 
|---|
| 36 | struct ebitmap *e; | 
|---|
| 37 | struct ebitmap_node *node; | 
|---|
| 38 |  | 
|---|
| 39 | if (!p->mls_enabled) | 
|---|
| 40 | return 0; | 
|---|
| 41 |  | 
|---|
| 42 | len = 1; /* for the beginning ":" */ | 
|---|
| 43 | for (l = 0; l < 2; l++) { | 
|---|
| 44 | u32 index_sens = context->range.level[l].sens; | 
|---|
| 45 | len += strlen(sym_name(p, SYM_LEVELS, element_nr: index_sens - 1)); | 
|---|
| 46 |  | 
|---|
| 47 | /* categories */ | 
|---|
| 48 | head = -2; | 
|---|
| 49 | prev = -2; | 
|---|
| 50 | e = &context->range.level[l].cat; | 
|---|
| 51 | ebitmap_for_each_positive_bit(e, node, i) | 
|---|
| 52 | { | 
|---|
| 53 | if (i - prev > 1) { | 
|---|
| 54 | /* one or more negative bits are skipped */ | 
|---|
| 55 | if (head != prev) { | 
|---|
| 56 | nm = sym_name(p, SYM_CATS, element_nr: prev); | 
|---|
| 57 | len += strlen(nm) + 1; | 
|---|
| 58 | } | 
|---|
| 59 | nm = sym_name(p, SYM_CATS, element_nr: i); | 
|---|
| 60 | len += strlen(nm) + 1; | 
|---|
| 61 | head = i; | 
|---|
| 62 | } | 
|---|
| 63 | prev = i; | 
|---|
| 64 | } | 
|---|
| 65 | if (prev != head) { | 
|---|
| 66 | nm = sym_name(p, SYM_CATS, element_nr: prev); | 
|---|
| 67 | len += strlen(nm) + 1; | 
|---|
| 68 | } | 
|---|
| 69 | if (l == 0) { | 
|---|
| 70 | if (mls_level_eq(l1: &context->range.level[0], | 
|---|
| 71 | l2: &context->range.level[1])) | 
|---|
| 72 | break; | 
|---|
| 73 | else | 
|---|
| 74 | len++; | 
|---|
| 75 | } | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 | return len; | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | /* | 
|---|
| 82 | * Write the security context string representation of | 
|---|
| 83 | * the MLS fields of `context' into the string `*scontext'. | 
|---|
| 84 | * Update `*scontext' to point to the end of the MLS fields. | 
|---|
| 85 | */ | 
|---|
| 86 | void mls_sid_to_context(struct policydb *p, struct context *context, | 
|---|
| 87 | char **scontext) | 
|---|
| 88 | { | 
|---|
| 89 | char *scontextp, *nm; | 
|---|
| 90 | int i, l, head, prev; | 
|---|
| 91 | struct ebitmap *e; | 
|---|
| 92 | struct ebitmap_node *node; | 
|---|
| 93 |  | 
|---|
| 94 | if (!p->mls_enabled) | 
|---|
| 95 | return; | 
|---|
| 96 |  | 
|---|
| 97 | scontextp = *scontext; | 
|---|
| 98 |  | 
|---|
| 99 | *scontextp = ':'; | 
|---|
| 100 | scontextp++; | 
|---|
| 101 |  | 
|---|
| 102 | for (l = 0; l < 2; l++) { | 
|---|
| 103 | strcpy(scontextp, sym_name(p, SYM_LEVELS, | 
|---|
| 104 | element_nr: context->range.level[l].sens - 1)); | 
|---|
| 105 | scontextp += strlen(scontextp); | 
|---|
| 106 |  | 
|---|
| 107 | /* categories */ | 
|---|
| 108 | head = -2; | 
|---|
| 109 | prev = -2; | 
|---|
| 110 | e = &context->range.level[l].cat; | 
|---|
| 111 | ebitmap_for_each_positive_bit(e, node, i) | 
|---|
| 112 | { | 
|---|
| 113 | if (i - prev > 1) { | 
|---|
| 114 | /* one or more negative bits are skipped */ | 
|---|
| 115 | if (prev != head) { | 
|---|
| 116 | if (prev - head > 1) | 
|---|
| 117 | *scontextp++ = '.'; | 
|---|
| 118 | else | 
|---|
| 119 | *scontextp++ = ','; | 
|---|
| 120 | nm = sym_name(p, SYM_CATS, element_nr: prev); | 
|---|
| 121 | strcpy(scontextp, nm); | 
|---|
| 122 | scontextp += strlen(nm); | 
|---|
| 123 | } | 
|---|
| 124 | if (prev < 0) | 
|---|
| 125 | *scontextp++ = ':'; | 
|---|
| 126 | else | 
|---|
| 127 | *scontextp++ = ','; | 
|---|
| 128 | nm = sym_name(p, SYM_CATS, element_nr: i); | 
|---|
| 129 | strcpy(scontextp, nm); | 
|---|
| 130 | scontextp += strlen(nm); | 
|---|
| 131 | head = i; | 
|---|
| 132 | } | 
|---|
| 133 | prev = i; | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | if (prev != head) { | 
|---|
| 137 | if (prev - head > 1) | 
|---|
| 138 | *scontextp++ = '.'; | 
|---|
| 139 | else | 
|---|
| 140 | *scontextp++ = ','; | 
|---|
| 141 | nm = sym_name(p, SYM_CATS, element_nr: prev); | 
|---|
| 142 | strcpy(scontextp, nm); | 
|---|
| 143 | scontextp += strlen(nm); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | if (l == 0) { | 
|---|
| 147 | if (mls_level_eq(l1: &context->range.level[0], | 
|---|
| 148 | l2: &context->range.level[1])) | 
|---|
| 149 | break; | 
|---|
| 150 | else | 
|---|
| 151 | *scontextp++ = '-'; | 
|---|
| 152 | } | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|
| 155 | *scontext = scontextp; | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | int mls_level_isvalid(struct policydb *p, struct mls_level *l) | 
|---|
| 159 | { | 
|---|
| 160 | struct level_datum *levdatum; | 
|---|
| 161 |  | 
|---|
| 162 | if (!l->sens || l->sens > p->p_levels.nprim) | 
|---|
| 163 | return 0; | 
|---|
| 164 | levdatum = symtab_search(s: &p->p_levels, | 
|---|
| 165 | name: sym_name(p, SYM_LEVELS, element_nr: l->sens - 1)); | 
|---|
| 166 | if (!levdatum) | 
|---|
| 167 | return 0; | 
|---|
| 168 |  | 
|---|
| 169 | /* | 
|---|
| 170 | * Return 1 iff all the bits set in l->cat are also be set in | 
|---|
| 171 | * levdatum->level->cat and no bit in l->cat is larger than | 
|---|
| 172 | * p->p_cats.nprim. | 
|---|
| 173 | */ | 
|---|
| 174 | return ebitmap_contains(e1: &levdatum->level.cat, e2: &l->cat, | 
|---|
| 175 | last_e2bit: p->p_cats.nprim); | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | int mls_range_isvalid(struct policydb *p, struct mls_range *r) | 
|---|
| 179 | { | 
|---|
| 180 | return (mls_level_isvalid(p, l: &r->level[0]) && | 
|---|
| 181 | mls_level_isvalid(p, l: &r->level[1]) && | 
|---|
| 182 | mls_level_dom(l1: &r->level[1], l2: &r->level[0])); | 
|---|
| 183 | } | 
|---|
| 184 |  | 
|---|
| 185 | /* | 
|---|
| 186 | * Return 1 if the MLS fields in the security context | 
|---|
| 187 | * structure `c' are valid.  Return 0 otherwise. | 
|---|
| 188 | */ | 
|---|
| 189 | int mls_context_isvalid(struct policydb *p, struct context *c) | 
|---|
| 190 | { | 
|---|
| 191 | struct user_datum *usrdatum; | 
|---|
| 192 |  | 
|---|
| 193 | if (!p->mls_enabled) | 
|---|
| 194 | return 1; | 
|---|
| 195 |  | 
|---|
| 196 | if (!mls_range_isvalid(p, r: &c->range)) | 
|---|
| 197 | return 0; | 
|---|
| 198 |  | 
|---|
| 199 | if (c->role == OBJECT_R_VAL) | 
|---|
| 200 | return 1; | 
|---|
| 201 |  | 
|---|
| 202 | /* | 
|---|
| 203 | * User must be authorized for the MLS range. | 
|---|
| 204 | */ | 
|---|
| 205 | if (!c->user || c->user > p->p_users.nprim) | 
|---|
| 206 | return 0; | 
|---|
| 207 | usrdatum = p->user_val_to_struct[c->user - 1]; | 
|---|
| 208 | if (!mls_range_contains(usrdatum->range, c->range)) | 
|---|
| 209 | return 0; /* user may not be associated with range */ | 
|---|
| 210 |  | 
|---|
| 211 | return 1; | 
|---|
| 212 | } | 
|---|
| 213 |  | 
|---|
| 214 | /* | 
|---|
| 215 | * Set the MLS fields in the security context structure | 
|---|
| 216 | * `context' based on the string representation in | 
|---|
| 217 | * the string `scontext'. | 
|---|
| 218 | * | 
|---|
| 219 | * This function modifies the string in place, inserting | 
|---|
| 220 | * NULL characters to terminate the MLS fields. | 
|---|
| 221 | * | 
|---|
| 222 | * If a def_sid is provided and no MLS field is present, | 
|---|
| 223 | * copy the MLS field of the associated default context. | 
|---|
| 224 | * Used for upgraded to MLS systems where objects may lack | 
|---|
| 225 | * MLS fields. | 
|---|
| 226 | * | 
|---|
| 227 | * Policy read-lock must be held for sidtab lookup. | 
|---|
| 228 | * | 
|---|
| 229 | */ | 
|---|
| 230 | int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext, | 
|---|
| 231 | struct context *context, struct sidtab *s, u32 def_sid) | 
|---|
| 232 | { | 
|---|
| 233 | char *sensitivity, *cur_cat, *next_cat, *rngptr; | 
|---|
| 234 | struct level_datum *levdatum; | 
|---|
| 235 | struct cat_datum *catdatum, *rngdatum; | 
|---|
| 236 | u32 i; | 
|---|
| 237 | int l, rc; | 
|---|
| 238 | char *rangep[2]; | 
|---|
| 239 |  | 
|---|
| 240 | if (!pol->mls_enabled) { | 
|---|
| 241 | /* | 
|---|
| 242 | * With no MLS, only return -EINVAL if there is a MLS field | 
|---|
| 243 | * and it did not come from an xattr. | 
|---|
| 244 | */ | 
|---|
| 245 | if (oldc && def_sid == SECSID_NULL) | 
|---|
| 246 | return -EINVAL; | 
|---|
| 247 | return 0; | 
|---|
| 248 | } | 
|---|
| 249 |  | 
|---|
| 250 | /* | 
|---|
| 251 | * No MLS component to the security context, try and map to | 
|---|
| 252 | * default if provided. | 
|---|
| 253 | */ | 
|---|
| 254 | if (!oldc) { | 
|---|
| 255 | struct context *defcon; | 
|---|
| 256 |  | 
|---|
| 257 | if (def_sid == SECSID_NULL) | 
|---|
| 258 | return -EINVAL; | 
|---|
| 259 |  | 
|---|
| 260 | defcon = sidtab_search(s, sid: def_sid); | 
|---|
| 261 | if (!defcon) | 
|---|
| 262 | return -EINVAL; | 
|---|
| 263 |  | 
|---|
| 264 | return mls_context_cpy(dst: context, src: defcon); | 
|---|
| 265 | } | 
|---|
| 266 |  | 
|---|
| 267 | /* | 
|---|
| 268 | * If we're dealing with a range, figure out where the two parts | 
|---|
| 269 | * of the range begin. | 
|---|
| 270 | */ | 
|---|
| 271 | rangep[0] = scontext; | 
|---|
| 272 | rangep[1] = strchr(scontext, '-'); | 
|---|
| 273 | if (rangep[1]) { | 
|---|
| 274 | rangep[1][0] = '\0'; | 
|---|
| 275 | rangep[1]++; | 
|---|
| 276 | } | 
|---|
| 277 |  | 
|---|
| 278 | /* For each part of the range: */ | 
|---|
| 279 | for (l = 0; l < 2; l++) { | 
|---|
| 280 | /* Split sensitivity and category set. */ | 
|---|
| 281 | sensitivity = rangep[l]; | 
|---|
| 282 | if (sensitivity == NULL) | 
|---|
| 283 | break; | 
|---|
| 284 | next_cat = strchr(sensitivity, ':'); | 
|---|
| 285 | if (next_cat) | 
|---|
| 286 | *(next_cat++) = '\0'; | 
|---|
| 287 |  | 
|---|
| 288 | /* Parse sensitivity. */ | 
|---|
| 289 | levdatum = symtab_search(s: &pol->p_levels, name: sensitivity); | 
|---|
| 290 | if (!levdatum) | 
|---|
| 291 | return -EINVAL; | 
|---|
| 292 | context->range.level[l].sens = levdatum->level.sens; | 
|---|
| 293 |  | 
|---|
| 294 | /* Extract category set. */ | 
|---|
| 295 | while (next_cat != NULL) { | 
|---|
| 296 | cur_cat = next_cat; | 
|---|
| 297 | next_cat = strchr(next_cat, ','); | 
|---|
| 298 | if (next_cat != NULL) | 
|---|
| 299 | *(next_cat++) = '\0'; | 
|---|
| 300 |  | 
|---|
| 301 | /* Separate into range if exists */ | 
|---|
| 302 | rngptr = strchr(cur_cat, '.'); | 
|---|
| 303 | if (rngptr != NULL) { | 
|---|
| 304 | /* Remove '.' */ | 
|---|
| 305 | *rngptr++ = '\0'; | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | catdatum = symtab_search(s: &pol->p_cats, name: cur_cat); | 
|---|
| 309 | if (!catdatum) | 
|---|
| 310 | return -EINVAL; | 
|---|
| 311 |  | 
|---|
| 312 | rc = ebitmap_set_bit(e: &context->range.level[l].cat, | 
|---|
| 313 | bit: catdatum->value - 1, value: 1); | 
|---|
| 314 | if (rc) | 
|---|
| 315 | return rc; | 
|---|
| 316 |  | 
|---|
| 317 | /* If range, set all categories in range */ | 
|---|
| 318 | if (rngptr == NULL) | 
|---|
| 319 | continue; | 
|---|
| 320 |  | 
|---|
| 321 | rngdatum = symtab_search(s: &pol->p_cats, name: rngptr); | 
|---|
| 322 | if (!rngdatum) | 
|---|
| 323 | return -EINVAL; | 
|---|
| 324 |  | 
|---|
| 325 | if (catdatum->value >= rngdatum->value) | 
|---|
| 326 | return -EINVAL; | 
|---|
| 327 |  | 
|---|
| 328 | for (i = catdatum->value; i < rngdatum->value; i++) { | 
|---|
| 329 | rc = ebitmap_set_bit( | 
|---|
| 330 | e: &context->range.level[l].cat, bit: i, value: 1); | 
|---|
| 331 | if (rc) | 
|---|
| 332 | return rc; | 
|---|
| 333 | } | 
|---|
| 334 | } | 
|---|
| 335 | } | 
|---|
| 336 |  | 
|---|
| 337 | /* If we didn't see a '-', the range start is also the range end. */ | 
|---|
| 338 | if (rangep[1] == NULL) { | 
|---|
| 339 | context->range.level[1].sens = context->range.level[0].sens; | 
|---|
| 340 | rc = ebitmap_cpy(dst: &context->range.level[1].cat, | 
|---|
| 341 | src: &context->range.level[0].cat); | 
|---|
| 342 | if (rc) | 
|---|
| 343 | return rc; | 
|---|
| 344 | } | 
|---|
| 345 |  | 
|---|
| 346 | return 0; | 
|---|
| 347 | } | 
|---|
| 348 |  | 
|---|
| 349 | /* | 
|---|
| 350 | * Set the MLS fields in the security context structure | 
|---|
| 351 | * `context' based on the string representation in | 
|---|
| 352 | * the string `str'.  This function will allocate temporary memory with the | 
|---|
| 353 | * given constraints of gfp_mask. | 
|---|
| 354 | */ | 
|---|
| 355 | int mls_from_string(struct policydb *p, char *str, struct context *context, | 
|---|
| 356 | gfp_t gfp_mask) | 
|---|
| 357 | { | 
|---|
| 358 | char *tmpstr; | 
|---|
| 359 | int rc; | 
|---|
| 360 |  | 
|---|
| 361 | if (!p->mls_enabled) | 
|---|
| 362 | return -EINVAL; | 
|---|
| 363 |  | 
|---|
| 364 | tmpstr = kstrdup(s: str, gfp: gfp_mask); | 
|---|
| 365 | if (!tmpstr) { | 
|---|
| 366 | rc = -ENOMEM; | 
|---|
| 367 | } else { | 
|---|
| 368 | rc = mls_context_to_sid(pol: p, oldc: ':', scontext: tmpstr, context, NULL, | 
|---|
| 369 | SECSID_NULL); | 
|---|
| 370 | kfree(objp: tmpstr); | 
|---|
| 371 | } | 
|---|
| 372 |  | 
|---|
| 373 | return rc; | 
|---|
| 374 | } | 
|---|
| 375 |  | 
|---|
| 376 | /* | 
|---|
| 377 | * Copies the MLS range `range' into `context'. | 
|---|
| 378 | */ | 
|---|
| 379 | int mls_range_set(struct context *context, struct mls_range *range) | 
|---|
| 380 | { | 
|---|
| 381 | int l, rc = 0; | 
|---|
| 382 |  | 
|---|
| 383 | /* Copy the MLS range into the  context */ | 
|---|
| 384 | for (l = 0; l < 2; l++) { | 
|---|
| 385 | context->range.level[l].sens = range->level[l].sens; | 
|---|
| 386 | rc = ebitmap_cpy(dst: &context->range.level[l].cat, | 
|---|
| 387 | src: &range->level[l].cat); | 
|---|
| 388 | if (rc) | 
|---|
| 389 | break; | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | return rc; | 
|---|
| 393 | } | 
|---|
| 394 |  | 
|---|
| 395 | int mls_setup_user_range(struct policydb *p, struct context *fromcon, | 
|---|
| 396 | struct user_datum *user, struct context *usercon) | 
|---|
| 397 | { | 
|---|
| 398 | if (p->mls_enabled) { | 
|---|
| 399 | struct mls_level *fromcon_sen = &(fromcon->range.level[0]); | 
|---|
| 400 | struct mls_level *fromcon_clr = &(fromcon->range.level[1]); | 
|---|
| 401 | struct mls_level *user_low = &(user->range.level[0]); | 
|---|
| 402 | struct mls_level *user_clr = &(user->range.level[1]); | 
|---|
| 403 | struct mls_level *user_def = &(user->dfltlevel); | 
|---|
| 404 | struct mls_level *usercon_sen = &(usercon->range.level[0]); | 
|---|
| 405 | struct mls_level *usercon_clr = &(usercon->range.level[1]); | 
|---|
| 406 |  | 
|---|
| 407 | /* Honor the user's default level if we can */ | 
|---|
| 408 | if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) | 
|---|
| 409 | *usercon_sen = *user_def; | 
|---|
| 410 | else if (mls_level_between(fromcon_sen, user_def, user_clr)) | 
|---|
| 411 | *usercon_sen = *fromcon_sen; | 
|---|
| 412 | else if (mls_level_between(fromcon_clr, user_low, user_def)) | 
|---|
| 413 | *usercon_sen = *user_low; | 
|---|
| 414 | else | 
|---|
| 415 | return -EINVAL; | 
|---|
| 416 |  | 
|---|
| 417 | /* Lower the clearance of available contexts | 
|---|
| 418 | if the clearance of "fromcon" is lower than | 
|---|
| 419 | that of the user's default clearance (but | 
|---|
| 420 | only if the "fromcon" clearance dominates | 
|---|
| 421 | the user's computed sensitivity level) */ | 
|---|
| 422 | if (mls_level_dom(l1: user_clr, l2: fromcon_clr)) | 
|---|
| 423 | *usercon_clr = *fromcon_clr; | 
|---|
| 424 | else if (mls_level_dom(l1: fromcon_clr, l2: user_clr)) | 
|---|
| 425 | *usercon_clr = *user_clr; | 
|---|
| 426 | else | 
|---|
| 427 | return -EINVAL; | 
|---|
| 428 | } | 
|---|
| 429 |  | 
|---|
| 430 | return 0; | 
|---|
| 431 | } | 
|---|
| 432 |  | 
|---|
| 433 | /* | 
|---|
| 434 | * Convert the MLS fields in the security context | 
|---|
| 435 | * structure `oldc' from the values specified in the | 
|---|
| 436 | * policy `oldp' to the values specified in the policy `newp', | 
|---|
| 437 | * storing the resulting context in `newc'. | 
|---|
| 438 | */ | 
|---|
| 439 | int mls_convert_context(struct policydb *oldp, struct policydb *newp, | 
|---|
| 440 | struct context *oldc, struct context *newc) | 
|---|
| 441 | { | 
|---|
| 442 | struct level_datum *levdatum; | 
|---|
| 443 | struct cat_datum *catdatum; | 
|---|
| 444 | struct ebitmap_node *node; | 
|---|
| 445 | u32 i; | 
|---|
| 446 | int l; | 
|---|
| 447 |  | 
|---|
| 448 | if (!oldp->mls_enabled || !newp->mls_enabled) | 
|---|
| 449 | return 0; | 
|---|
| 450 |  | 
|---|
| 451 | for (l = 0; l < 2; l++) { | 
|---|
| 452 | char *name = sym_name(p: oldp, SYM_LEVELS, | 
|---|
| 453 | element_nr: oldc->range.level[l].sens - 1); | 
|---|
| 454 |  | 
|---|
| 455 | levdatum = symtab_search(s: &newp->p_levels, name); | 
|---|
| 456 |  | 
|---|
| 457 | if (!levdatum) | 
|---|
| 458 | return -EINVAL; | 
|---|
| 459 | newc->range.level[l].sens = levdatum->level.sens; | 
|---|
| 460 |  | 
|---|
| 461 | ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node, | 
|---|
| 462 | i) | 
|---|
| 463 | { | 
|---|
| 464 | int rc; | 
|---|
| 465 |  | 
|---|
| 466 | catdatum = symtab_search(s: &newp->p_cats, | 
|---|
| 467 | name: sym_name(p: oldp, SYM_CATS, element_nr: i)); | 
|---|
| 468 | if (!catdatum) | 
|---|
| 469 | return -EINVAL; | 
|---|
| 470 | rc = ebitmap_set_bit(e: &newc->range.level[l].cat, | 
|---|
| 471 | bit: catdatum->value - 1, value: 1); | 
|---|
| 472 | if (rc) | 
|---|
| 473 | return rc; | 
|---|
| 474 | } | 
|---|
| 475 | } | 
|---|
| 476 |  | 
|---|
| 477 | return 0; | 
|---|
| 478 | } | 
|---|
| 479 |  | 
|---|
| 480 | int mls_compute_sid(struct policydb *p, struct context *scontext, | 
|---|
| 481 | struct context *tcontext, u16 tclass, u32 specified, | 
|---|
| 482 | struct context *newcontext, bool sock) | 
|---|
| 483 | { | 
|---|
| 484 | struct range_trans rtr; | 
|---|
| 485 | struct mls_range *r; | 
|---|
| 486 | struct class_datum *cladatum; | 
|---|
| 487 | char default_range = 0; | 
|---|
| 488 |  | 
|---|
| 489 | if (!p->mls_enabled) | 
|---|
| 490 | return 0; | 
|---|
| 491 |  | 
|---|
| 492 | switch (specified) { | 
|---|
| 493 | case AVTAB_TRANSITION: | 
|---|
| 494 | /* Look for a range transition rule. */ | 
|---|
| 495 | rtr.source_type = scontext->type; | 
|---|
| 496 | rtr.target_type = tcontext->type; | 
|---|
| 497 | rtr.target_class = tclass; | 
|---|
| 498 | r = policydb_rangetr_search(p, key: &rtr); | 
|---|
| 499 | if (r) | 
|---|
| 500 | return mls_range_set(context: newcontext, range: r); | 
|---|
| 501 |  | 
|---|
| 502 | if (tclass && tclass <= p->p_classes.nprim) { | 
|---|
| 503 | cladatum = p->class_val_to_struct[tclass - 1]; | 
|---|
| 504 | if (cladatum) | 
|---|
| 505 | default_range = cladatum->default_range; | 
|---|
| 506 | } | 
|---|
| 507 |  | 
|---|
| 508 | switch (default_range) { | 
|---|
| 509 | case DEFAULT_SOURCE_LOW: | 
|---|
| 510 | return mls_context_cpy_low(dst: newcontext, src: scontext); | 
|---|
| 511 | case DEFAULT_SOURCE_HIGH: | 
|---|
| 512 | return mls_context_cpy_high(dst: newcontext, src: scontext); | 
|---|
| 513 | case DEFAULT_SOURCE_LOW_HIGH: | 
|---|
| 514 | return mls_context_cpy(dst: newcontext, src: scontext); | 
|---|
| 515 | case DEFAULT_TARGET_LOW: | 
|---|
| 516 | return mls_context_cpy_low(dst: newcontext, src: tcontext); | 
|---|
| 517 | case DEFAULT_TARGET_HIGH: | 
|---|
| 518 | return mls_context_cpy_high(dst: newcontext, src: tcontext); | 
|---|
| 519 | case DEFAULT_TARGET_LOW_HIGH: | 
|---|
| 520 | return mls_context_cpy(dst: newcontext, src: tcontext); | 
|---|
| 521 | case DEFAULT_GLBLUB: | 
|---|
| 522 | return mls_context_glblub(dst: newcontext, c1: scontext, | 
|---|
| 523 | c2: tcontext); | 
|---|
| 524 | } | 
|---|
| 525 |  | 
|---|
| 526 | fallthrough; | 
|---|
| 527 | case AVTAB_CHANGE: | 
|---|
| 528 | if ((tclass == p->process_class) || sock) | 
|---|
| 529 | /* Use the process MLS attributes. */ | 
|---|
| 530 | return mls_context_cpy(dst: newcontext, src: scontext); | 
|---|
| 531 | else | 
|---|
| 532 | /* Use the process effective MLS attributes. */ | 
|---|
| 533 | return mls_context_cpy_low(dst: newcontext, src: scontext); | 
|---|
| 534 | case AVTAB_MEMBER: | 
|---|
| 535 | /* Use the process effective MLS attributes. */ | 
|---|
| 536 | return mls_context_cpy_low(dst: newcontext, src: scontext); | 
|---|
| 537 | } | 
|---|
| 538 | return -EINVAL; | 
|---|
| 539 | } | 
|---|
| 540 |  | 
|---|
| 541 | #ifdef CONFIG_NETLABEL | 
|---|
| 542 | /** | 
|---|
| 543 | * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel | 
|---|
| 544 | * @p: the policy | 
|---|
| 545 | * @context: the security context | 
|---|
| 546 | * @secattr: the NetLabel security attributes | 
|---|
| 547 | * | 
|---|
| 548 | * Description: | 
|---|
| 549 | * Given the security context copy the low MLS sensitivity level into the | 
|---|
| 550 | * NetLabel MLS sensitivity level field. | 
|---|
| 551 | * | 
|---|
| 552 | */ | 
|---|
| 553 | void mls_export_netlbl_lvl(struct policydb *p, struct context *context, | 
|---|
| 554 | struct netlbl_lsm_secattr *secattr) | 
|---|
| 555 | { | 
|---|
| 556 | if (!p->mls_enabled) | 
|---|
| 557 | return; | 
|---|
| 558 |  | 
|---|
| 559 | secattr->attr.mls.lvl = context->range.level[0].sens - 1; | 
|---|
| 560 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 
|---|
| 561 | } | 
|---|
| 562 |  | 
|---|
| 563 | /** | 
|---|
| 564 | * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels | 
|---|
| 565 | * @p: the policy | 
|---|
| 566 | * @context: the security context | 
|---|
| 567 | * @secattr: the NetLabel security attributes | 
|---|
| 568 | * | 
|---|
| 569 | * Description: | 
|---|
| 570 | * Given the security context and the NetLabel security attributes, copy the | 
|---|
| 571 | * NetLabel MLS sensitivity level into the context. | 
|---|
| 572 | * | 
|---|
| 573 | */ | 
|---|
| 574 | void mls_import_netlbl_lvl(struct policydb *p, struct context *context, | 
|---|
| 575 | struct netlbl_lsm_secattr *secattr) | 
|---|
| 576 | { | 
|---|
| 577 | if (!p->mls_enabled) | 
|---|
| 578 | return; | 
|---|
| 579 |  | 
|---|
| 580 | context->range.level[0].sens = secattr->attr.mls.lvl + 1; | 
|---|
| 581 | context->range.level[1].sens = context->range.level[0].sens; | 
|---|
| 582 | } | 
|---|
| 583 |  | 
|---|
| 584 | /** | 
|---|
| 585 | * mls_export_netlbl_cat - Export the MLS categories to NetLabel | 
|---|
| 586 | * @p: the policy | 
|---|
| 587 | * @context: the security context | 
|---|
| 588 | * @secattr: the NetLabel security attributes | 
|---|
| 589 | * | 
|---|
| 590 | * Description: | 
|---|
| 591 | * Given the security context copy the low MLS categories into the NetLabel | 
|---|
| 592 | * MLS category field.  Returns zero on success, negative values on failure. | 
|---|
| 593 | * | 
|---|
| 594 | */ | 
|---|
| 595 | int mls_export_netlbl_cat(struct policydb *p, struct context *context, | 
|---|
| 596 | struct netlbl_lsm_secattr *secattr) | 
|---|
| 597 | { | 
|---|
| 598 | int rc; | 
|---|
| 599 |  | 
|---|
| 600 | if (!p->mls_enabled) | 
|---|
| 601 | return 0; | 
|---|
| 602 |  | 
|---|
| 603 | rc = ebitmap_netlbl_export(ebmap: &context->range.level[0].cat, | 
|---|
| 604 | catmap: &secattr->attr.mls.cat); | 
|---|
| 605 | if (rc == 0 && secattr->attr.mls.cat != NULL) | 
|---|
| 606 | secattr->flags |= NETLBL_SECATTR_MLS_CAT; | 
|---|
| 607 |  | 
|---|
| 608 | return rc; | 
|---|
| 609 | } | 
|---|
| 610 |  | 
|---|
| 611 | /** | 
|---|
| 612 | * mls_import_netlbl_cat - Import the MLS categories from NetLabel | 
|---|
| 613 | * @p: the policy | 
|---|
| 614 | * @context: the security context | 
|---|
| 615 | * @secattr: the NetLabel security attributes | 
|---|
| 616 | * | 
|---|
| 617 | * Description: | 
|---|
| 618 | * Copy the NetLabel security attributes into the SELinux context; since the | 
|---|
| 619 | * NetLabel security attribute only contains a single MLS category use it for | 
|---|
| 620 | * both the low and high categories of the context.  Returns zero on success, | 
|---|
| 621 | * negative values on failure. | 
|---|
| 622 | * | 
|---|
| 623 | */ | 
|---|
| 624 | int mls_import_netlbl_cat(struct policydb *p, struct context *context, | 
|---|
| 625 | struct netlbl_lsm_secattr *secattr) | 
|---|
| 626 | { | 
|---|
| 627 | int rc; | 
|---|
| 628 |  | 
|---|
| 629 | if (!p->mls_enabled) | 
|---|
| 630 | return 0; | 
|---|
| 631 |  | 
|---|
| 632 | rc = ebitmap_netlbl_import(ebmap: &context->range.level[0].cat, | 
|---|
| 633 | catmap: secattr->attr.mls.cat); | 
|---|
| 634 | if (rc) | 
|---|
| 635 | goto import_netlbl_cat_failure; | 
|---|
| 636 | memcpy(to: &context->range.level[1].cat, from: &context->range.level[0].cat, | 
|---|
| 637 | len: sizeof(context->range.level[0].cat)); | 
|---|
| 638 |  | 
|---|
| 639 | return 0; | 
|---|
| 640 |  | 
|---|
| 641 | import_netlbl_cat_failure: | 
|---|
| 642 | ebitmap_destroy(e: &context->range.level[0].cat); | 
|---|
| 643 | return rc; | 
|---|
| 644 | } | 
|---|
| 645 | #endif /* CONFIG_NETLABEL */ | 
|---|
| 646 |  | 
|---|