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 = symtab_search(&p->p_levels,
 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 = symtab_search(&pol->p_levels, 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 = symtab_search(&pol->p_cats, 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 = symtab_search(&pol->p_cats, 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                char *name = sym_name(oldp, SYM_LEVELS,
 462                                      oldc->range.level[l].sens - 1);
 463
 464                levdatum = symtab_search(&newp->p_levels, name);
 465
 466                if (!levdatum)
 467                        return -EINVAL;
 468                newc->range.level[l].sens = levdatum->level->sens;
 469
 470                ebitmap_for_each_positive_bit(&oldc->range.level[l].cat,
 471                                              node, i) {
 472                        int rc;
 473
 474                        catdatum = symtab_search(&newp->p_cats,
 475                                                 sym_name(oldp, SYM_CATS, i));
 476                        if (!catdatum)
 477                                return -EINVAL;
 478                        rc = ebitmap_set_bit(&newc->range.level[l].cat,
 479                                             catdatum->value - 1, 1);
 480                        if (rc)
 481                                return rc;
 482                }
 483        }
 484
 485        return 0;
 486}
 487
 488int mls_compute_sid(struct policydb *p,
 489                    struct context *scontext,
 490                    struct context *tcontext,
 491                    u16 tclass,
 492                    u32 specified,
 493                    struct context *newcontext,
 494                    bool sock)
 495{
 496        struct range_trans rtr;
 497        struct mls_range *r;
 498        struct class_datum *cladatum;
 499        int default_range = 0;
 500
 501        if (!p->mls_enabled)
 502                return 0;
 503
 504        switch (specified) {
 505        case AVTAB_TRANSITION:
 506                /* Look for a range transition rule. */
 507                rtr.source_type = scontext->type;
 508                rtr.target_type = tcontext->type;
 509                rtr.target_class = tclass;
 510                r = policydb_rangetr_search(p, &rtr);
 511                if (r)
 512                        return mls_range_set(newcontext, r);
 513
 514                if (tclass && tclass <= p->p_classes.nprim) {
 515                        cladatum = p->class_val_to_struct[tclass - 1];
 516                        if (cladatum)
 517                                default_range = cladatum->default_range;
 518                }
 519
 520                switch (default_range) {
 521                case DEFAULT_SOURCE_LOW:
 522                        return mls_context_cpy_low(newcontext, scontext);
 523                case DEFAULT_SOURCE_HIGH:
 524                        return mls_context_cpy_high(newcontext, scontext);
 525                case DEFAULT_SOURCE_LOW_HIGH:
 526                        return mls_context_cpy(newcontext, scontext);
 527                case DEFAULT_TARGET_LOW:
 528                        return mls_context_cpy_low(newcontext, tcontext);
 529                case DEFAULT_TARGET_HIGH:
 530                        return mls_context_cpy_high(newcontext, tcontext);
 531                case DEFAULT_TARGET_LOW_HIGH:
 532                        return mls_context_cpy(newcontext, tcontext);
 533                case DEFAULT_GLBLUB:
 534                        return mls_context_glblub(newcontext,
 535                                                  scontext, tcontext);
 536                }
 537
 538                fallthrough;
 539        case AVTAB_CHANGE:
 540                if ((tclass == p->process_class) || sock)
 541                        /* Use the process MLS attributes. */
 542                        return mls_context_cpy(newcontext, scontext);
 543                else
 544                        /* Use the process effective MLS attributes. */
 545                        return mls_context_cpy_low(newcontext, scontext);
 546        case AVTAB_MEMBER:
 547                /* Use the process effective MLS attributes. */
 548                return mls_context_cpy_low(newcontext, scontext);
 549        }
 550        return -EINVAL;
 551}
 552
 553#ifdef CONFIG_NETLABEL
 554/**
 555 * mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
 556 * @context: the security context
 557 * @secattr: the NetLabel security attributes
 558 *
 559 * Description:
 560 * Given the security context copy the low MLS sensitivity level into the
 561 * NetLabel MLS sensitivity level field.
 562 *
 563 */
 564void mls_export_netlbl_lvl(struct policydb *p,
 565                           struct context *context,
 566                           struct netlbl_lsm_secattr *secattr)
 567{
 568        if (!p->mls_enabled)
 569                return;
 570
 571        secattr->attr.mls.lvl = context->range.level[0].sens - 1;
 572        secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 573}
 574
 575/**
 576 * mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
 577 * @context: the security context
 578 * @secattr: the NetLabel security attributes
 579 *
 580 * Description:
 581 * Given the security context and the NetLabel security attributes, copy the
 582 * NetLabel MLS sensitivity level into the context.
 583 *
 584 */
 585void mls_import_netlbl_lvl(struct policydb *p,
 586                           struct context *context,
 587                           struct netlbl_lsm_secattr *secattr)
 588{
 589        if (!p->mls_enabled)
 590                return;
 591
 592        context->range.level[0].sens = secattr->attr.mls.lvl + 1;
 593        context->range.level[1].sens = context->range.level[0].sens;
 594}
 595
 596/**
 597 * mls_export_netlbl_cat - Export the MLS categories to NetLabel
 598 * @context: the security context
 599 * @secattr: the NetLabel security attributes
 600 *
 601 * Description:
 602 * Given the security context copy the low MLS categories into the NetLabel
 603 * MLS category field.  Returns zero on success, negative values on failure.
 604 *
 605 */
 606int mls_export_netlbl_cat(struct policydb *p,
 607                          struct context *context,
 608                          struct netlbl_lsm_secattr *secattr)
 609{
 610        int rc;
 611
 612        if (!p->mls_enabled)
 613                return 0;
 614
 615        rc = ebitmap_netlbl_export(&context->range.level[0].cat,
 616                                   &secattr->attr.mls.cat);
 617        if (rc == 0 && secattr->attr.mls.cat != NULL)
 618                secattr->flags |= NETLBL_SECATTR_MLS_CAT;
 619
 620        return rc;
 621}
 622
 623/**
 624 * mls_import_netlbl_cat - Import the MLS categories from NetLabel
 625 * @context: the security context
 626 * @secattr: the NetLabel security attributes
 627 *
 628 * Description:
 629 * Copy the NetLabel security attributes into the SELinux context; since the
 630 * NetLabel security attribute only contains a single MLS category use it for
 631 * both the low and high categories of the context.  Returns zero on success,
 632 * negative values on failure.
 633 *
 634 */
 635int mls_import_netlbl_cat(struct policydb *p,
 636                          struct context *context,
 637                          struct netlbl_lsm_secattr *secattr)
 638{
 639        int rc;
 640
 641        if (!p->mls_enabled)
 642                return 0;
 643
 644        rc = ebitmap_netlbl_import(&context->range.level[0].cat,
 645                                   secattr->attr.mls.cat);
 646        if (rc)
 647                goto import_netlbl_cat_failure;
 648        memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
 649               sizeof(context->range.level[0].cat));
 650
 651        return 0;
 652
 653import_netlbl_cat_failure:
 654        ebitmap_destroy(&context->range.level[0].cat);
 655        return rc;
 656}
 657#endif /* CONFIG_NETLABEL */
 658