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 *
  74 * This function looks up the subject/object pair in the
  75 * access rule list and returns pointer to the matching rule if found,
  76 * NULL otherwise.
  77 *
  78 * NOTE:
  79 * Even though Smack labels are usually shared on smack_list
  80 * labels that come in off the network can't be imported
  81 * and added to the list for locking reasons.
  82 *
  83 * Therefore, it is necessary to check the contents of the labels,
  84 * not just the pointer values. Of course, in most cases the labels
  85 * will be on the list, so checking the pointers may be a worthwhile
  86 * optimization.
  87 */
  88int smk_access_entry(char *subject_label, char *object_label)
  89{
  90        u32 may = MAY_NOT;
  91        struct smack_rule *srp;
  92
  93        rcu_read_lock();
  94        list_for_each_entry_rcu(srp, &smack_rule_list, list) {
  95                if (srp->smk_subject == subject_label ||
  96                    strcmp(srp->smk_subject, subject_label) == 0) {
  97                        if (srp->smk_object == object_label ||
  98                            strcmp(srp->smk_object, object_label) == 0) {
  99                                may = srp->smk_access;
 100                                break;
 101                        }
 102                }
 103        }
 104        rcu_read_unlock();
 105
 106        return may;
 107}
 108
 109/**
 110 * smk_access - determine if a subject has a specific access to an object
 111 * @subject_label: a pointer to the subject's Smack label
 112 * @object_label: a pointer to the object's Smack label
 113 * @request: the access requested, in "MAY" format
 114 * @a : a pointer to the audit data
 115 *
 116 * This function looks up the subject/object pair in the
 117 * access rule list and returns 0 if the access is permitted,
 118 * non zero otherwise.
 119 *
 120 * Even though Smack labels are usually shared on smack_list
 121 * labels that come in off the network can't be imported
 122 * and added to the list for locking reasons.
 123 *
 124 * Therefore, it is necessary to check the contents of the labels,
 125 * not just the pointer values. Of course, in most cases the labels
 126 * will be on the list, so checking the pointers may be a worthwhile
 127 * optimization.
 128 */
 129int smk_access(char *subject_label, char *object_label, int request,
 130               struct smk_audit_info *a)
 131{
 132        u32 may = MAY_NOT;
 133        int rc = 0;
 134
 135        /*
 136         * Hardcoded comparisons.
 137         *
 138         * A star subject can't access any object.
 139         */
 140        if (subject_label == smack_known_star.smk_known ||
 141            strcmp(subject_label, smack_known_star.smk_known) == 0) {
 142                rc = -EACCES;
 143                goto out_audit;
 144        }
 145        /*
 146         * An internet object can be accessed by any subject.
 147         * Tasks cannot be assigned the internet label.
 148         * An internet subject can access any object.
 149         */
 150        if (object_label == smack_known_web.smk_known ||
 151            subject_label == smack_known_web.smk_known ||
 152            strcmp(object_label, smack_known_web.smk_known) == 0 ||
 153            strcmp(subject_label, smack_known_web.smk_known) == 0)
 154                goto out_audit;
 155        /*
 156         * A star object can be accessed by any subject.
 157         */
 158        if (object_label == smack_known_star.smk_known ||
 159            strcmp(object_label, smack_known_star.smk_known) == 0)
 160                goto out_audit;
 161        /*
 162         * An object can be accessed in any way by a subject
 163         * with the same label.
 164         */
 165        if (subject_label == object_label ||
 166            strcmp(subject_label, object_label) == 0)
 167                goto out_audit;
 168        /*
 169         * A hat subject can read any object.
 170         * A floor object can be read by any subject.
 171         */
 172        if ((request & MAY_ANYREAD) == request) {
 173                if (object_label == smack_known_floor.smk_known ||
 174                    strcmp(object_label, smack_known_floor.smk_known) == 0)
 175                        goto out_audit;
 176                if (subject_label == smack_known_hat.smk_known ||
 177                    strcmp(subject_label, smack_known_hat.smk_known) == 0)
 178                        goto out_audit;
 179        }
 180        /*
 181         * Beyond here an explicit relationship is required.
 182         * If the requested access is contained in the available
 183         * access (e.g. read is included in readwrite) it's
 184         * good.
 185         */
 186        may = smk_access_entry(subject_label, object_label);
 187        /*
 188         * This is a bit map operation.
 189         */
 190        if ((request & may) == request)
 191                goto out_audit;
 192
 193        rc = -EACCES;
 194out_audit:
 195#ifdef CONFIG_AUDIT
 196        if (a)
 197                smack_log(subject_label, object_label, request, rc, a);
 198#endif
 199        return rc;
 200}
 201
 202/**
 203 * smk_curacc - determine if current has a specific access to an object
 204 * @obj_label: a pointer to the object's Smack label
 205 * @mode: the access requested, in "MAY" format
 206 * @a : common audit data
 207 *
 208 * This function checks the current subject label/object label pair
 209 * in the access rule list and returns 0 if the access is permitted,
 210 * non zero otherwise. It allows that current may have the capability
 211 * to override the rules.
 212 */
 213int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
 214{
 215        int rc;
 216        char *sp = smk_of_current();
 217
 218        rc = smk_access(sp, obj_label, mode, NULL);
 219        if (rc == 0)
 220                goto out_audit;
 221
 222        /*
 223         * Return if a specific label has been designated as the
 224         * only one that gets privilege and current does not
 225         * have that label.
 226         */
 227        if (smack_onlycap != NULL && smack_onlycap != sp)
 228                goto out_audit;
 229
 230        if (capable(CAP_MAC_OVERRIDE))
 231                return 0;
 232
 233out_audit:
 234#ifdef CONFIG_AUDIT
 235        if (a)
 236                smack_log(sp, obj_label, mode, rc, a);
 237#endif
 238        return rc;
 239}
 240
 241#ifdef CONFIG_AUDIT
 242/**
 243 * smack_str_from_perm : helper to transalate an int to a
 244 * readable string
 245 * @string : the string to fill
 246 * @access : the int
 247 *
 248 */
 249static inline void smack_str_from_perm(char *string, int access)
 250{
 251        int i = 0;
 252        if (access & MAY_READ)
 253                string[i++] = 'r';
 254        if (access & MAY_WRITE)
 255                string[i++] = 'w';
 256        if (access & MAY_EXEC)
 257                string[i++] = 'x';
 258        if (access & MAY_APPEND)
 259                string[i++] = 'a';
 260        string[i] = '\0';
 261}
 262/**
 263 * smack_log_callback - SMACK specific information
 264 * will be called by generic audit code
 265 * @ab : the audit_buffer
 266 * @a  : audit_data
 267 *
 268 */
 269static void smack_log_callback(struct audit_buffer *ab, void *a)
 270{
 271        struct common_audit_data *ad = a;
 272        struct smack_audit_data *sad = &ad->smack_audit_data;
 273        audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
 274                         ad->smack_audit_data.function,
 275                         sad->result ? "denied" : "granted");
 276        audit_log_format(ab, " subject=");
 277        audit_log_untrustedstring(ab, sad->subject);
 278        audit_log_format(ab, " object=");
 279        audit_log_untrustedstring(ab, sad->object);
 280        audit_log_format(ab, " requested=%s", sad->request);
 281}
 282
 283/**
 284 *  smack_log - Audit the granting or denial of permissions.
 285 *  @subject_label : smack label of the requester
 286 *  @object_label  : smack label of the object being accessed
 287 *  @request: requested permissions
 288 *  @result: result from smk_access
 289 *  @a:  auxiliary audit data
 290 *
 291 * Audit the granting or denial of permissions in accordance
 292 * with the policy.
 293 */
 294void smack_log(char *subject_label, char *object_label, int request,
 295               int result, struct smk_audit_info *ad)
 296{
 297        char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
 298        struct smack_audit_data *sad;
 299        struct common_audit_data *a = &ad->a;
 300
 301        /* check if we have to log the current event */
 302        if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
 303                return;
 304        if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
 305                return;
 306
 307        if (a->smack_audit_data.function == NULL)
 308                a->smack_audit_data.function = "unknown";
 309
 310        /* end preparing the audit data */
 311        sad = &a->smack_audit_data;
 312        smack_str_from_perm(request_buffer, request);
 313        sad->subject = subject_label;
 314        sad->object  = object_label;
 315        sad->request = request_buffer;
 316        sad->result  = result;
 317        a->lsm_pre_audit = smack_log_callback;
 318
 319        common_lsm_audit(a);
 320}
 321#else /* #ifdef CONFIG_AUDIT */
 322void smack_log(char *subject_label, char *object_label, int request,
 323               int result, struct smk_audit_info *ad)
 324{
 325}
 326#endif
 327
 328static DEFINE_MUTEX(smack_known_lock);
 329
 330/**
 331 * smk_import_entry - import a label, return the list entry
 332 * @string: a text string that might be a Smack label
 333 * @len: the maximum size, or zero if it is NULL terminated.
 334 *
 335 * Returns a pointer to the entry in the label list that
 336 * matches the passed string, adding it if necessary.
 337 */
 338struct smack_known *smk_import_entry(const char *string, int len)
 339{
 340        struct smack_known *skp;
 341        char smack[SMK_LABELLEN];
 342        int found;
 343        int i;
 344
 345        if (len <= 0 || len > SMK_MAXLEN)
 346                len = SMK_MAXLEN;
 347
 348        for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
 349                if (found)
 350                        smack[i] = '\0';
 351                else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
 352                         string[i] == '/' || string[i] == '"' ||
 353                         string[i] == '\\' || string[i] == '\'') {
 354                        smack[i] = '\0';
 355                        found = 1;
 356                } else
 357                        smack[i] = string[i];
 358        }
 359
 360        if (smack[0] == '\0')
 361                return NULL;
 362
 363        mutex_lock(&smack_known_lock);
 364
 365        found = 0;
 366        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 367                if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
 368                        found = 1;
 369                        break;
 370                }
 371        }
 372
 373        if (found == 0) {
 374                skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
 375                if (skp != NULL) {
 376                        strncpy(skp->smk_known, smack, SMK_MAXLEN);
 377                        skp->smk_secid = smack_next_secid++;
 378                        skp->smk_cipso = NULL;
 379                        spin_lock_init(&skp->smk_cipsolock);
 380                        /*
 381                         * Make sure that the entry is actually
 382                         * filled before putting it on the list.
 383                         */
 384                        list_add_rcu(&skp->list, &smack_known_list);
 385                }
 386        }
 387
 388        mutex_unlock(&smack_known_lock);
 389
 390        return skp;
 391}
 392
 393/**
 394 * smk_import - import a smack label
 395 * @string: a text string that might be a Smack label
 396 * @len: the maximum size, or zero if it is NULL terminated.
 397 *
 398 * Returns a pointer to the label in the label list that
 399 * matches the passed string, adding it if necessary.
 400 */
 401char *smk_import(const char *string, int len)
 402{
 403        struct smack_known *skp;
 404
 405        /* labels cannot begin with a '-' */
 406        if (string[0] == '-')
 407                return NULL;
 408        skp = smk_import_entry(string, len);
 409        if (skp == NULL)
 410                return NULL;
 411        return skp->smk_known;
 412}
 413
 414/**
 415 * smack_from_secid - find the Smack label associated with a secid
 416 * @secid: an integer that might be associated with a Smack label
 417 *
 418 * Returns a pointer to the appropraite Smack label if there is one,
 419 * otherwise a pointer to the invalid Smack label.
 420 */
 421char *smack_from_secid(const u32 secid)
 422{
 423        struct smack_known *skp;
 424
 425        rcu_read_lock();
 426        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 427                if (skp->smk_secid == secid) {
 428                        rcu_read_unlock();
 429                        return skp->smk_known;
 430                }
 431        }
 432
 433        /*
 434         * If we got this far someone asked for the translation
 435         * of a secid that is not on the list.
 436         */
 437        rcu_read_unlock();
 438        return smack_known_invalid.smk_known;
 439}
 440
 441/**
 442 * smack_to_secid - find the secid associated with a Smack label
 443 * @smack: the Smack label
 444 *
 445 * Returns the appropriate secid if there is one,
 446 * otherwise 0
 447 */
 448u32 smack_to_secid(const char *smack)
 449{
 450        struct smack_known *skp;
 451
 452        rcu_read_lock();
 453        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 454                if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
 455                        rcu_read_unlock();
 456                        return skp->smk_secid;
 457                }
 458        }
 459        rcu_read_unlock();
 460        return 0;
 461}
 462
 463/**
 464 * smack_from_cipso - find the Smack label associated with a CIPSO option
 465 * @level: Bell & LaPadula level from the network
 466 * @cp: Bell & LaPadula categories from the network
 467 * @result: where to put the Smack value
 468 *
 469 * This is a simple lookup in the label table.
 470 *
 471 * This is an odd duck as far as smack handling goes in that
 472 * it sends back a copy of the smack label rather than a pointer
 473 * to the master list. This is done because it is possible for
 474 * a foreign host to send a smack label that is new to this
 475 * machine and hence not on the list. That would not be an
 476 * issue except that adding an entry to the master list can't
 477 * be done at that point.
 478 */
 479void smack_from_cipso(u32 level, char *cp, char *result)
 480{
 481        struct smack_known *kp;
 482        char *final = NULL;
 483
 484        rcu_read_lock();
 485        list_for_each_entry(kp, &smack_known_list, list) {
 486                if (kp->smk_cipso == NULL)
 487                        continue;
 488
 489                spin_lock_bh(&kp->smk_cipsolock);
 490
 491                if (kp->smk_cipso->smk_level == level &&
 492                    memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
 493                        final = kp->smk_known;
 494
 495                spin_unlock_bh(&kp->smk_cipsolock);
 496        }
 497        rcu_read_unlock();
 498        if (final == NULL)
 499                final = smack_known_huh.smk_known;
 500        strncpy(result, final, SMK_MAXLEN);
 501        return;
 502}
 503
 504/**
 505 * smack_to_cipso - find the CIPSO option to go with a Smack label
 506 * @smack: a pointer to the smack label in question
 507 * @cp: where to put the result
 508 *
 509 * Returns zero if a value is available, non-zero otherwise.
 510 */
 511int smack_to_cipso(const char *smack, struct smack_cipso *cp)
 512{
 513        struct smack_known *kp;
 514        int found = 0;
 515
 516        rcu_read_lock();
 517        list_for_each_entry_rcu(kp, &smack_known_list, list) {
 518                if (kp->smk_known == smack ||
 519                    strcmp(kp->smk_known, smack) == 0) {
 520                        found = 1;
 521                        break;
 522                }
 523        }
 524        rcu_read_unlock();
 525
 526        if (found == 0 || kp->smk_cipso == NULL)
 527                return -ENOENT;
 528
 529        memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
 530        return 0;
 531}
 532