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'.  Update `*scontext' to
 222 * point to the end of the string representation of
 223 * the MLS fields.
 224 *
 225 * This function modifies the string in place, inserting
 226 * NULL characters to terminate the MLS fields.
 227 *
 228 * If a def_sid is provided and no MLS field is present,
 229 * copy the MLS field of the associated default context.
 230 * Used for upgraded to MLS systems where objects may lack
 231 * MLS fields.
 232 *
 233 * Policy read-lock must be held for sidtab lookup.
 234 *
 235 */
 236int mls_context_to_sid(struct policydb *pol,
 237                       char oldc,
 238                       char **scontext,
 239                       struct context *context,
 240                       struct sidtab *s,
 241                       u32 def_sid)
 242{
 243
 244        char delim;
 245        char *scontextp, *p, *rngptr;
 246        struct level_datum *levdatum;
 247        struct cat_datum *catdatum, *rngdatum;
 248        int l, rc = -EINVAL;
 249
 250        if (!pol->mls_enabled) {
 251                if (def_sid != SECSID_NULL && oldc)
 252                        *scontext += strlen(*scontext) + 1;
 253                return 0;
 254        }
 255
 256        /*
 257         * No MLS component to the security context, try and map to
 258         * default if provided.
 259         */
 260        if (!oldc) {
 261                struct context *defcon;
 262
 263                if (def_sid == SECSID_NULL)
 264                        goto out;
 265
 266                defcon = sidtab_search(s, def_sid);
 267                if (!defcon)
 268                        goto out;
 269
 270                rc = mls_context_cpy(context, defcon);
 271                goto out;
 272        }
 273
 274        /* Extract low sensitivity. */
 275        scontextp = p = *scontext;
 276        while (*p && *p != ':' && *p != '-')
 277                p++;
 278
 279        delim = *p;
 280        if (delim != '\0')
 281                *p++ = '\0';
 282
 283        for (l = 0; l < 2; l++) {
 284                levdatum = hashtab_search(pol->p_levels.table, scontextp);
 285                if (!levdatum) {
 286                        rc = -EINVAL;
 287                        goto out;
 288                }
 289
 290                context->range.level[l].sens = levdatum->level->sens;
 291
 292                if (delim == ':') {
 293                        /* Extract category set. */
 294                        while (1) {
 295                                scontextp = p;
 296                                while (*p && *p != ',' && *p != '-')
 297                                        p++;
 298                                delim = *p;
 299                                if (delim != '\0')
 300                                        *p++ = '\0';
 301
 302                                /* Separate into range if exists */
 303                                rngptr = strchr(scontextp, '.');
 304                                if (rngptr != NULL) {
 305                                        /* Remove '.' */
 306                                        *rngptr++ = '\0';
 307                                }
 308
 309                                catdatum = hashtab_search(pol->p_cats.table,
 310                                                          scontextp);
 311                                if (!catdatum) {
 312                                        rc = -EINVAL;
 313                                        goto out;
 314                                }
 315
 316                                rc = ebitmap_set_bit(&context->range.level[l].cat,
 317                                                     catdatum->value - 1, 1);
 318                                if (rc)
 319                                        goto out;
 320
 321                                /* If range, set all categories in range */
 322                                if (rngptr) {
 323                                        int i;
 324
 325                                        rngdatum = hashtab_search(pol->p_cats.table, rngptr);
 326                                        if (!rngdatum) {
 327                                                rc = -EINVAL;
 328                                                goto out;
 329                                        }
 330
 331                                        if (catdatum->value >= rngdatum->value) {
 332                                                rc = -EINVAL;
 333                                                goto out;
 334                                        }
 335
 336                                        for (i = catdatum->value; i < rngdatum->value; i++) {
 337                                                rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
 338                                                if (rc)
 339                                                        goto out;
 340                                        }
 341                                }
 342
 343                                if (delim != ',')
 344                                        break;
 345                        }
 346                }
 347                if (delim == '-') {
 348                        /* Extract high sensitivity. */
 349                        scontextp = p;
 350                        while (*p && *p != ':')
 351                                p++;
 352
 353                        delim = *p;
 354                        if (delim != '\0')
 355                                *p++ = '\0';
 356                } else
 357                        break;
 358        }
 359
 360        if (l == 0) {
 361                context->range.level[1].sens = context->range.level[0].sens;
 362                rc = ebitmap_cpy(&context->range.level[1].cat,
 363                                 &context->range.level[0].cat);
 364                if (rc)
 365                        goto out;
 366        }
 367        *scontext = ++p;
 368        rc = 0;
 369out:
 370        return rc;
 371}
 372
 373/*
 374 * Set the MLS fields in the security context structure
 375 * `context' based on the string representation in
 376 * the string `str'.  This function will allocate temporary memory with the
 377 * given constraints of gfp_mask.
 378 */
 379int mls_from_string(struct policydb *p, char *str, struct context *context,
 380                    gfp_t gfp_mask)
 381{
 382        char *tmpstr, *freestr;
 383        int rc;
 384
 385        if (!p->mls_enabled)
 386                return -EINVAL;
 387
 388        /* we need freestr because mls_context_to_sid will change
 389           the value of tmpstr */
 390        tmpstr = freestr = kstrdup(str, gfp_mask);
 391        if (!tmpstr) {
 392                rc = -ENOMEM;
 393        } else {
 394                rc = mls_context_to_sid(p, ':', &tmpstr, context,
 395                                        NULL, SECSID_NULL);
 396                kfree(freestr);
 397        }
 398
 399        return rc;
 400}
 401
 402/*
 403 * Copies the MLS range `range' into `context'.
 404 */
 405int mls_range_set(struct context *context,
 406                                struct mls_range *range)
 407{
 408        int l, rc = 0;
 409
 410        /* Copy the MLS range into the  context */
 411        for (l = 0; l < 2; l++) {
 412                context->range.level[l].sens = range->level[l].sens;
 413                rc = ebitmap_cpy(&context->range.level[l].cat,
 414                                 &range->level[l].cat);
 415                if (rc)
 416                        break;
 417        }
 418
 419        return rc;
 420}
 421
 422int mls_setup_user_range(struct policydb *p,
 423                         struct context *fromcon, struct user_datum *user,
 424                         struct context *usercon)
 425{
 426        if (p->mls_enabled) {
 427                struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
 428                struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
 429                struct mls_level *user_low = &(user->range.level[0]);
 430                struct mls_level *user_clr = &(user->range.level[1]);
 431                struct mls_level *user_def = &(user->dfltlevel);
 432                struct mls_level *usercon_sen = &(usercon->range.level[0]);
 433                struct mls_level *usercon_clr = &(usercon->range.level[1]);
 434
 435                /* Honor the user's default level if we can */
 436                if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
 437                        *usercon_sen = *user_def;
 438                else if (mls_level_between(fromcon_sen, user_def, user_clr))
 439                        *usercon_sen = *fromcon_sen;
 440                else if (mls_level_between(fromcon_clr, user_low, user_def))
 441                        *usercon_sen = *user_low;
 442                else
 443                        return -EINVAL;
 444
 445                /* Lower the clearance of available contexts
 446                   if the clearance of "fromcon" is lower than
 447                   that of the user's default clearance (but
 448                   only if the "fromcon" clearance dominates
 449                   the user's computed sensitivity level) */
 450                if (mls_level_dom(user_clr, fromcon_clr))
 451                        *usercon_clr = *fromcon_clr;
 452                else if (mls_level_dom(fromcon_clr, user_clr))
 453                        *usercon_clr = *user_clr;
 454                else
 455                        return -EINVAL;
 456        }
 457
 458        return 0;
 459}
 460
 461/*
 462 * Convert the MLS fields in the security context
 463 * structure `c' from the values specified in the
 464 * policy `oldp' to the values specified in the policy `newp'.
 465 */
 466int mls_convert_context(struct policydb *oldp,
 467                        struct policydb *newp,
 468                        struct context *c)
 469{
 470        struct level_datum *levdatum;
 471        struct cat_datum *catdatum;
 472        struct ebitmap bitmap;
 473        struct ebitmap_node *node;
 474        int l, i;
 475
 476        if (!oldp->mls_enabled || !newp->mls_enabled)
 477                return 0;
 478
 479        for (l = 0; l < 2; l++) {
 480                levdatum = hashtab_search(newp->p_levels.table,
 481                                          sym_name(oldp, SYM_LEVELS,
 482                                                   c->range.level[l].sens - 1));
 483
 484                if (!levdatum)
 485                        return -EINVAL;
 486                c->range.level[l].sens = levdatum->level->sens;
 487
 488                ebitmap_init(&bitmap);
 489                ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
 490                        int rc;
 491
 492                        catdatum = hashtab_search(newp->p_cats.table,
 493                                                  sym_name(oldp, SYM_CATS, i));
 494                        if (!catdatum)
 495                                return -EINVAL;
 496                        rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
 497                        if (rc)
 498                                return rc;
 499
 500                        cond_resched();
 501                }
 502                ebitmap_destroy(&c->range.level[l].cat);
 503                c->range.level[l].cat = bitmap;
 504        }
 505
 506        return 0;
 507}
 508
 509int mls_compute_sid(struct policydb *p,
 510                    struct context *scontext,
 511                    struct context *tcontext,
 512                    u16 tclass,
 513                    u32 specified,
 514                    struct context *newcontext,
 515                    bool sock)
 516{
 517        struct range_trans rtr;
 518        struct mls_range *r;
 519        struct class_datum *cladatum;
 520        int default_range = 0;
 521
 522        if (!p->mls_enabled)
 523                return 0;
 524
 525        switch (specified) {
 526        case AVTAB_TRANSITION:
 527                /* Look for a range transition rule. */
 528                rtr.source_type = scontext->type;
 529                rtr.target_type = tcontext->type;
 530                rtr.target_class = tclass;
 531                r = hashtab_search(p->range_tr, &rtr);
 532                if (r)
 533                        return mls_range_set(newcontext, r);
 534
 535                if (tclass && tclass <= p->p_classes.nprim) {
 536                        cladatum = p->class_val_to_struct[tclass - 1];
 537                        if (cladatum)
 538                                default_range = cladatum->default_range;
 539                }
 540
 541                switch (default_range) {
 542                case DEFAULT_SOURCE_LOW:
 543                        return mls_context_cpy_low(newcontext, scontext);
 544                case DEFAULT_SOURCE_HIGH:
 545                        return mls_context_cpy_high(newcontext, scontext);
 546                case DEFAULT_SOURCE_LOW_HIGH:
 547                        return mls_context_cpy(newcontext, scontext);
 548                case DEFAULT_TARGET_LOW:
 549                        return mls_context_cpy_low(newcontext, tcontext);
 550                case DEFAULT_TARGET_HIGH:
 551                        return mls_context_cpy_high(newcontext, tcontext);
 552                case DEFAULT_TARGET_LOW_HIGH:
 553                        return mls_context_cpy(newcontext, tcontext);
 554                }
 555
 556                /* Fallthrough */
 557        case AVTAB_CHANGE:
 558                if ((tclass == p->process_class) || (sock == true))
 559                        /* Use the process MLS attributes. */
 560                        return mls_context_cpy(newcontext, scontext);
 561                else
 562                        /* Use the process effective MLS attributes. */
 563                        return mls_context_cpy_low(newcontext, scontext);
 564        case AVTAB_MEMBER:
 565                /* Use the process effective MLS attributes. */
 566                return mls_context_cpy_low(newcontext, scontext);
 567
 568        /* fall through */
 569        }
 570        return -EINVAL;
 571}
 572
 573#ifdef CONFIG_NETLABEL
 574/**
 575 * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
 576 * @context: the security context
 577 * @secattr: the NetLabel security attributes
 578 *
 579 * Description:
 580 * Given the security context copy the low MLS sensitivity level into the
 581 * NetLabel MLS sensitivity level field.
 582 *
 583 */
 584void mls_export_netlbl_lvl(struct policydb *p,
 585                           struct context *context,
 586                           struct netlbl_lsm_secattr *secattr)
 587{
 588        if (!p->mls_enabled)
 589                return;
 590
 591        secattr->attr.mls.lvl = context->range.level[0].sens - 1;
 592        secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 593}
 594
 595/**
 596 * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
 597 * @context: the security context
 598 * @secattr: the NetLabel security attributes
 599 *
 600 * Description:
 601 * Given the security context and the NetLabel security attributes, copy the
 602 * NetLabel MLS sensitivity level into the context.
 603 *
 604 */
 605void mls_import_netlbl_lvl(struct policydb *p,
 606                           struct context *context,
 607                           struct netlbl_lsm_secattr *secattr)
 608{
 609        if (!p->mls_enabled)
 610                return;
 611
 612        context->range.level[0].sens = secattr->attr.mls.lvl + 1;
 613        context->range.level[1].sens = context->range.level[0].sens;
 614}
 615
 616/**
 617 * mls_export_netlbl_cat - Export the MLS categories to NetLabel
 618 * @context: the security context
 619 * @secattr: the NetLabel security attributes
 620 *
 621 * Description:
 622 * Given the security context copy the low MLS categories into the NetLabel
 623 * MLS category field.  Returns zero on success, negative values on failure.
 624 *
 625 */
 626int mls_export_netlbl_cat(struct policydb *p,
 627                          struct context *context,
 628                          struct netlbl_lsm_secattr *secattr)
 629{
 630        int rc;
 631
 632        if (!p->mls_enabled)
 633                return 0;
 634
 635        rc = ebitmap_netlbl_export(&context->range.level[0].cat,
 636                                   &secattr->attr.mls.cat);
 637        if (rc == 0 && secattr->attr.mls.cat != NULL)
 638                secattr->flags |= NETLBL_SECATTR_MLS_CAT;
 639
 640        return rc;
 641}
 642
 643/**
 644 * mls_import_netlbl_cat - Import the MLS categories from NetLabel
 645 * @context: the security context
 646 * @secattr: the NetLabel security attributes
 647 *
 648 * Description:
 649 * Copy the NetLabel security attributes into the SELinux context; since the
 650 * NetLabel security attribute only contains a single MLS category use it for
 651 * both the low and high categories of the context.  Returns zero on success,
 652 * negative values on failure.
 653 *
 654 */
 655int mls_import_netlbl_cat(struct policydb *p,
 656                          struct context *context,
 657                          struct netlbl_lsm_secattr *secattr)
 658{
 659        int rc;
 660
 661        if (!p->mls_enabled)
 662                return 0;
 663
 664        rc = ebitmap_netlbl_import(&context->range.level[0].cat,
 665                                   secattr->attr.mls.cat);
 666        if (rc)
 667                goto import_netlbl_cat_failure;
 668        memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
 669               sizeof(context->range.level[0].cat));
 670
 671        return 0;
 672
 673import_netlbl_cat_failure:
 674        ebitmap_destroy(&context->range.level[0].cat);
 675        return rc;
 676}
 677#endif /* CONFIG_NETLABEL */
 678