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