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