Smack: Use the netlabel cache
authorCasey Schaufler <casey@schaufler-ca.com>
Wed, 12 Aug 2020 00:39:43 +0000 (17:39 -0700)
committerCasey Schaufler <cschaufler@localhost.localdomain>
Fri, 11 Sep 2020 22:31:31 +0000 (15:31 -0700)
Utilize the Netlabel cache mechanism for incoming packet matching.
Refactor the initialization of secattr structures, as it was being
done in two places.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c

index c5d745a..a9768b1 100644 (file)
@@ -297,6 +297,7 @@ struct smack_known *smk_find_entry(const char *);
 bool smack_privileged(int cap);
 bool smack_privileged_cred(int cap, const struct cred *cred);
 void smk_destroy_label_list(struct list_head *list);
+int smack_populate_secattr(struct smack_known *skp);
 
 /*
  * Shared data.
index 38ac3da..efe2406 100644 (file)
@@ -510,6 +510,42 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
        return 0;
 }
 
+/**
+ * smack_populate_secattr - fill in the smack_known netlabel information
+ * @skp: pointer to the structure to fill
+ *
+ * Populate the netlabel secattr structure for a Smack label.
+ *
+ * Returns 0 unless creating the category mapping fails
+ */
+int smack_populate_secattr(struct smack_known *skp)
+{
+       int slen;
+
+       skp->smk_netlabel.attr.secid = skp->smk_secid;
+       skp->smk_netlabel.domain = skp->smk_known;
+       skp->smk_netlabel.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
+       if (skp->smk_netlabel.cache != NULL) {
+               skp->smk_netlabel.flags |= NETLBL_SECATTR_CACHE;
+               skp->smk_netlabel.cache->free = NULL;
+               skp->smk_netlabel.cache->data = skp;
+       }
+       skp->smk_netlabel.flags |= NETLBL_SECATTR_SECID |
+                                  NETLBL_SECATTR_MLS_LVL |
+                                  NETLBL_SECATTR_DOMAIN;
+       /*
+        * If direct labeling works use it.
+        * Otherwise use mapped labeling.
+        */
+       slen = strlen(skp->smk_known);
+       if (slen < SMK_CIPSOLEN)
+               return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
+                                     &skp->smk_netlabel, slen);
+
+       return smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
+                             &skp->smk_netlabel, sizeof(skp->smk_secid));
+}
+
 /**
  * smk_import_entry - import a label, return the list entry
  * @string: a text string that might be a Smack label
@@ -523,7 +559,6 @@ struct smack_known *smk_import_entry(const char *string, int len)
 {
        struct smack_known *skp;
        char *smack;
-       int slen;
        int rc;
 
        smack = smk_parse_smack(string, len);
@@ -544,21 +579,8 @@ struct smack_known *smk_import_entry(const char *string, int len)
 
        skp->smk_known = smack;
        skp->smk_secid = smack_next_secid++;
-       skp->smk_netlabel.domain = skp->smk_known;
-       skp->smk_netlabel.flags =
-               NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
-       /*
-        * If direct labeling works use it.
-        * Otherwise use mapped labeling.
-        */
-       slen = strlen(smack);
-       if (slen < SMK_CIPSOLEN)
-               rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
-                              &skp->smk_netlabel, slen);
-       else
-               rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
-                              &skp->smk_netlabel, sizeof(skp->smk_secid));
 
+       rc = smack_populate_secattr(skp);
        if (rc >= 0) {
                INIT_LIST_HEAD(&skp->smk_rules);
                mutex_init(&skp->smk_rules_lock);
@@ -569,9 +591,6 @@ struct smack_known *smk_import_entry(const char *string, int len)
                smk_insert_entry(skp);
                goto unlockout;
        }
-       /*
-        * smk_netlbl_mls failed.
-        */
        kfree(skp);
        skp = ERR_PTR(rc);
 freeout:
index 7a79ddb..86db667 100644 (file)
@@ -3715,6 +3715,18 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
        int acat;
        int kcat;
 
+       /*
+        * Netlabel found it in the cache.
+        */
+       if ((sap->flags & NETLBL_SECATTR_CACHE) != 0)
+               return (struct smack_known *)sap->cache->data;
+
+       if ((sap->flags & NETLBL_SECATTR_SECID) != 0)
+               /*
+                * Looks like a fallback, which gives us a secid.
+                */
+               return smack_from_secid(sap->attr.secid);
+
        if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
                /*
                 * Looks like a CIPSO packet.
@@ -3762,11 +3774,6 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
                        return &smack_known_web;
                return &smack_known_star;
        }
-       if ((sap->flags & NETLBL_SECATTR_SECID) != 0)
-               /*
-                * Looks like a fallback, which gives us a secid.
-                */
-               return smack_from_secid(sap->attr.secid);
        /*
         * Without guidance regarding the smack value
         * for the packet fall back on the network
@@ -3845,6 +3852,9 @@ static struct smack_known *smack_from_skb(struct sk_buff *skb)
  * @family: address family
  * @skb: packet
  *
+ * Find the Smack label in the IP options. If it hasn't been
+ * added to the netlabel cache, add it here.
+ *
  * Returns smack_known of the IP options or NULL if that won't work.
  */
 static struct smack_known *smack_from_netlbl(struct sock *sk, u16 family,
@@ -3853,13 +3863,18 @@ static struct smack_known *smack_from_netlbl(struct sock *sk, u16 family,
        struct netlbl_lsm_secattr secattr;
        struct socket_smack *ssp = NULL;
        struct smack_known *skp = NULL;
+       int rc = 0;
 
        netlbl_secattr_init(&secattr);
 
        if (sk)
                ssp = sk->sk_security;
-       if (netlbl_skbuff_getattr(skb, family, &secattr) == 0)
+
+       if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) {
                skp = smack_from_secattr(&secattr, ssp);
+               if (secattr.flags & NETLBL_SECATTR_CACHEABLE)
+                       rc = netlbl_cache_add(skb, family, &skp->smk_netlabel);
+       }
 
        netlbl_secattr_destroy(&secattr);
 
index 9c43080..e567b4b 100644 (file)
@@ -922,6 +922,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
                skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat;
                skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl;
                rc = count;
+               /*
+                * This mapping may have been cached, so clear the cache.
+                */
+               netlbl_cache_invalidate();
        }
 
 out:
@@ -2950,15 +2954,6 @@ static struct file_system_type smk_fs_type = {
 
 static struct vfsmount *smackfs_mount;
 
-static int __init smk_preset_netlabel(struct smack_known *skp)
-{
-       skp->smk_netlabel.domain = skp->smk_known;
-       skp->smk_netlabel.flags =
-               NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
-       return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
-                               &skp->smk_netlabel, strlen(skp->smk_known));
-}
-
 /**
  * init_smk_fs - get the smackfs superblock
  *
@@ -2997,19 +2992,19 @@ static int __init init_smk_fs(void)
        smk_cipso_doi();
        smk_unlbl_ambient(NULL);
 
-       rc = smk_preset_netlabel(&smack_known_floor);
+       rc = smack_populate_secattr(&smack_known_floor);
        if (err == 0 && rc < 0)
                err = rc;
-       rc = smk_preset_netlabel(&smack_known_hat);
+       rc = smack_populate_secattr(&smack_known_hat);
        if (err == 0 && rc < 0)
                err = rc;
-       rc = smk_preset_netlabel(&smack_known_huh);
+       rc = smack_populate_secattr(&smack_known_huh);
        if (err == 0 && rc < 0)
                err = rc;
-       rc = smk_preset_netlabel(&smack_known_star);
+       rc = smack_populate_secattr(&smack_known_star);
        if (err == 0 && rc < 0)
                err = rc;
-       rc = smk_preset_netlabel(&smack_known_web);
+       rc = smack_populate_secattr(&smack_known_web);
        if (err == 0 && rc < 0)
                err = rc;