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        .smk_cipso      = NULL,
  23};
  24
  25struct smack_known smack_known_hat = {
  26        .smk_known      = "^",
  27        .smk_secid      = 3,
  28        .smk_cipso      = NULL,
  29};
  30
  31struct smack_known smack_known_star = {
  32        .smk_known      = "*",
  33        .smk_secid      = 4,
  34        .smk_cipso      = NULL,
  35};
  36
  37struct smack_known smack_known_floor = {
  38        .smk_known      = "_",
  39        .smk_secid      = 5,
  40        .smk_cipso      = NULL,
  41};
  42
  43struct smack_known smack_known_invalid = {
  44        .smk_known      = "",
  45        .smk_secid      = 6,
  46        .smk_cipso      = NULL,
  47};
  48
  49struct smack_known smack_known_web = {
  50        .smk_known      = "@",
  51        .smk_secid      = 7,
  52        .smk_cipso      = NULL,
  53};
  54
  55LIST_HEAD(smack_known_list);
  56
  57/*
  58 * The initial value needs to be bigger than any of the
  59 * known values above.
  60 */
  61static u32 smack_next_secid = 10;
  62
  63/*
  64 * what events do we log
  65 * can be overwritten at run-time by /smack/logging
  66 */
  67int log_policy = SMACK_AUDIT_DENIED;
  68
  69/**
  70 * smk_access_entry - look up matching access rule
  71 * @subject_label: a pointer to the subject's Smack label
  72 * @object_label: a pointer to the object's Smack label
  73 * @rule_list: the list of rules to search
  74 *
  75 * This function looks up the subject/object pair in the
  76 * access rule list and returns the access mode. If no
  77 * entry is found returns -ENOENT.
  78 *
  79 * NOTE:
  80 *
  81 * Earlier versions of this function allowed for labels that
  82 * were not on the label list. This was done to allow for
  83 * labels to come over the network that had never been seen
  84 * before on this host. Unless the receiving socket has the
  85 * star label this will always result in a failure check. The
  86 * star labeled socket case is now handled in the networking
  87 * hooks so there is no case where the label is not on the
  88 * label list. Checking to see if the address of two labels
  89 * is the same is now a reliable test.
  90 *
  91 * Do the object check first because that is more
  92 * likely to differ.
  93 */
  94int smk_access_entry(char *subject_label, char *object_label,
  95                        struct list_head *rule_list)
  96{
  97        int may = -ENOENT;
  98        struct smack_rule *srp;
  99
 100        list_for_each_entry_rcu(srp, rule_list, list) {
 101                if (srp->smk_object == object_label &&
 102                    srp->smk_subject == subject_label) {
 103                        may = srp->smk_access;
 104                        break;
 105                }
 106        }
 107
 108        return may;
 109}
 110
 111/**
 112 * smk_access - determine if a subject has a specific access to an object
 113 * @subject_label: a pointer to the subject's Smack label
 114 * @object_label: a pointer to the object's Smack label
 115 * @request: the access requested, in "MAY" format
 116 * @a : a pointer to the audit data
 117 *
 118 * This function looks up the subject/object pair in the
 119 * access rule list and returns 0 if the access is permitted,
 120 * non zero otherwise.
 121 *
 122 * Smack labels are shared on smack_list
 123 */
 124int smk_access(char *subject_label, char *object_label, int request,
 125               struct smk_audit_info *a)
 126{
 127        struct smack_known *skp;
 128        int may = MAY_NOT;
 129        int rc = 0;
 130
 131        /*
 132         * Hardcoded comparisons.
 133         *
 134         * A star subject can't access any object.
 135         */
 136        if (subject_label == smack_known_star.smk_known) {
 137                rc = -EACCES;
 138                goto out_audit;
 139        }
 140        /*
 141         * An internet object can be accessed by any subject.
 142         * Tasks cannot be assigned the internet label.
 143         * An internet subject can access any object.
 144         */
 145        if (object_label == smack_known_web.smk_known ||
 146            subject_label == smack_known_web.smk_known)
 147                goto out_audit;
 148        /*
 149         * A star object can be accessed by any subject.
 150         */
 151        if (object_label == smack_known_star.smk_known)
 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_label == object_label)
 158                goto out_audit;
 159        /*
 160         * A hat subject can read any object.
 161         * A floor object can be read by any subject.
 162         */
 163        if ((request & MAY_ANYREAD) == request) {
 164                if (object_label == smack_known_floor.smk_known)
 165                        goto out_audit;
 166                if (subject_label == smack_known_hat.smk_known)
 167                        goto out_audit;
 168        }
 169        /*
 170         * Beyond here an explicit relationship is required.
 171         * If the requested access is contained in the available
 172         * access (e.g. read is included in readwrite) it's
 173         * good. A negative response from smk_access_entry()
 174         * indicates there is no entry for this pair.
 175         */
 176        skp = smk_find_entry(subject_label);
 177        rcu_read_lock();
 178        may = smk_access_entry(subject_label, object_label, &skp->smk_rules);
 179        rcu_read_unlock();
 180
 181        if (may > 0 && (request & may) == request)
 182                goto out_audit;
 183
 184        rc = -EACCES;
 185out_audit:
 186#ifdef CONFIG_AUDIT
 187        if (a)
 188                smack_log(subject_label, object_label, request, rc, a);
 189#endif
 190        return rc;
 191}
 192
 193/**
 194 * smk_curacc - determine if current has a specific access to an object
 195 * @obj_label: a pointer to the object's Smack label
 196 * @mode: the access requested, in "MAY" format
 197 * @a : common audit data
 198 *
 199 * This function checks the current subject label/object label pair
 200 * in the access rule list and returns 0 if the access is permitted,
 201 * non zero otherwise. It allows that current may have the capability
 202 * to override the rules.
 203 */
 204int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
 205{
 206        struct task_smack *tsp = current_security();
 207        char *sp = smk_of_task(tsp);
 208        int may;
 209        int rc;
 210
 211        /*
 212         * Check the global rule list
 213         */
 214        rc = smk_access(sp, obj_label, mode, NULL);
 215        if (rc == 0) {
 216                /*
 217                 * If there is an entry in the task's rule list
 218                 * it can further restrict access.
 219                 */
 220                may = smk_access_entry(sp, obj_label, &tsp->smk_rules);
 221                if (may < 0)
 222                        goto out_audit;
 223                if ((mode & may) == mode)
 224                        goto out_audit;
 225                rc = -EACCES;
 226        }
 227
 228        /*
 229         * Return if a specific label has been designated as the
 230         * only one that gets privilege and current does not
 231         * have that label.
 232         */
 233        if (smack_onlycap != NULL && smack_onlycap != sp)
 234                goto out_audit;
 235
 236        if (capable(CAP_MAC_OVERRIDE))
 237                rc = 0;
 238
 239out_audit:
 240#ifdef CONFIG_AUDIT
 241        if (a)
 242                smack_log(sp, obj_label, mode, rc, a);
 243#endif
 244        return rc;
 245}
 246
 247#ifdef CONFIG_AUDIT
 248/**
 249 * smack_str_from_perm : helper to transalate an int to a
 250 * readable string
 251 * @string : the string to fill
 252 * @access : the int
 253 *
 254 */
 255static inline void smack_str_from_perm(char *string, int access)
 256{
 257        int i = 0;
 258        if (access & MAY_READ)
 259                string[i++] = 'r';
 260        if (access & MAY_WRITE)
 261                string[i++] = 'w';
 262        if (access & MAY_EXEC)
 263                string[i++] = 'x';
 264        if (access & MAY_APPEND)
 265                string[i++] = 'a';
 266        string[i] = '\0';
 267}
 268/**
 269 * smack_log_callback - SMACK specific information
 270 * will be called by generic audit code
 271 * @ab : the audit_buffer
 272 * @a  : audit_data
 273 *
 274 */
 275static void smack_log_callback(struct audit_buffer *ab, void *a)
 276{
 277        struct common_audit_data *ad = a;
 278        struct smack_audit_data *sad = &ad->smack_audit_data;
 279        audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
 280                         ad->smack_audit_data.function,
 281                         sad->result ? "denied" : "granted");
 282        audit_log_format(ab, " subject=");
 283        audit_log_untrustedstring(ab, sad->subject);
 284        audit_log_format(ab, " object=");
 285        audit_log_untrustedstring(ab, sad->object);
 286        audit_log_format(ab, " requested=%s", sad->request);
 287}
 288
 289/**
 290 *  smack_log - Audit the granting or denial of permissions.
 291 *  @subject_label : smack label of the requester
 292 *  @object_label  : smack label of the object being accessed
 293 *  @request: requested permissions
 294 *  @result: result from smk_access
 295 *  @a:  auxiliary audit data
 296 *
 297 * Audit the granting or denial of permissions in accordance
 298 * with the policy.
 299 */
 300void smack_log(char *subject_label, char *object_label, int request,
 301               int result, struct smk_audit_info *ad)
 302{
 303        char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
 304        struct smack_audit_data *sad;
 305        struct common_audit_data *a = &ad->a;
 306
 307        /* check if we have to log the current event */
 308        if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
 309                return;
 310        if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
 311                return;
 312
 313        if (a->smack_audit_data.function == NULL)
 314                a->smack_audit_data.function = "unknown";
 315
 316        /* end preparing the audit data */
 317        sad = &a->smack_audit_data;
 318        smack_str_from_perm(request_buffer, request);
 319        sad->subject = subject_label;
 320        sad->object  = object_label;
 321        sad->request = request_buffer;
 322        sad->result  = result;
 323        a->lsm_pre_audit = smack_log_callback;
 324
 325        common_lsm_audit(a);
 326}
 327#else /* #ifdef CONFIG_AUDIT */
 328void smack_log(char *subject_label, char *object_label, int request,
 329               int result, struct smk_audit_info *ad)
 330{
 331}
 332#endif
 333
 334static DEFINE_MUTEX(smack_known_lock);
 335
 336/**
 337 * smk_find_entry - find a label on the list, return the list entry
 338 * @string: a text string that might be a Smack label
 339 *
 340 * Returns a pointer to the entry in the label list that
 341 * matches the passed string.
 342 */
 343struct smack_known *smk_find_entry(const char *string)
 344{
 345        struct smack_known *skp;
 346
 347        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 348                if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0)
 349                        return skp;
 350        }
 351
 352        return NULL;
 353}
 354
 355/**
 356 * smk_parse_smack - parse smack label from a text string
 357 * @string: a text string that might contain a Smack label
 358 * @len: the maximum size, or zero if it is NULL terminated.
 359 * @smack: parsed smack label, or NULL if parse error
 360 */
 361void smk_parse_smack(const char *string, int len, char *smack)
 362{
 363        int found;
 364        int i;
 365
 366        if (len <= 0 || len > SMK_MAXLEN)
 367                len = SMK_MAXLEN;
 368
 369        for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
 370                if (found)
 371                        smack[i] = '\0';
 372                else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
 373                         string[i] == '/' || string[i] == '"' ||
 374                         string[i] == '\\' || string[i] == '\'') {
 375                        smack[i] = '\0';
 376                        found = 1;
 377                } else
 378                        smack[i] = string[i];
 379        }
 380}
 381
 382/**
 383 * smk_import_entry - import a label, return the list entry
 384 * @string: a text string that might be a Smack label
 385 * @len: the maximum size, or zero if it is NULL terminated.
 386 *
 387 * Returns a pointer to the entry in the label list that
 388 * matches the passed string, adding it if necessary.
 389 */
 390struct smack_known *smk_import_entry(const char *string, int len)
 391{
 392        struct smack_known *skp;
 393        char smack[SMK_LABELLEN];
 394
 395        smk_parse_smack(string, len, smack);
 396        if (smack[0] == '\0')
 397                return NULL;
 398
 399        mutex_lock(&smack_known_lock);
 400
 401        skp = smk_find_entry(smack);
 402
 403        if (skp == NULL) {
 404                skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
 405                if (skp != NULL) {
 406                        strncpy(skp->smk_known, smack, SMK_MAXLEN);
 407                        skp->smk_secid = smack_next_secid++;
 408                        skp->smk_cipso = NULL;
 409                        INIT_LIST_HEAD(&skp->smk_rules);
 410                        spin_lock_init(&skp->smk_cipsolock);
 411                        mutex_init(&skp->smk_rules_lock);
 412                        /*
 413                         * Make sure that the entry is actually
 414                         * filled before putting it on the list.
 415                         */
 416                        list_add_rcu(&skp->list, &smack_known_list);
 417                }
 418        }
 419
 420        mutex_unlock(&smack_known_lock);
 421
 422        return skp;
 423}
 424
 425/**
 426 * smk_import - import a smack label
 427 * @string: a text string that might be a Smack label
 428 * @len: the maximum size, or zero if it is NULL terminated.
 429 *
 430 * Returns a pointer to the label in the label list that
 431 * matches the passed string, adding it if necessary.
 432 */
 433char *smk_import(const char *string, int len)
 434{
 435        struct smack_known *skp;
 436
 437        /* labels cannot begin with a '-' */
 438        if (string[0] == '-')
 439                return NULL;
 440        skp = smk_import_entry(string, len);
 441        if (skp == NULL)
 442                return NULL;
 443        return skp->smk_known;
 444}
 445
 446/**
 447 * smack_from_secid - find the Smack label associated with a secid
 448 * @secid: an integer that might be associated with a Smack label
 449 *
 450 * Returns a pointer to the appropriate Smack label if there is one,
 451 * otherwise a pointer to the invalid Smack label.
 452 */
 453char *smack_from_secid(const u32 secid)
 454{
 455        struct smack_known *skp;
 456
 457        rcu_read_lock();
 458        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 459                if (skp->smk_secid == secid) {
 460                        rcu_read_unlock();
 461                        return skp->smk_known;
 462                }
 463        }
 464
 465        /*
 466         * If we got this far someone asked for the translation
 467         * of a secid that is not on the list.
 468         */
 469        rcu_read_unlock();
 470        return smack_known_invalid.smk_known;
 471}
 472
 473/**
 474 * smack_to_secid - find the secid associated with a Smack label
 475 * @smack: the Smack label
 476 *
 477 * Returns the appropriate secid if there is one,
 478 * otherwise 0
 479 */
 480u32 smack_to_secid(const char *smack)
 481{
 482        struct smack_known *skp;
 483
 484        rcu_read_lock();
 485        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 486                if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
 487                        rcu_read_unlock();
 488                        return skp->smk_secid;
 489                }
 490        }
 491        rcu_read_unlock();
 492        return 0;
 493}
 494
 495/**
 496 * smack_from_cipso - find the Smack label associated with a CIPSO option
 497 * @level: Bell & LaPadula level from the network
 498 * @cp: Bell & LaPadula categories from the network
 499 *
 500 * This is a simple lookup in the label table.
 501 *
 502 * Return the matching label from the label list or NULL.
 503 */
 504char *smack_from_cipso(u32 level, char *cp)
 505{
 506        struct smack_known *kp;
 507        char *final = NULL;
 508
 509        rcu_read_lock();
 510        list_for_each_entry(kp, &smack_known_list, list) {
 511                if (kp->smk_cipso == NULL)
 512                        continue;
 513
 514                spin_lock_bh(&kp->smk_cipsolock);
 515
 516                if (kp->smk_cipso->smk_level == level &&
 517                    memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
 518                        final = kp->smk_known;
 519
 520                spin_unlock_bh(&kp->smk_cipsolock);
 521
 522                if (final != NULL)
 523                        break;
 524        }
 525        rcu_read_unlock();
 526
 527        return final;
 528}
 529
 530/**
 531 * smack_to_cipso - find the CIPSO option to go with a Smack label
 532 * @smack: a pointer to the smack label in question
 533 * @cp: where to put the result
 534 *
 535 * Returns zero if a value is available, non-zero otherwise.
 536 */
 537int smack_to_cipso(const char *smack, struct smack_cipso *cp)
 538{
 539        struct smack_known *kp;
 540        int found = 0;
 541
 542        rcu_read_lock();
 543        list_for_each_entry_rcu(kp, &smack_known_list, list) {
 544                if (kp->smk_known == smack ||
 545                    strcmp(kp->smk_known, smack) == 0) {
 546                        found = 1;
 547                        break;
 548                }
 549        }
 550        rcu_read_unlock();
 551
 552        if (found == 0 || kp->smk_cipso == NULL)
 553                return -ENOENT;
 554
 555        memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
 556        return 0;
 557}
 558