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 */
  88int smk_access_entry(char *subject_label, char *object_label,
  89                        struct list_head *rule_list)
  90{
  91        int may = -ENOENT;
  92        struct smack_rule *srp;
  93
  94        list_for_each_entry_rcu(srp, rule_list, list) {
  95                if (srp->smk_object == object_label &&
  96                    srp->smk_subject == subject_label) {
  97                        may = srp->smk_access;
  98                        break;
  99                }
 100        }
 101
 102        return may;
 103}
 104
 105/**
 106 * smk_access - determine if a subject has a specific access to an object
 107 * @subject_label: a pointer to the subject's Smack label
 108 * @object_label: a pointer to the object's Smack label
 109 * @request: the access requested, in "MAY" format
 110 * @a : a pointer to the audit data
 111 *
 112 * This function looks up the subject/object pair in the
 113 * access rule list and returns 0 if the access is permitted,
 114 * non zero otherwise.
 115 *
 116 * Smack labels are shared on smack_list
 117 */
 118int smk_access(char *subject_label, char *object_label, int request,
 119               struct smk_audit_info *a)
 120{
 121        struct smack_known *skp;
 122        int may = MAY_NOT;
 123        int rc = 0;
 124
 125        /*
 126         * Hardcoded comparisons.
 127         *
 128         * A star subject can't access any object.
 129         */
 130        if (subject_label == smack_known_star.smk_known) {
 131                rc = -EACCES;
 132                goto out_audit;
 133        }
 134        /*
 135         * An internet object can be accessed by any subject.
 136         * Tasks cannot be assigned the internet label.
 137         * An internet subject can access any object.
 138         */
 139        if (object_label == smack_known_web.smk_known ||
 140            subject_label == smack_known_web.smk_known)
 141                goto out_audit;
 142        /*
 143         * A star object can be accessed by any subject.
 144         */
 145        if (object_label == smack_known_star.smk_known)
 146                goto out_audit;
 147        /*
 148         * An object can be accessed in any way by a subject
 149         * with the same label.
 150         */
 151        if (subject_label == object_label)
 152                goto out_audit;
 153        /*
 154         * A hat subject can read any object.
 155         * A floor object can be read by any subject.
 156         */
 157        if ((request & MAY_ANYREAD) == request) {
 158                if (object_label == smack_known_floor.smk_known)
 159                        goto out_audit;
 160                if (subject_label == smack_known_hat.smk_known)
 161                        goto out_audit;
 162        }
 163        /*
 164         * Beyond here an explicit relationship is required.
 165         * If the requested access is contained in the available
 166         * access (e.g. read is included in readwrite) it's
 167         * good. A negative response from smk_access_entry()
 168         * indicates there is no entry for this pair.
 169         */
 170        skp = smk_find_entry(subject_label);
 171        rcu_read_lock();
 172        may = smk_access_entry(subject_label, object_label, &skp->smk_rules);
 173        rcu_read_unlock();
 174
 175        if (may > 0 && (request & may) == request)
 176                goto out_audit;
 177
 178        rc = -EACCES;
 179out_audit:
 180#ifdef CONFIG_AUDIT
 181        if (a)
 182                smack_log(subject_label, object_label, request, rc, a);
 183#endif
 184        return rc;
 185}
 186
 187/**
 188 * smk_curacc - determine if current has a specific access to an object
 189 * @obj_label: a pointer to the object's Smack label
 190 * @mode: the access requested, in "MAY" format
 191 * @a : common audit data
 192 *
 193 * This function checks the current subject label/object label pair
 194 * in the access rule list and returns 0 if the access is permitted,
 195 * non zero otherwise. It allows that current may have the capability
 196 * to override the rules.
 197 */
 198int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
 199{
 200        struct task_smack *tsp = current_security();
 201        char *sp = smk_of_task(tsp);
 202        int may;
 203        int rc;
 204
 205        /*
 206         * Check the global rule list
 207         */
 208        rc = smk_access(sp, obj_label, mode, NULL);
 209        if (rc == 0) {
 210                /*
 211                 * If there is an entry in the task's rule list
 212                 * it can further restrict access.
 213                 */
 214                may = smk_access_entry(sp, obj_label, &tsp->smk_rules);
 215                if (may < 0)
 216                        goto out_audit;
 217                if ((mode & may) == mode)
 218                        goto out_audit;
 219                rc = -EACCES;
 220        }
 221
 222        /*
 223         * Allow for priviliged to override policy.
 224         */
 225        if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE))
 226                rc = 0;
 227
 228out_audit:
 229#ifdef CONFIG_AUDIT
 230        if (a)
 231                smack_log(sp, obj_label, mode, rc, a);
 232#endif
 233        return rc;
 234}
 235
 236#ifdef CONFIG_AUDIT
 237/**
 238 * smack_str_from_perm : helper to transalate an int to a
 239 * readable string
 240 * @string : the string to fill
 241 * @access : the int
 242 *
 243 */
 244static inline void smack_str_from_perm(char *string, int access)
 245{
 246        int i = 0;
 247        if (access & MAY_READ)
 248                string[i++] = 'r';
 249        if (access & MAY_WRITE)
 250                string[i++] = 'w';
 251        if (access & MAY_EXEC)
 252                string[i++] = 'x';
 253        if (access & MAY_APPEND)
 254                string[i++] = 'a';
 255        string[i] = '\0';
 256}
 257/**
 258 * smack_log_callback - SMACK specific information
 259 * will be called by generic audit code
 260 * @ab : the audit_buffer
 261 * @a  : audit_data
 262 *
 263 */
 264static void smack_log_callback(struct audit_buffer *ab, void *a)
 265{
 266        struct common_audit_data *ad = a;
 267        struct smack_audit_data *sad = ad->smack_audit_data;
 268        audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
 269                         ad->smack_audit_data->function,
 270                         sad->result ? "denied" : "granted");
 271        audit_log_format(ab, " subject=");
 272        audit_log_untrustedstring(ab, sad->subject);
 273        audit_log_format(ab, " object=");
 274        audit_log_untrustedstring(ab, sad->object);
 275        audit_log_format(ab, " requested=%s", sad->request);
 276}
 277
 278/**
 279 *  smack_log - Audit the granting or denial of permissions.
 280 *  @subject_label : smack label of the requester
 281 *  @object_label  : smack label of the object being accessed
 282 *  @request: requested permissions
 283 *  @result: result from smk_access
 284 *  @a:  auxiliary audit data
 285 *
 286 * Audit the granting or denial of permissions in accordance
 287 * with the policy.
 288 */
 289void smack_log(char *subject_label, char *object_label, int request,
 290               int result, struct smk_audit_info *ad)
 291{
 292        char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
 293        struct smack_audit_data *sad;
 294        struct common_audit_data *a = &ad->a;
 295
 296        /* check if we have to log the current event */
 297        if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
 298                return;
 299        if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
 300                return;
 301
 302        sad = a->smack_audit_data;
 303
 304        if (sad->function == NULL)
 305                sad->function = "unknown";
 306
 307        /* end preparing the audit data */
 308        smack_str_from_perm(request_buffer, request);
 309        sad->subject = subject_label;
 310        sad->object  = object_label;
 311        sad->request = request_buffer;
 312        sad->result  = result;
 313
 314        common_lsm_audit(a, smack_log_callback, NULL);
 315}
 316#else /* #ifdef CONFIG_AUDIT */
 317void smack_log(char *subject_label, char *object_label, int request,
 318               int result, struct smk_audit_info *ad)
 319{
 320}
 321#endif
 322
 323DEFINE_MUTEX(smack_known_lock);
 324
 325/**
 326 * smk_find_entry - find a label on the list, return the list entry
 327 * @string: a text string that might be a Smack label
 328 *
 329 * Returns a pointer to the entry in the label list that
 330 * matches the passed string.
 331 */
 332struct smack_known *smk_find_entry(const char *string)
 333{
 334        struct smack_known *skp;
 335
 336        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 337                if (strcmp(skp->smk_known, string) == 0)
 338                        return skp;
 339        }
 340
 341        return NULL;
 342}
 343
 344/**
 345 * smk_parse_smack - parse smack label from a text string
 346 * @string: a text string that might contain a Smack label
 347 * @len: the maximum size, or zero if it is NULL terminated.
 348 *
 349 * Returns a pointer to the clean label, or NULL
 350 */
 351char *smk_parse_smack(const char *string, int len)
 352{
 353        char *smack;
 354        int i;
 355
 356        if (len <= 0)
 357                len = strlen(string) + 1;
 358
 359        /*
 360         * Reserve a leading '-' as an indicator that
 361         * this isn't a label, but an option to interfaces
 362         * including /smack/cipso and /smack/cipso2
 363         */
 364        if (string[0] == '-')
 365                return NULL;
 366
 367        for (i = 0; i < len; i++)
 368                if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
 369                    string[i] == '"' || string[i] == '\\' || string[i] == '\'')
 370                        break;
 371
 372        if (i == 0 || i >= SMK_LONGLABEL)
 373                return NULL;
 374
 375        smack = kzalloc(i + 1, GFP_KERNEL);
 376        if (smack != NULL) {
 377                strncpy(smack, string, i + 1);
 378                smack[i] = '\0';
 379        }
 380        return smack;
 381}
 382
 383/**
 384 * smk_netlbl_mls - convert a catset to netlabel mls categories
 385 * @catset: the Smack categories
 386 * @sap: where to put the netlabel categories
 387 *
 388 * Allocates and fills attr.mls
 389 * Returns 0 on success, error code on failure.
 390 */
 391int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
 392                        int len)
 393{
 394        unsigned char *cp;
 395        unsigned char m;
 396        int cat;
 397        int rc;
 398        int byte;
 399
 400        sap->flags |= NETLBL_SECATTR_MLS_CAT;
 401        sap->attr.mls.lvl = level;
 402        sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
 403        sap->attr.mls.cat->startbit = 0;
 404
 405        for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
 406                for (m = 0x80; m != 0; m >>= 1, cat++) {
 407                        if ((m & *cp) == 0)
 408                                continue;
 409                        rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat,
 410                                                          cat, GFP_ATOMIC);
 411                        if (rc < 0) {
 412                                netlbl_secattr_catmap_free(sap->attr.mls.cat);
 413                                return rc;
 414                        }
 415                }
 416
 417        return 0;
 418}
 419
 420/**
 421 * smk_import_entry - import a label, return the list entry
 422 * @string: a text string that might be a Smack label
 423 * @len: the maximum size, or zero if it is NULL terminated.
 424 *
 425 * Returns a pointer to the entry in the label list that
 426 * matches the passed string, adding it if necessary.
 427 */
 428struct smack_known *smk_import_entry(const char *string, int len)
 429{
 430        struct smack_known *skp;
 431        char *smack;
 432        int slen;
 433        int rc;
 434
 435        smack = smk_parse_smack(string, len);
 436        if (smack == NULL)
 437                return NULL;
 438
 439        mutex_lock(&smack_known_lock);
 440
 441        skp = smk_find_entry(smack);
 442        if (skp != NULL)
 443                goto freeout;
 444
 445        skp = kzalloc(sizeof(*skp), GFP_KERNEL);
 446        if (skp == NULL)
 447                goto freeout;
 448
 449        skp->smk_known = smack;
 450        skp->smk_secid = smack_next_secid++;
 451        skp->smk_netlabel.domain = skp->smk_known;
 452        skp->smk_netlabel.flags =
 453                NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
 454        /*
 455         * If direct labeling works use it.
 456         * Otherwise use mapped labeling.
 457         */
 458        slen = strlen(smack);
 459        if (slen < SMK_CIPSOLEN)
 460                rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
 461                               &skp->smk_netlabel, slen);
 462        else
 463                rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
 464                               &skp->smk_netlabel, sizeof(skp->smk_secid));
 465
 466        if (rc >= 0) {
 467                INIT_LIST_HEAD(&skp->smk_rules);
 468                mutex_init(&skp->smk_rules_lock);
 469                /*
 470                 * Make sure that the entry is actually
 471                 * filled before putting it on the list.
 472                 */
 473                list_add_rcu(&skp->list, &smack_known_list);
 474                goto unlockout;
 475        }
 476        /*
 477         * smk_netlbl_mls failed.
 478         */
 479        kfree(skp);
 480        skp = NULL;
 481freeout:
 482        kfree(smack);
 483unlockout:
 484        mutex_unlock(&smack_known_lock);
 485
 486        return skp;
 487}
 488
 489/**
 490 * smk_import - import a smack label
 491 * @string: a text string that might be a Smack label
 492 * @len: the maximum size, or zero if it is NULL terminated.
 493 *
 494 * Returns a pointer to the label in the label list that
 495 * matches the passed string, adding it if necessary.
 496 */
 497char *smk_import(const char *string, int len)
 498{
 499        struct smack_known *skp;
 500
 501        /* labels cannot begin with a '-' */
 502        if (string[0] == '-')
 503                return NULL;
 504        skp = smk_import_entry(string, len);
 505        if (skp == NULL)
 506                return NULL;
 507        return skp->smk_known;
 508}
 509
 510/**
 511 * smack_from_secid - find the Smack label associated with a secid
 512 * @secid: an integer that might be associated with a Smack label
 513 *
 514 * Returns a pointer to the appropriate Smack label if there is one,
 515 * otherwise a pointer to the invalid Smack label.
 516 */
 517char *smack_from_secid(const u32 secid)
 518{
 519        struct smack_known *skp;
 520
 521        rcu_read_lock();
 522        list_for_each_entry_rcu(skp, &smack_known_list, list) {
 523                if (skp->smk_secid == secid) {
 524                        rcu_read_unlock();
 525                        return skp->smk_known;
 526                }
 527        }
 528
 529        /*
 530         * If we got this far someone asked for the translation
 531         * of a secid that is not on the list.
 532         */
 533        rcu_read_unlock();
 534        return smack_known_invalid.smk_known;
 535}
 536
 537/**
 538 * smack_to_secid - find the secid associated with a Smack label
 539 * @smack: the Smack label
 540 *
 541 * Returns the appropriate secid if there is one,
 542 * otherwise 0
 543 */
 544u32 smack_to_secid(const char *smack)
 545{
 546        struct smack_known *skp = smk_find_entry(smack);
 547
 548        if (skp == NULL)
 549                return 0;
 550        return skp->smk_secid;
 551}
 552
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.