linux/security/smack/smack_access.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
   3 *
   4 *      This program is free software; you can redistribute it and/or modify
   5 *      it under the terms of the GNU General Public License as published by
   6 *      the Free Software Foundation, version 2.
   7 *
   8 * Author:
   9 *      Casey Schaufler <casey@schaufler-ca.com>
  10 *
  11 */
  12
  13#include <linux/types.h>
  14#include <linux/slab.h>
  15#include <linux/fs.h>
  16#include <linux/sched.h>
  17#include "smack.h"
  18
  19struct smack_known smack_known_huh = {
  20        .smk_known      = "?",
  21        .smk_secid      = 2,
  22};
  23
  24struct smack_known smack_known_hat = {
  25        .smk_known      = "^",
  26        .smk_secid      = 3,
  27};
  28
  29struct smack_known smack_known_star = {
  30        .smk_known      = "*",
  31        .smk_secid      = 4,
  32};
  33
  34struct smack_known smack_known_floor = {
  35        .smk_known      = "_",
  36        .smk_secid      = 5,
  37};
  38
  39struct smack_known smack_known_invalid = {
  40        .smk_known      = "",
  41        .smk_secid      = 6,
  42};
  43
  44struct smack_known smack_known_web = {
  45        .smk_known      = "@",
  46        .smk_secid      = 7,
  47};
  48
  49LIST_HEAD(smack_known_list);
  50
  51/*
  52 * The initial value needs to be bigger than any of the
  53 * known values above.
  54 */
  55static u32 smack_next_secid = 10;
  56
  57/*
  58 * what events do we log
  59 * can be overwritten at run-time by /smack/logging
  60 */
  61int log_policy = SMACK_AUDIT_DENIED;
  62
  63/**
  64 * smk_access_entry - look up matching access rule
  65 * @subject_label: a pointer to the subject's Smack label
  66 * @object_label: a pointer to the object's Smack label
  67 * @rule_list: the list of rules to search
  68 *
  69 * This function looks up the subject/object pair in the
  70 * access rule list and returns the access mode. If no
  71 * entry is found returns -ENOENT.
  72 *
  73 * NOTE:
  74 *
  75 * Earlier versions of this function allowed for labels that
  76 * were not on the label list. This was done to allow for
  77 * labels to come over the network that had never been seen
  78 * before on this host. Unless the receiving socket has the
  79 * star label this will always result in a failure check. The
  80 * star labeled socket case is now handled in the networking
  81 * hooks so there is no case where the label is not on the
  82 * label list. Checking to see if the address of two labels
  83 * is the same is now a reliable test.
  84 *
  85 * Do the object check first because that is more
  86 * likely to differ.
  87 *
  88 * Allowing write access implies allowing locking.
  89 */
  90int smk_access_entry(char *subject_label, char *object_label,
  91                        struct list_head *rule_list)
  92{
  93        int may = -ENOENT;
  94        struct smack_rule *srp;
  95
  96        list_for_each_entry_rcu(srp, rule_list, list) {
  97                if (srp->smk_object->smk_known == object_label &&
  98                    srp->smk_subject->smk_known == subject_label) {
  99                        may = srp->smk_access;
 100                        break;
 101                }
 102        }
 103
 104        /*
 105         * MAY_WRITE implies MAY_LOCK.
 106         */
 107        if ((may & MAY_WRITE) == MAY_WRITE)
 108                may |= MAY_LOCK;
 109        return may;
 110}
 111
 112/**
 113 * smk_access - determine if a subject has a specific access to an object
 114 * @subject: a pointer to the subject's Smack label entry
 115 * @object: a pointer to the object's Smack label entry
 116 * @request: the access requested, in "MAY" format
 117 * @a : a pointer to the audit data
 118 *
 119 * This function looks up the subject/object pair in the
 120 * access rule list and returns 0 if the access is permitted,
 121 * non zero otherwise.
 122 *
 123 * Smack labels are shared on smack_list
 124 */
 125int smk_access(struct smack_known *subject, struct smack_known *object,
 126               int request, struct smk_audit_info *a)
 127{
 128        int may = MAY_NOT;
 129        int rc = 0;
 130
 131        /*
 132         * Hardcoded comparisons.
 133         */
 134        /*
 135         * A star subject can't access any object.
 136         */
 137        if (subject == &smack_known_star) {
 138                rc = -EACCES;
 139                goto out_audit;
 140        }
 141        /*
 142         * An internet object can be accessed by any subject.
 143         * Tasks cannot be assigned the internet label.
 144         * An internet subject can access any object.
 145         */
 146        if (object == &smack_known_web || subject == &smack_known_web)
 147                goto out_audit;
 148        /*
 149         * A star object can be accessed by any subject.
 150         */
 151        if (object == &smack_known_star)
 152                goto out_audit;
 153        /*
 154         * An object can be accessed in any way by a subject
 155         * with the same label.
 156         */
 157        if (subject->smk_known == object->smk_known)
 158                goto out_audit;
 159        /*
 160         * A hat subject can read or lock any object.
 161         * A floor object can be read or locked by any subject.
 162         */
 163        if ((request & MAY_ANYREAD) == request ||
 164            (request & MAY_LOCK) == request) {
 165                if (object == &smack_known_floor)
 166                        goto out_audit;
 167                if (subject == &smack_known_hat)
 168                        goto out_audit;
 169        }
 170        /*
 171         * Beyond here an explicit relationship is required.
 172         * If the requested access is contained in the available
 173         * access (e.g. read is included in readwrite) it's
 174         * good. A negative response from smk_access_entry()
 175         * indicates there is no entry for this pair.
 176         */
 177        rcu_read_lock();
 178        may = smk_access_entry(subject->smk_known, object->smk_known,
 179                               &subject->smk_rules);
 180        rcu_read_unlock();
 181
 182        if (may <= 0 || (request & may) != request) {
 183                rc = -EACCES;
 184                goto out_audit;
 185        }
 186#ifdef CONFIG_SECURITY_SMACK_BRINGUP
 187        /*
 188         * Return a positive value if using bringup mode.
 189         * This allows the hooks to identify checks that
 190         * succeed because of "b" rules.
 191         */
 192        if (may & MAY_BRINGUP)
 193                rc = SMACK_BRINGUP_ALLOW;
 194#endif
 195
 196out_audit:
 197
 198#ifdef CONFIG_SECURITY_SMACK_BRINGUP
 199        if (rc < 0) {
 200                if (object == smack_unconfined)
 201                        rc = SMACK_UNCONFINED_OBJECT;
 202                if (subject == smack_unconfined)
 203                        rc = SMACK_UNCONFINED_SUBJECT;
 204        }
 205#endif
 206
 207#ifdef CONFIG_AUDIT
 208        if (a)
 209                smack_log(subject->smk_known, object->smk_known,
 210                          request, rc, a);
 211#endif
 212
 213        return rc;
 214}
 215
 216/**
 217 * smk_tskacc - determine if a task has a specific access to an object
 218 * @tsp: a pointer to the subject's task
 219 * @obj_known: a pointer to the object's label entry
 220 * @mode: the access requested, in "MAY" format
 221 * @a : common audit data
 222 *
 223 * This function checks the subject task's label/object label pair
 224 * in the access rule list and returns 0 if the access is permitted,
 225 * non zero otherwise. It allows that the task may have the capability
 226 * to override the rules.
 227 */
 228int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
 229               u32 mode, struct smk_audit_info *a)
 230{
 231        struct smack_known *sbj_known = smk_of_task(tsp);
 232        int may;
 233        int rc;
 234
 235        /*
 236         * Check the global rule list
 237         */
 238        rc = smk_access(sbj_known, obj_known, mode, NULL);
 239        if (rc >= 0) {
 240                /*
 241                 * If there is an entry in the task's rule list
 242                 * it can further restrict access.
 243                 */
 244                may = smk_access_entry(sbj_known->smk_known,
 245                                       obj_known->smk_known,
 246                                       &tsp->smk_rules);
 247                if (may < 0)
 248                        goto out_audit;
 249                if ((mode & may) == mode)
 250                        goto out_audit;
 251                rc = -EACCES;
 252        }
 253
 254        /*
 255         * Allow for priviliged to override policy.
 256         */
 257        if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE))
 258                rc = 0;
 259
 260out_audit:
 261#ifdef CONFIG_AUDIT
 262        if (a)
 263                smack_log(sbj_known->smk_known, obj_known->smk_known,
 264                          mode, rc, a);
 265#endif
 266        return rc;
 267}
 268
 269/**
 270 * smk_curacc - determine if current has a specific access to an object
 271 * @obj_known: a pointer to the object's Smack label entry
 272 * @mode: the access requested, in "MAY" format
 273 * @a : common audit data
 274 *
 275 * This function checks the current subject label/object label pair
 276 * in the access rule list and returns 0 if the access is permitted,
 277 * non zero otherwise. It allows that current may have the capability
 278 * to override the rules.
 279 */
 280int smk_curacc(struct smack_known *obj_known,
 281               u32 mode, struct smk_audit_info *a)
 282{
 283        struct task_smack *tsp = current_security();
 284
 285        return smk_tskacc(tsp, obj_known, mode, a);
 286}
 287
 288#ifdef CONFIG_AUDIT
 289/**
 290 * smack_str_from_perm : helper to transalate an int to a
 291 * readable string
 292 * @string : the string to fill
 293 * @access : the int
 294 *
 295 */
 296static inline void smack_str_from_perm(char *string, int access)
 297{
 298        int i = 0;
 299
 300        if (access & MAY_READ)
 301                string[i++] = 'r';
 302        if (access & MAY_WRITE)
 303                string[i++] = 'w';
 304        if (access & MAY_EXEC)
 305                string[i++] = 'x';
 306        if (access & MAY_APPEND)
 307                string[i++] = 'a';
 308        if (access & MAY_TRANSMUTE)
 309                string[i++] = 't';
 310        if (access & MAY_LOCK)
 311                string[i++] = 'l';
 312        string[i] = '\0';
 313}
 314/**
 315 * smack_log_callback - SMACK specific information
 316 * will be called by generic audit code
 317 * @ab : the audit_buffer
 318 * @a  : audit_data
 319 *
 320 */
 321static void smack_log_callback(struct audit_buffer *ab, void *a)
 322{
 323        struct common_audit_data *ad = a;
 324        struct smack_audit_data *sad = ad->smack_audit_data;
 325        audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
 326                         ad->smack_audit_data->function,
 327                         sad->result ? "denied" : "granted");
 328        audit_log_format(ab, " subject=");
 329        audit_log_untrustedstring(ab, sad->subject);
 330        audit_log_format(ab, " object=");
 331        audit_log_untrustedstring(ab, sad->object);
 332        if (sad->request[0] == '\0')
 333                audit_log_format(ab, " labels_differ");
 334        else
 335                audit_log_format(ab, " requested=%s", sad->request);
 336}
 337
 338/**
 339 *  smack_log - Audit the granting or denial of permissions.
 340 *  @subject_label : smack label of the requester
 341 *  @object_label  : smack label of the object being accessed
 342 *  @request: requested permissions
 343 *  @result: result from smk_access
 344 *  @a:  auxiliary audit data
 345 *
 346 * Audit the granting or denial of permissions in accordance
 347 * with the policy.
 348 */
 349void smack_log(char *subject_label, char *object_label, int request,
 350               int result, struct smk_audit_info *ad)
 351{
 352#ifdef CONFIG_SECURITY_SMACK_BRINGUP
 353        char request_buffer[SMK_NUM_ACCESS_TYPE + 5];
 354#else
 355        char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
 356#endif
 357        struct smack_audit_data *sad;
 358        struct common_audit_data *a = &ad->a;
 359
 360        /* check if we have to log the current event */
 361        if (result < 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
 362                return;
 363        if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
 364                return;
 365
 366        sad = a->smack_audit_data;
 367
 368        if (sad->function == NULL)
 369                sad->function = "unknown";
 370
 371        /* end preparing the audit data */
 372        smack_str_from_perm(request_buffer, request);
 373        sad->subject = subject_label;
 374        sad->object  = object_label;
 375#ifdef CONFIG_SECURITY_SMACK_BRINGUP
 376        /*
 377         * The result may be positive in bringup mode.
 378         * A positive result is an allow, but not for normal reasons.
 379         * Mark it as successful, but don't filter it out even if
 380         * the logging policy says to do so.
 381         */
 382        if (result == SMACK_UNCONFINED_SUBJECT)
 383                strcat(request_buffer, "(US)");
 384        else if (result == SMACK_UNCONFINED_OBJECT)
 385                strcat(request_buffer, "(UO)");
 386
 387        if (result > 0)
 388                result = 0;
 389#endif
 390        sad->request = request_buffer;
 391        sad->result  = result;
 392
 393        common_lsm_audit(a, smack_log_callback, NULL);
 394}
 395#else /* #ifdef CONFIG_AUDIT */
 396void smack_log(char *subject_label, char *object_label, int request,
 397               int result, struct smk_audit_info *ad)
 398{
 399}
 400#endif
 401
 402DEFINE_MUTEX(smack_known_lock);
 403
 404struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
 405
 406/**
 407 * smk_insert_entry - insert a smack label into a hash map,
 408 *
 409 * this function must be called under smack_known_lock
 410 */
 411void smk_insert_entry(struct smack_known *skp)
 412{
 413        unsigned int hash;
 414        struct hlist_head *head;
 415
 416        hash = full_name_hash(skp->smk_known, strlen(skp->smk_known));
 417        head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
 418
 419        hlist_add_head_rcu(&skp->smk_hashed, head);
 420        list_add_rcu(&skp->list, &smack_known_list);
 421}
 422
 423/**
 424 * smk_find_entry - find a label on the list, return the list entry
 425 * @string: a text string that might be a Smack label
 426 *
 427 * Returns a pointer to the entry in the label list that
 428 * matches the passed string or NULL if not found.
 429 */
 430struct smack_known *smk_find_entry(const char *string)
 431{
 432        unsigned int hash;
 433        struct hlist_head *head;
 434        struct smack_known *skp;
 435
 436        hash = full_name_hash(string, strlen(string));
 437        head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
 438
 439        hlist_for_each_entry_rcu(skp, head, smk_hashed)
 440                if (strcmp(skp->smk_known, string) == 0)
 441                        return skp;
 442
 443        return NULL;
 444}
 445
 446/**
 447 * smk_parse_smack - parse smack label from a text string
 448 * @string: a text string that might contain a Smack label
 449 * @len: the maximum size, or zero if it is NULL terminated.
 450 *
 451 * Returns a pointer to the clean label or an error code.
 452 */
 453char *smk_parse_smack(const char *string, int len)
 454{
 455        char *smack;
 456        int i;
 457
 458        if (len <= 0)
 459                len = strlen(string) + 1;
 460
 461        /*
 462         * Reserve a leading '-' as an indicator that
 463         * this isn't a label, but an option to interfaces
 464         * including /smack/cipso and /smack/cipso2
 465         */
 466        if (string[0] == '-')
 467                return ERR_PTR(-EINVAL);
 468
 469        for (i = 0; i < len; i++)
 470                if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
 471                    string[i] == '"' || string[i] == '\\' || string[i] == '\'')
 472                        break;
 473
 474        if (i == 0 || i >= SMK_LONGLABEL)
 475                return ERR_PTR(-EINVAL);
 476
 477        smack = kzalloc(i + 1, GFP_KERNEL);
 478        if (smack == NULL)
 479                return ERR_PTR(-ENOMEM);
 480
 481        strncpy(smack, string, i);
 482
 483        return smack;
 484}
 485
 486/**
 487 * smk_netlbl_mls - convert a catset to netlabel mls categories
 488 * @catset: the Smack categories
 489 * @sap: where to put the netlabel categories
 490 *
 491 * Allocates and fills attr.mls
 492 * Returns 0 on success, error code on failure.
 493 */
 494int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
 495                        int len)
 496{
 497        unsigned char *cp;
 498        unsigned char m;
 499        int cat;
 500        int rc;
 501        int byte;
 502
 503        sap->flags |= NETLBL_SECATTR_MLS_CAT;
 504        sap->attr.mls.lvl = level;
 505        sap->attr.mls.cat = NULL;
 506
 507        for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
 508                for (m = 0x80; m != 0; m >>= 1, cat++) {
 509                        if ((m & *cp) == 0)
 510                                continue;
 511                        rc = netlbl_catmap_setbit(&sap->attr.mls.cat,
 512                                                  cat, GFP_ATOMIC);
 513                        if (rc < 0) {
 514                                netlbl_catmap_free(sap->attr.mls.cat);
 515                                return rc;
 516                        }
 517                }
 518
 519        return 0;
 520}
 521
 522/**
 523 * smk_import_entry - import a label, return the list entry
 524 * @string: a text string that might be a Smack label
 525 * @len: the maximum size, or zero if it is NULL terminated.
 526 *
 527 * Returns a pointer to the entry in the label list that
 528 * matches the passed string, adding it if necessary,
 529 * or an error code.
 530 */
 531struct smack_known *smk_import_entry(const char *string, int len)
 532{
 533        struct smack_known *skp;
 534        char *smack;
 535        int slen;
 536        int rc;
 537
 538        smack = smk_parse_smack(string, len);
 539        if (IS_ERR(smack))
 540                return ERR_CAST(smack);
 541
 542        mutex_lock(&smack_known_lock);
 543
 544        skp = smk_find_entry(smack);
 545        if (skp != NULL)
 546                goto freeout;
 547
 548        skp = kzalloc(sizeof(*skp), GFP_KERNEL);
 549        if (skp == NULL) {
 550                skp = ERR_PTR(-ENOMEM);
 551                goto freeout;
 552        }
 553
 554        skp->smk_known = smack;
 555        skp->smk_secid = smack_next_secid++;
 556        skp->smk_netlabel.domain = skp->smk_known;
 557        skp->smk_netlabel.flags =
 558                NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
 559        /*
 560         * If direct labeling works use it.
 561         * Otherwise use mapped labeling.
 562         */
 563        slen = strlen(smack);
 564        if (slen < SMK_CIPSOLEN)
 565                rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
 566                               &skp->smk_netlabel, slen);
 567        else
 568                rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
 569                               &skp->smk_netlabel, sizeof(skp->smk_secid));
 570
 571        if (rc >= 0) {
 572                INIT_LIST_HEAD(&skp->smk_rules);
 573                mutex_init(&skp->smk_rules_lock);
 574                /*
 575                 * Make sure that the entry is actually
 576                 * filled before putting it on the list.
 577                 */
 578                smk_insert_entry(skp);
 579                goto unlockout;
 580        }
 581        /*
 582         * smk_netlbl_mls failed.
 583         */
 584        kfree(skp);
 585        skp = ERR_PTR(rc);
 586freeout:
 587        kfree(smack);
 588unlockout:
 589        mutex_unlock(&smack_known_lock);
 590
 591        return skp;
 592}
 593
 594/**
 595 * smack_from_secid - find the Smack label associated with a secid
 596 * @secid: an integer that might be associated with a Smack label
 597 *
 598 * Returns a pointer to the appropriate Smack label entry if there is one,
 599 * otherwise a pointer to the invalid Smack label.
 600 */
 601struct smack_known *smack_from_secid(const u32 secid)
 602{
 603        struct smack_known *skp;
 604
 605        rcu_read_lock();
 606        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 607                if (skp->smk_secid == secid) {
 608                        rcu_read_unlock();
 609                        return skp;
 610                }
 611        }
 612
 613        /*
 614         * If we got this far someone asked for the translation
 615         * of a secid that is not on the list.
 616         */
 617        rcu_read_unlock();
 618        return &smack_known_invalid;
 619}
 620
 621/*
 622 * Unless a process is running with one of these labels
 623 * even having CAP_MAC_OVERRIDE isn't enough to grant
 624 * privilege to violate MAC policy. If no labels are
 625 * designated (the empty list case) capabilities apply to
 626 * everyone.
 627 */
 628LIST_HEAD(smack_onlycap_list);
 629DEFINE_MUTEX(smack_onlycap_lock);
 630
 631/*
 632 * Is the task privileged and allowed to be privileged
 633 * by the onlycap rule.
 634 *
 635 * Returns 1 if the task is allowed to be privileged, 0 if it's not.
 636 */
 637int smack_privileged(int cap)
 638{
 639        struct smack_known *skp = smk_of_current();
 640        struct smack_known_list_elem *sklep;
 641
 642        /*
 643         * All kernel tasks are privileged
 644         */
 645        if (unlikely(current->flags & PF_KTHREAD))
 646                return 1;
 647
 648        if (!capable(cap))
 649                return 0;
 650
 651        rcu_read_lock();
 652        if (list_empty(&smack_onlycap_list)) {
 653                rcu_read_unlock();
 654                return 1;
 655        }
 656
 657        list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
 658                if (sklep->smk_label == skp) {
 659                        rcu_read_unlock();
 660                        return 1;
 661                }
 662        }
 663        rcu_read_unlock();
 664
 665        return 0;
 666}
 667