root/security/smack/smack_access.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smk_access_entry
  2. smk_access
  3. smk_tskacc
  4. smk_curacc
  5. smack_str_from_perm
  6. smack_log_callback
  7. smack_log
  8. smack_log
  9. smk_insert_entry
  10. smk_find_entry
  11. smk_parse_smack
  12. smk_netlbl_mls
  13. smk_import_entry
  14. smack_from_secid
  15. smack_privileged_cred
  16. smack_privileged

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

/* [<][>][^][v][top][bottom][index][help] */