Merge commit 'v3.17' into next
authorJames Morris <james.l.morris@oracle.com>
Wed, 19 Nov 2014 10:32:12 +0000 (21:32 +1100)
committerJames Morris <james.l.morris@oracle.com>
Wed, 19 Nov 2014 10:32:12 +0000 (21:32 +1100)
67 files changed:
Documentation/kernel-parameters.txt
Documentation/security/keys.txt
MAINTAINERS
crypto/asymmetric_keys/asymmetric_keys.h
crypto/asymmetric_keys/asymmetric_type.c
crypto/asymmetric_keys/pkcs7_key_type.c
crypto/asymmetric_keys/pkcs7_parser.c
crypto/asymmetric_keys/pkcs7_parser.h
crypto/asymmetric_keys/pkcs7_trust.c
crypto/asymmetric_keys/pkcs7_verify.c
crypto/asymmetric_keys/signature.c
crypto/asymmetric_keys/x509_cert_parser.c
crypto/asymmetric_keys/x509_parser.h
crypto/asymmetric_keys/x509_public_key.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsacl.c
fs/namei.c
fs/nfs/idmap.c
fs/nfsd/vfs.c
include/crypto/public_key.h
include/keys/asymmetric-type.h
include/keys/user-type.h
include/linux/ima.h
include/linux/kernel.h
include/linux/key-type.h
include/linux/security.h
lib/hexdump.c
net/ceph/crypto.c
net/dns_resolver/dns_key.c
net/rxrpc/ar-key.c
security/integrity/Kconfig
security/integrity/Makefile
security/integrity/digsig_asymmetric.c
security/integrity/evm/Kconfig
security/integrity/evm/evm_main.c
security/integrity/ima/Kconfig
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template.c
security/integrity/integrity.h
security/keys/big_key.c
security/keys/encrypted-keys/encrypted.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c
security/keys/user_defined.c
security/selinux/hooks.c
security/selinux/include/netif.h
security/selinux/include/objsec.h
security/selinux/netif.c
security/selinux/ss/services.c
security/smack/Kconfig
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c

index 10d51c2f10d712b179f5e6f67d0b9032bb42b75c..4fb49e0d250139b29d8c5240d21d4d6563a08c39 100644 (file)
@@ -1304,7 +1304,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Set number of hash buckets for inode cache.
 
        ima_appraise=   [IMA] appraise integrity measurements
-                       Format: { "off" | "enforce" | "fix" }
+                       Format: { "off" | "enforce" | "fix" | "log" }
                        default: "enforce"
 
        ima_appraise_tcb [IMA]
index 8727c194ca16a56f483b2f0cd2712654c0b948b4..821c936e1a634f0cb2cb6e4774177c2364c2e75d 100644 (file)
@@ -888,11 +888,11 @@ payload contents" for more information.
                                const char *callout_info);
 
     This is used to request a key or keyring with a description that matches
-    the description specified according to the key type's match function. This
-    permits approximate matching to occur. If callout_string is not NULL, then
-    /sbin/request-key will be invoked in an attempt to obtain the key from
-    userspace. In that case, callout_string will be passed as an argument to
-    the program.
+    the description specified according to the key type's match_preparse()
+    method. This permits approximate matching to occur. If callout_string is
+    not NULL, then /sbin/request-key will be invoked in an attempt to obtain
+    the key from userspace. In that case, callout_string will be passed as an
+    argument to the program.
 
     Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
     returned.
@@ -1170,7 +1170,7 @@ The structure has a number of fields, some of which are mandatory:
      The method should return 0 if successful or a negative error code
      otherwise.
 
-     
+
  (*) void (*free_preparse)(struct key_preparsed_payload *prep);
 
      This method is only required if the preparse() method is provided,
@@ -1225,16 +1225,55 @@ The structure has a number of fields, some of which are mandatory:
      It is safe to sleep in this method.
 
 
- (*) int (*match)(const struct key *key, const void *desc);
+ (*) int (*match_preparse)(struct key_match_data *match_data);
+
+     This method is optional.  It is called when a key search is about to be
+     performed.  It is given the following structure:
 
-     This method is called to match a key against a description. It should
-     return non-zero if the two match, zero if they don't.
+       struct key_match_data {
+               bool (*cmp)(const struct key *key,
+                           const struct key_match_data *match_data);
+               const void      *raw_data;
+               void            *preparsed;
+               unsigned        lookup_type;
+       };
 
-     This method should not need to lock the key in any way. The type and
-     description can be considered invariant, and the payload should not be
-     accessed (the key may not yet be instantiated).
+     On entry, raw_data will be pointing to the criteria to be used in matching
+     a key by the caller and should not be modified.  (*cmp)() will be pointing
+     to the default matcher function (which does an exact description match
+     against raw_data) and lookup_type will be set to indicate a direct lookup.
 
-     It is not safe to sleep in this method; the caller may hold spinlocks.
+     The following lookup_type values are available:
+
+      [*] KEYRING_SEARCH_LOOKUP_DIRECT - A direct lookup hashes the type and
+         description to narrow down the search to a small number of keys.
+
+      [*] KEYRING_SEARCH_LOOKUP_ITERATE - An iterative lookup walks all the
+         keys in the keyring until one is matched.  This must be used for any
+         search that's not doing a simple direct match on the key description.
+
+     The method may set cmp to point to a function of its choice that does some
+     other form of match, may set lookup_type to KEYRING_SEARCH_LOOKUP_ITERATE
+     and may attach something to the preparsed pointer for use by (*cmp)().
+     (*cmp)() should return true if a key matches and false otherwise.
+
+     If preparsed is set, it may be necessary to use the match_free() method to
+     clean it up.
+
+     The method should return 0 if successful or a negative error code
+     otherwise.
+
+     It is permitted to sleep in this method, but (*cmp)() may not sleep as
+     locks will be held over it.
+
+     If match_preparse() is not provided, keys of this type will be matched
+     exactly by their description.
+
+
+ (*) void (*match_free)(struct key_match_data *match_data);
+
+     This method is optional.  If given, it called to clean up
+     match_data->preparsed after a successful call to match_preparse().
 
 
  (*) void (*revoke)(struct key *key);
index f10ed3914ea85da75f4f61c86533dd04abcfce5e..ccb0feff5aaf535690c54e590ef10311a58dbab3 100644 (file)
@@ -8094,6 +8094,8 @@ F:        drivers/mmc/host/sdhci-pltfm.[ch]
 
 SECURE COMPUTING
 M:     Kees Cook <keescook@chromium.org>
+R:     Andy Lutomirski <luto@amacapital.net>
+R:     Will Drewry <wad@chromium.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
 S:     Supported
 F:     kernel/seccomp.c
index a63c551c65570006ef2281ad2dc3ad6b70622482..f97330886d587527c7211acb5d41831f382530f0 100644 (file)
@@ -9,9 +9,10 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
-int asymmetric_keyid_match(const char *kid, const char *id);
+extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
 
-static inline const char *asymmetric_key_id(const struct key *key)
+static inline
+const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
 {
        return key->type_data.p[1];
 }
index eb8cd46961a5aa5a6a7470c6d17008d1745bbdf6..bcbbbd794e1da209d519baca7de8b0ddf1115716 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/ctype.h>
 #include "asymmetric_keys.h"
 
 MODULE_LICENSE("GPL");
@@ -22,85 +23,209 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(asymmetric_key_parsers);
 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 
-/*
- * Match asymmetric key id with partial match
- * @id:                key id to match in a form "id:<id>"
+/**
+ * asymmetric_key_generate_id: Construct an asymmetric key ID
+ * @val_1: First binary blob
+ * @len_1: Length of first binary blob
+ * @val_2: Second binary blob
+ * @len_2: Length of second binary blob
+ *
+ * Construct an asymmetric key ID from a pair of binary blobs.
  */
-int asymmetric_keyid_match(const char *kid, const char *id)
+struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+                                                    size_t len_1,
+                                                    const void *val_2,
+                                                    size_t len_2)
 {
-       size_t idlen, kidlen;
+       struct asymmetric_key_id *kid;
+
+       kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
+                     GFP_KERNEL);
+       if (!kid)
+               return ERR_PTR(-ENOMEM);
+       kid->len = len_1 + len_2;
+       memcpy(kid->data, val_1, len_1);
+       memcpy(kid->data + len_1, val_2, len_2);
+       return kid;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
 
-       if (!kid || !id)
-               return 0;
+/**
+ * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
+ * @kid_1, @kid_2: The key IDs to compare
+ */
+bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+                           const struct asymmetric_key_id *kid2)
+{
+       if (!kid1 || !kid2)
+               return false;
+       if (kid1->len != kid2->len)
+               return false;
+       return memcmp(kid1->data, kid2->data, kid1->len) == 0;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
 
-       /* make it possible to use id as in the request: "id:<id>" */
-       if (strncmp(id, "id:", 3) == 0)
-               id += 3;
+/**
+ * asymmetric_key_id_partial - Return true if two asymmetric keys IDs
+ * partially match
+ * @kid_1, @kid_2: The key IDs to compare
+ */
+bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
+                              const struct asymmetric_key_id *kid2)
+{
+       if (!kid1 || !kid2)
+               return false;
+       if (kid1->len < kid2->len)
+               return false;
+       return memcmp(kid1->data + (kid1->len - kid2->len),
+                     kid2->data, kid2->len) == 0;
+}
+EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
 
-       /* Anything after here requires a partial match on the ID string */
-       idlen = strlen(id);
-       kidlen = strlen(kid);
-       if (idlen > kidlen)
-               return 0;
+/**
+ * asymmetric_match_key_ids - Search asymmetric key IDs
+ * @kids: The list of key IDs to check
+ * @match_id: The key ID we're looking for
+ * @match: The match function to use
+ */
+static bool asymmetric_match_key_ids(
+       const struct asymmetric_key_ids *kids,
+       const struct asymmetric_key_id *match_id,
+       bool (*match)(const struct asymmetric_key_id *kid1,
+                     const struct asymmetric_key_id *kid2))
+{
+       int i;
+
+       if (!kids || !match_id)
+               return false;
+       for (i = 0; i < ARRAY_SIZE(kids->id); i++)
+               if (match(kids->id[i], match_id))
+                       return true;
+       return false;
+}
 
-       kid += kidlen - idlen;
-       if (strcasecmp(id, kid) != 0)
-               return 0;
+/**
+ * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
+ * @id: The ID as a hex string.
+ */
+struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
+{
+       struct asymmetric_key_id *match_id;
+       size_t hexlen;
+       int ret;
 
-       return 1;
+       if (!*id)
+               return ERR_PTR(-EINVAL);
+       hexlen = strlen(id);
+       if (hexlen & 1)
+               return ERR_PTR(-EINVAL);
+
+       match_id = kmalloc(sizeof(struct asymmetric_key_id) + hexlen / 2,
+                          GFP_KERNEL);
+       if (!match_id)
+               return ERR_PTR(-ENOMEM);
+       match_id->len = hexlen / 2;
+       ret = hex2bin(match_id->data, id, hexlen / 2);
+       if (ret < 0) {
+               kfree(match_id);
+               return ERR_PTR(-EINVAL);
+       }
+       return match_id;
 }
-EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
 
 /*
- * Match asymmetric keys on (part of) their name
- * We have some shorthand methods for matching keys.  We allow:
- *
- *     "<desc>"        - request a key by description
- *     "id:<id>"       - request a key matching the ID
- *     "<subtype>:<id>" - request a key of a subtype
+ * Match asymmetric keys by an exact match on an ID.
  */
-static int asymmetric_key_match(const struct key *key, const void *description)
+static bool asymmetric_key_cmp(const struct key *key,
+                              const struct key_match_data *match_data)
 {
-       const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
-       const char *spec = description;
-       const char *id;
-       ptrdiff_t speclen;
+       const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+       const struct asymmetric_key_id *match_id = match_data->preparsed;
 
-       if (!subtype || !spec || !*spec)
-               return 0;
+       return asymmetric_match_key_ids(kids, match_id,
+                                       asymmetric_key_id_same);
+}
 
-       /* See if the full key description matches as is */
-       if (key->description && strcmp(key->description, description) == 0)
-               return 1;
+/*
+ * Match asymmetric keys by a partial match on an IDs.
+ */
+static bool asymmetric_key_cmp_partial(const struct key *key,
+                                      const struct key_match_data *match_data)
+{
+       const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+       const struct asymmetric_key_id *match_id = match_data->preparsed;
 
-       /* All tests from here on break the criterion description into a
-        * specifier, a colon and then an identifier.
-        */
-       id = strchr(spec, ':');
-       if (!id)
-               return 0;
+       return asymmetric_match_key_ids(kids, match_id,
+                                       asymmetric_key_id_partial);
+}
+
+/*
+ * Preparse the match criterion.  If we don't set lookup_type and cmp,
+ * the default will be an exact match on the key description.
+ *
+ * There are some specifiers for matching key IDs rather than by the key
+ * description:
+ *
+ *     "id:<id>" - find a key by partial match on any available ID
+ *     "ex:<id>" - find a key by exact match on any available ID
+ *
+ * These have to be searched by iteration rather than by direct lookup because
+ * the key is hashed according to its description.
+ */
+static int asymmetric_key_match_preparse(struct key_match_data *match_data)
+{
+       struct asymmetric_key_id *match_id;
+       const char *spec = match_data->raw_data;
+       const char *id;
+       bool (*cmp)(const struct key *, const struct key_match_data *) =
+               asymmetric_key_cmp;
 
-       speclen = id - spec;
-       id++;
+       if (!spec || !*spec)
+               return -EINVAL;
+       if (spec[0] == 'i' &&
+           spec[1] == 'd' &&
+           spec[2] == ':') {
+               id = spec + 3;
+               cmp = asymmetric_key_cmp_partial;
+       } else if (spec[0] == 'e' &&
+                  spec[1] == 'x' &&
+                  spec[2] == ':') {
+               id = spec + 3;
+       } else {
+               goto default_match;
+       }
 
-       if (speclen == 2 && memcmp(spec, "id", 2) == 0)
-               return asymmetric_keyid_match(asymmetric_key_id(key), id);
+       match_id = asymmetric_key_hex_to_key_id(id);
+       if (IS_ERR(match_id))
+               return PTR_ERR(match_id);
 
-       if (speclen == subtype->name_len &&
-           memcmp(spec, subtype->name, speclen) == 0)
-               return 1;
+       match_data->preparsed = match_id;
+       match_data->cmp = cmp;
+       match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+       return 0;
 
+default_match:
        return 0;
 }
 
+/*
+ * Free the preparsed the match criterion.
+ */
+static void asymmetric_key_match_free(struct key_match_data *match_data)
+{
+       kfree(match_data->preparsed);
+}
+
 /*
  * Describe the asymmetric key
  */
 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
 {
        const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
-       const char *kid = asymmetric_key_id(key);
-       size_t n;
+       const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+       const struct asymmetric_key_id *kid;
+       const unsigned char *p;
+       int n;
 
        seq_puts(m, key->description);
 
@@ -108,13 +233,16 @@ static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
                seq_puts(m, ": ");
                subtype->describe(key, m);
 
-               if (kid) {
+               if (kids && kids->id[1]) {
+                       kid = kids->id[1];
                        seq_putc(m, ' ');
-                       n = strlen(kid);
-                       if (n <= 8)
-                               seq_puts(m, kid);
-                       else
-                               seq_puts(m, kid + n - 8);
+                       n = kid->len;
+                       p = kid->data;
+                       if (n > 4) {
+                               p += n - 4;
+                               n = 4;
+                       }
+                       seq_printf(m, "%*phN", n, p);
                }
 
                seq_puts(m, " [");
@@ -165,6 +293,8 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 {
        struct asymmetric_key_subtype *subtype = prep->type_data[0];
+       struct asymmetric_key_ids *kids = prep->type_data[1];
+       int i;
 
        pr_devel("==>%s()\n", __func__);
 
@@ -172,7 +302,11 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
                subtype->destroy(prep->payload[0]);
                module_put(subtype->owner);
        }
-       kfree(prep->type_data[1]);
+       if (kids) {
+               for (i = 0; i < ARRAY_SIZE(kids->id); i++)
+                       kfree(kids->id[i]);
+               kfree(kids);
+       }
        kfree(prep->description);
 }
 
@@ -182,13 +316,20 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 static void asymmetric_key_destroy(struct key *key)
 {
        struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
+       struct asymmetric_key_ids *kids = key->type_data.p[1];
+
        if (subtype) {
                subtype->destroy(key->payload.data);
                module_put(subtype->owner);
                key->type_data.p[0] = NULL;
        }
-       kfree(key->type_data.p[1]);
-       key->type_data.p[1] = NULL;
+
+       if (kids) {
+               kfree(kids->id[0]);
+               kfree(kids->id[1]);
+               kfree(kids);
+               key->type_data.p[1] = NULL;
+       }
 }
 
 struct key_type key_type_asymmetric = {
@@ -196,10 +337,10 @@ struct key_type key_type_asymmetric = {
        .preparse       = asymmetric_key_preparse,
        .free_preparse  = asymmetric_key_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = asymmetric_key_match,
+       .match_preparse = asymmetric_key_match_preparse,
+       .match_free     = asymmetric_key_match_free,
        .destroy        = asymmetric_key_destroy,
        .describe       = asymmetric_key_describe,
-       .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
 };
 EXPORT_SYMBOL_GPL(key_type_asymmetric);
 
index 3de5fb011de0b3b64e0dfde2b2c6d17c631dd3d1..751f8fd7335db2203f7257edc8ad680dc7ea2a14 100644 (file)
@@ -72,11 +72,9 @@ error:
  */
 static struct key_type key_type_pkcs7 = {
        .name                   = "pkcs7_test",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = pkcs7_preparse,
        .free_preparse          = user_free_preparse,
        .instantiate            = generic_key_instantiate,
-       .match                  = user_match,
        .revoke                 = user_revoke,
        .destroy                = user_destroy,
        .describe               = user_describe,
index 42e56aa7d277ef5236f8c3192f064c0a48d59a60..3bd5a1e4c493e23a78835cb82ff7623fa21fa6c2 100644 (file)
@@ -29,8 +29,25 @@ struct pkcs7_parse_context {
        enum OID        last_oid;               /* Last OID encountered */
        unsigned        x509_index;
        unsigned        sinfo_index;
+       const void      *raw_serial;
+       unsigned        raw_serial_size;
+       unsigned        raw_issuer_size;
+       const void      *raw_issuer;
 };
 
+/*
+ * Free a signed information block.
+ */
+static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
+{
+       if (sinfo) {
+               mpi_free(sinfo->sig.mpi[0]);
+               kfree(sinfo->sig.digest);
+               kfree(sinfo->signing_cert_id);
+               kfree(sinfo);
+       }
+}
+
 /**
  * pkcs7_free_message - Free a PKCS#7 message
  * @pkcs7: The PKCS#7 message to free
@@ -54,9 +71,7 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7)
                while (pkcs7->signed_infos) {
                        sinfo = pkcs7->signed_infos;
                        pkcs7->signed_infos = sinfo->next;
-                       mpi_free(sinfo->sig.mpi[0]);
-                       kfree(sinfo->sig.digest);
-                       kfree(sinfo);
+                       pkcs7_free_signed_info(sinfo);
                }
                kfree(pkcs7);
        }
@@ -71,51 +86,46 @@ EXPORT_SYMBOL_GPL(pkcs7_free_message);
 struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
 {
        struct pkcs7_parse_context *ctx;
-       struct pkcs7_message *msg;
-       long ret;
+       struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
+       int ret;
 
-       ret = -ENOMEM;
-       msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
-       if (!msg)
-               goto error_no_sig;
        ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
        if (!ctx)
-               goto error_no_ctx;
+               goto out_no_ctx;
+       ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
+       if (!ctx->msg)
+               goto out_no_msg;
        ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
        if (!ctx->sinfo)
-               goto error_no_sinfo;
+               goto out_no_sinfo;
 
-       ctx->msg = msg;
        ctx->data = (unsigned long)data;
        ctx->ppcerts = &ctx->certs;
        ctx->ppsinfo = &ctx->msg->signed_infos;
 
        /* Attempt to decode the signature */
        ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
-       if (ret < 0)
-               goto error_decode;
+       if (ret < 0) {
+               msg = ERR_PTR(ret);
+               goto out;
+       }
 
+       msg = ctx->msg;
+       ctx->msg = NULL;
+
+out:
        while (ctx->certs) {
                struct x509_certificate *cert = ctx->certs;
                ctx->certs = cert->next;
                x509_free_certificate(cert);
        }
-       mpi_free(ctx->sinfo->sig.mpi[0]);
-       kfree(ctx->sinfo->sig.digest);
-       kfree(ctx->sinfo);
+       pkcs7_free_signed_info(ctx->sinfo);
+out_no_sinfo:
+       pkcs7_free_message(ctx->msg);
+out_no_msg:
        kfree(ctx);
+out_no_ctx:
        return msg;
-
-error_decode:
-       mpi_free(ctx->sinfo->sig.mpi[0]);
-       kfree(ctx->sinfo->sig.digest);
-       kfree(ctx->sinfo);
-error_no_sinfo:
-       kfree(ctx);
-error_no_ctx:
-       pkcs7_free_message(msg);
-error_no_sig:
-       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(pkcs7_parse_message);
 
@@ -246,10 +256,10 @@ int pkcs7_extract_cert(void *context, size_t hdrlen,
        if (IS_ERR(x509))
                return PTR_ERR(x509);
 
-       pr_debug("Got cert for %s\n", x509->subject);
-       pr_debug("- fingerprint %s\n", x509->fingerprint);
-
        x509->index = ++ctx->x509_index;
+       pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
+       pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
+
        *ctx->ppcerts = x509;
        ctx->ppcerts = &x509->next;
        return 0;
@@ -338,8 +348,8 @@ int pkcs7_sig_note_serial(void *context, size_t hdrlen,
                          const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
-       ctx->sinfo->raw_serial = value;
-       ctx->sinfo->raw_serial_size = vlen;
+       ctx->raw_serial = value;
+       ctx->raw_serial_size = vlen;
        return 0;
 }
 
@@ -351,8 +361,8 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
                          const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
-       ctx->sinfo->raw_issuer = value;
-       ctx->sinfo->raw_issuer_size = vlen;
+       ctx->raw_issuer = value;
+       ctx->raw_issuer_size = vlen;
        return 0;
 }
 
@@ -385,10 +395,21 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
                           const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
-
-       ctx->sinfo->index = ++ctx->sinfo_index;
-       *ctx->ppsinfo = ctx->sinfo;
-       ctx->ppsinfo = &ctx->sinfo->next;
+       struct pkcs7_signed_info *sinfo = ctx->sinfo;
+       struct asymmetric_key_id *kid;
+
+       /* Generate cert issuer + serial number key ID */
+       kid = asymmetric_key_generate_id(ctx->raw_serial,
+                                        ctx->raw_serial_size,
+                                        ctx->raw_issuer,
+                                        ctx->raw_issuer_size);
+       if (IS_ERR(kid))
+               return PTR_ERR(kid);
+
+       sinfo->signing_cert_id = kid;
+       sinfo->index = ++ctx->sinfo_index;
+       *ctx->ppsinfo = sinfo;
+       ctx->ppsinfo = &sinfo->next;
        ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
        if (!ctx->sinfo)
                return -ENOMEM;
index d25f4d15370fff5634ac87bdef71cca0f9a3e581..efc7dc9b8f9cfbc2ac9223e141239efb43bd60ae 100644 (file)
@@ -23,6 +23,7 @@ struct pkcs7_signed_info {
        struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
        unsigned index;
        bool trusted;
+       bool unsupported_crypto;        /* T if not usable due to missing crypto */
 
        /* Message digest - the digest of the Content Data (or NULL) */
        const void      *msgdigest;
@@ -33,10 +34,7 @@ struct pkcs7_signed_info {
        const void      *authattrs;
 
        /* Issuing cert serial number and issuer's name */
-       const void      *raw_serial;
-       unsigned        raw_serial_size;
-       unsigned        raw_issuer_size;
-       const void      *raw_issuer;
+       struct asymmetric_key_id *signing_cert_id;
 
        /* Message signature.
         *
index e666eb011a85f276c2410926766a3bd93e87b945..1d29376072da4a502e720fe10fc8fb34f6c4749a 100644 (file)
@@ -23,9 +23,9 @@
 /**
  * Check the trust on one PKCS#7 SignedInfo block.
  */
-int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
-                            struct pkcs7_signed_info *sinfo,
-                            struct key *trust_keyring)
+static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
+                                   struct pkcs7_signed_info *sinfo,
+                                   struct key *trust_keyring)
 {
        struct public_key_signature *sig = &sinfo->sig;
        struct x509_certificate *x509, *last = NULL, *p;
@@ -35,6 +35,11 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
        kenter(",%u,", sinfo->index);
 
+       if (sinfo->unsupported_crypto) {
+               kleave(" = -ENOPKG [cached]");
+               return -ENOPKG;
+       }
+
        for (x509 = sinfo->signer; x509; x509 = x509->signer) {
                if (x509->seen) {
                        if (x509->verified) {
@@ -49,15 +54,18 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
                /* Look to see if this certificate is present in the trusted
                 * keys.
                 */
-               key = x509_request_asymmetric_key(trust_keyring, x509->subject,
-                                                 x509->fingerprint);
-               if (!IS_ERR(key))
+               key = x509_request_asymmetric_key(trust_keyring, x509->id,
+                                                 false);
+               if (!IS_ERR(key)) {
                        /* One of the X.509 certificates in the PKCS#7 message
                         * is apparently the same as one we already trust.
                         * Verify that the trusted variant can also validate
                         * the signature on the descendant.
                         */
+                       pr_devel("sinfo %u: Cert %u as key %x\n",
+                                sinfo->index, x509->index, key_serial(key));
                        goto matched;
+               }
                if (key == ERR_PTR(-ENOMEM))
                        return -ENOMEM;
 
@@ -77,16 +85,36 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
        /* No match - see if the root certificate has a signer amongst the
         * trusted keys.
         */
-       if (!last || !last->issuer || !last->authority) {
-               kleave(" = -ENOKEY [no backref]");
-               return -ENOKEY;
+       if (last && last->authority) {
+               key = x509_request_asymmetric_key(trust_keyring, last->authority,
+                                                 false);
+               if (!IS_ERR(key)) {
+                       x509 = last;
+                       pr_devel("sinfo %u: Root cert %u signer is key %x\n",
+                                sinfo->index, x509->index, key_serial(key));
+                       goto matched;
+               }
+               if (PTR_ERR(key) != -ENOKEY)
+                       return PTR_ERR(key);
+       }
+
+       /* As a last resort, see if we have a trusted public key that matches
+        * the signed info directly.
+        */
+       key = x509_request_asymmetric_key(trust_keyring,
+                                         sinfo->signing_cert_id,
+                                         false);
+       if (!IS_ERR(key)) {
+               pr_devel("sinfo %u: Direct signer is key %x\n",
+                        sinfo->index, key_serial(key));
+               x509 = NULL;
+               goto matched;
        }
+       if (PTR_ERR(key) != -ENOKEY)
+               return PTR_ERR(key);
 
-       key = x509_request_asymmetric_key(trust_keyring, last->issuer,
-                                         last->authority);
-       if (IS_ERR(key))
-               return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
-       x509 = last;
+       kleave(" = -ENOKEY [no backref]");
+       return -ENOKEY;
 
 matched:
        ret = verify_signature(key, sig);
@@ -100,10 +128,12 @@ matched:
        }
 
 verified:
-       x509->verified = true;
-       for (p = sinfo->signer; p != x509; p = p->signer) {
-               p->verified = true;
-               p->trusted = trusted;
+       if (x509) {
+               x509->verified = true;
+               for (p = sinfo->signer; p != x509; p = p->signer) {
+                       p->verified = true;
+                       p->trusted = trusted;
+               }
        }
        sinfo->trusted = trusted;
        kleave(" = 0");
@@ -141,24 +171,28 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
 {
        struct pkcs7_signed_info *sinfo;
        struct x509_certificate *p;
-       int cached_ret = 0, ret;
+       int cached_ret = -ENOKEY;
+       int ret;
 
        for (p = pkcs7->certs; p; p = p->next)
                p->seen = false;
 
        for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
                ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
-               if (ret < 0) {
-                       if (ret == -ENOPKG) {
+               switch (ret) {
+               case -ENOKEY:
+                       continue;
+               case -ENOPKG:
+                       if (cached_ret == -ENOKEY)
                                cached_ret = -ENOPKG;
-                       } else if (ret == -ENOKEY) {
-                               if (cached_ret == 0)
-                                       cached_ret = -ENOKEY;
-                       } else {
-                               return ret;
-                       }
+                       continue;
+               case 0:
+                       *_trusted |= sinfo->trusted;
+                       cached_ret = 0;
+                       continue;
+               default:
+                       return ret;
                }
-               *_trusted |= sinfo->trusted;
        }
 
        return cached_ret;
index c62cf8006e1f4e8d160e7cc6423b31d318ed58cc..cd455450b069e3c58d1a202484e3ccba2d5d7da1 100644 (file)
@@ -131,8 +131,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
        struct x509_certificate *x509;
        unsigned certix = 1;
 
-       kenter("%u,%u,%u",
-              sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
+       kenter("%u", sinfo->index);
 
        for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
                /* I'm _assuming_ that the generator of the PKCS#7 message will
@@ -140,21 +139,11 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
                 * PKCS#7 message - but I can't be 100% sure of that.  It's
                 * possible this will need element-by-element comparison.
                 */
-               if (x509->raw_serial_size != sinfo->raw_serial_size ||
-                   memcmp(x509->raw_serial, sinfo->raw_serial,
-                          sinfo->raw_serial_size) != 0)
+               if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
                        continue;
                pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
                         sinfo->index, certix);
 
-               if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
-                   memcmp(x509->raw_issuer, sinfo->raw_issuer,
-                          sinfo->raw_issuer_size) != 0) {
-                       pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
-                               sinfo->index);
-                       continue;
-               }
-
                if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
                        pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
                                sinfo->index);
@@ -164,9 +153,14 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
                sinfo->signer = x509;
                return 0;
        }
-       pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
-               sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
-       return -ENOKEY;
+
+       /* The relevant X.509 cert isn't found here, but it might be found in
+        * the trust keyring.
+        */
+       pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
+                sinfo->index,
+                sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
+       return 0;
 }
 
 /*
@@ -184,15 +178,18 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                p->seen = false;
 
        for (;;) {
-               pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
+               pr_debug("verify %s: %*phN\n",
+                        x509->subject,
+                        x509->raw_serial_size, x509->raw_serial);
                x509->seen = true;
                ret = x509_get_sig_params(x509);
                if (ret < 0)
-                       return ret;
+                       goto maybe_missing_crypto_in_x509;
 
                pr_debug("- issuer %s\n", x509->issuer);
                if (x509->authority)
-                       pr_debug("- authkeyid %s\n", x509->authority);
+                       pr_debug("- authkeyid %*phN\n",
+                                x509->authority->len, x509->authority->data);
 
                if (!x509->authority ||
                    strcmp(x509->subject, x509->issuer) == 0) {
@@ -209,7 +206,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 
                        ret = x509_check_signature(x509->pub, x509);
                        if (ret < 0)
-                               return ret;
+                               goto maybe_missing_crypto_in_x509;
                        x509->signer = x509;
                        pr_debug("- self-signed\n");
                        return 0;
@@ -218,13 +215,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                /* Look through the X.509 certificates in the PKCS#7 message's
                 * list to see if the next one is there.
                 */
-               pr_debug("- want %s\n", x509->authority);
+               pr_debug("- want %*phN\n",
+                        x509->authority->len, x509->authority->data);
                for (p = pkcs7->certs; p; p = p->next) {
-                       pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
-                       if (p->raw_subject_size == x509->raw_issuer_size &&
-                           strcmp(p->fingerprint, x509->authority) == 0 &&
-                           memcmp(p->raw_subject, x509->raw_issuer,
-                                  x509->raw_issuer_size) == 0)
+                       if (!p->skid)
+                               continue;
+                       pr_debug("- cmp [%u] %*phN\n",
+                                p->index, p->skid->len, p->skid->data);
+                       if (asymmetric_key_id_same(p->skid, x509->authority))
                                goto found_issuer;
                }
 
@@ -233,7 +231,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                return 0;
 
        found_issuer:
-               pr_debug("- issuer %s\n", p->subject);
+               pr_debug("- subject %s\n", p->subject);
                if (p->seen) {
                        pr_warn("Sig %u: X.509 chain contains loop\n",
                                sinfo->index);
@@ -250,6 +248,17 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                x509 = p;
                might_sleep();
        }
+
+maybe_missing_crypto_in_x509:
+       /* Just prune the certificate chain at this point if we lack some
+        * crypto module to go further.  Note, however, we don't want to set
+        * sinfo->missing_crypto as the signed info block may still be
+        * validatable against an X.509 cert lower in the chain that we have a
+        * trusted copy of.
+        */
+       if (ret == -ENOPKG)
+               return 0;
+       return ret;
 }
 
 /*
@@ -269,11 +278,14 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
        if (ret < 0)
                return ret;
 
-       /* Find the key for the signature */
+       /* Find the key for the signature if there is one */
        ret = pkcs7_find_key(pkcs7, sinfo);
        if (ret < 0)
                return ret;
 
+       if (!sinfo->signer)
+               return 0;
+
        pr_devel("Using X.509[%u] for sig %u\n",
                 sinfo->signer->index, sinfo->index);
 
@@ -291,11 +303,33 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 /**
  * pkcs7_verify - Verify a PKCS#7 message
  * @pkcs7: The PKCS#7 message to be verified
+ *
+ * Verify a PKCS#7 message is internally consistent - that is, the data digest
+ * matches the digest in the AuthAttrs and any signature in the message or one
+ * of the X.509 certificates it carries that matches another X.509 cert in the
+ * message can be verified.
+ *
+ * This does not look to match the contents of the PKCS#7 message against any
+ * external public keys.
+ *
+ * Returns, in order of descending priority:
+ *
+ *  (*) -EKEYREJECTED if a signature failed to match for which we found an
+ *     appropriate X.509 certificate, or:
+ *
+ *  (*) -EBADMSG if some part of the message was invalid, or:
+ *
+ *  (*) -ENOPKG if none of the signature chains are verifiable because suitable
+ *     crypto modules couldn't be found, or:
+ *
+ *  (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
+ *     (note that a signature chain may be of zero length), or:
  */
 int pkcs7_verify(struct pkcs7_message *pkcs7)
 {
        struct pkcs7_signed_info *sinfo;
        struct x509_certificate *x509;
+       int enopkg = -ENOPKG;
        int ret, n;
 
        kenter("");
@@ -304,18 +338,24 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
                ret = x509_get_sig_params(x509);
                if (ret < 0)
                        return ret;
-               pr_debug("X.509[%u] %s\n", n, x509->authority);
+               pr_debug("X.509[%u] %*phN\n",
+                        n, x509->authority->len, x509->authority->data);
        }
 
        for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
                ret = pkcs7_verify_one(pkcs7, sinfo);
                if (ret < 0) {
+                       if (ret == -ENOPKG) {
+                               sinfo->unsupported_crypto = true;
+                               continue;
+                       }
                        kleave(" = %d", ret);
                        return ret;
                }
+               enopkg = 0;
        }
 
-       kleave(" = 0");
-       return 0;
+       kleave(" = %d", enopkg);
+       return enopkg;
 }
 EXPORT_SYMBOL_GPL(pkcs7_verify);
index 50b3f880b4ff0d761fa29bfc9d58344235e42c31..7525fd183574c826b2f85a5f4de3ba47e4c585ab 100644 (file)
@@ -11,6 +11,7 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) "SIG: "fmt
 #include <keys/asymmetric-subtype.h>
 #include <linux/module.h>
 #include <linux/err.h>
index ac72348c186aef8ad71618f5d9d014d5aa1d05a3..a668d90302d38c541fb5a78aa5442019cc739b21 100644 (file)
@@ -46,7 +46,8 @@ void x509_free_certificate(struct x509_certificate *cert)
                public_key_destroy(cert->pub);
                kfree(cert->issuer);
                kfree(cert->subject);
-               kfree(cert->fingerprint);
+               kfree(cert->id);
+               kfree(cert->skid);
                kfree(cert->authority);
                kfree(cert->sig.digest);
                mpi_free(cert->sig.rsa.s);
@@ -62,6 +63,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 {
        struct x509_certificate *cert;
        struct x509_parse_context *ctx;
+       struct asymmetric_key_id *kid;
        long ret;
 
        ret = -ENOMEM;
@@ -89,6 +91,17 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
        if (ret < 0)
                goto error_decode;
 
+       /* Generate cert issuer + serial number key ID */
+       kid = asymmetric_key_generate_id(cert->raw_serial,
+                                        cert->raw_serial_size,
+                                        cert->raw_issuer,
+                                        cert->raw_issuer_size);
+       if (IS_ERR(kid)) {
+               ret = PTR_ERR(kid);
+               goto error_decode;
+       }
+       cert->id = kid;
+
        kfree(ctx);
        return cert;
 
@@ -407,36 +420,36 @@ int x509_process_extension(void *context, size_t hdrlen,
                           const void *value, size_t vlen)
 {
        struct x509_parse_context *ctx = context;
+       struct asymmetric_key_id *kid;
        const unsigned char *v = value;
-       char *f;
        int i;
 
        pr_debug("Extension: %u\n", ctx->last_oid);
 
        if (ctx->last_oid == OID_subjectKeyIdentifier) {
                /* Get hold of the key fingerprint */
-               if (vlen < 3)
+               if (ctx->cert->skid || vlen < 3)
                        return -EBADMSG;
                if (v[0] != ASN1_OTS || v[1] != vlen - 2)
                        return -EBADMSG;
                v += 2;
                vlen -= 2;
 
-               f = kmalloc(vlen * 2 + 1, GFP_KERNEL);
-               if (!f)
-                       return -ENOMEM;
-               for (i = 0; i < vlen; i++)
-                       sprintf(f + i * 2, "%02x", v[i]);
-               pr_debug("fingerprint %s\n", f);
-               ctx->cert->fingerprint = f;
+               ctx->cert->raw_skid_size = vlen;
+               ctx->cert->raw_skid = v;
+               kid = asymmetric_key_generate_id(ctx->cert->raw_subject,
+                                                ctx->cert->raw_subject_size,
+                                                v, vlen);
+               if (IS_ERR(kid))
+                       return PTR_ERR(kid);
+               ctx->cert->skid = kid;
+               pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
                return 0;
        }
 
        if (ctx->last_oid == OID_authorityKeyIdentifier) {
-               size_t key_len;
-
                /* Get hold of the CA key fingerprint */
-               if (vlen < 5)
+               if (ctx->cert->authority || vlen < 5)
                        return -EBADMSG;
 
                /* Authority Key Identifier must be a Constructed SEQUENCE */
@@ -454,7 +467,7 @@ int x509_process_extension(void *context, size_t hdrlen,
                            v[3] > vlen - 4)
                                return -EBADMSG;
 
-                       key_len = v[3];
+                       vlen = v[3];
                        v += 4;
                } else {
                        /* Long Form length */
@@ -476,17 +489,17 @@ int x509_process_extension(void *context, size_t hdrlen,
                            v[sub + 1] > vlen - 4 - sub)
                                return -EBADMSG;
 
-                       key_len = v[sub + 1];
+                       vlen = v[sub + 1];
                        v += (sub + 2);
                }
 
-               f = kmalloc(key_len * 2 + 1, GFP_KERNEL);
-               if (!f)
-                       return -ENOMEM;
-               for (i = 0; i < key_len; i++)
-                       sprintf(f + i * 2, "%02x", v[i]);
-               pr_debug("authority   %s\n", f);
-               ctx->cert->authority = f;
+               kid = asymmetric_key_generate_id(ctx->cert->raw_issuer,
+                                                ctx->cert->raw_issuer_size,
+                                                v, vlen);
+               if (IS_ERR(kid))
+                       return PTR_ERR(kid);
+               pr_debug("authkeyid %*phN\n", kid->len, kid->data);
+               ctx->cert->authority = kid;
                return 0;
        }
 
index 1b76f207c1f3aeb3f8a5ade16979675aecd1c397..3dfe6b5d6f0b90433d9aefb2a627d70068f4d928 100644 (file)
@@ -19,8 +19,9 @@ struct x509_certificate {
        struct public_key_signature sig;        /* Signature parameters */
        char            *issuer;                /* Name of certificate issuer */
        char            *subject;               /* Name of certificate subject */
-       char            *fingerprint;           /* Key fingerprint as hex */
-       char            *authority;             /* Authority key fingerprint as hex */
+       struct asymmetric_key_id *id;           /* Serial number + issuer */
+       struct asymmetric_key_id *skid;         /* Subject + subjectKeyId (optional) */
+       struct asymmetric_key_id *authority;    /* Authority key identifier (optional) */
        struct tm       valid_from;
        struct tm       valid_to;
        const void      *tbs;                   /* Signed data */
@@ -33,10 +34,13 @@ struct x509_certificate {
        const void      *raw_issuer;            /* Raw issuer name in ASN.1 */
        const void      *raw_subject;           /* Raw subject name in ASN.1 */
        unsigned        raw_subject_size;
+       unsigned        raw_skid_size;
+       const void      *raw_skid;              /* Raw subjectKeyId in ASN.1 */
        unsigned        index;
        bool            seen;                   /* Infinite recursion prevention */
        bool            verified;
        bool            trusted;
+       bool            unsupported_crypto;     /* T if can't be verified due to missing crypto */
 };
 
 /*
index f3d62307e6eef7bf507dc78dddc4822739100cf9..a6c42031628e94172a112700f6cdb5cd01da9789 100644 (file)
@@ -25,7 +25,7 @@
 #include "x509_parser.h"
 
 static bool use_builtin_keys;
-static char *ca_keyid;
+static struct asymmetric_key_id *ca_keyid;
 
 #ifndef MODULE
 static int __init ca_keys_setup(char *str)
@@ -33,10 +33,16 @@ static int __init ca_keys_setup(char *str)
        if (!str)               /* default system keyring */
                return 1;
 
-       if (strncmp(str, "id:", 3) == 0)
-               ca_keyid = str; /* owner key 'id:xxxxxx' */
-       else if (strcmp(str, "builtin") == 0)
+       if (strncmp(str, "id:", 3) == 0) {
+               struct asymmetric_key_id *p;
+               p = asymmetric_key_hex_to_key_id(str + 3);
+               if (p == ERR_PTR(-EINVAL))
+                       pr_err("Unparsable hex string in ca_keys\n");
+               else if (!IS_ERR(p))
+                       ca_keyid = p;   /* owner key 'id:xxxxxx' */
+       } else if (strcmp(str, "builtin") == 0) {
                use_builtin_keys = true;
+       }
 
        return 1;
 }
@@ -46,31 +52,35 @@ __setup("ca_keys=", ca_keys_setup);
 /**
  * x509_request_asymmetric_key - Request a key by X.509 certificate params.
  * @keyring: The keys to search.
- * @subject: The name of the subject to whom the key belongs.
- * @key_id: The subject key ID as a hex string.
+ * @kid: The key ID.
+ * @partial: Use partial match if true, exact if false.
  *
  * Find a key in the given keyring by subject name and key ID.  These might,
  * for instance, be the issuer name and the authority key ID of an X.509
  * certificate that needs to be verified.
  */
 struct key *x509_request_asymmetric_key(struct key *keyring,
-                                       const char *subject,
-                                       const char *key_id)
+                                       const struct asymmetric_key_id *kid,
+                                       bool partial)
 {
        key_ref_t key;
-       size_t subject_len = strlen(subject), key_id_len = strlen(key_id);
-       char *id;
+       char *id, *p;
 
-       /* Construct an identifier "<subjname>:<keyid>". */
-       id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL);
+       /* Construct an identifier "id:<keyid>". */
+       p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
        if (!id)
                return ERR_PTR(-ENOMEM);
 
-       memcpy(id, subject, subject_len);
-       id[subject_len + 0] = ':';
-       id[subject_len + 1] = ' ';
-       memcpy(id + subject_len + 2, key_id, key_id_len);
-       id[subject_len + 2 + key_id_len] = 0;
+       if (partial) {
+               *p++ = 'i';
+               *p++ = 'd';
+       } else {
+               *p++ = 'e';
+               *p++ = 'x';
+       }
+       *p++ = ':';
+       p = bin2hex(p, kid->data, kid->len);
+       *p = 0;
 
        pr_debug("Look up: \"%s\"\n", id);
 
@@ -112,6 +122,8 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
        pr_devel("==>%s()\n", __func__);
 
+       if (cert->unsupported_crypto)
+               return -ENOPKG;
        if (cert->sig.rsa.s)
                return 0;
 
@@ -124,8 +136,13 @@ int x509_get_sig_params(struct x509_certificate *cert)
         * big the hash operational data will be.
         */
        tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
-       if (IS_ERR(tfm))
-               return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+       if (IS_ERR(tfm)) {
+               if (PTR_ERR(tfm) == -ENOENT) {
+                       cert->unsupported_crypto = true;
+                       return -ENOPKG;
+               }
+               return PTR_ERR(tfm);
+       }
 
        desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
        digest_size = crypto_shash_digestsize(tfm);
@@ -172,6 +189,8 @@ int x509_check_signature(const struct public_key *pub,
                return ret;
 
        ret = public_key_verify_signature(pub, &cert->sig);
+       if (ret == -ENOPKG)
+               cert->unsupported_crypto = true;
        pr_debug("Cert Verification: %d\n", ret);
        return ret;
 }
@@ -195,11 +214,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
        if (!trust_keyring)
                return -EOPNOTSUPP;
 
-       if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
+       if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid))
                return -EPERM;
 
-       key = x509_request_asymmetric_key(trust_keyring,
-                                         cert->issuer, cert->authority);
+       key = x509_request_asymmetric_key(trust_keyring, cert->authority,
+                                         false);
        if (!IS_ERR(key))  {
                if (!use_builtin_keys
                    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
@@ -214,9 +233,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
  */
 static int x509_key_preparse(struct key_preparsed_payload *prep)
 {
+       struct asymmetric_key_ids *kids;
        struct x509_certificate *cert;
+       const char *q;
        size_t srlen, sulen;
-       char *desc = NULL;
+       char *desc = NULL, *p;
        int ret;
 
        cert = x509_cert_parse(prep->data, prep->datalen);
@@ -249,19 +270,12 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
                 pkey_algo_name[cert->sig.pkey_algo],
                 hash_algo_name[cert->sig.pkey_hash_algo]);
 
-       if (!cert->fingerprint) {
-               pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
-                       cert->subject);
-               ret = -EKEYREJECTED;
-               goto error_free_cert;
-       }
-
        cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
        cert->pub->id_type = PKEY_ID_X509;
 
        /* Check the signature on the key if it appears to be self-signed */
        if (!cert->authority ||
-           strcmp(cert->fingerprint, cert->authority) == 0) {
+           asymmetric_key_id_same(cert->skid, cert->authority)) {
                ret = x509_check_signature(cert->pub, cert); /* self-signed */
                if (ret < 0)
                        goto error_free_cert;
@@ -273,31 +287,52 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 
        /* Propose a description */
        sulen = strlen(cert->subject);
-       srlen = strlen(cert->fingerprint);
+       if (cert->raw_skid) {
+               srlen = cert->raw_skid_size;
+               q = cert->raw_skid;
+       } else {
+               srlen = cert->raw_serial_size;
+               q = cert->raw_serial;
+       }
+       if (srlen > 1 && *q == 0) {
+               srlen--;
+               q++;
+       }
+
        ret = -ENOMEM;
-       desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
+       desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
        if (!desc)
                goto error_free_cert;
-       memcpy(desc, cert->subject, sulen);
-       desc[sulen] = ':';
-       desc[sulen + 1] = ' ';
-       memcpy(desc + sulen + 2, cert->fingerprint, srlen);
-       desc[sulen + 2 + srlen] = 0;
+       p = memcpy(desc, cert->subject, sulen);
+       p += sulen;
+       *p++ = ':';
+       *p++ = ' ';
+       p = bin2hex(p, q, srlen);
+       *p = 0;
+
+       kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
+       if (!kids)
+               goto error_free_desc;
+       kids->id[0] = cert->id;
+       kids->id[1] = cert->skid;
 
        /* We're pinning the module by being linked against it */
        __module_get(public_key_subtype.owner);
        prep->type_data[0] = &public_key_subtype;
-       prep->type_data[1] = cert->fingerprint;
+       prep->type_data[1] = kids;
        prep->payload[0] = cert->pub;
        prep->description = desc;
        prep->quotalen = 100;
 
        /* We've finished with the certificate */
        cert->pub = NULL;
-       cert->fingerprint = NULL;
+       cert->id = NULL;
+       cert->skid = NULL;
        desc = NULL;
        ret = 0;
 
+error_free_desc:
+       kfree(desc);
 error_free_cert:
        x509_free_certificate(cert);
        return ret;
index a3e932547617ea016ebb59ff2c9aa738d157153b..f4cf200b3c76714ca5a059b1ecdcca6f2e77b338 100644 (file)
@@ -62,7 +62,6 @@ cifs_spnego_key_destroy(struct key *key)
 struct key_type cifs_spnego_key_type = {
        .name           = "cifs.spnego",
        .instantiate    = cifs_spnego_key_instantiate,
-       .match          = user_match,
        .destroy        = cifs_spnego_key_destroy,
        .describe       = user_describe,
 };
index 7ff866dbb89eb7b31033ce1e99f7b56f664fbdf6..6d00c419cbae0b54016ba997f55baf1ac7c54956 100644 (file)
@@ -84,7 +84,6 @@ static struct key_type cifs_idmap_key_type = {
        .instantiate = cifs_idmap_key_instantiate,
        .destroy     = cifs_idmap_key_destroy,
        .describe    = user_describe,
-       .match       = user_match,
 };
 
 static char *
index a7b05bf82d31ad2e8eacbac999a049cab1f8d446..3ddb044f370273079674c189461fb21dca2c597f 100644 (file)
@@ -3074,7 +3074,7 @@ opened:
        error = open_check_o_direct(file);
        if (error)
                goto exit_fput;
-       error = ima_file_check(file, op->acc_mode);
+       error = ima_file_check(file, op->acc_mode, *opened);
        if (error)
                goto exit_fput;
 
index 7dd55b745c4d96cf07de07fc1a925a3590fbd802..2f5db844c172534a229d86b011be1f6ec2c29aff 100644 (file)
@@ -177,7 +177,6 @@ static struct key_type key_type_id_resolver = {
        .preparse       = user_preparse,
        .free_preparse  = user_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = user_describe,
@@ -401,7 +400,6 @@ static struct key_type key_type_id_resolver_legacy = {
        .preparse       = user_preparse,
        .free_preparse  = user_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = user_describe,
index f501a9b5c9df18f5ec7cc360d385aa0c9dfb8344..6ab077bb897e1ede9b791ffe0a23e07f12380634 100644 (file)
@@ -708,7 +708,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
                host_err = PTR_ERR(*filp);
                *filp = NULL;
        } else {
-               host_err = ima_file_check(*filp, may_flags);
+               host_err = ima_file_check(*filp, may_flags, 0);
 
                if (may_flags & NFSD_MAY_64BIT_COOKIE)
                        (*filp)->f_mode |= FMODE_64BITHASH;
index 0d164c6af5397f6a87a9c794bf2c4bbc8cd6c5c5..54add206990166ff44aca927d024d4d62b8256a1 100644 (file)
@@ -15,6 +15,7 @@
 #define _LINUX_PUBLIC_KEY_H
 
 #include <linux/mpi.h>
+#include <keys/asymmetric-type.h>
 #include <crypto/hash_info.h>
 
 enum pkey_algo {
@@ -98,8 +99,9 @@ struct key;
 extern int verify_signature(const struct key *key,
                            const struct public_key_signature *sig);
 
+struct asymmetric_key_id;
 extern struct key *x509_request_asymmetric_key(struct key *keyring,
-                                              const char *issuer,
-                                              const char *key_id);
+                                              const struct asymmetric_key_id *kid,
+                                              bool partial);
 
 #endif /* _LINUX_PUBLIC_KEY_H */
index 7dd473496180b6637b7c213f900d114d3b7d76cf..c0754abb2f5676b8d8df7c0df4d44efdc3767d48 100644 (file)
 
 extern struct key_type key_type_asymmetric;
 
+/*
+ * Identifiers for an asymmetric key ID.  We have three ways of looking up a
+ * key derived from an X.509 certificate:
+ *
+ * (1) Serial Number & Issuer.  Non-optional.  This is the only valid way to
+ *     map a PKCS#7 signature to an X.509 certificate.
+ *
+ * (2) Issuer & Subject Unique IDs.  Optional.  These were the original way to
+ *     match X.509 certificates, but have fallen into disuse in favour of (3).
+ *
+ * (3) Auth & Subject Key Identifiers.  Optional.  SKIDs are only provided on
+ *     CA keys that are intended to sign other keys, so don't appear in end
+ *     user certificates unless forced.
+ *
+ * We could also support an PGP key identifier, which is just a SHA1 sum of the
+ * public key and certain parameters, but since we don't support PGP keys at
+ * the moment, we shall ignore those.
+ *
+ * What we actually do is provide a place where binary identifiers can be
+ * stashed and then compare against them when checking for an id match.
+ */
+struct asymmetric_key_id {
+       unsigned short  len;
+       unsigned char   data[];
+};
+
+struct asymmetric_key_ids {
+       void            *id[2];
+};
+
+extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
+                                  const struct asymmetric_key_id *kid2);
+
+extern bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
+                                     const struct asymmetric_key_id *kid2);
+
+extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
+                                                           size_t len_1,
+                                                           const void *val_2,
+                                                           size_t len_2);
+
 /*
  * The payload is at the discretion of the subtype.
  */
index 3ab1873a4bfab05571bdbc60a60c8a31df5dfde5..cebefb069c44a51bed96e7fc671f0e839bf94d6a 100644 (file)
@@ -40,7 +40,6 @@ struct key_preparsed_payload;
 extern int user_preparse(struct key_preparsed_payload *prep);
 extern void user_free_preparse(struct key_preparsed_payload *prep);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
-extern int user_match(const struct key *key, const void *criterion);
 extern void user_revoke(struct key *key);
 extern void user_destroy(struct key *key);
 extern void user_describe(const struct key *user, struct seq_file *m);
index 7cf5e9b3255013deb9b4feac058112f5d7acdc5a..120ccc53fcb7f85d80a3f1f0f94c2241e864fbb2 100644 (file)
@@ -15,7 +15,7 @@ struct linux_binprm;
 
 #ifdef CONFIG_IMA
 extern int ima_bprm_check(struct linux_binprm *bprm);
-extern int ima_file_check(struct file *file, int mask);
+extern int ima_file_check(struct file *file, int mask, int opened);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
 extern int ima_module_check(struct file *file);
@@ -27,7 +27,7 @@ static inline int ima_bprm_check(struct linux_binprm *bprm)
        return 0;
 }
 
-static inline int ima_file_check(struct file *file, int mask)
+static inline int ima_file_check(struct file *file, int mask, int opened)
 {
        return 0;
 }
index 95624bed87ef6f8c389e78621b628240bf408208..7c0ad8e385107203c611cb50f25979b8c4970937 100644 (file)
@@ -496,6 +496,7 @@ static inline char *hex_byte_pack_upper(char *buf, u8 byte)
 
 extern int hex_to_bin(char ch);
 extern int __must_check hex2bin(u8 *dst, const char *src, size_t count);
+extern char *bin2hex(char *dst, const void *src, size_t count);
 
 bool mac_pton(const char *s, u8 *mac);
 
index 44792ee649de2513b8f5dba53d29758cacef2f24..ff9f1d3942356ffd1f16ab777cb8c7ed201b35e8 100644 (file)
@@ -52,6 +52,24 @@ struct key_preparsed_payload {
 typedef int (*request_key_actor_t)(struct key_construction *key,
                                   const char *op, void *aux);
 
+/*
+ * Preparsed matching criterion.
+ */
+struct key_match_data {
+       /* Comparison function, defaults to exact description match, but can be
+        * overridden by type->match_preparse().  Should return true if a match
+        * is found and false if not.
+        */
+       bool (*cmp)(const struct key *key,
+                   const struct key_match_data *match_data);
+
+       const void      *raw_data;      /* Raw match data */
+       void            *preparsed;     /* For ->match_preparse() to stash stuff */
+       unsigned        lookup_type;    /* Type of lookup for this search. */
+#define KEYRING_SEARCH_LOOKUP_DIRECT   0x0000  /* Direct lookup by description. */
+#define KEYRING_SEARCH_LOOKUP_ITERATE  0x0001  /* Iterative search. */
+};
+
 /*
  * kernel managed key type definition
  */
@@ -65,11 +83,6 @@ struct key_type {
         */
        size_t def_datalen;
 
-       /* Default key search algorithm. */
-       unsigned def_lookup_type;
-#define KEYRING_SEARCH_LOOKUP_DIRECT   0x0000  /* Direct lookup by description. */
-#define KEYRING_SEARCH_LOOKUP_ITERATE  0x0001  /* Iterative search. */
-
        /* vet a description */
        int (*vet_description)(const char *description);
 
@@ -96,8 +109,15 @@ struct key_type {
         */
        int (*update)(struct key *key, struct key_preparsed_payload *prep);
 
-       /* match a key against a description */
-       int (*match)(const struct key *key, const void *desc);
+       /* Preparse the data supplied to ->match() (optional).  The
+        * data to be preparsed can be found in match_data->raw_data.
+        * The lookup type can also be set by this function.
+        */
+       int (*match_preparse)(struct key_match_data *match_data);
+
+       /* Free preparsed match data (optional).  This should be supplied it
+        * ->match_preparse() is supplied. */
+       void (*match_free)(struct key_match_data *match_data);
 
        /* clear some of the data from a key on revokation (optional)
         * - the key's semaphore will be write-locked by the caller
index 623f90e5f38de3f2fcc0a751a25eb10a97f21cd5..3b3aeb1b74cb21aba59947e01ecb992a129c6749 100644 (file)
@@ -2108,7 +2108,7 @@ static inline int security_dentry_init_security(struct dentry *dentry,
 static inline int security_inode_init_security(struct inode *inode,
                                                struct inode *dir,
                                                const struct qstr *qstr,
-                                               const initxattrs initxattrs,
+                                               const initxattrs xattrs,
                                                void *fs_data)
 {
        return 0;
index 8499c810909a58ae100b7db96a01ea74b5c14948..270773b91923ce5a0e65c479b1af32b146dfc5d3 100644 (file)
@@ -58,6 +58,22 @@ int hex2bin(u8 *dst, const char *src, size_t count)
 }
 EXPORT_SYMBOL(hex2bin);
 
+/**
+ * bin2hex - convert binary data to an ascii hexadecimal string
+ * @dst: ascii hexadecimal result
+ * @src: binary data
+ * @count: binary data length
+ */
+char *bin2hex(char *dst, const void *src, size_t count)
+{
+       const unsigned char *_src = src;
+
+       while (count--)
+               dst = hex_byte_pack(dst, *_src++);
+       return dst;
+}
+EXPORT_SYMBOL(bin2hex);
+
 /**
  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
  * @buf: data blob to dump
index ffeba8f9dda929df4f111a9ef652cf1830f348a9..62fc5e7a9acf7506eba2de7ae314ba6067870ceb 100644 (file)
@@ -476,7 +476,6 @@ struct key_type key_type_ceph = {
        .preparse       = ceph_key_preparse,
        .free_preparse  = ceph_key_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .destroy        = ceph_key_destroy,
 };
 
index f380b2c581781433f2091fec38c7ad77f46f1fae..31cd4fd754869b8e621f0c5ecbfa5bca855684a7 100644 (file)
@@ -176,11 +176,11 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
  * The domain name may be a simple name or an absolute domain name (which
  * should end with a period).  The domain name is case-independent.
  */
-static int
-dns_resolver_match(const struct key *key, const void *description)
+static bool dns_resolver_cmp(const struct key *key,
+                            const struct key_match_data *match_data)
 {
        int slen, dlen, ret = 0;
-       const char *src = key->description, *dsp = description;
+       const char *src = key->description, *dsp = match_data->raw_data;
 
        kenter("%s,%s", src, dsp);
 
@@ -208,6 +208,16 @@ no_match:
        return ret;
 }
 
+/*
+ * Preparse the match criterion.
+ */
+static int dns_resolver_match_preparse(struct key_match_data *match_data)
+{
+       match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+       match_data->cmp = dns_resolver_cmp;
+       return 0;
+}
+
 /*
  * Describe a DNS key
  */
@@ -242,7 +252,7 @@ struct key_type key_type_dns_resolver = {
        .preparse       = dns_resolver_preparse,
        .free_preparse  = dns_resolver_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = dns_resolver_match,
+       .match_preparse = dns_resolver_match_preparse,
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = dns_resolver_describe,
index 1b24191167f1f5de119271f05a3f7f6dcfb5e376..db0f39f5ef96dcff51e10f09f6eebf4490be8d1e 100644 (file)
@@ -44,7 +44,6 @@ struct key_type key_type_rxrpc = {
        .preparse       = rxrpc_preparse,
        .free_preparse  = rxrpc_free_preparse,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .destroy        = rxrpc_destroy,
        .describe       = rxrpc_describe,
        .read           = rxrpc_read,
@@ -61,7 +60,6 @@ struct key_type key_type_rxrpc_s = {
        .preparse       = rxrpc_preparse_s,
        .free_preparse  = rxrpc_free_preparse_s,
        .instantiate    = generic_key_instantiate,
-       .match          = user_match,
        .destroy        = rxrpc_destroy_s,
        .describe       = rxrpc_describe,
 };
index 245c6d92065b36ae748c6936d696d4a2222d9b9d..b76235ae4786f2c34bc26072fad69bf457b124ce 100644 (file)
@@ -1,11 +1,23 @@
 #
 config INTEGRITY
-       def_bool y
-       depends on IMA || EVM
+       bool "Integrity subsystem"
+       depends on SECURITY
+       default y
+       help
+         This option enables the integrity subsystem, which is comprised
+         of a number of different components including the Integrity
+         Measurement Architecture (IMA), Extended Verification Module
+         (EVM), IMA-appraisal extension, digital signature verification
+         extension and audit measurement log support.
+
+         Each of these components can be enabled/disabled separately.
+         Refer to the individual components for additional details.
+
+if INTEGRITY
 
 config INTEGRITY_SIGNATURE
        boolean "Digital signature verification using multiple keyrings"
-       depends on INTEGRITY && KEYS
+       depends on KEYS
        default n
        select SIGNATURE
        help
@@ -17,9 +29,21 @@ config INTEGRITY_SIGNATURE
          This is useful for evm and module keyrings, when keys are
          usually only added from initramfs.
 
+config INTEGRITY_ASYMMETRIC_KEYS
+       boolean "Enable asymmetric keys support"
+       depends on INTEGRITY_SIGNATURE
+       default n
+        select ASYMMETRIC_KEY_TYPE
+        select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+        select PUBLIC_KEY_ALGO_RSA
+        select X509_CERTIFICATE_PARSER
+       help
+         This option enables digital signature verification using
+         asymmetric keys.
+
 config INTEGRITY_AUDIT
        bool "Enables integrity auditing support "
-       depends on INTEGRITY && AUDIT
+       depends on AUDIT
        default y
        help
          In addition to enabling integrity auditing support, this
@@ -32,17 +56,7 @@ config INTEGRITY_AUDIT
          be enabled by specifying 'integrity_audit=1' on the kernel
          command line.
 
-config INTEGRITY_ASYMMETRIC_KEYS
-       boolean "Enable asymmetric keys support"
-       depends on INTEGRITY_SIGNATURE
-       default n
-        select ASYMMETRIC_KEY_TYPE
-        select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
-        select PUBLIC_KEY_ALGO_RSA
-        select X509_CERTIFICATE_PARSER
-       help
-         This option enables digital signature verification using
-         asymmetric keys.
-
 source security/integrity/ima/Kconfig
 source security/integrity/evm/Kconfig
+
+endif   # if INTEGRITY
index 0793f4811cb7d6644def01b8563d8bc913619fe0..8d1f4bf5108759188ba843e3ef7ba4e4ad5ae1c1 100644 (file)
@@ -3,11 +3,11 @@
 #
 
 obj-$(CONFIG_INTEGRITY) += integrity.o
-obj-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
-obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
-obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
 
 integrity-y := iint.o
+integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
+integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
+integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
 
 subdir-$(CONFIG_IMA)                   += ima
 obj-$(CONFIG_IMA)                      += ima/
index 9eae4809006be6f364ed9e5fe31ccb897381b856..4fec1816a2b3b18385a2ec5c5590e4d72dc7775b 100644 (file)
@@ -13,6 +13,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/err.h>
+#include <linux/ratelimit.h>
 #include <linux/key-type.h>
 #include <crypto/public_key.h>
 #include <keys/asymmetric-type.h>
@@ -27,7 +28,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
        struct key *key;
        char name[12];
 
-       sprintf(name, "id:%x", keyid);
+       sprintf(name, "id:%08x", keyid);
 
        pr_debug("key search: \"%s\"\n", name);
 
@@ -45,8 +46,8 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
        }
 
        if (IS_ERR(key)) {
-               pr_warn("Request for unknown key '%s' err %ld\n",
-                       name, PTR_ERR(key));
+               pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
+                                  name, PTR_ERR(key));
                switch (PTR_ERR(key)) {
                        /* Hide some search errors */
                case -EACCES:
index d606f3d12d6bfb8f27d849a3b4fa9fc9ee411875..df586fa00ef1e9891efae42d629e952c05eaec4d 100644 (file)
@@ -1,6 +1,5 @@
 config EVM
        boolean "EVM support"
-       depends on SECURITY
        select KEYS
        select ENCRYPTED_KEYS
        select CRYPTO_HMAC
@@ -12,10 +11,6 @@ config EVM
 
          If you are unsure how to answer this question, answer N.
 
-if EVM
-
-menu "EVM options"
-
 config EVM_ATTR_FSUUID
        bool "FSUUID (version 2)"
        default y
@@ -47,6 +42,3 @@ config EVM_EXTRA_SMACK_XATTRS
          additional info to the calculation, requires existing EVM
          labeled file systems to be relabeled.
 
-endmenu
-
-endif
index 3bcb80df4d01f1ca30927c7e61c6b2b19b5ca15f..9685af330de5db40f4d7d097ea736b377dd68b36 100644 (file)
@@ -126,14 +126,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
        rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
                                GFP_NOFS);
        if (rc <= 0) {
-               if (rc == 0)
-                       evm_status = INTEGRITY_FAIL; /* empty */
-               else if (rc == -ENODATA) {
+               evm_status = INTEGRITY_FAIL;
+               if (rc == -ENODATA) {
                        rc = evm_find_protected_xattrs(dentry);
                        if (rc > 0)
                                evm_status = INTEGRITY_NOLABEL;
                        else if (rc == 0)
                                evm_status = INTEGRITY_NOXATTRS; /* new file */
+               } else if (rc == -EOPNOTSUPP) {
+                       evm_status = INTEGRITY_UNKNOWN;
                }
                goto out;
        }
@@ -284,6 +285,13 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
                goto out;
        }
        evm_status = evm_verify_current_integrity(dentry);
+       if (evm_status == INTEGRITY_NOXATTRS) {
+               struct integrity_iint_cache *iint;
+
+               iint = integrity_iint_find(dentry->d_inode);
+               if (iint && (iint->flags & IMA_NEW_FILE))
+                       return 0;
+       }
 out:
        if (evm_status != INTEGRITY_PASS)
                integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
@@ -352,7 +360,6 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
                return;
 
        evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
-       return;
 }
 
 /**
@@ -372,7 +379,6 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
        mutex_lock(&inode->i_mutex);
        evm_update_evmxattr(dentry, xattr_name, NULL, 0);
        mutex_unlock(&inode->i_mutex);
-       return;
 }
 
 /**
@@ -414,7 +420,6 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
 
        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
                evm_update_evmxattr(dentry, NULL, NULL, 0);
-       return;
 }
 
 /*
index 08758fbd496f90c9176a726d3f48b7d91bb3e82a..e099875643c54b11b3aabe7031b5a5fbcbee342d 100644 (file)
@@ -2,8 +2,6 @@
 #
 config IMA
        bool "Integrity Measurement Architecture(IMA)"
-       depends on SECURITY
-       select INTEGRITY
        select SECURITYFS
        select CRYPTO
        select CRYPTO_HMAC
index 57da4bd7ba0c9cf0c465daaceeaaa77cdfe5f21d..8ee997dff13937521157d02c6aac27b25903b46f 100644 (file)
@@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
 #define IMA_TEMPLATE_IMA_NAME "ima"
 #define IMA_TEMPLATE_IMA_FMT "d|n"
 
+/* current content of the policy */
+extern int ima_policy_flag;
+
 /* set during initialization */
 extern int ima_initialized;
 extern int ima_used_chip;
@@ -90,10 +93,7 @@ extern struct list_head ima_measurements;    /* list of all measurements */
 
 /* Internal IMA function definitions */
 int ima_init(void);
-void ima_cleanup(void);
 int ima_fs_init(void);
-void ima_fs_cleanup(void);
-int ima_inode_alloc(struct inode *inode);
 int ima_add_template_entry(struct ima_template_entry *entry, int violation,
                           const char *op, struct inode *inode,
                           const unsigned char *filename);
@@ -110,8 +110,6 @@ void ima_print_digest(struct seq_file *m, u8 *digest, int size);
 struct ima_template_desc *ima_template_desc_current(void);
 int ima_init_template(void);
 
-int ima_init_template(void);
-
 /*
  * used to protect h_table and sha_table
  */
@@ -151,12 +149,6 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
 void ima_free_template_entry(struct ima_template_entry *entry);
 const char *ima_d_path(struct path *path, char **pathbuf);
 
-/* rbtree tree calls to lookup, insert, delete
- * integrity data associated with an inode.
- */
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
-struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
-
 /* IMA policy related functions */
 enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
 
@@ -164,20 +156,22 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                     int flags);
 void ima_init_policy(void);
 void ima_update_policy(void);
+void ima_update_policy_flag(void);
 ssize_t ima_parse_add_rule(char *);
 void ima_delete_rules(void);
 
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE   0x01
 #define IMA_APPRAISE_FIX       0x02
-#define IMA_APPRAISE_MODULES   0x04
-#define IMA_APPRAISE_FIRMWARE  0x08
+#define IMA_APPRAISE_LOG       0x04
+#define IMA_APPRAISE_MODULES   0x08
+#define IMA_APPRAISE_FIRMWARE  0x10
 
 #ifdef CONFIG_IMA_APPRAISE
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                             struct file *file, const unsigned char *filename,
                             struct evm_ima_xattr_data *xattr_value,
-                            int xattr_len);
+                            int xattr_len, int opened);
 int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
 enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
@@ -193,7 +187,7 @@ static inline int ima_appraise_measurement(int func,
                                           struct file *file,
                                           const unsigned char *filename,
                                           struct evm_ima_xattr_data *xattr_value,
-                                          int xattr_len)
+                                          int xattr_len, int opened)
 {
        return INTEGRITY_UNKNOWN;
 }
index d9cd5ce14d2be3a341e9046213dfe6bb2b4c1306..86885979918c187fef5298c86ba9de7a97ab968b 100644 (file)
@@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function)
        return ima_match_policy(inode, function, mask, flags);
 }
 
-int ima_must_measure(struct inode *inode, int mask, int function)
-{
-       return ima_match_policy(inode, function, mask, IMA_MEASURE);
-}
-
 /*
  * ima_collect_measurement - collect file measurement
  *
@@ -330,10 +325,9 @@ const char *ima_d_path(struct path *path, char **pathbuf)
 {
        char *pathname = NULL;
 
-       /* We will allow 11 spaces for ' (deleted)' to be appended */
-       *pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
+       *pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
        if (*pathbuf) {
-               pathname = d_path(path, *pathbuf, PATH_MAX + 11);
+               pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
                if (IS_ERR(pathname)) {
                        kfree(*pathbuf);
                        *pathbuf = NULL;
index 86bfd5c5df85e0bec07bc6be5e7ab58bd98c945c..922685483bd3625355af6202bb435728ac62c11f 100644 (file)
@@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str)
 {
        if (strncmp(str, "off", 3) == 0)
                ima_appraise = 0;
+       else if (strncmp(str, "log", 3) == 0)
+               ima_appraise = IMA_APPRAISE_LOG;
        else if (strncmp(str, "fix", 3) == 0)
                ima_appraise = IMA_APPRAISE_FIX;
        return 1;
@@ -183,7 +185,7 @@ int ima_read_xattr(struct dentry *dentry,
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                             struct file *file, const unsigned char *filename,
                             struct evm_ima_xattr_data *xattr_value,
-                            int xattr_len)
+                            int xattr_len, int opened)
 {
        static const char op[] = "appraise_data";
        char *cause = "unknown";
@@ -192,8 +194,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
        enum integrity_status status = INTEGRITY_UNKNOWN;
        int rc = xattr_len, hash_start = 0;
 
-       if (!ima_appraise)
-               return 0;
        if (!inode->i_op->getxattr)
                return INTEGRITY_UNKNOWN;
 
@@ -202,8 +202,11 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                        goto out;
 
                cause = "missing-hash";
-               status =
-                   (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
+               status = INTEGRITY_NOLABEL;
+               if (opened & FILE_CREATED) {
+                       iint->flags |= IMA_NEW_FILE;
+                       status = INTEGRITY_PASS;
+               }
                goto out;
        }
 
@@ -315,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
        struct integrity_iint_cache *iint;
        int must_appraise, rc;
 
-       if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
+       if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
            || !inode->i_op->removexattr)
                return;
 
@@ -353,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
 {
        struct integrity_iint_cache *iint;
 
-       if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode))
+       if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
                return;
 
        iint = integrity_iint_find(inode);
index 0bd732843fe70861b0d1bb58bceada6c972f8122..d34e7dfc1118070a5888fd12629e388ee9aeae65 100644 (file)
@@ -80,24 +80,24 @@ static int ima_kernel_read(struct file *file, loff_t offset,
 {
        mm_segment_t old_fs;
        char __user *buf = addr;
-       ssize_t ret;
+       ssize_t ret = -EINVAL;
 
        if (!(file->f_mode & FMODE_READ))
                return -EBADF;
-       if (!file->f_op->read && !file->f_op->aio_read)
-               return -EINVAL;
 
        old_fs = get_fs();
        set_fs(get_ds());
        if (file->f_op->read)
                ret = file->f_op->read(file, buf, count, &offset);
-       else
+       else if (file->f_op->aio_read)
                ret = do_sync_read(file, buf, count, &offset);
+       else if (file->f_op->read_iter)
+               ret = new_sync_read(file, buf, count, &offset);
        set_fs(old_fs);
        return ret;
 }
 
-int ima_init_crypto(void)
+int __init ima_init_crypto(void)
 {
        long rc;
 
@@ -116,7 +116,10 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
        struct crypto_shash *tfm = ima_shash_tfm;
        int rc;
 
-       if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) {
+       if (algo < 0 || algo >= HASH_ALGO__LAST)
+               algo = ima_hash_algo;
+
+       if (algo != ima_hash_algo) {
                tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
                if (IS_ERR(tfm)) {
                        rc = PTR_ERR(tfm);
@@ -200,7 +203,10 @@ static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
        struct crypto_ahash *tfm = ima_ahash_tfm;
        int rc;
 
-       if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
+       if (algo < 0 || algo >= HASH_ALGO__LAST)
+               algo = ima_hash_algo;
+
+       if (algo != ima_hash_algo || !tfm) {
                tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
                if (!IS_ERR(tfm)) {
                        if (algo == ima_hash_algo)
index e8f9d70a465d11168748967928e34491f46c1765..9164fc8cac84adb53d79b867d7547fcaaf35aa70 100644 (file)
@@ -43,7 +43,7 @@ int ima_used_chip;
  * a different value.) Violations add a zero entry to the measurement
  * list and extend the aggregate PCR value with ff...ff's.
  */
-static void __init ima_add_boot_aggregate(void)
+static int __init ima_add_boot_aggregate(void)
 {
        static const char op[] = "add_boot_aggregate";
        const char *audit_cause = "ENOMEM";
@@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void)
 
        result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
                                         NULL, 0, &entry);
-       if (result < 0)
-               return;
+       if (result < 0) {
+               audit_cause = "alloc_entry";
+               goto err_out;
+       }
 
        result = ima_store_template(entry, violation, NULL,
                                    boot_aggregate_name);
-       if (result < 0)
+       if (result < 0) {
                ima_free_template_entry(entry);
-       return;
+               audit_cause = "store_entry";
+               goto err_out;
+       }
+       return 0;
 err_out:
        integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
                            audit_cause, result, 0);
+       return result;
 }
 
 int __init ima_init(void)
@@ -98,6 +104,10 @@ int __init ima_init(void)
        if (!ima_used_chip)
                pr_info("No TPM chip found, activating TPM-bypass!\n");
 
+       rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
+       if (rc)
+               return rc;
+
        rc = ima_init_crypto();
        if (rc)
                return rc;
@@ -105,7 +115,10 @@ int __init ima_init(void)
        if (rc != 0)
                return rc;
 
-       ima_add_boot_aggregate();       /* boot aggregate must be first entry */
+       rc = ima_add_boot_aggregate();  /* boot aggregate must be first entry */
+       if (rc != 0)
+               return rc;
+
        ima_init_policy();
 
        return ima_fs_init();
index 2917f980bf3075c3dacff3531cf03d8e4e39e6f6..62f59eca32d3099fb8199aaf6b80db42197d53ec 100644 (file)
@@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup);
  *       could result in a file measurement error.
  *
  */
-static void ima_rdwr_violation_check(struct file *file)
+static void ima_rdwr_violation_check(struct file *file,
+                                    struct integrity_iint_cache *iint,
+                                    int must_measure,
+                                    char **pathbuf,
+                                    const char **pathname)
 {
        struct inode *inode = file_inode(file);
        fmode_t mode = file->f_mode;
        bool send_tomtou = false, send_writers = false;
-       char *pathbuf = NULL;
-       const char *pathname;
-
-       if (!S_ISREG(inode->i_mode) || !ima_initialized)
-               return;
 
        if (mode & FMODE_WRITE) {
                if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
-                       struct integrity_iint_cache *iint;
-                       iint = integrity_iint_find(inode);
+                       if (!iint)
+                               iint = integrity_iint_find(inode);
                        /* IMA_MEASURE is set from reader side */
                        if (iint && (iint->flags & IMA_MEASURE))
                                send_tomtou = true;
                }
        } else {
-               if ((atomic_read(&inode->i_writecount) > 0) &&
-                   ima_must_measure(inode, MAY_READ, FILE_CHECK))
+               if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
                        send_writers = true;
        }
 
        if (!send_tomtou && !send_writers)
                return;
 
-       pathname = ima_d_path(&file->f_path, &pathbuf);
+       *pathname = ima_d_path(&file->f_path, pathbuf);
 
        if (send_tomtou)
-               ima_add_violation(file, pathname, "invalid_pcr", "ToMToU");
+               ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
        if (send_writers)
-               ima_add_violation(file, pathname,
+               ima_add_violation(file, *pathname,
                                  "invalid_pcr", "open_writers");
-       kfree(pathbuf);
 }
 
 static void ima_check_last_writer(struct integrity_iint_cache *iint,
@@ -124,11 +121,13 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
                return;
 
        mutex_lock(&inode->i_mutex);
-       if (atomic_read(&inode->i_writecount) == 1 &&
-           iint->version != inode->i_version) {
-               iint->flags &= ~IMA_DONE_MASK;
-               if (iint->flags & IMA_APPRAISE)
-                       ima_update_xattr(iint, file);
+       if (atomic_read(&inode->i_writecount) == 1) {
+               if ((iint->version != inode->i_version) ||
+                   (iint->flags & IMA_NEW_FILE)) {
+                       iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
+                       if (iint->flags & IMA_APPRAISE)
+                               ima_update_xattr(iint, file);
+               }
        }
        mutex_unlock(&inode->i_mutex);
 }
@@ -154,19 +153,20 @@ void ima_file_free(struct file *file)
        ima_check_last_writer(iint, inode, file);
 }
 
-static int process_measurement(struct file *file, const char *filename,
-                              int mask, int function)
+static int process_measurement(struct file *file, int mask, int function,
+                              int opened)
 {
        struct inode *inode = file_inode(file);
-       struct integrity_iint_cache *iint;
+       struct integrity_iint_cache *iint = NULL;
        struct ima_template_desc *template_desc;
        char *pathbuf = NULL;
        const char *pathname = NULL;
-       int rc = -ENOMEM, action, must_appraise, _func;
+       int rc = -ENOMEM, action, must_appraise;
        struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
        int xattr_len = 0;
+       bool violation_check;
 
-       if (!ima_initialized || !S_ISREG(inode->i_mode))
+       if (!ima_policy_flag || !S_ISREG(inode->i_mode))
                return 0;
 
        /* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
@@ -174,19 +174,33 @@ static int process_measurement(struct file *file, const char *filename,
         * Included is the appraise submask.
         */
        action = ima_get_action(inode, mask, function);
-       if (!action)
+       violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) &&
+                          (ima_policy_flag & IMA_MEASURE));
+       if (!action && !violation_check)
                return 0;
 
        must_appraise = action & IMA_APPRAISE;
 
        /*  Is the appraise rule hook specific?  */
-       _func = (action & IMA_FILE_APPRAISE) ? FILE_CHECK : function;
+       if (action & IMA_FILE_APPRAISE)
+               function = FILE_CHECK;
 
        mutex_lock(&inode->i_mutex);
 
-       iint = integrity_inode_get(inode);
-       if (!iint)
-               goto out;
+       if (action) {
+               iint = integrity_inode_get(inode);
+               if (!iint)
+                       goto out;
+       }
+
+       if (violation_check) {
+               ima_rdwr_violation_check(file, iint, action & IMA_MEASURE,
+                                        &pathbuf, &pathname);
+               if (!action) {
+                       rc = 0;
+                       goto out_free;
+               }
+       }
 
        /* Determine if already appraised/measured based on bitmask
         * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
@@ -199,15 +213,13 @@ static int process_measurement(struct file *file, const char *filename,
        /* Nothing to do, just return existing appraised status */
        if (!action) {
                if (must_appraise)
-                       rc = ima_get_cache_status(iint, _func);
+                       rc = ima_get_cache_status(iint, function);
                goto out_digsig;
        }
 
        template_desc = ima_template_desc_current();
-       if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
-               if (action & IMA_APPRAISE_SUBMASK)
-                       xattr_ptr = &xattr_value;
-       } else
+       if ((action & IMA_APPRAISE_SUBMASK) ||
+                   strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
                xattr_ptr = &xattr_value;
 
        rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
@@ -217,23 +229,26 @@ static int process_measurement(struct file *file, const char *filename,
                goto out_digsig;
        }
 
-       pathname = filename ?: ima_d_path(&file->f_path, &pathbuf);
+       if (!pathname)  /* ima_rdwr_violation possibly pre-fetched */
+               pathname = ima_d_path(&file->f_path, &pathbuf);
 
        if (action & IMA_MEASURE)
                ima_store_measurement(iint, file, pathname,
                                      xattr_value, xattr_len);
        if (action & IMA_APPRAISE_SUBMASK)
-               rc = ima_appraise_measurement(_func, iint, file, pathname,
-                                             xattr_value, xattr_len);
+               rc = ima_appraise_measurement(function, iint, file, pathname,
+                                             xattr_value, xattr_len, opened);
        if (action & IMA_AUDIT)
                ima_audit_measurement(iint, pathname);
-       kfree(pathbuf);
+
 out_digsig:
        if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
                rc = -EACCES;
+       kfree(xattr_value);
+out_free:
+       kfree(pathbuf);
 out:
        mutex_unlock(&inode->i_mutex);
-       kfree(xattr_value);
        if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
                return -EACCES;
        return 0;
@@ -253,7 +268,7 @@ out:
 int ima_file_mmap(struct file *file, unsigned long prot)
 {
        if (file && (prot & PROT_EXEC))
-               return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK);
+               return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0);
        return 0;
 }
 
@@ -272,10 +287,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
  */
 int ima_bprm_check(struct linux_binprm *bprm)
 {
-       return process_measurement(bprm->file,
-                                  (strcmp(bprm->filename, bprm->interp) == 0) ?
-                                  bprm->filename : bprm->interp,
-                                  MAY_EXEC, BPRM_CHECK);
+       return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0);
 }
 
 /**
@@ -288,12 +300,11 @@ int ima_bprm_check(struct linux_binprm *bprm)
  * On success return 0.  On integrity appraisal error, assuming the file
  * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
  */
-int ima_file_check(struct file *file, int mask)
+int ima_file_check(struct file *file, int mask, int opened)
 {
-       ima_rdwr_violation_check(file);
-       return process_measurement(file, NULL,
+       return process_measurement(file,
                                   mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
-                                  FILE_CHECK);
+                                  FILE_CHECK, opened);
 }
 EXPORT_SYMBOL_GPL(ima_file_check);
 
@@ -316,7 +327,7 @@ int ima_module_check(struct file *file)
 #endif
                return 0;       /* We rely on module signature checking */
        }
-       return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
+       return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0);
 }
 
 int ima_fw_from_file(struct file *file, char *buf, size_t size)
@@ -327,7 +338,7 @@ int ima_fw_from_file(struct file *file, char *buf, size_t size)
                        return -EACCES; /* INTEGRITY_UNKNOWN */
                return 0;
        }
-       return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK);
+       return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0);
 }
 
 static int __init init_ima(void)
@@ -336,14 +347,10 @@ static int __init init_ima(void)
 
        hash_setup(CONFIG_IMA_DEFAULT_HASH);
        error = ima_init();
-       if (error)
-               goto out;
-
-       error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
-       if (error)
-               goto out;
-       ima_initialized = 1;
-out:
+       if (!error) {
+               ima_initialized = 1;
+               ima_update_policy_flag();
+       }
        return error;
 }
 
index 07099a8bc2835d8a8bb0ef3f7ec2f826796fd270..cdc620b2152f9431ddd9e73e651ecc4587802939 100644 (file)
@@ -35,6 +35,8 @@
 #define DONT_APPRAISE  0x0008
 #define AUDIT          0x0040
 
+int ima_policy_flag;
+
 #define MAX_LSM_RULES 6
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
        LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
@@ -295,6 +297,26 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
        return action;
 }
 
+/*
+ * Initialize the ima_policy_flag variable based on the currently
+ * loaded policy.  Based on this flag, the decision to short circuit
+ * out of a function or not call the function in the first place
+ * can be made earlier.
+ */
+void ima_update_policy_flag(void)
+{
+       struct ima_rule_entry *entry;
+
+       ima_policy_flag = 0;
+       list_for_each_entry(entry, ima_rules, list) {
+               if (entry->action & IMA_DO_MASK)
+                       ima_policy_flag |= entry->action;
+       }
+
+       if (!ima_appraise)
+               ima_policy_flag &= ~IMA_APPRAISE;
+}
+
 /**
  * ima_init_policy - initialize the default measure rules.
  *
@@ -341,6 +363,7 @@ void ima_update_policy(void)
 
        if (ima_rules == &ima_default_rules) {
                ima_rules = &ima_policy_rules;
+               ima_update_policy_flag();
                cause = "complete";
                result = 0;
        }
index a076a967ec4768f64ebfcd0a84509080e7eb6b18..e854862c9337d7ad52f8b4d59f801ec180f6513c 100644 (file)
@@ -152,24 +152,6 @@ out:
        return result;
 }
 
-static int init_defined_templates(void)
-{
-       int i = 0;
-       int result = 0;
-
-       /* Init defined templates. */
-       for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
-               struct ima_template_desc *template = &defined_templates[i];
-
-               result = template_desc_init_fields(template->fmt,
-                                                  &(template->fields),
-                                                  &(template->num_fields));
-               if (result < 0)
-                       return result;
-       }
-       return result;
-}
-
 struct ima_template_desc *ima_template_desc_current(void)
 {
        if (!ima_template)
@@ -178,13 +160,11 @@ struct ima_template_desc *ima_template_desc_current(void)
        return ima_template;
 }
 
-int ima_init_template(void)
+int __init ima_init_template(void)
 {
-       int result;
-
-       result = init_defined_templates();
-       if (result < 0)
-               return result;
+       struct ima_template_desc *template = ima_template_desc_current();
 
-       return 0;
+       return template_desc_init_fields(template->fmt,
+                                        &(template->fields),
+                                        &(template->num_fields));
 }
index 19b8e314ca964efdff3cf7ddf30851f9f0e29d80..c0379d13dbe16f8d4c9705e1c80fd8b2c7b0e4df 100644 (file)
@@ -31,6 +31,7 @@
 #define IMA_DIGSIG             0x01000000
 #define IMA_DIGSIG_REQUIRED    0x02000000
 #define IMA_PERMIT_DIRECTIO    0x04000000
+#define IMA_NEW_FILE           0x08000000
 
 #define IMA_DO_MASK            (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
                                 IMA_APPRAISE_SUBMASK)
@@ -116,7 +117,6 @@ struct integrity_iint_cache {
 /* rbtree tree calls to lookup, insert, delete
  * integrity data associated with an inode.
  */
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
 #define INTEGRITY_KEYRING_EVM          0
index c2f91a0cf8899cb0d8d69fd06ebcc05405cf45f7..b6adb94f6d52573aecf2e38a16724e06895dded6 100644 (file)
@@ -33,11 +33,9 @@ MODULE_LICENSE("GPL");
  */
 struct key_type key_type_big_key = {
        .name                   = "big_key",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = big_key_preparse,
        .free_preparse          = big_key_free_preparse,
        .instantiate            = generic_key_instantiate,
-       .match                  = user_match,
        .revoke                 = big_key_revoke,
        .destroy                = big_key_destroy,
        .describe               = big_key_describe,
index 5fe443d120afe81826902cc70efecff24ccee1bb..db9675db10262021612016bed79ade14a960d089 100644 (file)
@@ -970,7 +970,6 @@ struct key_type key_type_encrypted = {
        .name = "encrypted",
        .instantiate = encrypted_instantiate,
        .update = encrypted_update,
-       .match = user_match,
        .destroy = encrypted_destroy,
        .describe = user_describe,
        .read = encrypted_read,
index 5f20da01fd8d317f835375de9654f42c1a1b4e8b..b8960c4959a5e53635180054d27d788105ebf134 100644 (file)
@@ -107,20 +107,16 @@ extern int iterate_over_keyring(const struct key *keyring,
                                int (*func)(const struct key *key, void *data),
                                void *data);
 
-typedef int (*key_match_func_t)(const struct key *, const void *);
-
 struct keyring_search_context {
        struct keyring_index_key index_key;
        const struct cred       *cred;
-       key_match_func_t        match;
-       const void              *match_data;
+       struct key_match_data   match_data;
        unsigned                flags;
-#define KEYRING_SEARCH_LOOKUP_TYPE     0x0001  /* [as type->def_lookup_type] */
-#define KEYRING_SEARCH_NO_STATE_CHECK  0x0002  /* Skip state checks */
-#define KEYRING_SEARCH_DO_STATE_CHECK  0x0004  /* Override NO_STATE_CHECK */
-#define KEYRING_SEARCH_NO_UPDATE_TIME  0x0008  /* Don't update times */
-#define KEYRING_SEARCH_NO_CHECK_PERM   0x0010  /* Don't check permissions */
-#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0020  /* Give an error on excessive depth */
+#define KEYRING_SEARCH_NO_STATE_CHECK  0x0001  /* Skip state checks */
+#define KEYRING_SEARCH_DO_STATE_CHECK  0x0002  /* Override NO_STATE_CHECK */
+#define KEYRING_SEARCH_NO_UPDATE_TIME  0x0004  /* Don't update times */
+#define KEYRING_SEARCH_NO_CHECK_PERM   0x0008  /* Don't check permissions */
+#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010  /* Give an error on excessive depth */
 
        int (*iterator)(const void *object, void *iterator_data);
 
@@ -131,6 +127,8 @@ struct keyring_search_context {
        struct timespec         now;
 };
 
+extern bool key_default_cmp(const struct key *key,
+                           const struct key_match_data *match_data);
 extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                                    struct keyring_search_context *ctx);
 
@@ -152,7 +150,8 @@ extern struct key *request_key_and_link(struct key_type *type,
                                        struct key *dest_keyring,
                                        unsigned long flags);
 
-extern int lookup_user_key_possessed(const struct key *key, const void *target);
+extern bool lookup_user_key_possessed(const struct key *key,
+                                     const struct key_match_data *match_data);
 extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
                                 key_perm_t perm);
 #define KEY_LOOKUP_CREATE      0x01
index 6d0cad16f00265a1dc31d8a0804984040fb47995..e17ba6aefdc0820b6c5c3af7cfc90d4e20094915 100644 (file)
@@ -799,7 +799,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        }
 
        key_ref = ERR_PTR(-EINVAL);
-       if (!index_key.type->match || !index_key.type->instantiate ||
+       if (!index_key.type->instantiate ||
            (!index_key.description && !index_key.type->preparse))
                goto error_put_type;
 
index e26f860e5f2ec5e88e77c797da6c8642b1291697..eff88a5f5d40da17611d381bcf4e219a90bcc972 100644 (file)
@@ -37,6 +37,8 @@ static int key_get_type_from_user(char *type,
                return ret;
        if (ret == 0 || ret >= len)
                return -EINVAL;
+       if (type[0] == '.')
+               return -EPERM;
        type[len - 1] = '\0';
        return 0;
 }
index 8314a7d2104df95ead666466213819504a31d5c2..8177010174f7b3d47773a43e48bf2b171b264c5f 100644 (file)
@@ -89,7 +89,6 @@ struct key_type key_type_keyring = {
        .preparse       = keyring_preparse,
        .free_preparse  = keyring_free_preparse,
        .instantiate    = keyring_instantiate,
-       .match          = user_match,
        .revoke         = keyring_revoke,
        .destroy        = keyring_destroy,
        .describe       = keyring_describe,
@@ -511,6 +510,15 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
 }
 EXPORT_SYMBOL(keyring_alloc);
 
+/*
+ * By default, we keys found by getting an exact match on their descriptions.
+ */
+bool key_default_cmp(const struct key *key,
+                    const struct key_match_data *match_data)
+{
+       return strcmp(key->description, match_data->raw_data) == 0;
+}
+
 /*
  * Iteration function to consider each key found.
  */
@@ -545,7 +553,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
        }
 
        /* keys that don't match */
-       if (!ctx->match(key, ctx->match_data)) {
+       if (!ctx->match_data.cmp(key, &ctx->match_data)) {
                kleave(" = 0 [!match]");
                return 0;
        }
@@ -585,8 +593,7 @@ skipped:
  */
 static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
 {
-       if ((ctx->flags & KEYRING_SEARCH_LOOKUP_TYPE) ==
-           KEYRING_SEARCH_LOOKUP_DIRECT) {
+       if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
                const void *object;
 
                object = assoc_array_find(&keyring->keys,
@@ -627,7 +634,7 @@ static bool search_nested_keyrings(struct key *keyring,
        /* Check to see if this top-level keyring is what we are looking for
         * and whether it is valid or not.
         */
-       if (ctx->flags & KEYRING_SEARCH_LOOKUP_ITERATE ||
+       if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
            keyring_compare_object(keyring, &ctx->index_key)) {
                ctx->skipped_ret = 2;
                ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
@@ -885,16 +892,25 @@ key_ref_t keyring_search(key_ref_t keyring,
                .index_key.type         = type,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = type->match,
-               .match_data             = description,
-               .flags                  = (type->def_lookup_type |
-                                          KEYRING_SEARCH_DO_STATE_CHECK),
+               .match_data.cmp         = key_default_cmp,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_DO_STATE_CHECK,
        };
+       key_ref_t key;
+       int ret;
 
-       if (!ctx.match)
-               return ERR_PTR(-ENOKEY);
+       if (type->match_preparse) {
+               ret = type->match_preparse(&ctx.match_data);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+       }
 
-       return keyring_search_aux(keyring, &ctx);
+       key = keyring_search_aux(keyring, &ctx);
+
+       if (type->match_free)
+               type->match_free(&ctx.match_data);
+       return key;
 }
 EXPORT_SYMBOL(keyring_search);
 
@@ -1014,7 +1030,7 @@ static int keyring_detect_cycle_iterator(const void *object,
 
        /* We might get a keyring with matching index-key that is nonetheless a
         * different keyring. */
-       if (key != ctx->match_data)
+       if (key != ctx->match_data.raw_data)
                return 0;
 
        ctx->result = ERR_PTR(-EDEADLK);
@@ -1031,14 +1047,14 @@ static int keyring_detect_cycle_iterator(const void *object,
 static int keyring_detect_cycle(struct key *A, struct key *B)
 {
        struct keyring_search_context ctx = {
-               .index_key      = A->index_key,
-               .match_data     = A,
-               .iterator       = keyring_detect_cycle_iterator,
-               .flags          = (KEYRING_SEARCH_LOOKUP_DIRECT |
-                                  KEYRING_SEARCH_NO_STATE_CHECK |
-                                  KEYRING_SEARCH_NO_UPDATE_TIME |
-                                  KEYRING_SEARCH_NO_CHECK_PERM |
-                                  KEYRING_SEARCH_DETECT_TOO_DEEP),
+               .index_key              = A->index_key,
+               .match_data.raw_data    = A,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .iterator               = keyring_detect_cycle_iterator,
+               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
+                                          KEYRING_SEARCH_NO_UPDATE_TIME |
+                                          KEYRING_SEARCH_NO_CHECK_PERM |
+                                          KEYRING_SEARCH_DETECT_TOO_DEEP),
        };
 
        rcu_read_lock();
index d3f6f2fd21db84bc197ed82b14808b6bc9bc4e87..972eeb336b8145b0529001c38f64a53e2e8f8c5a 100644 (file)
@@ -194,10 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v)
                .index_key.type         = key->type,
                .index_key.description  = key->description,
                .cred                   = current_cred(),
-               .match                  = lookup_user_key_possessed,
-               .match_data             = key,
-               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
-                                          KEYRING_SEARCH_LOOKUP_DIRECT),
+               .match_data.cmp         = lookup_user_key_possessed,
+               .match_data.raw_data    = key,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
        };
 
        key_ref = make_key_ref(key, 0);
index 0cf8a130a267ca58fbc5599787c93b9913cfc576..bd536cb221e237c6cab654b4d4d927daf3f27340 100644 (file)
@@ -489,9 +489,10 @@ found:
 /*
  * See if the key we're looking at is the target key.
  */
-int lookup_user_key_possessed(const struct key *key, const void *target)
+bool lookup_user_key_possessed(const struct key *key,
+                              const struct key_match_data *match_data)
 {
-       return key == target;
+       return key == match_data->raw_data;
 }
 
 /*
@@ -516,9 +517,9 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
                          key_perm_t perm)
 {
        struct keyring_search_context ctx = {
-               .match  = lookup_user_key_possessed,
-               .flags  = (KEYRING_SEARCH_NO_STATE_CHECK |
-                          KEYRING_SEARCH_LOOKUP_DIRECT),
+               .match_data.cmp         = lookup_user_key_possessed,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
        };
        struct request_key_auth *rka;
        struct key *key;
@@ -673,7 +674,7 @@ try_again:
                ctx.index_key.type              = key->type;
                ctx.index_key.description       = key->description;
                ctx.index_key.desc_len          = strlen(key->description);
-               ctx.match_data                  = key;
+               ctx.match_data.raw_data         = key;
                kdebug("check possessed");
                skey_ref = search_process_keyrings(&ctx);
                kdebug("possessed=%p", skey_ref);
index 26a94f18af9444ef709fbc964de6fc1c92e4a8a5..bb4337c7ae1b3978fd5e36d692d8cacf27b89816 100644 (file)
@@ -513,9 +513,9 @@ struct key *request_key_and_link(struct key_type *type,
                .index_key.type         = type,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = type->match,
-               .match_data             = description,
-               .flags                  = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .match_data.cmp         = key_default_cmp,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
        };
        struct key *key;
        key_ref_t key_ref;
@@ -525,6 +525,14 @@ struct key *request_key_and_link(struct key_type *type,
               ctx.index_key.type->name, ctx.index_key.description,
               callout_info, callout_len, aux, dest_keyring, flags);
 
+       if (type->match_preparse) {
+               ret = type->match_preparse(&ctx.match_data);
+               if (ret < 0) {
+                       key = ERR_PTR(ret);
+                       goto error;
+               }
+       }
+
        /* search all the process keyrings for a key */
        key_ref = search_process_keyrings(&ctx);
 
@@ -537,7 +545,7 @@ struct key *request_key_and_link(struct key_type *type,
                        if (ret < 0) {
                                key_put(key);
                                key = ERR_PTR(ret);
-                               goto error;
+                               goto error_free;
                        }
                }
        } else if (PTR_ERR(key_ref) != -EAGAIN) {
@@ -547,12 +555,15 @@ struct key *request_key_and_link(struct key_type *type,
                 * should consult userspace if we can */
                key = ERR_PTR(-ENOKEY);
                if (!callout_info)
-                       goto error;
+                       goto error_free;
 
                key = construct_key_and_link(&ctx, callout_info, callout_len,
                                             aux, dest_keyring, flags);
        }
 
+error_free:
+       if (type->match_free)
+               type->match_free(&ctx.match_data);
 error:
        kleave(" = %p", key);
        return key;
index 842e6f410d5052b6e3dad7c7d0ac8d6290293733..6639e2cb885322c6a43924496b2a68be25b9a5e6 100644 (file)
@@ -44,12 +44,12 @@ struct key_type key_type_request_key_auth = {
        .read           = request_key_auth_read,
 };
 
-int request_key_auth_preparse(struct key_preparsed_payload *prep)
+static int request_key_auth_preparse(struct key_preparsed_payload *prep)
 {
        return 0;
 }
 
-void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
+static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
 {
 }
 
@@ -246,9 +246,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
                .index_key.type         = &key_type_request_key_auth,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = user_match,
-               .match_data             = description,
-               .flags                  = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .match_data.cmp         = key_default_cmp,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
        };
        struct key *authkey;
        key_ref_t authkey_ref;
index 6b804aa4529a171bfab534307903b142c23cf891..c0594cb07adab14f1efeb970a8c0dd85d86a7931 100644 (file)
@@ -1096,7 +1096,6 @@ struct key_type key_type_trusted = {
        .name = "trusted",
        .instantiate = trusted_instantiate,
        .update = trusted_update,
-       .match = user_match,
        .destroy = trusted_destroy,
        .describe = user_describe,
        .read = trusted_read,
index eee340011f2bd54d7b12f3f28a25ec3f8396b5fd..36b47bbd3d8cc277de55e0c0cdd722618ca13231 100644 (file)
@@ -26,12 +26,10 @@ static int logon_vet_description(const char *desc);
  */
 struct key_type key_type_user = {
        .name                   = "user",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = user_preparse,
        .free_preparse          = user_free_preparse,
        .instantiate            = generic_key_instantiate,
        .update                 = user_update,
-       .match                  = user_match,
        .revoke                 = user_revoke,
        .destroy                = user_destroy,
        .describe               = user_describe,
@@ -48,12 +46,10 @@ EXPORT_SYMBOL_GPL(key_type_user);
  */
 struct key_type key_type_logon = {
        .name                   = "logon",
-       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
        .preparse               = user_preparse,
        .free_preparse          = user_free_preparse,
        .instantiate            = generic_key_instantiate,
        .update                 = user_update,
-       .match                  = user_match,
        .revoke                 = user_revoke,
        .destroy                = user_destroy,
        .describe               = user_describe,
@@ -138,16 +134,6 @@ error:
 
 EXPORT_SYMBOL_GPL(user_update);
 
-/*
- * match users on their name
- */
-int user_match(const struct key *key, const void *description)
-{
-       return strcmp(key->description, description) == 0;
-}
-
-EXPORT_SYMBOL_GPL(user_match);
-
 /*
  * dispose of the links from a revoked keyring
  * - called with the key sem write-locked
index b0e940497e23bb47a0460e57a65952f2b4dc7e03..29e64d4ca099511520b8e5b8cf0af83255c52473 100644 (file)
@@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 
 /* binprm security operations */
 
+static int check_nnp_nosuid(const struct linux_binprm *bprm,
+                           const struct task_security_struct *old_tsec,
+                           const struct task_security_struct *new_tsec)
+{
+       int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
+       int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID);
+       int rc;
+
+       if (!nnp && !nosuid)
+               return 0; /* neither NNP nor nosuid */
+
+       if (new_tsec->sid == old_tsec->sid)
+               return 0; /* No change in credentials */
+
+       /*
+        * The only transitions we permit under NNP or nosuid
+        * are transitions to bounded SIDs, i.e. SIDs that are
+        * guaranteed to only be allowed a subset of the permissions
+        * of the current SID.
+        */
+       rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
+       if (rc) {
+               /*
+                * On failure, preserve the errno values for NNP vs nosuid.
+                * NNP:  Operation not permitted for caller.
+                * nosuid:  Permission denied to file.
+                */
+               if (nnp)
+                       return -EPERM;
+               else
+                       return -EACCES;
+       }
+       return 0;
+}
+
 static int selinux_bprm_set_creds(struct linux_binprm *bprm)
 {
        const struct task_security_struct *old_tsec;
@@ -2133,14 +2168,10 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                /* Reset exec SID on execve. */
                new_tsec->exec_sid = 0;
 
-               /*
-                * Minimize confusion: if no_new_privs or nosuid and a
-                * transition is explicitly requested, then fail the exec.
-                */
-               if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
-                       return -EPERM;
-               if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
-                       return -EACCES;
+               /* Fail on NNP or nosuid if not an allowed transition. */
+               rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+               if (rc)
+                       return rc;
        } else {
                /* Check for a default transition on this program. */
                rc = security_transition_sid(old_tsec->sid, isec->sid,
@@ -2148,15 +2179,19 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                                             &new_tsec->sid);
                if (rc)
                        return rc;
+
+               /*
+                * Fallback to old SID on NNP or nosuid if not an allowed
+                * transition.
+                */
+               rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+               if (rc)
+                       new_tsec->sid = old_tsec->sid;
        }
 
        ad.type = LSM_AUDIT_DATA_PATH;
        ad.u.path = bprm->file->f_path;
 
-       if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
-           (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS))
-               new_tsec->sid = old_tsec->sid;
-
        if (new_tsec->sid == old_tsec->sid) {
                rc = avc_has_perm(old_tsec->sid, isec->sid,
                                  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
@@ -4272,15 +4307,15 @@ static int selinux_socket_unix_may_send(struct socket *sock,
                            &ad);
 }
 
-static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
-                                   u32 peer_sid,
+static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
+                                   char *addrp, u16 family, u32 peer_sid,
                                    struct common_audit_data *ad)
 {
        int err;
        u32 if_sid;
        u32 node_sid;
 
-       err = sel_netif_sid(ifindex, &if_sid);
+       err = sel_netif_sid(ns, ifindex, &if_sid);
        if (err)
                return err;
        err = avc_has_perm(peer_sid, if_sid,
@@ -4373,8 +4408,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
                if (err)
                        return err;
-               err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
-                                              peer_sid, &ad);
+               err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
+                                              addrp, family, peer_sid, &ad);
                if (err) {
                        selinux_netlbl_err(skb, err, 0);
                        return err;
@@ -4692,10 +4727,9 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
-                       audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
-                                 "SELinux:  unrecognized netlink message"
-                                 " type=%hu for sclass=%hu\n",
-                                 nlh->nlmsg_type, sksec->sclass);
+                       WARN_ONCE(1, "selinux_nlmsg_perm: unrecognized netlink message:"
+                                 " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
+                                 sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
                        if (!selinux_enforcing || security_get_allow_unknown())
                                err = 0;
                }
@@ -4713,7 +4747,8 @@ out:
 
 #ifdef CONFIG_NETFILTER
 
-static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
+static unsigned int selinux_ip_forward(struct sk_buff *skb,
+                                      const struct net_device *indev,
                                       u16 family)
 {
        int err;
@@ -4739,14 +4774,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
 
        ad.type = LSM_AUDIT_DATA_NET;
        ad.u.net = &net;
-       ad.u.net->netif = ifindex;
+       ad.u.net->netif = indev->ifindex;
        ad.u.net->family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
                return NF_DROP;
 
        if (peerlbl_active) {
-               err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
-                                              peer_sid, &ad);
+               err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
+                                              addrp, family, peer_sid, &ad);
                if (err) {
                        selinux_netlbl_err(skb, err, 1);
                        return NF_DROP;
@@ -4775,7 +4810,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
                                         const struct net_device *out,
                                         int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_forward(skb, in->ifindex, PF_INET);
+       return selinux_ip_forward(skb, in, PF_INET);
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -4785,7 +4820,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
                                         const struct net_device *out,
                                         int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_forward(skb, in->ifindex, PF_INET6);
+       return selinux_ip_forward(skb, in, PF_INET6);
 }
 #endif /* IPV6 */
 
@@ -4873,11 +4908,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
        return NF_ACCEPT;
 }
 
-static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
+static unsigned int selinux_ip_postroute(struct sk_buff *skb,
+                                        const struct net_device *outdev,
                                         u16 family)
 {
        u32 secmark_perm;
        u32 peer_sid;
+       int ifindex = outdev->ifindex;
        struct sock *sk;
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
@@ -4958,6 +4995,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                        case PF_INET6:
                                if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
                                        return NF_ACCEPT;
+                               break;
                        default:
                                return NF_DROP_ERR(-ECONNREFUSED);
                        }
@@ -4989,7 +5027,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                u32 if_sid;
                u32 node_sid;
 
-               if (sel_netif_sid(ifindex, &if_sid))
+               if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
                        return NF_DROP;
                if (avc_has_perm(peer_sid, if_sid,
                                 SECCLASS_NETIF, NETIF__EGRESS, &ad))
@@ -5011,7 +5049,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
                                           const struct net_device *out,
                                           int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_postroute(skb, out->ifindex, PF_INET);
+       return selinux_ip_postroute(skb, out, PF_INET);
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -5021,7 +5059,7 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
                                           const struct net_device *out,
                                           int (*okfn)(struct sk_buff *))
 {
-       return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
+       return selinux_ip_postroute(skb, out, PF_INET6);
 }
 #endif /* IPV6 */
 
@@ -6035,7 +6073,7 @@ security_initcall(selinux_init);
 
 #if defined(CONFIG_NETFILTER)
 
-static struct nf_hook_ops selinux_ipv4_ops[] = {
+static struct nf_hook_ops selinux_nf_ops[] = {
        {
                .hook =         selinux_ipv4_postroute,
                .owner =        THIS_MODULE,
@@ -6056,12 +6094,8 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
                .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_LOCAL_OUT,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
-       }
-};
-
+       },
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-static struct nf_hook_ops selinux_ipv6_ops[] = {
        {
                .hook =         selinux_ipv6_postroute,
                .owner =        THIS_MODULE,
@@ -6075,32 +6109,24 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
                .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP6_PRI_SELINUX_FIRST,
-       }
-};
-
+       },
 #endif /* IPV6 */
+};
 
 static int __init selinux_nf_ip_init(void)
 {
-       int err = 0;
+       int err;
 
        if (!selinux_enabled)
-               goto out;
+               return 0;
 
        printk(KERN_DEBUG "SELinux:  Registering netfilter hooks\n");
 
-       err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
+       err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
        if (err)
-               panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
+               panic("SELinux: nf_register_hooks: error %d\n", err);
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
-       if (err)
-               panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
-#endif /* IPV6 */
-
-out:
-       return err;
+       return 0;
 }
 
 __initcall(selinux_nf_ip_init);
@@ -6110,10 +6136,7 @@ static void selinux_nf_ip_exit(void)
 {
        printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
 
-       nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
-#endif /* IPV6 */
+       nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
 }
 #endif
 
index 57c6eae81eacac6226273963ee89602cdf736983..c7214544409015a3fbc6cda9a7386e394f50be2b 100644 (file)
 #ifndef _SELINUX_NETIF_H_
 #define _SELINUX_NETIF_H_
 
+#include <net/net_namespace.h>
+
 void sel_netif_flush(void);
 
-int sel_netif_sid(int ifindex, u32 *sid);
+int sel_netif_sid(struct net *ns, int ifindex, u32 *sid);
 
 #endif /* _SELINUX_NETIF_H_ */
 
index 078e553f52f27a03ab83490f20bb2353782d2ef2..81fa718d5cb38817fdda9ad580f8316ef5d3e5c6 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/binfmts.h>
 #include <linux/in.h>
 #include <linux/spinlock.h>
+#include <net/net_namespace.h>
 #include "flask.h"
 #include "avc.h"
 
@@ -78,6 +79,7 @@ struct ipc_security_struct {
 };
 
 struct netif_security_struct {
+       struct net *ns;                 /* network namespace */
        int ifindex;                    /* device index */
        u32 sid;                        /* SID for this interface */
 };
index 50ce177d71a0561cdc0c0aaf4aabb13e4c7662ef..e607b4473ef678c71e8a7a882f9b298491b52dd9 100644 (file)
@@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
 
 /**
  * sel_netif_hashfn - Hashing function for the interface table
+ * @ns: the network namespace
  * @ifindex: the network interface
  *
  * Description:
@@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
  * bucket number for the given interface.
  *
  */
-static inline u32 sel_netif_hashfn(int ifindex)
+static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
 {
-       return (ifindex & (SEL_NETIF_HASH_SIZE - 1));
+       return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1));
 }
 
 /**
  * sel_netif_find - Search for an interface record
+ * @ns: the network namespace
  * @ifindex: the network interface
  *
  * Description:
@@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex)
  * If an entry can not be found in the table return NULL.
  *
  */
-static inline struct sel_netif *sel_netif_find(int ifindex)
+static inline struct sel_netif *sel_netif_find(const struct net *ns,
+                                              int ifindex)
 {
-       int idx = sel_netif_hashfn(ifindex);
+       int idx = sel_netif_hashfn(ns, ifindex);
        struct sel_netif *netif;
 
        list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
-               /* all of the devices should normally fit in the hash, so we
-                * optimize for that case */
-               if (likely(netif->nsec.ifindex == ifindex))
+               if (net_eq(netif->nsec.ns, ns) &&
+                   netif->nsec.ifindex == ifindex)
                        return netif;
 
        return NULL;
@@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif)
        if (sel_netif_total >= SEL_NETIF_HASH_MAX)
                return -ENOSPC;
 
-       idx = sel_netif_hashfn(netif->nsec.ifindex);
+       idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex);
        list_add_rcu(&netif->list, &sel_netif_hash[idx]);
        sel_netif_total++;
 
@@ -120,6 +122,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
 
 /**
  * sel_netif_sid_slow - Lookup the SID of a network interface using the policy
+ * @ns: the network namespace
  * @ifindex: the network interface
  * @sid: interface SID
  *
@@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
  * failure.
  *
  */
-static int sel_netif_sid_slow(int ifindex, u32 *sid)
+static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
 {
        int ret;
        struct sel_netif *netif;
@@ -140,7 +143,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
        /* NOTE: we always use init's network namespace since we don't
         * currently support containers */
 
-       dev = dev_get_by_index(&init_net, ifindex);
+       dev = dev_get_by_index(ns, ifindex);
        if (unlikely(dev == NULL)) {
                printk(KERN_WARNING
                       "SELinux: failure in sel_netif_sid_slow(),"
@@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
        }
 
        spin_lock_bh(&sel_netif_lock);
-       netif = sel_netif_find(ifindex);
+       netif = sel_netif_find(ns, ifindex);
        if (netif != NULL) {
                *sid = netif->nsec.sid;
                ret = 0;
@@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
        ret = security_netif_sid(dev->name, &new->nsec.sid);
        if (ret != 0)
                goto out;
+       new->nsec.ns = ns;
        new->nsec.ifindex = ifindex;
        ret = sel_netif_insert(new);
        if (ret != 0)
@@ -184,6 +188,7 @@ out:
 
 /**
  * sel_netif_sid - Lookup the SID of a network interface
+ * @ns: the network namespace
  * @ifindex: the network interface
  * @sid: interface SID
  *
@@ -195,12 +200,12 @@ out:
  * on failure.
  *
  */
-int sel_netif_sid(int ifindex, u32 *sid)
+int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
 {
        struct sel_netif *netif;
 
        rcu_read_lock();
-       netif = sel_netif_find(ifindex);
+       netif = sel_netif_find(ns, ifindex);
        if (likely(netif != NULL)) {
                *sid = netif->nsec.sid;
                rcu_read_unlock();
@@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid)
        }
        rcu_read_unlock();
 
-       return sel_netif_sid_slow(ifindex, sid);
+       return sel_netif_sid_slow(ns, ifindex, sid);
 }
 
 /**
  * sel_netif_kill - Remove an entry from the network interface table
+ * @ns: the network namespace
  * @ifindex: the network interface
  *
  * Description:
@@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid)
  * table if it exists.
  *
  */
-static void sel_netif_kill(int ifindex)
+static void sel_netif_kill(const struct net *ns, int ifindex)
 {
        struct sel_netif *netif;
 
        rcu_read_lock();
        spin_lock_bh(&sel_netif_lock);
-       netif = sel_netif_find(ifindex);
+       netif = sel_netif_find(ns, ifindex);
        if (netif)
                sel_netif_destroy(netif);
        spin_unlock_bh(&sel_netif_lock);
@@ -257,11 +263,8 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 
-       if (dev_net(dev) != &init_net)
-               return NOTIFY_DONE;
-
        if (event == NETDEV_DOWN)
-               sel_netif_kill(dev->ifindex);
+               sel_netif_kill(dev_net(dev), dev->ifindex);
 
        return NOTIFY_DONE;
 }
index 2aa9d172dc7e73d87ccbc7f73bbc3e8ad2206e45..a1d3944751b9e2fbfd23e18b694b00cd150880dc 100644 (file)
@@ -728,7 +728,7 @@ static int security_validtrans_handle_fail(struct context *ocontext,
        if (context_struct_to_string(tcontext, &t, &tlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                 "security_validate_transition:  denied for"
+                 "op=security_validate_transition seresult=denied"
                  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
                  o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
 out:
@@ -877,7 +877,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
                        audit_log(current->audit_context,
                                  GFP_ATOMIC, AUDIT_SELINUX_ERR,
                                  "op=security_bounded_transition "
-                                 "result=denied "
+                                 "seresult=denied "
                                  "oldcontext=%s newcontext=%s",
                                  old_name, new_name);
                }
@@ -1351,8 +1351,8 @@ static int compute_sid_handle_invalid_context(
        if (context_struct_to_string(newcontext, &n, &nlen))
                goto out;
        audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                 "security_compute_sid:  invalid context %s"
-                 " for scontext=%s"
+                 "op=security_compute_sid invalid_context=%s"
+                 " scontext=%s"
                  " tcontext=%s"
                  " tclass=%s",
                  n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
@@ -2607,8 +2607,10 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
                rc = convert_context_handle_invalid_context(&newcon);
                if (rc) {
                        if (!context_struct_to_string(&newcon, &s, &len)) {
-                               audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
-                                         "security_sid_mls_copy: invalid context %s", s);
+                               audit_log(current->audit_context,
+                                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                                         "op=security_sid_mls_copy "
+                                         "invalid_context=%s", s);
                                kfree(s);
                        }
                        goto out_unlock;
index e69de9c642b7f03c8648457495511ca0c8bc839c..b065f97894185557c88fe77c554719a3deca955d 100644 (file)
@@ -12,3 +12,19 @@ config SECURITY_SMACK
          of other mandatory security schemes.
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_SMACK_BRINGUP
+       bool "Reporting on access granted by Smack rules"
+       depends on SECURITY_SMACK
+       default n
+       help
+         Enable the bring-up ("b") access mode in Smack rules.
+         When access is granted by a rule with the "b" mode a
+         message about the access requested is generated. The
+         intention is that a process can be granted a wide set
+         of access initially with the bringup mode set on the
+         rules. The developer can use the information to
+         identify which rules are necessary and what accesses
+         may be inappropriate. The developer can reduce the
+         access rule set once the behavior is well understood.
+         This is a superior mechanism to the oft abused
+         "permissive" mode of other systems.
index 020307ef097296f2eac85be8ae823fdad93ff508..b828a379377c9cd1c2dee54bc2ddab5b3bde920a 100644 (file)
@@ -71,11 +71,11 @@ struct smack_known {
 #define SMK_CIPSOLEN   24
 
 struct superblock_smack {
-       char            *smk_root;
-       char            *smk_floor;
-       char            *smk_hat;
-       char            *smk_default;
-       int             smk_initialized;
+       struct smack_known      *smk_root;
+       struct smack_known      *smk_floor;
+       struct smack_known      *smk_hat;
+       struct smack_known      *smk_default;
+       int                     smk_initialized;
 };
 
 struct socket_smack {
@@ -88,7 +88,7 @@ struct socket_smack {
  * Inode smack data
  */
 struct inode_smack {
-       char                    *smk_inode;     /* label of the fso */
+       struct smack_known      *smk_inode;     /* label of the fso */
        struct smack_known      *smk_task;      /* label of the task */
        struct smack_known      *smk_mmap;      /* label of the mmap domain */
        struct mutex            smk_lock;       /* initialization lock */
@@ -112,7 +112,7 @@ struct task_smack {
 struct smack_rule {
        struct list_head        list;
        struct smack_known      *smk_subject;
-       char                    *smk_object;
+       struct smack_known      *smk_object;
        int                     smk_access;
 };
 
@@ -123,7 +123,7 @@ struct smk_netlbladdr {
        struct list_head        list;
        struct sockaddr_in      smk_host;       /* network address */
        struct in_addr          smk_mask;       /* network mask */
-       char                    *smk_label;     /* label */
+       struct smack_known      *smk_label;     /* label */
 };
 
 /*
@@ -191,6 +191,7 @@ struct smk_port_label {
  */
 #define MAY_TRANSMUTE  0x00001000      /* Controls directory labeling */
 #define MAY_LOCK       0x00002000      /* Locks should be writes, but ... */
+#define MAY_BRINGUP    0x00004000      /* Report use of this rule */
 
 /*
  * Just to make the common cases easier to deal with
@@ -200,9 +201,9 @@ struct smk_port_label {
 #define MAY_NOT                0
 
 /*
- * Number of access types used by Smack (rwxatl)
+ * Number of access types used by Smack (rwxatlb)
  */
-#define SMK_NUM_ACCESS_TYPE 6
+#define SMK_NUM_ACCESS_TYPE 7
 
 /* SMACK data */
 struct smack_audit_data {
@@ -226,23 +227,23 @@ struct smk_audit_info {
 /*
  * These functions are in smack_lsm.c
  */
-struct inode_smack *new_inode_smack(char *);
+struct inode_smack *new_inode_smack(struct smack_known *);
 
 /*
  * These functions are in smack_access.c
  */
 int smk_access_entry(char *, char *, struct list_head *);
-int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
-int smk_tskacc(struct task_smack *, char *, u32, struct smk_audit_info *);
-int smk_curacc(char *, u32, struct smk_audit_info *);
+int smk_access(struct smack_known *, struct smack_known *,
+              int, struct smk_audit_info *);
+int smk_tskacc(struct task_smack *, struct smack_known *,
+              u32, struct smk_audit_info *);
+int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
 struct smack_known *smack_from_secid(const u32);
 char *smk_parse_smack(const char *string, int len);
 int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
-char *smk_import(const char *, int);
 struct smack_known *smk_import_entry(const char *, int);
 void smk_insert_entry(struct smack_known *skp);
 struct smack_known *smk_find_entry(const char *);
-u32 smack_to_secid(const char *);
 
 /*
  * Shared data.
@@ -252,7 +253,7 @@ extern int smack_cipso_mapped;
 extern struct smack_known *smack_net_ambient;
 extern struct smack_known *smack_onlycap;
 extern struct smack_known *smack_syslog_label;
-extern const char *smack_cipso_option;
+extern struct smack_known smack_cipso_option;
 extern int smack_ptrace_rule;
 
 extern struct smack_known smack_known_floor;
@@ -281,9 +282,9 @@ static inline int smk_inode_transmutable(const struct inode *isp)
 }
 
 /*
- * Present a pointer to the smack label in an inode blob.
+ * Present a pointer to the smack label entry in an inode blob.
  */
-static inline char *smk_of_inode(const struct inode *isp)
+static inline struct smack_known *smk_of_inode(const struct inode *isp)
 {
        struct inode_smack *sip = isp->i_security;
        return sip->smk_inode;
index f97d0842e6217a3578caa85730c95ce6b5683087..5b970ffde024aff51a8f59bc54f47107916ce0de 100644 (file)
@@ -94,7 +94,7 @@ int smk_access_entry(char *subject_label, char *object_label,
        struct smack_rule *srp;
 
        list_for_each_entry_rcu(srp, rule_list, list) {
-               if (srp->smk_object == object_label &&
+               if (srp->smk_object->smk_known == object_label &&
                    srp->smk_subject->smk_known == subject_label) {
                        may = srp->smk_access;
                        break;
@@ -111,8 +111,8 @@ int smk_access_entry(char *subject_label, char *object_label,
 
 /**
  * smk_access - determine if a subject has a specific access to an object
- * @subject_known: a pointer to the subject's Smack label entry
- * @object_label: a pointer to the object's Smack label
+ * @subject: a pointer to the subject's Smack label entry
+ * @object: a pointer to the object's Smack label entry
  * @request: the access requested, in "MAY" format
  * @a : a pointer to the audit data
  *
@@ -122,8 +122,8 @@ int smk_access_entry(char *subject_label, char *object_label,
  *
  * Smack labels are shared on smack_list
  */
-int smk_access(struct smack_known *subject_known, char *object_label,
-               int request, struct smk_audit_info *a)
+int smk_access(struct smack_known *subject, struct smack_known *object,
+              int request, struct smk_audit_info *a)
 {
        int may = MAY_NOT;
        int rc = 0;
@@ -133,7 +133,7 @@ int smk_access(struct smack_known *subject_known, char *object_label,
         *
         * A star subject can't access any object.
         */
-       if (subject_known == &smack_known_star) {
+       if (subject == &smack_known_star) {
                rc = -EACCES;
                goto out_audit;
        }
@@ -142,28 +142,28 @@ int smk_access(struct smack_known *subject_known, char *object_label,
         * Tasks cannot be assigned the internet label.
         * An internet subject can access any object.
         */
-       if (object_label == smack_known_web.smk_known ||
-           subject_known == &smack_known_web)
+       if (object == &smack_known_web ||
+           subject == &smack_known_web)
                goto out_audit;
        /*
         * A star object can be accessed by any subject.
         */
-       if (object_label == smack_known_star.smk_known)
+       if (object == &smack_known_star)
                goto out_audit;
        /*
         * An object can be accessed in any way by a subject
         * with the same label.
         */
-       if (subject_known->smk_known == object_label)
+       if (subject->smk_known == object->smk_known)
                goto out_audit;
        /*
         * A hat subject can read any object.
         * A floor object can be read by any subject.
         */
        if ((request & MAY_ANYREAD) == request) {
-               if (object_label == smack_known_floor.smk_known)
+               if (object == &smack_known_floor)
                        goto out_audit;
-               if (subject_known == &smack_known_hat)
+               if (subject == &smack_known_hat)
                        goto out_audit;
        }
        /*
@@ -174,27 +174,38 @@ int smk_access(struct smack_known *subject_known, char *object_label,
         * indicates there is no entry for this pair.
         */
        rcu_read_lock();
-       may = smk_access_entry(subject_known->smk_known, object_label,
-                               &subject_known->smk_rules);
+       may = smk_access_entry(subject->smk_known, object->smk_known,
+                              &subject->smk_rules);
        rcu_read_unlock();
 
-       if (may > 0 && (request & may) == request)
+       if (may <= 0 || (request & may) != request) {
+               rc = -EACCES;
                goto out_audit;
+       }
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+       /*
+        * Return a positive value if using bringup mode.
+        * This allows the hooks to identify checks that
+        * succeed because of "b" rules.
+        */
+       if (may & MAY_BRINGUP)
+               rc = MAY_BRINGUP;
+#endif
 
-       rc = -EACCES;
 out_audit:
 #ifdef CONFIG_AUDIT
        if (a)
-               smack_log(subject_known->smk_known, object_label, request,
-                               rc, a);
+               smack_log(subject->smk_known, object->smk_known,
+                         request, rc, a);
 #endif
+
        return rc;
 }
 
 /**
  * smk_tskacc - determine if a task has a specific access to an object
- * @tsp: a pointer to the subject task
- * @obj_label: a pointer to the object's Smack label
+ * @tsp: a pointer to the subject's task
+ * @obj_known: a pointer to the object's label entry
  * @mode: the access requested, in "MAY" format
  * @a : common audit data
  *
@@ -203,24 +214,25 @@ out_audit:
  * non zero otherwise. It allows that the task may have the capability
  * to override the rules.
  */
-int smk_tskacc(struct task_smack *subject, char *obj_label,
+int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
               u32 mode, struct smk_audit_info *a)
 {
-       struct smack_known *skp = smk_of_task(subject);
+       struct smack_known *sbj_known = smk_of_task(tsp);
        int may;
        int rc;
 
        /*
         * Check the global rule list
         */
-       rc = smk_access(skp, obj_label, mode, NULL);
-       if (rc == 0) {
+       rc = smk_access(sbj_known, obj_known, mode, NULL);
+       if (rc >= 0) {
                /*
                 * If there is an entry in the task's rule list
                 * it can further restrict access.
                 */
-               may = smk_access_entry(skp->smk_known, obj_label,
-                                       &subject->smk_rules);
+               may = smk_access_entry(sbj_known->smk_known,
+                                      obj_known->smk_known,
+                                      &tsp->smk_rules);
                if (may < 0)
                        goto out_audit;
                if ((mode & may) == mode)
@@ -237,14 +249,15 @@ int smk_tskacc(struct task_smack *subject, char *obj_label,
 out_audit:
 #ifdef CONFIG_AUDIT
        if (a)
-               smack_log(skp->smk_known, obj_label, mode, rc, a);
+               smack_log(sbj_known->smk_known, obj_known->smk_known,
+                         mode, rc, a);
 #endif
        return rc;
 }
 
 /**
  * smk_curacc - determine if current has a specific access to an object
- * @obj_label: a pointer to the object's Smack label
+ * @obj_known: a pointer to the object's Smack label entry
  * @mode: the access requested, in "MAY" format
  * @a : common audit data
  *
@@ -253,11 +266,12 @@ out_audit:
  * non zero otherwise. It allows that current may have the capability
  * to override the rules.
  */
-int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
+int smk_curacc(struct smack_known *obj_known,
+              u32 mode, struct smk_audit_info *a)
 {
        struct task_smack *tsp = current_security();
 
-       return smk_tskacc(tsp, obj_label, mode, a);
+       return smk_tskacc(tsp, obj_known, mode, a);
 }
 
 #ifdef CONFIG_AUDIT
@@ -328,6 +342,13 @@ void smack_log(char *subject_label, char *object_label, int request,
        struct smack_audit_data *sad;
        struct common_audit_data *a = &ad->a;
 
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+       /*
+        * The result may be positive in bringup mode.
+        */
+       if (result > 0)
+               result = 0;
+#endif
        /* check if we have to log the current event */
        if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
                return;
@@ -543,27 +564,6 @@ unlockout:
        return skp;
 }
 
-/**
- * smk_import - import a smack label
- * @string: a text string that might be a Smack label
- * @len: the maximum size, or zero if it is NULL terminated.
- *
- * Returns a pointer to the label in the label list that
- * matches the passed string, adding it if necessary.
- */
-char *smk_import(const char *string, int len)
-{
-       struct smack_known *skp;
-
-       /* labels cannot begin with a '-' */
-       if (string[0] == '-')
-               return NULL;
-       skp = smk_import_entry(string, len);
-       if (skp == NULL)
-               return NULL;
-       return skp->smk_known;
-}
-
 /**
  * smack_from_secid - find the Smack label associated with a secid
  * @secid: an integer that might be associated with a Smack label
@@ -590,19 +590,3 @@ struct smack_known *smack_from_secid(const u32 secid)
        rcu_read_unlock();
        return &smack_known_invalid;
 }
-
-/**
- * smack_to_secid - find the secid associated with a Smack label
- * @smack: the Smack label
- *
- * Returns the appropriate secid if there is one,
- * otherwise 0
- */
-u32 smack_to_secid(const char *smack)
-{
-       struct smack_known *skp = smk_find_entry(smack);
-
-       if (skp == NULL)
-               return 0;
-       return skp->smk_secid;
-}
index e6ab307ce86e2fc1d1d04d35d2869fe1385ea724..93dc876734a4f7f7db8097bf014f52aba6ec05c4 100644 (file)
 
 LIST_HEAD(smk_ipv6_port_list);
 
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static void smk_bu_mode(int mode, char *s)
+{
+       int i = 0;
+
+       if (mode & MAY_READ)
+               s[i++] = 'r';
+       if (mode & MAY_WRITE)
+               s[i++] = 'w';
+       if (mode & MAY_EXEC)
+               s[i++] = 'x';
+       if (mode & MAY_APPEND)
+               s[i++] = 'a';
+       if (mode & MAY_TRANSMUTE)
+               s[i++] = 't';
+       if (mode & MAY_LOCK)
+               s[i++] = 'l';
+       if (i == 0)
+               s[i++] = '-';
+       s[i] = '\0';
+}
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_note(char *note, struct smack_known *sskp,
+                      struct smack_known *oskp, int mode, int rc)
+{
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) %s\n",
+               sskp->smk_known, oskp->smk_known, acc, note);
+       return 0;
+}
+#else
+#define smk_bu_note(note, sskp, oskp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_current(char *note, struct smack_known *oskp,
+                         int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) %s %s\n",
+               tsp->smk_task->smk_known, oskp->smk_known,
+               acc, current->comm, note);
+       return 0;
+}
+#else
+#define smk_bu_current(note, oskp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_task(struct task_struct *otp, int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       struct task_smack *otsp = task_security(otp);
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
+               tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc,
+               current->comm, otp->comm);
+       return 0;
+}
+#else
+#define smk_bu_task(otp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_inode(struct inode *inode, int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) inode=(%s %ld) %s\n",
+               tsp->smk_task->smk_known, smk_of_inode(inode)->smk_known, acc,
+               inode->i_sb->s_id, inode->i_ino, current->comm);
+       return 0;
+}
+#else
+#define smk_bu_inode(inode, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_file(struct file *file, int mode, int rc)
+{
+       struct task_smack *tsp = current_security();
+       struct smack_known *sskp = tsp->smk_task;
+       struct inode *inode = file->f_inode;
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+               sskp->smk_known, (char *)file->f_security, acc,
+               inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+               current->comm);
+       return 0;
+}
+#else
+#define smk_bu_file(file, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_credfile(const struct cred *cred, struct file *file,
+                               int mode, int rc)
+{
+       struct task_smack *tsp = cred->security;
+       struct smack_known *sskp = tsp->smk_task;
+       struct inode *inode = file->f_inode;
+       char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+       if (rc <= 0)
+               return rc;
+
+       smk_bu_mode(mode, acc);
+       pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+               sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
+               inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+               current->comm);
+       return 0;
+}
+#else
+#define smk_bu_credfile(cred, file, mode, RC) (RC)
+#endif
+
 /**
  * smk_fetch - Fetch the smack label from a file.
  * @ip: a pointer to the inode
@@ -87,11 +232,11 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
 
 /**
  * new_inode_smack - allocate an inode security blob
- * @smack: a pointer to the Smack label to use in the blob
+ * @skp: a pointer to the Smack label entry to use in the blob
  *
  * Returns the new blob or NULL if there's no memory available
  */
-struct inode_smack *new_inode_smack(char *smack)
+struct inode_smack *new_inode_smack(struct smack_known *skp)
 {
        struct inode_smack *isp;
 
@@ -99,7 +244,7 @@ struct inode_smack *new_inode_smack(char *smack)
        if (isp == NULL)
                return NULL;
 
-       isp->smk_inode = smack;
+       isp->smk_inode = skp;
        isp->smk_flags = 0;
        mutex_init(&isp->smk_lock);
 
@@ -178,20 +323,20 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode)
 /**
  * smk_ptrace_rule_check - helper for ptrace access
  * @tracer: tracer process
- * @tracee_label: label of the process that's about to be traced,
- *                the pointer must originate from smack structures
+ * @tracee_known: label entry of the process that's about to be traced
  * @mode: ptrace attachment mode (PTRACE_MODE_*)
  * @func: name of the function that called us, used for audit
  *
  * Returns 0 on access granted, -error on error
  */
-static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
+static int smk_ptrace_rule_check(struct task_struct *tracer,
+                                struct smack_known *tracee_known,
                                 unsigned int mode, const char *func)
 {
        int rc;
        struct smk_audit_info ad, *saip = NULL;
        struct task_smack *tsp;
-       struct smack_known *skp;
+       struct smack_known *tracer_known;
 
        if ((mode & PTRACE_MODE_NOAUDIT) == 0) {
                smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK);
@@ -200,12 +345,12 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
        }
 
        tsp = task_security(tracer);
-       skp = smk_of_task(tsp);
+       tracer_known = smk_of_task(tsp);
 
        if ((mode & PTRACE_MODE_ATTACH) &&
            (smack_ptrace_rule == SMACK_PTRACE_EXACT ||
             smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
-               if (skp->smk_known == tracee_label)
+               if (tracer_known->smk_known == tracee_known->smk_known)
                        rc = 0;
                else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
                        rc = -EACCES;
@@ -215,13 +360,15 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
                        rc = -EACCES;
 
                if (saip)
-                       smack_log(skp->smk_known, tracee_label, 0, rc, saip);
+                       smack_log(tracer_known->smk_known,
+                                 tracee_known->smk_known,
+                                 0, rc, saip);
 
                return rc;
        }
 
        /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
-       rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip);
+       rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
        return rc;
 }
 
@@ -250,7 +397,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
 
        skp = smk_of_task(task_security(ctp));
 
-       rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__);
+       rc = smk_ptrace_rule_check(current, skp, mode, __func__);
        return rc;
 }
 
@@ -273,8 +420,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
 
        skp = smk_of_task(current_security());
 
-       rc = smk_ptrace_rule_check(ptp, skp->smk_known,
-                                  PTRACE_MODE_ATTACH, __func__);
+       rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
        return rc;
 }
 
@@ -318,10 +464,10 @@ static int smack_sb_alloc_security(struct super_block *sb)
        if (sbsp == NULL)
                return -ENOMEM;
 
-       sbsp->smk_root = smack_known_floor.smk_known;
-       sbsp->smk_default = smack_known_floor.smk_known;
-       sbsp->smk_floor = smack_known_floor.smk_known;
-       sbsp->smk_hat = smack_known_hat.smk_known;
+       sbsp->smk_root = &smack_known_floor;
+       sbsp->smk_default = &smack_known_floor;
+       sbsp->smk_floor = &smack_known_floor;
+       sbsp->smk_hat = &smack_known_hat;
        /*
         * smk_initialized will be zero from kzalloc.
         */
@@ -405,7 +551,6 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
        struct smack_known *skp;
        char *op;
        char *commap;
-       char *nsp;
        int transmute = 0;
        int specified = 0;
 
@@ -421,38 +566,38 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
 
                if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
                        op += strlen(SMK_FSHAT);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_hat = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_hat = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
                        op += strlen(SMK_FSFLOOR);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_floor = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_floor = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSDEFAULT,
                                   strlen(SMK_FSDEFAULT)) == 0) {
                        op += strlen(SMK_FSDEFAULT);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_default = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_default = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
                        op += strlen(SMK_FSROOT);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_root = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_root = skp;
                                specified = 1;
                        }
                } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
                        op += strlen(SMK_FSTRANS);
-                       nsp = smk_import(op, 0);
-                       if (nsp != NULL) {
-                               sp->smk_root = nsp;
+                       skp = smk_import_entry(op, 0);
+                       if (skp != NULL) {
+                               sp->smk_root = skp;
                                transmute = 1;
                                specified = 1;
                        }
@@ -469,8 +614,8 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
                 * Unprivileged mounts get root and default from the caller.
                 */
                skp = smk_of_current();
-               sp->smk_root = skp->smk_known;
-               sp->smk_default = skp->smk_known;
+               sp->smk_root = skp;
+               sp->smk_default = skp;
        }
        /*
         * Initialize the root inode.
@@ -507,6 +652,7 @@ static int smack_sb_statfs(struct dentry *dentry)
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
+       rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc);
        return rc;
 }
 
@@ -546,7 +692,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
                tracer = ptrace_parent(current);
                if (likely(tracer != NULL))
                        rc = smk_ptrace_rule_check(tracer,
-                                                  isp->smk_task->smk_known,
+                                                  isp->smk_task,
                                                   PTRACE_MODE_ATTACH,
                                                   __func__);
                rcu_read_unlock();
@@ -607,7 +753,7 @@ static int smack_inode_alloc_security(struct inode *inode)
 {
        struct smack_known *skp = smk_of_current();
 
-       inode->i_security = new_inode_smack(skp->smk_known);
+       inode->i_security = new_inode_smack(skp);
        if (inode->i_security == NULL)
                return -ENOMEM;
        return 0;
@@ -627,8 +773,8 @@ static void smack_inode_free_security(struct inode *inode)
 
 /**
  * smack_inode_init_security - copy out the smack from an inode
- * @inode: the inode
- * @dir: unused
+ * @inode: the newly created inode
+ * @dir: containing directory object
  * @qstr: unused
  * @name: where to put the attribute name
  * @value: where to put the attribute value
@@ -642,8 +788,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 {
        struct inode_smack *issp = inode->i_security;
        struct smack_known *skp = smk_of_current();
-       char *isp = smk_of_inode(inode);
-       char *dsp = smk_of_inode(dir);
+       struct smack_known *isp = smk_of_inode(inode);
+       struct smack_known *dsp = smk_of_inode(dir);
        int may;
 
        if (name)
@@ -651,7 +797,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 
        if (value) {
                rcu_read_lock();
-               may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules);
+               may = smk_access_entry(skp->smk_known, dsp->smk_known,
+                                      &skp->smk_rules);
                rcu_read_unlock();
 
                /*
@@ -666,13 +813,13 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
                        issp->smk_flags |= SMK_INODE_CHANGED;
                }
 
-               *value = kstrdup(isp, GFP_NOFS);
+               *value = kstrdup(isp->smk_known, GFP_NOFS);
                if (*value == NULL)
                        return -ENOMEM;
        }
 
        if (len)
-               *len = strlen(isp) + 1;
+               *len = strlen(isp->smk_known);
 
        return 0;
 }
@@ -688,7 +835,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
                            struct dentry *new_dentry)
 {
-       char *isp;
+       struct smack_known *isp;
        struct smk_audit_info ad;
        int rc;
 
@@ -697,11 +844,13 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
 
        isp = smk_of_inode(old_dentry->d_inode);
        rc = smk_curacc(isp, MAY_WRITE, &ad);
+       rc = smk_bu_inode(old_dentry->d_inode, MAY_WRITE, rc);
 
        if (rc == 0 && new_dentry->d_inode != NULL) {
                isp = smk_of_inode(new_dentry->d_inode);
                smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
                rc = smk_curacc(isp, MAY_WRITE, &ad);
+               rc = smk_bu_inode(new_dentry->d_inode, MAY_WRITE, rc);
        }
 
        return rc;
@@ -728,6 +877,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
         * You need write access to the thing you're unlinking
         */
        rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad);
+       rc = smk_bu_inode(ip, MAY_WRITE, rc);
        if (rc == 0) {
                /*
                 * You also need write access to the containing directory
@@ -735,6 +885,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
                smk_ad_setfield_u_fs_inode(&ad, dir);
                rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+               rc = smk_bu_inode(dir, MAY_WRITE, rc);
        }
        return rc;
 }
@@ -759,6 +910,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
         * You need write access to the thing you're removing
         */
        rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
        if (rc == 0) {
                /*
                 * You also need write access to the containing directory
@@ -766,6 +918,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
                smk_ad_setfield_u_fs_inode(&ad, dir);
                rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+               rc = smk_bu_inode(dir, MAY_WRITE, rc);
        }
 
        return rc;
@@ -773,10 +926,10 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
 
 /**
  * smack_inode_rename - Smack check on rename
- * @old_inode: the old directory
- * @old_dentry: unused
- * @new_inode: the new directory
- * @new_dentry: unused
+ * @old_inode: unused
+ * @old_dentry: the old object
+ * @new_inode: unused
+ * @new_dentry: the new object
  *
  * Read and write access is required on both the old and
  * new directories.
@@ -789,7 +942,7 @@ static int smack_inode_rename(struct inode *old_inode,
                              struct dentry *new_dentry)
 {
        int rc;
-       char *isp;
+       struct smack_known *isp;
        struct smk_audit_info ad;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
@@ -797,11 +950,13 @@ static int smack_inode_rename(struct inode *old_inode,
 
        isp = smk_of_inode(old_dentry->d_inode);
        rc = smk_curacc(isp, MAY_READWRITE, &ad);
+       rc = smk_bu_inode(old_dentry->d_inode, MAY_READWRITE, rc);
 
        if (rc == 0 && new_dentry->d_inode != NULL) {
                isp = smk_of_inode(new_dentry->d_inode);
                smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
                rc = smk_curacc(isp, MAY_READWRITE, &ad);
+               rc = smk_bu_inode(new_dentry->d_inode, MAY_READWRITE, rc);
        }
        return rc;
 }
@@ -819,6 +974,7 @@ static int smack_inode_permission(struct inode *inode, int mask)
 {
        struct smk_audit_info ad;
        int no_block = mask & MAY_NOT_BLOCK;
+       int rc;
 
        mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
        /*
@@ -832,7 +988,9 @@ static int smack_inode_permission(struct inode *inode, int mask)
                return -ECHILD;
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
        smk_ad_setfield_u_fs_inode(&ad, inode);
-       return smk_curacc(smk_of_inode(inode), mask, &ad);
+       rc = smk_curacc(smk_of_inode(inode), mask, &ad);
+       rc = smk_bu_inode(inode, mask, rc);
+       return rc;
 }
 
 /**
@@ -845,6 +1003,8 @@ static int smack_inode_permission(struct inode *inode, int mask)
 static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        struct smk_audit_info ad;
+       int rc;
+
        /*
         * Need to allow for clearing the setuid bit.
         */
@@ -853,12 +1013,14 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
  * smack_inode_getattr - Smack check for getting attributes
- * @mnt: unused
+ * @mnt: vfsmount of the object
  * @dentry: the object
  *
  * Returns 0 if access is permitted, an error code otherwise
@@ -867,21 +1029,24 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
        struct smk_audit_info ad;
        struct path path;
+       int rc;
 
        path.dentry = dentry;
        path.mnt = mnt;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, path);
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+       return rc;
 }
 
 /**
  * smack_inode_setxattr - Smack check for setting xattrs
  * @dentry: the object
  * @name: name of the attribute
- * @value: unused
- * @size: unused
+ * @value: value of the attribute
+ * @size: size of the value
  * @flags: unused
  *
  * This protects the Smack attribute explicitly.
@@ -923,7 +1088,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
                rc = -EPERM;
 
        if (rc == 0 && check_import) {
-               skp = smk_import_entry(value, size);
+               skp = size ? smk_import_entry(value, size) : NULL;
                if (skp == NULL || (check_star &&
                    (skp == &smack_known_star || skp == &smack_known_web)))
                        rc = -EINVAL;
@@ -932,8 +1097,10 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       if (rc == 0)
+       if (rc == 0) {
                rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+               rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+       }
 
        return rc;
 }
@@ -963,9 +1130,9 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
        if (strcmp(name, XATTR_NAME_SMACK) == 0) {
                skp = smk_import_entry(value, size);
                if (skp != NULL)
-                       isp->smk_inode = skp->smk_known;
+                       isp->smk_inode = skp;
                else
-                       isp->smk_inode = smack_known_invalid.smk_known;
+                       isp->smk_inode = &smack_known_invalid;
        } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
                skp = smk_import_entry(value, size);
                if (skp != NULL)
@@ -993,11 +1160,14 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
 static int smack_inode_getxattr(struct dentry *dentry, const char *name)
 {
        struct smk_audit_info ad;
+       int rc;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
-       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+       return rc;
 }
 
 /**
@@ -1033,6 +1203,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+       rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
        if (rc != 0)
                return rc;
 
@@ -1070,14 +1241,14 @@ static int smack_inode_getsecurity(const struct inode *inode,
        struct socket *sock;
        struct super_block *sbp;
        struct inode *ip = (struct inode *)inode;
-       char *isp;
+       struct smack_known *isp;
        int ilen;
        int rc = 0;
 
        if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
                isp = smk_of_inode(inode);
-               ilen = strlen(isp) + 1;
-               *buffer = isp;
+               ilen = strlen(isp->smk_known);
+               *buffer = isp->smk_known;
                return ilen;
        }
 
@@ -1095,15 +1266,15 @@ static int smack_inode_getsecurity(const struct inode *inode,
        ssp = sock->sk->sk_security;
 
        if (strcmp(name, XATTR_SMACK_IPIN) == 0)
-               isp = ssp->smk_in->smk_known;
+               isp = ssp->smk_in;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
-               isp = ssp->smk_out->smk_known;
+               isp = ssp->smk_out;
        else
                return -EOPNOTSUPP;
 
-       ilen = strlen(isp) + 1;
+       ilen = strlen(isp->smk_known);
        if (rc == 0) {
-               *buffer = isp;
+               *buffer = isp->smk_known;
                rc = ilen;
        }
 
@@ -1122,13 +1293,12 @@ static int smack_inode_getsecurity(const struct inode *inode,
 static int smack_inode_listsecurity(struct inode *inode, char *buffer,
                                    size_t buffer_size)
 {
-       int len = strlen(XATTR_NAME_SMACK);
+       int len = sizeof(XATTR_NAME_SMACK);
 
-       if (buffer != NULL && len <= buffer_size) {
+       if (buffer != NULL && len <= buffer_size)
                memcpy(buffer, XATTR_NAME_SMACK, len);
-               return len;
-       }
-       return -EINVAL;
+
+       return len;
 }
 
 /**
@@ -1140,7 +1310,7 @@ static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
 {
        struct inode_smack *isp = inode->i_security;
 
-       *secid = smack_to_secid(isp->smk_inode);
+       *secid = isp->smk_inode->smk_secid;
 }
 
 /*
@@ -1179,7 +1349,7 @@ static int smack_file_alloc_security(struct file *file)
 {
        struct smack_known *skp = smk_of_current();
 
-       file->f_security = skp->smk_known;
+       file->f_security = skp;
        return 0;
 }
 
@@ -1214,11 +1384,15 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
-       if (_IOC_DIR(cmd) & _IOC_WRITE)
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
                rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+               rc = smk_bu_file(file, MAY_WRITE, rc);
+       }
 
-       if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
+       if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
                rc = smk_curacc(file->f_security, MAY_READ, &ad);
+               rc = smk_bu_file(file, MAY_READ, rc);
+       }
 
        return rc;
 }
@@ -1233,10 +1407,13 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
 static int smack_file_lock(struct file *file, unsigned int cmd)
 {
        struct smk_audit_info ad;
+       int rc;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
-       return smk_curacc(file->f_security, MAY_LOCK, &ad);
+       rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+       rc = smk_bu_file(file, MAY_LOCK, rc);
+       return rc;
 }
 
 /**
@@ -1266,12 +1443,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
                smk_ad_setfield_u_fs_path(&ad, file->f_path);
                rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+               rc = smk_bu_file(file, MAY_LOCK, rc);
                break;
        case F_SETOWN:
        case F_SETSIG:
                smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
                smk_ad_setfield_u_fs_path(&ad, file->f_path);
                rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+               rc = smk_bu_file(file, MAY_WRITE, rc);
                break;
        default:
                break;
@@ -1298,7 +1477,7 @@ static int smack_mmap_file(struct file *file,
        struct smack_known *mkp;
        struct smack_rule *srp;
        struct task_smack *tsp;
-       char *osmack;
+       struct smack_known *okp;
        struct inode_smack *isp;
        int may;
        int mmay;
@@ -1324,18 +1503,19 @@ static int smack_mmap_file(struct file *file,
         * to that rule's object label.
         */
        list_for_each_entry_rcu(srp, &skp->smk_rules, list) {
-               osmack = srp->smk_object;
+               okp = srp->smk_object;
                /*
                 * Matching labels always allows access.
                 */
-               if (mkp->smk_known == osmack)
+               if (mkp->smk_known == okp->smk_known)
                        continue;
                /*
                 * If there is a matching local rule take
                 * that into account as well.
                 */
-               may = smk_access_entry(srp->smk_subject->smk_known, osmack,
-                                       &tsp->smk_rules);
+               may = smk_access_entry(srp->smk_subject->smk_known,
+                                      okp->smk_known,
+                                      &tsp->smk_rules);
                if (may == -ENOENT)
                        may = srp->smk_access;
                else
@@ -1352,8 +1532,8 @@ static int smack_mmap_file(struct file *file,
                 * If there isn't one a SMACK64MMAP subject
                 * can't have as much access as current.
                 */
-               mmay = smk_access_entry(mkp->smk_known, osmack,
-                                               &mkp->smk_rules);
+               mmay = smk_access_entry(mkp->smk_known, okp->smk_known,
+                                       &mkp->smk_rules);
                if (mmay == -ENOENT) {
                        rc = -EACCES;
                        break;
@@ -1362,8 +1542,8 @@ static int smack_mmap_file(struct file *file,
                 * If there is a local entry it modifies the
                 * potential access, too.
                 */
-               tmay = smk_access_entry(mkp->smk_known, osmack,
-                                               &tsp->smk_rules);
+               tmay = smk_access_entry(mkp->smk_known, okp->smk_known,
+                                       &tsp->smk_rules);
                if (tmay != -ENOENT)
                        mmay &= tmay;
 
@@ -1394,7 +1574,7 @@ static int smack_file_set_fowner(struct file *file)
 {
        struct smack_known *skp = smk_of_current();
 
-       file->f_security = skp->smk_known;
+       file->f_security = skp;
        return 0;
 }
 
@@ -1424,14 +1604,15 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
        file = container_of(fown, struct file, f_owner);
 
        /* we don't log here as rc can be overriden */
-       skp = smk_find_entry(file->f_security);
-       rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL);
+       skp = file->f_security;
+       rc = smk_access(skp, tkp, MAY_WRITE, NULL);
+       rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc);
        if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
                rc = 0;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, tsk);
-       smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad);
+       smack_log(skp->smk_known, tkp->smk_known, MAY_WRITE, rc, &ad);
        return rc;
 }
 
@@ -1443,6 +1624,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
  */
 static int smack_file_receive(struct file *file)
 {
+       int rc;
        int may = 0;
        struct smk_audit_info ad;
 
@@ -1456,7 +1638,9 @@ static int smack_file_receive(struct file *file)
        if (file->f_mode & FMODE_WRITE)
                may |= MAY_WRITE;
 
-       return smk_curacc(file->f_security, may, &ad);
+       rc = smk_curacc(file->f_security, may, &ad);
+       rc = smk_bu_file(file, may, rc);
+       return rc;
 }
 
 /**
@@ -1478,12 +1662,15 @@ static int smack_file_open(struct file *file, const struct cred *cred)
        struct smk_audit_info ad;
        int rc;
 
-       if (smack_privileged(CAP_MAC_OVERRIDE))
+       if (smack_privileged(CAP_MAC_OVERRIDE)) {
+               file->f_security = isp->smk_inode;
                return 0;
+       }
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
        rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad);
+       rc = smk_bu_credfile(cred, file, MAY_READ, rc);
        if (rc == 0)
                file->f_security = isp->smk_inode;
 
@@ -1622,7 +1809,7 @@ static int smack_kernel_create_files_as(struct cred *new,
        struct inode_smack *isp = inode->i_security;
        struct task_smack *tsp = new->security;
 
-       tsp->smk_forked = smk_find_entry(isp->smk_inode);
+       tsp->smk_forked = isp->smk_inode;
        tsp->smk_task = tsp->smk_forked;
        return 0;
 }
@@ -1640,10 +1827,13 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
 {
        struct smk_audit_info ad;
        struct smack_known *skp = smk_of_task(task_security(p));
+       int rc;
 
        smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
-       return smk_curacc(skp->smk_known, access, &ad);
+       rc = smk_curacc(skp, access, &ad);
+       rc = smk_bu_task(p, access, rc);
+       return rc;
 }
 
 /**
@@ -1797,6 +1987,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
        struct smk_audit_info ad;
        struct smack_known *skp;
        struct smack_known *tkp = smk_of_task(task_security(p));
+       int rc;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
@@ -1804,15 +1995,20 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
         * Sending a signal requires that the sender
         * can write the receiver.
         */
-       if (secid == 0)
-               return smk_curacc(tkp->smk_known, MAY_WRITE, &ad);
+       if (secid == 0) {
+               rc = smk_curacc(tkp, MAY_WRITE, &ad);
+               rc = smk_bu_task(p, MAY_WRITE, rc);
+               return rc;
+       }
        /*
         * If the secid isn't 0 we're dealing with some USB IO
         * specific behavior. This is not clean. For one thing
         * we can't take privilege into account.
         */
        skp = smack_from_secid(secid);
-       return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad);
+       rc = smk_access(skp, tkp, MAY_WRITE, &ad);
+       rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
@@ -1846,7 +2042,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
        struct inode_smack *isp = inode->i_security;
        struct smack_known *skp = smk_of_task(task_security(p));
 
-       isp->smk_inode = skp->smk_known;
+       isp->smk_inode = skp;
 }
 
 /*
@@ -1904,7 +2100,7 @@ static void smack_sk_free_security(struct sock *sk)
 *
 * Returns the label of the far end or NULL if it's not special.
 */
-static char *smack_host_label(struct sockaddr_in *sip)
+static struct smack_known *smack_host_label(struct sockaddr_in *sip)
 {
        struct smk_netlbladdr *snp;
        struct in_addr *siap = &sip->sin_addr;
@@ -1921,7 +2117,7 @@ static char *smack_host_label(struct sockaddr_in *sip)
                if ((&snp->smk_host.sin_addr)->s_addr ==
                    (siap->s_addr & (&snp->smk_mask)->s_addr)) {
                        /* we have found the special CIPSO option */
-                       if (snp->smk_label == smack_cipso_option)
+                       if (snp->smk_label == &smack_cipso_option)
                                return NULL;
                        return snp->smk_label;
                }
@@ -1986,13 +2182,13 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
        struct smack_known *skp;
        int rc;
        int sk_lbl;
-       char *hostsp;
+       struct smack_known *hkp;
        struct socket_smack *ssp = sk->sk_security;
        struct smk_audit_info ad;
 
        rcu_read_lock();
-       hostsp = smack_host_label(sap);
-       if (hostsp != NULL) {
+       hkp = smack_host_label(sap);
+       if (hkp != NULL) {
 #ifdef CONFIG_AUDIT
                struct lsm_network_audit net;
 
@@ -2003,7 +2199,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
 #endif
                sk_lbl = SMACK_UNLABELED_SOCKET;
                skp = ssp->smk_out;
-               rc = smk_access(skp, hostsp, MAY_WRITE, &ad);
+               rc = smk_access(skp, hkp, MAY_WRITE, &ad);
+               rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc);
        } else {
                sk_lbl = SMACK_CIPSO_SOCKET;
                rc = 0;
@@ -2104,18 +2301,19 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
        struct socket_smack *ssp = sk->sk_security;
        struct smack_known *skp;
        unsigned short port = 0;
-       char *object;
+       struct smack_known *object;
        struct smk_audit_info ad;
+       int rc;
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
 #endif
 
        if (act == SMK_RECEIVING) {
                skp = smack_net_ambient;
-               object = ssp->smk_in->smk_known;
+               object = ssp->smk_in;
        } else {
                skp = ssp->smk_out;
-               object = smack_net_ambient->smk_known;
+               object = smack_net_ambient;
        }
 
        /*
@@ -2142,7 +2340,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
        list_for_each_entry(spp, &smk_ipv6_port_list, list) {
                if (spp->smk_port != port)
                        continue;
-               object = spp->smk_in->smk_known;
+               object = spp->smk_in;
                if (act == SMK_CONNECTING)
                        ssp->smk_packet = spp->smk_out;
                break;
@@ -2159,7 +2357,9 @@ auditout:
        else
                ad.a.u.net->v6info.daddr = address->sin6_addr;
 #endif
-       return smk_access(skp, object, MAY_WRITE, &ad);
+       rc = smk_access(skp, object, MAY_WRITE, &ad);
+       rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
@@ -2191,7 +2391,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
                return -EINVAL;
 
        if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
-               nsp->smk_inode = skp->smk_known;
+               nsp->smk_inode = skp;
                nsp->smk_flags |= SMK_INODE_INSTANT;
                return 0;
        }
@@ -2333,7 +2533,7 @@ static int smack_msg_msg_alloc_security(struct msg_msg *msg)
 {
        struct smack_known *skp = smk_of_current();
 
-       msg->security = skp->smk_known;
+       msg->security = skp;
        return 0;
 }
 
@@ -2354,9 +2554,9 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
  *
  * Returns a pointer to the smack value
  */
-static char *smack_of_shm(struct shmid_kernel *shp)
+static struct smack_known *smack_of_shm(struct shmid_kernel *shp)
 {
-       return (char *)shp->shm_perm.security;
+       return (struct smack_known *)shp->shm_perm.security;
 }
 
 /**
@@ -2370,7 +2570,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
        struct kern_ipc_perm *isp = &shp->shm_perm;
        struct smack_known *skp = smk_of_current();
 
-       isp->security = skp->smk_known;
+       isp->security = skp;
        return 0;
 }
 
@@ -2396,14 +2596,17 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
  */
 static int smk_curacc_shm(struct shmid_kernel *shp, int access)
 {
-       char *ssp = smack_of_shm(shp);
+       struct smack_known *ssp = smack_of_shm(shp);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = shp->shm_perm.id;
 #endif
-       return smk_curacc(ssp, access, &ad);
+       rc = smk_curacc(ssp, access, &ad);
+       rc = smk_bu_current("shm", ssp, access, rc);
+       return rc;
 }
 
 /**
@@ -2478,9 +2681,9 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
  *
  * Returns a pointer to the smack value
  */
-static char *smack_of_sem(struct sem_array *sma)
+static struct smack_known *smack_of_sem(struct sem_array *sma)
 {
-       return (char *)sma->sem_perm.security;
+       return (struct smack_known *)sma->sem_perm.security;
 }
 
 /**
@@ -2494,7 +2697,7 @@ static int smack_sem_alloc_security(struct sem_array *sma)
        struct kern_ipc_perm *isp = &sma->sem_perm;
        struct smack_known *skp = smk_of_current();
 
-       isp->security = skp->smk_known;
+       isp->security = skp;
        return 0;
 }
 
@@ -2520,14 +2723,17 @@ static void smack_sem_free_security(struct sem_array *sma)
  */
 static int smk_curacc_sem(struct sem_array *sma, int access)
 {
-       char *ssp = smack_of_sem(sma);
+       struct smack_known *ssp = smack_of_sem(sma);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = sma->sem_perm.id;
 #endif
-       return smk_curacc(ssp, access, &ad);
+       rc = smk_curacc(ssp, access, &ad);
+       rc = smk_bu_current("sem", ssp, access, rc);
+       return rc;
 }
 
 /**
@@ -2613,7 +2819,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
        struct kern_ipc_perm *kisp = &msq->q_perm;
        struct smack_known *skp = smk_of_current();
 
-       kisp->security = skp->smk_known;
+       kisp->security = skp;
        return 0;
 }
 
@@ -2634,11 +2840,11 @@ static void smack_msg_queue_free_security(struct msg_queue *msq)
  * smack_of_msq - the smack pointer for the msq
  * @msq: the object
  *
- * Returns a pointer to the smack value
+ * Returns a pointer to the smack label entry
  */
-static char *smack_of_msq(struct msg_queue *msq)
+static struct smack_known *smack_of_msq(struct msg_queue *msq)
 {
-       return (char *)msq->q_perm.security;
+       return (struct smack_known *)msq->q_perm.security;
 }
 
 /**
@@ -2650,14 +2856,17 @@ static char *smack_of_msq(struct msg_queue *msq)
  */
 static int smk_curacc_msq(struct msg_queue *msq, int access)
 {
-       char *msp = smack_of_msq(msq);
+       struct smack_known *msp = smack_of_msq(msq);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = msq->q_perm.id;
 #endif
-       return smk_curacc(msp, access, &ad);
+       rc = smk_curacc(msp, access, &ad);
+       rc = smk_bu_current("msq", msp, access, rc);
+       return rc;
 }
 
 /**
@@ -2750,15 +2959,18 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
  */
 static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 {
-       char *isp = ipp->security;
+       struct smack_known *iskp = ipp->security;
        int may = smack_flags_to_may(flag);
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
        ad.a.u.ipc_id = ipp->id;
 #endif
-       return smk_curacc(isp, may, &ad);
+       rc = smk_curacc(iskp, may, &ad);
+       rc = smk_bu_current("svipc", iskp, may, rc);
+       return rc;
 }
 
 /**
@@ -2768,9 +2980,9 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
  */
 static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
 {
-       char *smack = ipp->security;
+       struct smack_known *iskp = ipp->security;
 
-       *secid = smack_to_secid(smack);
+       *secid = iskp->smk_secid;
 }
 
 /**
@@ -2787,7 +2999,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        struct inode_smack *isp;
        struct smack_known *skp;
        struct smack_known *ckp = smk_of_current();
-       char *final;
+       struct smack_known *final;
        char trattr[TRANS_TRUE_SIZE];
        int transflag = 0;
        int rc;
@@ -2827,8 +3039,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                         * so there's no opportunity to set the mount
                         * options.
                         */
-                       sbsp->smk_root = smack_known_star.smk_known;
-                       sbsp->smk_default = smack_known_star.smk_known;
+                       sbsp->smk_root = &smack_known_star;
+                       sbsp->smk_default = &smack_known_star;
                }
                isp->smk_inode = sbsp->smk_root;
                isp->smk_flags |= SMK_INODE_INSTANT;
@@ -2858,7 +3070,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 *
                 * Cgroupfs is special
                 */
-               final = smack_known_star.smk_known;
+               final = &smack_known_star;
                break;
        case DEVPTS_SUPER_MAGIC:
                /*
@@ -2866,7 +3078,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * Programs that change smack have to treat the
                 * pty with respect.
                 */
-               final = ckp->smk_known;
+               final = ckp;
                break;
        case PROC_SUPER_MAGIC:
                /*
@@ -2880,7 +3092,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * but watch out, because they're volitile,
                 * getting recreated on every reboot.
                 */
-               final = smack_known_star.smk_known;
+               final = &smack_known_star;
                /*
                 * No break.
                 *
@@ -2899,7 +3111,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * UNIX domain sockets use lower level socket data.
                 */
                if (S_ISSOCK(inode->i_mode)) {
-                       final = smack_known_star.smk_known;
+                       final = &smack_known_star;
                        break;
                }
                /*
@@ -2916,7 +3128,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                dp = dget(opt_dentry);
                skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
                if (skp != NULL)
-                       final = skp->smk_known;
+                       final = skp;
 
                /*
                 * Transmuting directory
@@ -2965,7 +3177,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        }
 
        if (final == NULL)
-               isp->smk_inode = ckp->smk_known;
+               isp->smk_inode = ckp;
        else
                isp->smk_inode = final;
 
@@ -3090,9 +3302,13 @@ static int smack_unix_stream_connect(struct sock *sock,
                smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
                smk_ad_setfield_u_net_sk(&ad, other);
 #endif
-               rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad);
-               if (rc == 0)
-                       rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL);
+               rc = smk_access(skp, okp, MAY_WRITE, &ad);
+               rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
+               if (rc == 0) {
+                       rc = smk_access(okp, skp, MAY_WRITE, NULL);
+                       rc = smk_bu_note("UDS connect", okp, skp,
+                                               MAY_WRITE, rc);
+               }
        }
 
        /*
@@ -3118,8 +3334,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
 {
        struct socket_smack *ssp = sock->sk->sk_security;
        struct socket_smack *osp = other->sk->sk_security;
-       struct smack_known *skp;
        struct smk_audit_info ad;
+       int rc;
 
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
@@ -3131,8 +3347,9 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
        if (smack_privileged(CAP_MAC_OVERRIDE))
                return 0;
 
-       skp = ssp->smk_out;
-       return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad);
+       rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+       rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc);
+       return rc;
 }
 
 /**
@@ -3346,7 +3563,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                 * This is the simplist possible security model
                 * for networking.
                 */
-               rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
+               rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+               rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
+                                       MAY_WRITE, rc);
                if (rc != 0)
                        netlbl_skbuff_err(skb, rc, 0);
                break;
@@ -3489,7 +3708,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        struct netlbl_lsm_secattr secattr;
        struct sockaddr_in addr;
        struct iphdr *hdr;
-       char *hsp;
+       struct smack_known *hskp;
        int rc;
        struct smk_audit_info ad;
 #ifdef CONFIG_AUDIT
@@ -3526,7 +3745,8 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
         * Receiving a packet requires that the other end be able to write
         * here. Read access is not required.
         */
-       rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
+       rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+       rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc);
        if (rc != 0)
                return rc;
 
@@ -3544,10 +3764,10 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        hdr = ip_hdr(skb);
        addr.sin_addr.s_addr = hdr->saddr;
        rcu_read_lock();
-       hsp = smack_host_label(&addr);
+       hskp = smack_host_label(&addr);
        rcu_read_unlock();
 
-       if (hsp == NULL)
+       if (hskp == NULL)
                rc = netlbl_req_setattr(req, &skp->smk_netlabel);
        else
                netlbl_req_delattr(req);
@@ -3599,7 +3819,7 @@ static int smack_key_alloc(struct key *key, const struct cred *cred,
 {
        struct smack_known *skp = smk_of_task(cred->security);
 
-       key->security = skp->smk_known;
+       key->security = skp;
        return 0;
 }
 
@@ -3630,6 +3850,7 @@ static int smack_key_permission(key_ref_t key_ref,
        struct smk_audit_info ad;
        struct smack_known *tkp = smk_of_task(cred->security);
        int request = 0;
+       int rc;
 
        keyp = key_ref_to_ptr(key_ref);
        if (keyp == NULL)
@@ -3654,7 +3875,9 @@ static int smack_key_permission(key_ref_t key_ref,
                request = MAY_READ;
        if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
                request = MAY_WRITE;
-       return smk_access(tkp, keyp->security, request, &ad);
+       rc = smk_access(tkp, keyp->security, request, &ad);
+       rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
+       return rc;
 }
 #endif /* CONFIG_KEYS */
 
@@ -3685,6 +3908,7 @@ static int smack_key_permission(key_ref_t key_ref,
  */
 static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
 {
+       struct smack_known *skp;
        char **rule = (char **)vrule;
        *rule = NULL;
 
@@ -3694,7 +3918,9 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
        if (op != Audit_equal && op != Audit_not_equal)
                return -EINVAL;
 
-       *rule = smk_import(rulestr, 0);
+       skp = smk_import_entry(rulestr, 0);
+       if (skp)
+               *rule = skp->smk_known;
 
        return 0;
 }
@@ -3813,7 +4039,12 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
  */
 static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
-       *secid = smack_to_secid(secdata);
+       struct smack_known *skp = smk_find_entry(secdata);
+
+       if (skp)
+               *secid = skp->smk_secid;
+       else
+               *secid = 0;
        return 0;
 }
 
index 3c720ff105917dcedbfda26c7814f8cc8716fa8f..bce4e8f1b267cef89501cd5538bdff86940cd81c 100644 (file)
@@ -131,14 +131,17 @@ LIST_HEAD(smack_rule_list);
 
 struct smack_parsed_rule {
        struct smack_known      *smk_subject;
-       char                    *smk_object;
+       struct smack_known      *smk_object;
        int                     smk_access1;
        int                     smk_access2;
 };
 
 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
 
-const char *smack_cipso_option = SMACK_CIPSO_OPTION;
+struct smack_known smack_cipso_option = {
+       .smk_known      = SMACK_CIPSO_OPTION,
+       .smk_secid      = 0,
+};
 
 /*
  * Values for parsing cipso rules
@@ -304,6 +307,10 @@ static int smk_perm_from_str(const char *string)
                case 'L':
                        perm |= MAY_LOCK;
                        break;
+               case 'b':
+               case 'B':
+                       perm |= MAY_BRINGUP;
+                       break;
                default:
                        return perm;
                }
@@ -335,7 +342,7 @@ static int smk_fill_rule(const char *subject, const char *object,
                if (rule->smk_subject == NULL)
                        return -EINVAL;
 
-               rule->smk_object = smk_import(object, len);
+               rule->smk_object = smk_import_entry(object, len);
                if (rule->smk_object == NULL)
                        return -EINVAL;
        } else {
@@ -355,7 +362,7 @@ static int smk_fill_rule(const char *subject, const char *object,
                kfree(cp);
                if (skp == NULL)
                        return -ENOENT;
-               rule->smk_object = skp->smk_known;
+               rule->smk_object = skp;
        }
 
        rule->smk_access1 = smk_perm_from_str(access1);
@@ -594,13 +601,15 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
         * anything you read back.
         */
        if (strlen(srp->smk_subject->smk_known) >= max ||
-           strlen(srp->smk_object) >= max)
+           strlen(srp->smk_object->smk_known) >= max)
                return;
 
        if (srp->smk_access == 0)
                return;
 
-       seq_printf(s, "%s %s", srp->smk_subject->smk_known, srp->smk_object);
+       seq_printf(s, "%s %s",
+                  srp->smk_subject->smk_known,
+                  srp->smk_object->smk_known);
 
        seq_putc(s, ' ');
 
@@ -616,6 +625,8 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
                seq_putc(s, 't');
        if (srp->smk_access & MAY_LOCK)
                seq_putc(s, 'l');
+       if (srp->smk_access & MAY_BRINGUP)
+               seq_putc(s, 'b');
 
        seq_putc(s, '\n');
 }
@@ -1067,7 +1078,7 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
        for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++);
 
        seq_printf(s, "%u.%u.%u.%u/%d %s\n",
-               hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
+               hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known);
 
        return 0;
 }
@@ -1147,10 +1158,10 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
 static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct smk_netlbladdr *skp;
+       struct smk_netlbladdr *snp;
        struct sockaddr_in newname;
        char *smack;
-       char *sp;
+       struct smack_known *skp;
        char *data;
        char *host = (char *)&newname.sin_addr.s_addr;
        int rc;
@@ -1213,15 +1224,15 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
         * If smack begins with '-', it is an option, don't import it
         */
        if (smack[0] != '-') {
-               sp = smk_import(smack, 0);
-               if (sp == NULL) {
+               skp = smk_import_entry(smack, 0);
+               if (skp == NULL) {
                        rc = -EINVAL;
                        goto free_out;
                }
        } else {
                /* check known options */
-               if (strcmp(smack, smack_cipso_option) == 0)
-                       sp = (char *)smack_cipso_option;
+               if (strcmp(smack, smack_cipso_option.smk_known) == 0)
+                       skp = &smack_cipso_option;
                else {
                        rc = -EINVAL;
                        goto free_out;
@@ -1244,9 +1255,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        nsa = newname.sin_addr.s_addr;
        /* try to find if the prefix is already in the list */
        found = 0;
-       list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
-               if (skp->smk_host.sin_addr.s_addr == nsa &&
-                   skp->smk_mask.s_addr == mask.s_addr) {
+       list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) {
+               if (snp->smk_host.sin_addr.s_addr == nsa &&
+                   snp->smk_mask.s_addr == mask.s_addr) {
                        found = 1;
                        break;
                }
@@ -1254,26 +1265,26 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
        smk_netlabel_audit_set(&audit_info);
 
        if (found == 0) {
-               skp = kzalloc(sizeof(*skp), GFP_KERNEL);
-               if (skp == NULL)
+               snp = kzalloc(sizeof(*snp), GFP_KERNEL);
+               if (snp == NULL)
                        rc = -ENOMEM;
                else {
                        rc = 0;
-                       skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
-                       skp->smk_mask.s_addr = mask.s_addr;
-                       skp->smk_label = sp;
-                       smk_netlbladdr_insert(skp);
+                       snp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
+                       snp->smk_mask.s_addr = mask.s_addr;
+                       snp->smk_label = skp;
+                       smk_netlbladdr_insert(snp);
                }
        } else {
                /* we delete the unlabeled entry, only if the previous label
                 * wasn't the special CIPSO option */
-               if (skp->smk_label != smack_cipso_option)
+               if (snp->smk_label != &smack_cipso_option)
                        rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
-                                       &skp->smk_host.sin_addr, &skp->smk_mask,
+                                       &snp->smk_host.sin_addr, &snp->smk_mask,
                                        PF_INET, &audit_info);
                else
                        rc = 0;
-               skp->smk_label = sp;
+               snp->smk_label = skp;
        }
 
        /*
@@ -1281,10 +1292,10 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
         * this host so that incoming packets get labeled.
         * but only if we didn't get the special CIPSO option
         */
-       if (rc == 0 && sp != smack_cipso_option)
+       if (rc == 0 && skp != &smack_cipso_option)
                rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
-                       &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
-                       smack_to_secid(skp->smk_label), &audit_info);
+                       &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET,
+                       snp->smk_label->smk_secid, &audit_info);
 
        if (rc == 0)
                rc = count;
@@ -1677,7 +1688,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
        if (smack_onlycap != NULL && smack_onlycap != skp)
                return -EPERM;
 
-       data = kzalloc(count, GFP_KERNEL);
+       data = kzalloc(count + 1, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
@@ -1880,7 +1891,10 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
        else if (res != -ENOENT)
                return -EINVAL;
 
-       data[0] = res == 0 ? '1' : '0';
+       /*
+        * smk_access() can return a value > 0 in the "bringup" case.
+        */
+       data[0] = res >= 0 ? '1' : '0';
        data[1] = '\0';
 
        simple_transaction_set(file, 2);
@@ -2228,7 +2242,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
        if (!smack_privileged(CAP_MAC_ADMIN))
                return -EPERM;
 
-       data = kzalloc(count, GFP_KERNEL);
+       data = kzalloc(count + 1, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;