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.moore@hp.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 (!selinux_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(policydb.p_sens_val_to_name[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 = policydb.p_cat_val_to_name[prev];
  59                                        len += strlen(nm) + 1;
  60                                }
  61                                nm = policydb.p_cat_val_to_name[i];
  62                                len += strlen(nm) + 1;
  63                                head = i;
  64                        }
  65                        prev = i;
  66                }
  67                if (prev != head) {
  68                        nm = policydb.p_cat_val_to_name[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 (!selinux_mls_enabled)
  97                return;
  98
  99        scontextp = *scontext;
 100
 101        *scontextp = ':';
 102        scontextp++;
 103
 104        for (l = 0; l < 2; l++) {
 105                strcpy(scontextp,
 106                       policydb.p_sens_val_to_name[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 = policydb.p_cat_val_to_name[prev];
 122                                        strcpy(scontextp, nm);
 123                                        scontextp += strlen(nm);
 124                                }
 125                                if (prev < 0)
 126                                        *scontextp++ = ':';
 127                                else
 128                                        *scontextp++ = ',';
 129                                nm = policydb.p_cat_val_to_name[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 = policydb.p_cat_val_to_name[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                                  p->p_sens_val_to_name[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 (!selinux_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 (!selinux_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 (!selinux_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 */
 410static inline int 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 (selinux_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 (!selinux_mls_enabled)
 481                return 0;
 482
 483        for (l = 0; l < 2; l++) {
 484                levdatum = hashtab_search(newp->p_levels.table,
 485                        oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
 486
 487                if (!levdatum)
 488                        return -EINVAL;
 489                c->range.level[l].sens = levdatum->level->sens;
 490
 491                ebitmap_init(&bitmap);
 492                ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
 493                        int rc;
 494
 495                        catdatum = hashtab_search(newp->p_cats.table,
 496                                                  oldp->p_cat_val_to_name[i]);
 497                        if (!catdatum)
 498                                return -EINVAL;
 499                        rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
 500                        if (rc)
 501                                return rc;
 502                }
 503                ebitmap_destroy(&c->range.level[l].cat);
 504                c->range.level[l].cat = bitmap;
 505        }
 506
 507        return 0;
 508}
 509
 510int mls_compute_sid(struct context *scontext,
 511                    struct context *tcontext,
 512                    u16 tclass,
 513                    u32 specified,
 514                    struct context *newcontext)
 515{
 516        struct range_trans *rtr;
 517
 518        if (!selinux_mls_enabled)
 519                return 0;
 520
 521        switch (specified) {
 522        case AVTAB_TRANSITION:
 523                /* Look for a range transition rule. */
 524                for (rtr = policydb.range_tr; rtr; rtr = rtr->next) {
 525                        if (rtr->source_type == scontext->type &&
 526                            rtr->target_type == tcontext->type &&
 527                            rtr->target_class == tclass) {
 528                                /* Set the range from the rule */
 529                                return mls_range_set(newcontext,
 530                                                     &rtr->target_range);
 531                        }
 532                }
 533                /* Fallthrough */
 534        case AVTAB_CHANGE:
 535                if (tclass == SECCLASS_PROCESS)
 536                        /* Use the process MLS attributes. */
 537                        return mls_context_cpy(newcontext, scontext);
 538                else
 539                        /* Use the process effective MLS attributes. */
 540                        return mls_context_cpy_low(newcontext, scontext);
 541        case AVTAB_MEMBER:
 542                /* Use the process effective MLS attributes. */
 543                return mls_context_cpy_low(newcontext, scontext);
 544        default:
 545                return -EINVAL;
 546        }
 547        return -EINVAL;
 548}
 549
 550#ifdef CONFIG_NETLABEL
 551/**
 552 * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
 553 * @context: the security context
 554 * @secattr: the NetLabel security attributes
 555 *
 556 * Description:
 557 * Given the security context copy the low MLS sensitivity level into the
 558 * NetLabel MLS sensitivity level field.
 559 *
 560 */
 561void mls_export_netlbl_lvl(struct context *context,
 562                           struct netlbl_lsm_secattr *secattr)
 563{
 564        if (!selinux_mls_enabled)
 565                return;
 566
 567        secattr->attr.mls.lvl = context->range.level[0].sens - 1;
 568        secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 569}
 570
 571/**
 572 * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
 573 * @context: the security context
 574 * @secattr: the NetLabel security attributes
 575 *
 576 * Description:
 577 * Given the security context and the NetLabel security attributes, copy the
 578 * NetLabel MLS sensitivity level into the context.
 579 *
 580 */
 581void mls_import_netlbl_lvl(struct context *context,
 582                           struct netlbl_lsm_secattr *secattr)
 583{
 584        if (!selinux_mls_enabled)
 585                return;
 586
 587        context->range.level[0].sens = secattr->attr.mls.lvl + 1;
 588        context->range.level[1].sens = context->range.level[0].sens;
 589}
 590
 591/**
 592 * mls_export_netlbl_cat - Export the MLS categories to NetLabel
 593 * @context: the security context
 594 * @secattr: the NetLabel security attributes
 595 *
 596 * Description:
 597 * Given the security context copy the low MLS categories into the NetLabel
 598 * MLS category field.  Returns zero on success, negative values on failure.
 599 *
 600 */
 601int mls_export_netlbl_cat(struct context *context,
 602                          struct netlbl_lsm_secattr *secattr)
 603{
 604        int rc;
 605
 606        if (!selinux_mls_enabled)
 607                return 0;
 608
 609        rc = ebitmap_netlbl_export(&context->range.level[0].cat,
 610                                   &secattr->attr.mls.cat);
 611        if (rc == 0 && secattr->attr.mls.cat != NULL)
 612                secattr->flags |= NETLBL_SECATTR_MLS_CAT;
 613
 614        return rc;
 615}
 616
 617/**
 618 * mls_import_netlbl_cat - Import the MLS categories from NetLabel
 619 * @context: the security context
 620 * @secattr: the NetLabel security attributes
 621 *
 622 * Description:
 623 * Copy the NetLabel security attributes into the SELinux context; since the
 624 * NetLabel security attribute only contains a single MLS category use it for
 625 * both the low and high categories of the context.  Returns zero on success,
 626 * negative values on failure.
 627 *
 628 */
 629int mls_import_netlbl_cat(struct context *context,
 630                          struct netlbl_lsm_secattr *secattr)
 631{
 632        int rc;
 633
 634        if (!selinux_mls_enabled)
 635                return 0;
 636
 637        rc = ebitmap_netlbl_import(&context->range.level[0].cat,
 638                                   secattr->attr.mls.cat);
 639        if (rc != 0)
 640                goto import_netlbl_cat_failure;
 641
 642        rc = ebitmap_cpy(&context->range.level[1].cat,
 643                         &context->range.level[0].cat);
 644        if (rc != 0)
 645                goto import_netlbl_cat_failure;
 646
 647        return 0;
 648
 649import_netlbl_cat_failure:
 650        ebitmap_destroy(&context->range.level[0].cat);
 651        ebitmap_destroy(&context->range.level[1].cat);
 652        return rc;
 653}
 654#endif /* CONFIG_NETLABEL */
 655