Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
0004  *
0005  * Author:
0006  *      Casey Schaufler <casey@schaufler-ca.com>
0007  */
0008 
0009 #include <linux/types.h>
0010 #include <linux/slab.h>
0011 #include <linux/fs.h>
0012 #include <linux/sched.h>
0013 #include "smack.h"
0014 
0015 struct smack_known smack_known_huh = {
0016     .smk_known  = "?",
0017     .smk_secid  = 2,
0018 };
0019 
0020 struct smack_known smack_known_hat = {
0021     .smk_known  = "^",
0022     .smk_secid  = 3,
0023 };
0024 
0025 struct smack_known smack_known_star = {
0026     .smk_known  = "*",
0027     .smk_secid  = 4,
0028 };
0029 
0030 struct smack_known smack_known_floor = {
0031     .smk_known  = "_",
0032     .smk_secid  = 5,
0033 };
0034 
0035 struct smack_known smack_known_web = {
0036     .smk_known  = "@",
0037     .smk_secid  = 7,
0038 };
0039 
0040 LIST_HEAD(smack_known_list);
0041 
0042 /*
0043  * The initial value needs to be bigger than any of the
0044  * known values above.
0045  */
0046 static u32 smack_next_secid = 10;
0047 
0048 /*
0049  * what events do we log
0050  * can be overwritten at run-time by /smack/logging
0051  */
0052 int log_policy = SMACK_AUDIT_DENIED;
0053 
0054 /**
0055  * smk_access_entry - look up matching access rule
0056  * @subject_label: a pointer to the subject's Smack label
0057  * @object_label: a pointer to the object's Smack label
0058  * @rule_list: the list of rules to search
0059  *
0060  * This function looks up the subject/object pair in the
0061  * access rule list and returns the access mode. If no
0062  * entry is found returns -ENOENT.
0063  *
0064  * NOTE:
0065  *
0066  * Earlier versions of this function allowed for labels that
0067  * were not on the label list. This was done to allow for
0068  * labels to come over the network that had never been seen
0069  * before on this host. Unless the receiving socket has the
0070  * star label this will always result in a failure check. The
0071  * star labeled socket case is now handled in the networking
0072  * hooks so there is no case where the label is not on the
0073  * label list. Checking to see if the address of two labels
0074  * is the same is now a reliable test.
0075  *
0076  * Do the object check first because that is more
0077  * likely to differ.
0078  *
0079  * Allowing write access implies allowing locking.
0080  */
0081 int smk_access_entry(char *subject_label, char *object_label,
0082             struct list_head *rule_list)
0083 {
0084     struct smack_rule *srp;
0085 
0086     list_for_each_entry_rcu(srp, rule_list, list) {
0087         if (srp->smk_object->smk_known == object_label &&
0088             srp->smk_subject->smk_known == subject_label) {
0089             int may = srp->smk_access;
0090             /*
0091              * MAY_WRITE implies MAY_LOCK.
0092              */
0093             if ((may & MAY_WRITE) == MAY_WRITE)
0094                 may |= MAY_LOCK;
0095             return may;
0096         }
0097     }
0098 
0099     return -ENOENT;
0100 }
0101 
0102 /**
0103  * smk_access - determine if a subject has a specific access to an object
0104  * @subject: a pointer to the subject's Smack label entry
0105  * @object: a pointer to the object's Smack label entry
0106  * @request: the access requested, in "MAY" format
0107  * @a : a pointer to the audit data
0108  *
0109  * This function looks up the subject/object pair in the
0110  * access rule list and returns 0 if the access is permitted,
0111  * non zero otherwise.
0112  *
0113  * Smack labels are shared on smack_list
0114  */
0115 int smk_access(struct smack_known *subject, struct smack_known *object,
0116            int request, struct smk_audit_info *a)
0117 {
0118     int may = MAY_NOT;
0119     int rc = 0;
0120 
0121     /*
0122      * Hardcoded comparisons.
0123      */
0124     /*
0125      * A star subject can't access any object.
0126      */
0127     if (subject == &smack_known_star) {
0128         rc = -EACCES;
0129         goto out_audit;
0130     }
0131     /*
0132      * An internet object can be accessed by any subject.
0133      * Tasks cannot be assigned the internet label.
0134      * An internet subject can access any object.
0135      */
0136     if (object == &smack_known_web || subject == &smack_known_web)
0137         goto out_audit;
0138     /*
0139      * A star object can be accessed by any subject.
0140      */
0141     if (object == &smack_known_star)
0142         goto out_audit;
0143     /*
0144      * An object can be accessed in any way by a subject
0145      * with the same label.
0146      */
0147     if (subject->smk_known == object->smk_known)
0148         goto out_audit;
0149     /*
0150      * A hat subject can read or lock any object.
0151      * A floor object can be read or locked by any subject.
0152      */
0153     if ((request & MAY_ANYREAD) == request ||
0154         (request & MAY_LOCK) == request) {
0155         if (object == &smack_known_floor)
0156             goto out_audit;
0157         if (subject == &smack_known_hat)
0158             goto out_audit;
0159     }
0160     /*
0161      * Beyond here an explicit relationship is required.
0162      * If the requested access is contained in the available
0163      * access (e.g. read is included in readwrite) it's
0164      * good. A negative response from smk_access_entry()
0165      * indicates there is no entry for this pair.
0166      */
0167     rcu_read_lock();
0168     may = smk_access_entry(subject->smk_known, object->smk_known,
0169                    &subject->smk_rules);
0170     rcu_read_unlock();
0171 
0172     if (may <= 0 || (request & may) != request) {
0173         rc = -EACCES;
0174         goto out_audit;
0175     }
0176 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
0177     /*
0178      * Return a positive value if using bringup mode.
0179      * This allows the hooks to identify checks that
0180      * succeed because of "b" rules.
0181      */
0182     if (may & MAY_BRINGUP)
0183         rc = SMACK_BRINGUP_ALLOW;
0184 #endif
0185 
0186 out_audit:
0187 
0188 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
0189     if (rc < 0) {
0190         if (object == smack_unconfined)
0191             rc = SMACK_UNCONFINED_OBJECT;
0192         if (subject == smack_unconfined)
0193             rc = SMACK_UNCONFINED_SUBJECT;
0194     }
0195 #endif
0196 
0197 #ifdef CONFIG_AUDIT
0198     if (a)
0199         smack_log(subject->smk_known, object->smk_known,
0200               request, rc, a);
0201 #endif
0202 
0203     return rc;
0204 }
0205 
0206 /**
0207  * smk_tskacc - determine if a task has a specific access to an object
0208  * @tsp: a pointer to the subject's task
0209  * @obj_known: a pointer to the object's label entry
0210  * @mode: the access requested, in "MAY" format
0211  * @a : common audit data
0212  *
0213  * This function checks the subject task's label/object label pair
0214  * in the access rule list and returns 0 if the access is permitted,
0215  * non zero otherwise. It allows that the task may have the capability
0216  * to override the rules.
0217  */
0218 int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
0219            u32 mode, struct smk_audit_info *a)
0220 {
0221     struct smack_known *sbj_known = smk_of_task(tsp);
0222     int may;
0223     int rc;
0224 
0225     /*
0226      * Check the global rule list
0227      */
0228     rc = smk_access(sbj_known, obj_known, mode, NULL);
0229     if (rc >= 0) {
0230         /*
0231          * If there is an entry in the task's rule list
0232          * it can further restrict access.
0233          */
0234         may = smk_access_entry(sbj_known->smk_known,
0235                        obj_known->smk_known,
0236                        &tsp->smk_rules);
0237         if (may < 0)
0238             goto out_audit;
0239         if ((mode & may) == mode)
0240             goto out_audit;
0241         rc = -EACCES;
0242     }
0243 
0244     /*
0245      * Allow for priviliged to override policy.
0246      */
0247     if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE))
0248         rc = 0;
0249 
0250 out_audit:
0251 #ifdef CONFIG_AUDIT
0252     if (a)
0253         smack_log(sbj_known->smk_known, obj_known->smk_known,
0254               mode, rc, a);
0255 #endif
0256     return rc;
0257 }
0258 
0259 /**
0260  * smk_curacc - determine if current has a specific access to an object
0261  * @obj_known: a pointer to the object's Smack label entry
0262  * @mode: the access requested, in "MAY" format
0263  * @a : common audit data
0264  *
0265  * This function checks the current subject label/object label pair
0266  * in the access rule list and returns 0 if the access is permitted,
0267  * non zero otherwise. It allows that current may have the capability
0268  * to override the rules.
0269  */
0270 int smk_curacc(struct smack_known *obj_known,
0271            u32 mode, struct smk_audit_info *a)
0272 {
0273     struct task_smack *tsp = smack_cred(current_cred());
0274 
0275     return smk_tskacc(tsp, obj_known, mode, a);
0276 }
0277 
0278 #ifdef CONFIG_AUDIT
0279 /**
0280  * smack_str_from_perm : helper to transalate an int to a
0281  * readable string
0282  * @string : the string to fill
0283  * @access : the int
0284  *
0285  */
0286 static inline void smack_str_from_perm(char *string, int access)
0287 {
0288     int i = 0;
0289 
0290     if (access & MAY_READ)
0291         string[i++] = 'r';
0292     if (access & MAY_WRITE)
0293         string[i++] = 'w';
0294     if (access & MAY_EXEC)
0295         string[i++] = 'x';
0296     if (access & MAY_APPEND)
0297         string[i++] = 'a';
0298     if (access & MAY_TRANSMUTE)
0299         string[i++] = 't';
0300     if (access & MAY_LOCK)
0301         string[i++] = 'l';
0302     string[i] = '\0';
0303 }
0304 /**
0305  * smack_log_callback - SMACK specific information
0306  * will be called by generic audit code
0307  * @ab : the audit_buffer
0308  * @a  : audit_data
0309  *
0310  */
0311 static void smack_log_callback(struct audit_buffer *ab, void *a)
0312 {
0313     struct common_audit_data *ad = a;
0314     struct smack_audit_data *sad = ad->smack_audit_data;
0315     audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
0316              ad->smack_audit_data->function,
0317              sad->result ? "denied" : "granted");
0318     audit_log_format(ab, " subject=");
0319     audit_log_untrustedstring(ab, sad->subject);
0320     audit_log_format(ab, " object=");
0321     audit_log_untrustedstring(ab, sad->object);
0322     if (sad->request[0] == '\0')
0323         audit_log_format(ab, " labels_differ");
0324     else
0325         audit_log_format(ab, " requested=%s", sad->request);
0326 }
0327 
0328 /**
0329  *  smack_log - Audit the granting or denial of permissions.
0330  *  @subject_label : smack label of the requester
0331  *  @object_label  : smack label of the object being accessed
0332  *  @request: requested permissions
0333  *  @result: result from smk_access
0334  *  @ad:  auxiliary audit data
0335  *
0336  * Audit the granting or denial of permissions in accordance
0337  * with the policy.
0338  */
0339 void smack_log(char *subject_label, char *object_label, int request,
0340            int result, struct smk_audit_info *ad)
0341 {
0342 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
0343     char request_buffer[SMK_NUM_ACCESS_TYPE + 5];
0344 #else
0345     char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
0346 #endif
0347     struct smack_audit_data *sad;
0348     struct common_audit_data *a = &ad->a;
0349 
0350     /* check if we have to log the current event */
0351     if (result < 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
0352         return;
0353     if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
0354         return;
0355 
0356     sad = a->smack_audit_data;
0357 
0358     if (sad->function == NULL)
0359         sad->function = "unknown";
0360 
0361     /* end preparing the audit data */
0362     smack_str_from_perm(request_buffer, request);
0363     sad->subject = subject_label;
0364     sad->object  = object_label;
0365 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
0366     /*
0367      * The result may be positive in bringup mode.
0368      * A positive result is an allow, but not for normal reasons.
0369      * Mark it as successful, but don't filter it out even if
0370      * the logging policy says to do so.
0371      */
0372     if (result == SMACK_UNCONFINED_SUBJECT)
0373         strcat(request_buffer, "(US)");
0374     else if (result == SMACK_UNCONFINED_OBJECT)
0375         strcat(request_buffer, "(UO)");
0376 
0377     if (result > 0)
0378         result = 0;
0379 #endif
0380     sad->request = request_buffer;
0381     sad->result  = result;
0382 
0383     common_lsm_audit(a, smack_log_callback, NULL);
0384 }
0385 #else /* #ifdef CONFIG_AUDIT */
0386 void smack_log(char *subject_label, char *object_label, int request,
0387                int result, struct smk_audit_info *ad)
0388 {
0389 }
0390 #endif
0391 
0392 DEFINE_MUTEX(smack_known_lock);
0393 
0394 struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
0395 
0396 /**
0397  * smk_insert_entry - insert a smack label into a hash map,
0398  * @skp: smack label
0399  *
0400  * this function must be called under smack_known_lock
0401  */
0402 void smk_insert_entry(struct smack_known *skp)
0403 {
0404     unsigned int hash;
0405     struct hlist_head *head;
0406 
0407     hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
0408     head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
0409 
0410     hlist_add_head_rcu(&skp->smk_hashed, head);
0411     list_add_rcu(&skp->list, &smack_known_list);
0412 }
0413 
0414 /**
0415  * smk_find_entry - find a label on the list, return the list entry
0416  * @string: a text string that might be a Smack label
0417  *
0418  * Returns a pointer to the entry in the label list that
0419  * matches the passed string or NULL if not found.
0420  */
0421 struct smack_known *smk_find_entry(const char *string)
0422 {
0423     unsigned int hash;
0424     struct hlist_head *head;
0425     struct smack_known *skp;
0426 
0427     hash = full_name_hash(NULL, string, strlen(string));
0428     head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
0429 
0430     hlist_for_each_entry_rcu(skp, head, smk_hashed)
0431         if (strcmp(skp->smk_known, string) == 0)
0432             return skp;
0433 
0434     return NULL;
0435 }
0436 
0437 /**
0438  * smk_parse_smack - parse smack label from a text string
0439  * @string: a text string that might contain a Smack label
0440  * @len: the maximum size, or zero if it is NULL terminated.
0441  *
0442  * Returns a pointer to the clean label or an error code.
0443  */
0444 char *smk_parse_smack(const char *string, int len)
0445 {
0446     char *smack;
0447     int i;
0448 
0449     if (len <= 0)
0450         len = strlen(string) + 1;
0451 
0452     /*
0453      * Reserve a leading '-' as an indicator that
0454      * this isn't a label, but an option to interfaces
0455      * including /smack/cipso and /smack/cipso2
0456      */
0457     if (string[0] == '-')
0458         return ERR_PTR(-EINVAL);
0459 
0460     for (i = 0; i < len; i++)
0461         if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
0462             string[i] == '"' || string[i] == '\\' || string[i] == '\'')
0463             break;
0464 
0465     if (i == 0 || i >= SMK_LONGLABEL)
0466         return ERR_PTR(-EINVAL);
0467 
0468     smack = kstrndup(string, i, GFP_NOFS);
0469     if (!smack)
0470         return ERR_PTR(-ENOMEM);
0471     return smack;
0472 }
0473 
0474 /**
0475  * smk_netlbl_mls - convert a catset to netlabel mls categories
0476  * @level: MLS sensitivity level
0477  * @catset: the Smack categories
0478  * @sap: where to put the netlabel categories
0479  * @len: number of bytes for the levels in a CIPSO IP option
0480  *
0481  * Allocates and fills attr.mls
0482  * Returns 0 on success, error code on failure.
0483  */
0484 int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
0485             int len)
0486 {
0487     unsigned char *cp;
0488     unsigned char m;
0489     int cat;
0490     int rc;
0491     int byte;
0492 
0493     sap->flags |= NETLBL_SECATTR_MLS_CAT;
0494     sap->attr.mls.lvl = level;
0495     sap->attr.mls.cat = NULL;
0496 
0497     for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
0498         for (m = 0x80; m != 0; m >>= 1, cat++) {
0499             if ((m & *cp) == 0)
0500                 continue;
0501             rc = netlbl_catmap_setbit(&sap->attr.mls.cat,
0502                           cat, GFP_NOFS);
0503             if (rc < 0) {
0504                 netlbl_catmap_free(sap->attr.mls.cat);
0505                 return rc;
0506             }
0507         }
0508 
0509     return 0;
0510 }
0511 
0512 /**
0513  * smack_populate_secattr - fill in the smack_known netlabel information
0514  * @skp: pointer to the structure to fill
0515  *
0516  * Populate the netlabel secattr structure for a Smack label.
0517  *
0518  * Returns 0 unless creating the category mapping fails
0519  */
0520 int smack_populate_secattr(struct smack_known *skp)
0521 {
0522     int slen;
0523 
0524     skp->smk_netlabel.attr.secid = skp->smk_secid;
0525     skp->smk_netlabel.domain = skp->smk_known;
0526     skp->smk_netlabel.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
0527     if (skp->smk_netlabel.cache != NULL) {
0528         skp->smk_netlabel.flags |= NETLBL_SECATTR_CACHE;
0529         skp->smk_netlabel.cache->free = NULL;
0530         skp->smk_netlabel.cache->data = skp;
0531     }
0532     skp->smk_netlabel.flags |= NETLBL_SECATTR_SECID |
0533                    NETLBL_SECATTR_MLS_LVL |
0534                    NETLBL_SECATTR_DOMAIN;
0535     /*
0536      * If direct labeling works use it.
0537      * Otherwise use mapped labeling.
0538      */
0539     slen = strlen(skp->smk_known);
0540     if (slen < SMK_CIPSOLEN)
0541         return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
0542                       &skp->smk_netlabel, slen);
0543 
0544     return smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
0545                   &skp->smk_netlabel, sizeof(skp->smk_secid));
0546 }
0547 
0548 /**
0549  * smk_import_entry - import a label, return the list entry
0550  * @string: a text string that might be a Smack label
0551  * @len: the maximum size, or zero if it is NULL terminated.
0552  *
0553  * Returns a pointer to the entry in the label list that
0554  * matches the passed string, adding it if necessary,
0555  * or an error code.
0556  */
0557 struct smack_known *smk_import_entry(const char *string, int len)
0558 {
0559     struct smack_known *skp;
0560     char *smack;
0561     int rc;
0562 
0563     smack = smk_parse_smack(string, len);
0564     if (IS_ERR(smack))
0565         return ERR_CAST(smack);
0566 
0567     mutex_lock(&smack_known_lock);
0568 
0569     skp = smk_find_entry(smack);
0570     if (skp != NULL)
0571         goto freeout;
0572 
0573     skp = kzalloc(sizeof(*skp), GFP_NOFS);
0574     if (skp == NULL) {
0575         skp = ERR_PTR(-ENOMEM);
0576         goto freeout;
0577     }
0578 
0579     skp->smk_known = smack;
0580     skp->smk_secid = smack_next_secid++;
0581 
0582     rc = smack_populate_secattr(skp);
0583     if (rc >= 0) {
0584         INIT_LIST_HEAD(&skp->smk_rules);
0585         mutex_init(&skp->smk_rules_lock);
0586         /*
0587          * Make sure that the entry is actually
0588          * filled before putting it on the list.
0589          */
0590         smk_insert_entry(skp);
0591         goto unlockout;
0592     }
0593     kfree(skp);
0594     skp = ERR_PTR(rc);
0595 freeout:
0596     kfree(smack);
0597 unlockout:
0598     mutex_unlock(&smack_known_lock);
0599 
0600     return skp;
0601 }
0602 
0603 /**
0604  * smack_from_secid - find the Smack label associated with a secid
0605  * @secid: an integer that might be associated with a Smack label
0606  *
0607  * Returns a pointer to the appropriate Smack label entry if there is one,
0608  * otherwise a pointer to the invalid Smack label.
0609  */
0610 struct smack_known *smack_from_secid(const u32 secid)
0611 {
0612     struct smack_known *skp;
0613 
0614     rcu_read_lock();
0615     list_for_each_entry_rcu(skp, &smack_known_list, list) {
0616         if (skp->smk_secid == secid) {
0617             rcu_read_unlock();
0618             return skp;
0619         }
0620     }
0621 
0622     /*
0623      * If we got this far someone asked for the translation
0624      * of a secid that is not on the list.
0625      */
0626     rcu_read_unlock();
0627     return &smack_known_huh;
0628 }
0629 
0630 /*
0631  * Unless a process is running with one of these labels
0632  * even having CAP_MAC_OVERRIDE isn't enough to grant
0633  * privilege to violate MAC policy. If no labels are
0634  * designated (the empty list case) capabilities apply to
0635  * everyone.
0636  */
0637 LIST_HEAD(smack_onlycap_list);
0638 DEFINE_MUTEX(smack_onlycap_lock);
0639 
0640 /**
0641  * smack_privileged_cred - are all privilege requirements met by cred
0642  * @cap: The requested capability
0643  * @cred: the credential to use
0644  *
0645  * Is the task privileged and allowed to be privileged
0646  * by the onlycap rule.
0647  *
0648  * Returns true if the task is allowed to be privileged, false if it's not.
0649  */
0650 bool smack_privileged_cred(int cap, const struct cred *cred)
0651 {
0652     struct task_smack *tsp = smack_cred(cred);
0653     struct smack_known *skp = tsp->smk_task;
0654     struct smack_known_list_elem *sklep;
0655     int rc;
0656 
0657     rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE);
0658     if (rc)
0659         return false;
0660 
0661     rcu_read_lock();
0662     if (list_empty(&smack_onlycap_list)) {
0663         rcu_read_unlock();
0664         return true;
0665     }
0666 
0667     list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
0668         if (sklep->smk_label == skp) {
0669             rcu_read_unlock();
0670             return true;
0671         }
0672     }
0673     rcu_read_unlock();
0674 
0675     return false;
0676 }
0677 
0678 /**
0679  * smack_privileged - are all privilege requirements met
0680  * @cap: The requested capability
0681  *
0682  * Is the task privileged and allowed to be privileged
0683  * by the onlycap rule.
0684  *
0685  * Returns true if the task is allowed to be privileged, false if it's not.
0686  */
0687 bool smack_privileged(int cap)
0688 {
0689     /*
0690      * All kernel tasks are privileged
0691      */
0692     if (unlikely(current->flags & PF_KTHREAD))
0693         return true;
0694 
0695     return smack_privileged_cred(cap, current_cred());
0696 }