Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Nov 2015 23:32:38 +0000 (15:32 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 5 Nov 2015 23:32:38 +0000 (15:32 -0800)
Pull security subsystem update from James Morris:
 "This is mostly maintenance updates across the subsystem, with a
  notable update for TPM 2.0, and addition of Jarkko Sakkinen as a
  maintainer of that"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (40 commits)
  apparmor: clarify CRYPTO dependency
  selinux: Use a kmem_cache for allocation struct file_security_struct
  selinux: ioctl_has_perm should be static
  selinux: use sprintf return value
  selinux: use kstrdup() in security_get_bools()
  selinux: use kmemdup in security_sid_to_context_core()
  selinux: remove pointless cast in selinux_inode_setsecurity()
  selinux: introduce security_context_str_to_sid
  selinux: do not check open perm on ftruncate call
  selinux: change CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE default
  KEYS: Merge the type-specific data with the payload data
  KEYS: Provide a script to extract a module signature
  KEYS: Provide a script to extract the sys cert list from a vmlinux file
  keys: Be more consistent in selection of union members used
  certs: add .gitignore to stop git nagging about x509_certificate_list
  KEYS: use kvfree() in add_key
  Smack: limited capability for changing process label
  TPM: remove unnecessary little endian conversion
  vTPM: support little endian guests
  char: Drop owner assignment from i2c_driver
  ...

89 files changed:
Documentation/ABI/testing/sysfs-driver-ppi
Documentation/crypto/asymmetric-keys.txt
Documentation/security/Smack.txt
Documentation/security/keys.txt
MAINTAINERS
arch/powerpc/kernel/prom_init.c
certs/.gitignore [new file with mode: 0644]
crypto/asymmetric_keys/asymmetric_keys.h
crypto/asymmetric_keys/asymmetric_type.c
crypto/asymmetric_keys/public_key.c
crypto/asymmetric_keys/signature.c
crypto/asymmetric_keys/x509_parser.h
crypto/asymmetric_keys/x509_public_key.c
drivers/char/tpm/st33zp24/Kconfig
drivers/char/tpm/st33zp24/i2c.c
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm2-cmd.c
drivers/char/tpm/tpm_crb.c
drivers/char/tpm/tpm_eventlog.c
drivers/char/tpm/tpm_eventlog.h
drivers/char/tpm/tpm_i2c_atmel.c
drivers/char/tpm/tpm_i2c_infineon.c
drivers/char/tpm/tpm_i2c_nuvoton.c
drivers/char/tpm/tpm_ibmvtpm.c
drivers/char/tpm/tpm_of.c
drivers/char/tpm/tpm_ppi.c
drivers/char/tpm/tpm_tis.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsacl.c
fs/cifs/connect.c
fs/cifs/sess.c
fs/cifs/smb2pdu.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ext4/crypto_key.c
fs/f2fs/crypto_key.c
fs/fscache/object-list.c
fs/nfs/nfs4idmap.c
fs/sysfs/group.c
include/crypto/public_key.h
include/keys/asymmetric-subtype.h
include/keys/asymmetric-type.h
include/keys/trusted-type.h
include/keys/user-type.h
include/linux/key-type.h
include/linux/key.h
include/linux/sysfs.h
include/linux/tpm.h
kernel/.gitignore
kernel/module_signing.c
lib/digsig.c
net/ceph/ceph_common.c
net/ceph/crypto.c
net/dns_resolver/dns_key.c
net/dns_resolver/dns_query.c
net/dns_resolver/internal.h
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-key.c
net/rxrpc/ar-output.c
net/rxrpc/ar-security.c
net/rxrpc/rxkad.c
scripts/extract-module-sig.pl [new file with mode: 0755]
scripts/extract-sys-certs.pl [new file with mode: 0755]
security/apparmor/Kconfig
security/integrity/digsig.c
security/integrity/evm/evm_crypto.c
security/keys/big_key.c
security/keys/encrypted-keys/encrypted.c
security/keys/encrypted-keys/encrypted.h
security/keys/encrypted-keys/masterkey_trusted.c
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c
security/keys/trusted.h
security/keys/user_defined.c
security/selinux/Kconfig
security/selinux/hooks.c
security/selinux/include/security.h
security/selinux/selinuxfs.c
security/selinux/ss/services.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c

index 7d1435bc976c702a7cb432a49632e7f3a6a2f6f3..9921ef285899f03ccca71c13ebbac0a7522a359e 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/devices/pnp0/<bus-num>/ppi/
+What:          /sys/class/tpm/tpmX/ppi/
 Date:          August 2012
 Kernel Version:        3.6
 Contact:       xiaoyan.zhang@intel.com
@@ -8,9 +8,14 @@ Description:
                folder makes sense. The folder path can be got by command
                'find /sys/ -name 'pcrs''. For the detail information of PPI,
                please refer to the PPI specification from
+
                http://www.trustedcomputinggroup.org/
 
-What:          /sys/devices/pnp0/<bus-num>/ppi/version
+               In Linux 4.2 ppi was moved to the character device directory.
+               A symlink from tpmX/device/ppi to tpmX/ppi to provide backwards
+               compatibility.
+
+What:          /sys/class/tpm/tpmX/ppi/version
 Date:          August 2012
 Contact:       xiaoyan.zhang@intel.com
 Description:
@@ -18,7 +23,7 @@ Description:
                platform.
                This file is readonly.
 
-What:          /sys/devices/pnp0/<bus-num>/ppi/request
+What:          /sys/class/tpm/tpmX/ppi/request
 Date:          August 2012
 Contact:       xiaoyan.zhang@intel.com
 Description:
@@ -28,7 +33,7 @@ Description:
                integer value range from 1 to 160, and 0 means no request.
                This file can be read and written.
 
-What:          /sys/devices/pnp0/00:<bus-num>/ppi/response
+What:          /sys/class/tpm/tpmX/ppi/response
 Date:          August 2012
 Contact:       xiaoyan.zhang@intel.com
 Description:
@@ -37,7 +42,7 @@ Description:
                : <response description>".
                This file is readonly.
 
-What:          /sys/devices/pnp0/<bus-num>/ppi/transition_action
+What:          /sys/class/tpm/tpmX/ppi/transition_action
 Date:          August 2012
 Contact:       xiaoyan.zhang@intel.com
 Description:
@@ -47,7 +52,7 @@ Description:
                description>".
                This file is readonly.
 
-What:          /sys/devices/pnp0/<bus-num>/ppi/tcg_operations
+What:          /sys/class/tpm/tpmX/ppi/tcg_operations
 Date:          August 2012
 Contact:       xiaoyan.zhang@intel.com
 Description:
@@ -58,7 +63,7 @@ Description:
                This attribute is only supported by PPI version 1.2+.
                This file is readonly.
 
-What:          /sys/devices/pnp0/<bus-num>/ppi/vs_operations
+What:          /sys/class/tpm/tpmX/ppi/vs_operations
 Date:          August 2012
 Contact:       xiaoyan.zhang@intel.com
 Description:
index b7675904a7478a4d52fc2d23b4157adcdd132761..8c07e0ea6bc0e49552f6c5b264cc4404773d629d 100644 (file)
@@ -186,7 +186,7 @@ and looks like the following:
                                        const struct public_key_signature *sig);
        };
 
-Asymmetric keys point to this with their type_data[0] member.
+Asymmetric keys point to this with their payload[asym_subtype] member.
 
 The owner and name fields should be set to the owning module and the name of
 the subtype.  Currently, the name is only used for print statements.
@@ -269,8 +269,7 @@ mandatory:
 
        struct key_preparsed_payload {
                char            *description;
-               void            *type_data[2];
-               void            *payload;
+               void            *payload[4];
                const void      *data;
                size_t          datalen;
                size_t          quotalen;
@@ -283,16 +282,18 @@ mandatory:
      not theirs.
 
      If the parser is happy with the blob, it should propose a description for
-     the key and attach it to ->description, ->type_data[0] should be set to
-     point to the subtype to be used, ->payload should be set to point to the
-     initialised data for that subtype, ->type_data[1] should point to a hex
-     fingerprint and quotalen should be updated to indicate how much quota this
-     key should account for.
-
-     When clearing up, the data attached to ->type_data[1] and ->description
-     will be kfree()'d and the data attached to ->payload will be passed to the
-     subtype's ->destroy() method to be disposed of.  A module reference for
-     the subtype pointed to by ->type_data[0] will be put.
+     the key and attach it to ->description, ->payload[asym_subtype] should be
+     set to point to the subtype to be used, ->payload[asym_crypto] should be
+     set to point to the initialised data for that subtype,
+     ->payload[asym_key_ids] should point to one or more hex fingerprints and
+     quotalen should be updated to indicate how much quota this key should
+     account for.
+
+     When clearing up, the data attached to ->payload[asym_key_ids] and
+     ->description will be kfree()'d and the data attached to
+     ->payload[asm_crypto] will be passed to the subtype's ->destroy() method
+     to be disposed of.  A module reference for the subtype pointed to by
+     ->payload[asym_subtype] will be put.
 
 
      If the data format is not recognised, -EBADMSG should be returned.  If it
index 5e6d07fbed07c5483a73a5d47c9ba8ec67a9e7c6..945cc633d883dea13713264d3bf4bb19dd49ab55 100644 (file)
@@ -255,6 +255,16 @@ unconfined
        the access permitted if it wouldn't be otherwise. Note that this
        is dangerous and can ruin the proper labeling of your system.
        It should never be used in production.
+relabel-self
+       This interface contains a list of labels to which the process can
+       transition to, by writing to /proc/self/attr/current.
+       Normally a process can change its own label to any legal value, but only
+       if it has CAP_MAC_ADMIN. This interface allows a process without
+       CAP_MAC_ADMIN to relabel itself to one of labels from predefined list.
+       A process without CAP_MAC_ADMIN can change its label only once. When it
+       does, this list will be cleared.
+       The values are set by writing the desired labels, separated
+       by spaces, to the file or cleared by writing "-" to the file.
 
 If you are using the smackload utility
 you can add access rules in /etc/smack/accesses. They take the form:
index c9e7f4f223a55b6fed9e740cc2f17a4a773e02da..8c183873b2b77f771deb13dd74c21c49e19ec5ed 100644 (file)
@@ -1049,12 +1049,12 @@ search a specific keyring, so using keyrings in this way is of limited utility.
 NOTES ON ACCESSING PAYLOAD CONTENTS
 ===================================
 
-The simplest payload is just a number in key->payload.value. In this case,
-there's no need to indulge in RCU or locking when accessing the payload.
+The simplest payload is just data stored in key->payload directly.  In this
+case, there's no need to indulge in RCU or locking when accessing the payload.
 
-More complex payload contents must be allocated and a pointer to them set in
-key->payload.data. One of the following ways must be selected to access the
-data:
+More complex payload contents must be allocated and pointers to them set in the
+key->payload.data[] array.  One of the following ways must be selected to
+access the data:
 
  (1) Unmodifiable key type.
 
@@ -1092,6 +1092,13 @@ data:
      the payload. key->datalen cannot be relied upon to be consistent with the
      payload just dereferenced if the key's semaphore is not held.
 
+     Note that key->payload.data[0] has a shadow that is marked for __rcu
+     usage.  This is called key->payload.rcu_data0.  The following accessors
+     wrap the RCU calls to this element:
+
+       rcu_assign_keypointer(struct key *key, void *data);
+       void *rcu_dereference_key(struct key *key);
+
 
 ===================
 DEFINING A KEY TYPE
@@ -1143,8 +1150,7 @@ The structure has a number of fields, some of which are mandatory:
 
        struct key_preparsed_payload {
                char            *description;
-               void            *type_data[2];
-               void            *payload;
+               union key_payload payload;
                const void      *data;
                size_t          datalen;
                size_t          quotalen;
@@ -1160,10 +1166,9 @@ The structure has a number of fields, some of which are mandatory:
      attached as a string to the description field.  This will be used for the
      key description if the caller of add_key() passes NULL or "".
 
-     The method can attach anything it likes to type_data[] and payload.  These
-     are merely passed along to the instantiate() or update() operations.  If
-     set, the expiry time will be applied to the key if it is instantiated from
-     this data.
+     The method can attach anything it likes to payload.  This is merely passed
+     along to the instantiate() or update() operations.  If set, the expiry
+     time will be applied to the key if it is instantiated from this data.
 
      The method should return 0 if successful or a negative error code
      otherwise.
@@ -1172,11 +1177,10 @@ The structure has a number of fields, some of which are mandatory:
  (*) void (*free_preparse)(struct key_preparsed_payload *prep);
 
      This method is only required if the preparse() method is provided,
-     otherwise it is unused.  It cleans up anything attached to the
-     description, type_data and payload fields of the key_preparsed_payload
-     struct as filled in by the preparse() method.  It will always be called
-     after preparse() returns successfully, even if instantiate() or update()
-     succeed.
+     otherwise it is unused.  It cleans up anything attached to the description
+     and payload fields of the key_preparsed_payload struct as filled in by the
+     preparse() method.  It will always be called after preparse() returns
+     successfully, even if instantiate() or update() succeed.
 
 
  (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
@@ -1197,6 +1201,11 @@ The structure has a number of fields, some of which are mandatory:
 
      It is safe to sleep in this method.
 
+     generic_key_instantiate() is provided to simply copy the data from
+     prep->payload.data[] to key->payload.data[], with RCU-safe assignment on
+     the first element.  It will then clear prep->payload.data[] so that the
+     free_preparse method doesn't release the data.
+
 
  (*) int (*update)(struct key *key, const void *data, size_t datalen);
 
index 283d602a0240dd732036f06890e1ca7f512d49ef..162972876cd325866658c8aeef56804e8d6d2189 100644 (file)
@@ -10738,6 +10738,7 @@ F:      drivers/media/pci/tw68/
 TPM DEVICE DRIVER
 M:     Peter Huewe <peterhuewe@gmx.de>
 M:     Marcel Selhorst <tpmdd@selhorst.net>
+M:     Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
 R:     Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
 W:     http://tpmdd.sourceforge.net
 L:     tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
index 15099c41622e99b5c3beb44c00bf58bb6f42ebcc..92dea8df6b26d178cb4c3eca6b5fc0b4e1890019 100644 (file)
@@ -1425,27 +1425,45 @@ static void __init prom_instantiate_sml(void)
 {
        phandle ibmvtpm_node;
        ihandle ibmvtpm_inst;
-       u32 entry = 0, size = 0;
+       u32 entry = 0, size = 0, succ = 0;
        u64 base;
+       __be32 val;
 
        prom_debug("prom_instantiate_sml: start...\n");
 
-       ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/ibm,vtpm"));
+       ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/vdevice/vtpm"));
        prom_debug("ibmvtpm_node: %x\n", ibmvtpm_node);
        if (!PHANDLE_VALID(ibmvtpm_node))
                return;
 
-       ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/ibm,vtpm"));
+       ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/vdevice/vtpm"));
        if (!IHANDLE_VALID(ibmvtpm_inst)) {
                prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst);
                return;
        }
 
-       if (call_prom_ret("call-method", 2, 2, &size,
-                         ADDR("sml-get-handover-size"),
-                         ibmvtpm_inst) != 0 || size == 0) {
-               prom_printf("SML get handover size failed\n");
-               return;
+       if (prom_getprop(ibmvtpm_node, "ibm,sml-efi-reformat-supported",
+                        &val, sizeof(val)) != PROM_ERROR) {
+               if (call_prom_ret("call-method", 2, 2, &succ,
+                                 ADDR("reformat-sml-to-efi-alignment"),
+                                 ibmvtpm_inst) != 0 || succ == 0) {
+                       prom_printf("Reformat SML to EFI alignment failed\n");
+                       return;
+               }
+
+               if (call_prom_ret("call-method", 2, 2, &size,
+                                 ADDR("sml-get-allocated-size"),
+                                 ibmvtpm_inst) != 0 || size == 0) {
+                       prom_printf("SML get allocated size failed\n");
+                       return;
+               }
+       } else {
+               if (call_prom_ret("call-method", 2, 2, &size,
+                                 ADDR("sml-get-handover-size"),
+                                 ibmvtpm_inst) != 0 || size == 0) {
+                       prom_printf("SML get handover size failed\n");
+                       return;
+               }
        }
 
        base = alloc_down(size, PAGE_SIZE, 0);
@@ -1454,6 +1472,8 @@ static void __init prom_instantiate_sml(void)
 
        prom_printf("instantiating sml at 0x%x...", base);
 
+       memset((void *)base, 0, size);
+
        if (call_prom_ret("call-method", 4, 2, &entry,
                          ADDR("sml-handover"),
                          ibmvtpm_inst, size, base) != 0 || entry == 0) {
@@ -1464,9 +1484,9 @@ static void __init prom_instantiate_sml(void)
 
        reserve_mem(base, size);
 
-       prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-base",
+       prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-base",
                     &base, sizeof(base));
-       prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-size",
+       prom_setprop(ibmvtpm_node, "/vdevice/vtpm", "linux,sml-size",
                     &size, sizeof(size));
 
        prom_debug("sml base     = 0x%x\n", base);
diff --git a/certs/.gitignore b/certs/.gitignore
new file mode 100644 (file)
index 0000000..f51aea4
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Generated files
+#
+x509_certificate_list
index 3f5b537ab33ec36f640ca6ca61038ba8390fda22..1d450b580245157b500db100de8576f4027bf030 100644 (file)
@@ -14,8 +14,3 @@ extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
 extern int __asymmetric_key_hex_to_key_id(const char *id,
                                          struct asymmetric_key_id *match_id,
                                          size_t hexlen);
-static inline
-const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
-{
-       return key->type_data.p[1];
-}
index 1916680ad81b08fc6db5a0f9f2751dc0526b3e9b..9f2165b27d52efe6fcae3c64956a2c717a3d93da 100644 (file)
@@ -306,26 +306,35 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
        return ret;
 }
 
+/*
+ * Clean up the key ID list
+ */
+static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
+{
+       int i;
+
+       if (kids) {
+               for (i = 0; i < ARRAY_SIZE(kids->id); i++)
+                       kfree(kids->id[i]);
+               kfree(kids);
+       }
+}
+
 /*
  * Clean up the preparse data
  */
 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;
+       struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype];
+       struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids];
 
        pr_devel("==>%s()\n", __func__);
 
        if (subtype) {
-               subtype->destroy(prep->payload[0]);
+               subtype->destroy(prep->payload.data[asym_crypto]);
                module_put(subtype->owner);
        }
-       if (kids) {
-               for (i = 0; i < ARRAY_SIZE(kids->id); i++)
-                       kfree(kids->id[i]);
-               kfree(kids);
-       }
+       asymmetric_key_free_kids(kids);
        kfree(prep->description);
 }
 
@@ -335,20 +344,19 @@ 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];
+       struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
+       void *data = key->payload.data[asym_crypto];
+
+       key->payload.data[asym_crypto] = NULL;
+       key->payload.data[asym_subtype] = NULL;
+       key->payload.data[asym_key_ids] = NULL;
 
        if (subtype) {
-               subtype->destroy(key->payload.data);
+               subtype->destroy(data);
                module_put(subtype->owner);
-               key->type_data.p[0] = NULL;
        }
 
-       if (kids) {
-               kfree(kids->id[0]);
-               kfree(kids->id[1]);
-               kfree(kids);
-               key->type_data.p[1] = NULL;
-       }
+       asymmetric_key_free_kids(kids);
 }
 
 struct key_type key_type_asymmetric = {
index 81efccbe22d5b21d3e31e44f504fc23cefd32d76..6db4c01c6503ff267e0d7ecbe4dbf09496743c15 100644 (file)
@@ -49,7 +49,7 @@ EXPORT_SYMBOL_GPL(pkey_id_type_name);
 static void public_key_describe(const struct key *asymmetric_key,
                                struct seq_file *m)
 {
-       struct public_key *key = asymmetric_key->payload.data;
+       struct public_key *key = asymmetric_key->payload.data[asym_crypto];
 
        if (key)
                seq_printf(m, "%s.%s",
@@ -112,7 +112,7 @@ EXPORT_SYMBOL_GPL(public_key_verify_signature);
 static int public_key_verify_signature_2(const struct key *key,
                                         const struct public_key_signature *sig)
 {
-       const struct public_key *pk = key->payload.data;
+       const struct public_key *pk = key->payload.data[asym_crypto];
        return public_key_verify_signature(pk, sig);
 }
 
index 7525fd183574c826b2f85a5f4de3ba47e4c585ab..9441240f7d2a51e746331dc8aa720ae4280685e4 100644 (file)
@@ -37,7 +37,7 @@ int verify_signature(const struct key *key,
                return -EINVAL;
        subtype = asymmetric_key_subtype(key);
        if (!subtype ||
-           !key->payload.data)
+           !key->payload.data[0])
                return -EINVAL;
        if (!subtype->verify_signature)
                return -ENOTSUPP;
index 1de01eaec88490c6c24d669a6f02c6b4fc2e9959..dbeed6018e63675db5316e254760f10e4a28a2b4 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/time.h>
 #include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
 
 struct x509_certificate {
        struct x509_certificate *next;
index 68c3c40501ab058e7d0d1a6c13fc630d0d542c9d..2a44b3752471d0b34d19fbe4a66305863dfcafb8 100644 (file)
@@ -267,7 +267,8 @@ static int x509_validate_trust(struct x509_certificate *cert,
        if (!IS_ERR(key))  {
                if (!use_builtin_keys
                    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
-                       ret = x509_check_signature(key->payload.data, cert);
+                       ret = x509_check_signature(key->payload.data[asym_crypto],
+                                                  cert);
                key_put(key);
        }
        return ret;
@@ -353,9 +354,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 
        /* 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] = kids;
-       prep->payload[0] = cert->pub;
+       prep->payload.data[asym_subtype] = &public_key_subtype;
+       prep->payload.data[asym_key_ids] = kids;
+       prep->payload.data[asym_crypto] = cert->pub;
        prep->description = desc;
        prep->quotalen = 100;
 
index 09cb727864f0950f9e52e6ba1607124ede64f9e4..19c007461d1cbd7acae8b6fee4d8d51fbcb7f5de 100644 (file)
@@ -1,6 +1,6 @@
 config TCG_TIS_ST33ZP24
        tristate "STMicroelectronics TPM Interface Specification 1.2 Interface"
-       depends on GPIOLIB
+       depends on GPIOLIB || COMPILE_TEST
        ---help---
          STMicroelectronics ST33ZP24 core driver. It implements the core
          TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will
index ad1ee180e0c2cac8f1fa8353d222102b3bb85254..309d2767c6a109c27cd73a833f9670a7360cd521 100644 (file)
@@ -258,7 +258,6 @@ static SIMPLE_DEV_PM_OPS(st33zp24_i2c_ops, st33zp24_pm_suspend,
 
 static struct i2c_driver st33zp24_i2c_driver = {
        .driver = {
-               .owner = THIS_MODULE,
                .name = TPM_ST33_I2C,
                .pm = &st33zp24_i2c_ops,
                .of_match_table = of_match_ptr(of_st33zp24_i2c_match),
index 1082d4bb016a9e4d7caf795a5128509780134916..f26b0ae23bea77719c5f6e13e9cfcc33d5706405 100644 (file)
@@ -119,6 +119,9 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
        chip->dev.class = tpm_class;
        chip->dev.release = tpm_dev_release;
        chip->dev.parent = chip->pdev;
+#ifdef CONFIG_ACPI
+       chip->dev.groups = chip->groups;
+#endif
 
        if (chip->dev_num == 0)
                chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
@@ -182,12 +185,6 @@ static int tpm1_chip_register(struct tpm_chip *chip)
        if (rc)
                return rc;
 
-       rc = tpm_add_ppi(chip);
-       if (rc) {
-               tpm_sysfs_del_device(chip);
-               return rc;
-       }
-
        chip->bios_dir = tpm_bios_log_setup(chip->devname);
 
        return 0;
@@ -201,8 +198,6 @@ static void tpm1_chip_unregister(struct tpm_chip *chip)
        if (chip->bios_dir)
                tpm_bios_log_teardown(chip->bios_dir);
 
-       tpm_remove_ppi(chip);
-
        tpm_sysfs_del_device(chip);
 }
 
@@ -225,10 +220,20 @@ int tpm_chip_register(struct tpm_chip *chip)
        if (rc)
                return rc;
 
+       tpm_add_ppi(chip);
+
        rc = tpm_dev_add_device(chip);
        if (rc)
                goto out_err;
 
+       if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+               rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj,
+                                                           &chip->dev.kobj,
+                                                           "ppi");
+               if (rc)
+                       goto out_err;
+       }
+
        /* Make the chip available. */
        spin_lock(&driver_lock);
        list_add_rcu(&chip->list, &tpm_chip_list);
@@ -263,6 +268,9 @@ void tpm_chip_unregister(struct tpm_chip *chip)
        spin_unlock(&driver_lock);
        synchronize_rcu();
 
+       if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
+               sysfs_remove_link(&chip->pdev->kobj, "ppi");
+
        tpm1_chip_unregister(chip);
        tpm_dev_del_device(chip);
 }
index e85d3416d89918e4050eeec8dd32233f2589dc44..c50637db3a8a9336f002d44046135bdb49fa7088 100644 (file)
@@ -665,6 +665,30 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
        return rc;
 }
 
+/**
+ * tpm_is_tpm2 - is the chip a TPM2 chip?
+ * @chip_num:  tpm idx # or ANY
+ *
+ * Returns < 0 on error, and 1 or 0 on success depending whether the chip
+ * is a TPM2 chip.
+ */
+int tpm_is_tpm2(u32 chip_num)
+{
+       struct tpm_chip *chip;
+       int rc;
+
+       chip = tpm_chip_find_get(chip_num);
+       if (chip == NULL)
+               return -ENODEV;
+
+       rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
+
+       tpm_chip_put(chip);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_is_tpm2);
+
 /**
  * tpm_pcr_read - read a pcr value
  * @chip_num:  tpm idx # or ANY
@@ -1021,6 +1045,58 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
 
+/**
+ * tpm_seal_trusted() - seal a trusted key
+ * @chip_num: A specific chip number for the request or TPM_ANY_NUM
+ * @options: authentication values and other options
+ * @payload: the key data in clear and encrypted form
+ *
+ * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
+ * are supported.
+ */
+int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload,
+                    struct trusted_key_options *options)
+{
+       struct tpm_chip *chip;
+       int rc;
+
+       chip = tpm_chip_find_get(chip_num);
+       if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
+               return -ENODEV;
+
+       rc = tpm2_seal_trusted(chip, payload, options);
+
+       tpm_chip_put(chip);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_seal_trusted);
+
+/**
+ * tpm_unseal_trusted() - unseal a trusted key
+ * @chip_num: A specific chip number for the request or TPM_ANY_NUM
+ * @options: authentication values and other options
+ * @payload: the key data in clear and encrypted form
+ *
+ * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
+ * are supported.
+ */
+int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload,
+                      struct trusted_key_options *options)
+{
+       struct tpm_chip *chip;
+       int rc;
+
+       chip = tpm_chip_find_get(chip_num);
+       if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
+               return -ENODEV;
+
+       rc = tpm2_unseal_trusted(chip, payload, options);
+
+       tpm_chip_put(chip);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_unseal_trusted);
+
 static int __init tpm_init(void)
 {
        int rc;
index f8319a0860fd702f51e7658fe22f49607efb1b4e..a4257a32964f40c189f7a1dc54bd252efa48532a 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2015 Intel Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -28,6 +29,7 @@
 #include <linux/tpm.h>
 #include <linux/acpi.h>
 #include <linux/cdev.h>
+#include <linux/highmem.h>
 
 enum tpm_const {
        TPM_MINOR = 224,        /* officially assigned */
@@ -88,6 +90,9 @@ enum tpm2_return_codes {
 
 enum tpm2_algorithms {
        TPM2_ALG_SHA1           = 0x0004,
+       TPM2_ALG_KEYEDHASH      = 0x0008,
+       TPM2_ALG_SHA256         = 0x000B,
+       TPM2_ALG_NULL           = 0x0010
 };
 
 enum tpm2_command_codes {
@@ -95,6 +100,10 @@ enum tpm2_command_codes {
        TPM2_CC_SELF_TEST       = 0x0143,
        TPM2_CC_STARTUP         = 0x0144,
        TPM2_CC_SHUTDOWN        = 0x0145,
+       TPM2_CC_CREATE          = 0x0153,
+       TPM2_CC_LOAD            = 0x0157,
+       TPM2_CC_UNSEAL          = 0x015E,
+       TPM2_CC_FLUSH_CONTEXT   = 0x0165,
        TPM2_CC_GET_CAPABILITY  = 0x017A,
        TPM2_CC_GET_RANDOM      = 0x017B,
        TPM2_CC_PCR_READ        = 0x017E,
@@ -115,6 +124,13 @@ enum tpm2_startup_types {
        TPM2_SU_STATE   = 0x0001,
 };
 
+enum tpm2_start_method {
+       TPM2_START_ACPI = 2,
+       TPM2_START_FIFO = 6,
+       TPM2_START_CRB = 7,
+       TPM2_START_CRB_WITH_ACPI = 8,
+};
+
 struct tpm_chip;
 
 struct tpm_vendor_specific {
@@ -151,8 +167,7 @@ struct tpm_vendor_specific {
 
 enum tpm_chip_flags {
        TPM_CHIP_FLAG_REGISTERED        = BIT(0),
-       TPM_CHIP_FLAG_PPI               = BIT(1),
-       TPM_CHIP_FLAG_TPM2              = BIT(2),
+       TPM_CHIP_FLAG_TPM2              = BIT(1),
 };
 
 struct tpm_chip {
@@ -175,6 +190,8 @@ struct tpm_chip {
        struct dentry **bios_dir;
 
 #ifdef CONFIG_ACPI
+       const struct attribute_group *groups[2];
+       unsigned int groups_cnt;
        acpi_handle acpi_dev_handle;
        char ppi_version[TPM_PPI_VERSION_LEN + 1];
 #endif /* CONFIG_ACPI */
@@ -182,7 +199,7 @@ struct tpm_chip {
        struct list_head list;
 };
 
-#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
+#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
 
 static inline void tpm_chip_put(struct tpm_chip *chip)
 {
@@ -382,6 +399,101 @@ struct tpm_cmd_t {
        tpm_cmd_params  params;
 } __packed;
 
+/* A string buffer type for constructing TPM commands. This is based on the
+ * ideas of string buffer code in security/keys/trusted.h but is heap based
+ * in order to keep the stack usage minimal.
+ */
+
+enum tpm_buf_flags {
+       TPM_BUF_OVERFLOW        = BIT(0),
+};
+
+struct tpm_buf {
+       struct page *data_page;
+       unsigned int flags;
+       u8 *data;
+};
+
+static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
+{
+       struct tpm_input_header *head;
+
+       buf->data_page = alloc_page(GFP_HIGHUSER);
+       if (!buf->data_page)
+               return -ENOMEM;
+
+       buf->flags = 0;
+       buf->data = kmap(buf->data_page);
+
+       head = (struct tpm_input_header *) buf->data;
+
+       head->tag = cpu_to_be16(tag);
+       head->length = cpu_to_be32(sizeof(*head));
+       head->ordinal = cpu_to_be32(ordinal);
+
+       return 0;
+}
+
+static inline void tpm_buf_destroy(struct tpm_buf *buf)
+{
+       kunmap(buf->data_page);
+       __free_page(buf->data_page);
+}
+
+static inline u32 tpm_buf_length(struct tpm_buf *buf)
+{
+       struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
+
+       return be32_to_cpu(head->length);
+}
+
+static inline u16 tpm_buf_tag(struct tpm_buf *buf)
+{
+       struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
+
+       return be16_to_cpu(head->tag);
+}
+
+static inline void tpm_buf_append(struct tpm_buf *buf,
+                                 const unsigned char *new_data,
+                                 unsigned int new_len)
+{
+       struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
+       u32 len = tpm_buf_length(buf);
+
+       /* Return silently if overflow has already happened. */
+       if (buf->flags & TPM_BUF_OVERFLOW)
+               return;
+
+       if ((len + new_len) > PAGE_SIZE) {
+               WARN(1, "tpm_buf: overflow\n");
+               buf->flags |= TPM_BUF_OVERFLOW;
+               return;
+       }
+
+       memcpy(&buf->data[len], new_data, new_len);
+       head->length = cpu_to_be32(len + new_len);
+}
+
+static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
+{
+       tpm_buf_append(buf, &value, 1);
+}
+
+static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
+{
+       __be16 value2 = cpu_to_be16(value);
+
+       tpm_buf_append(buf, (u8 *) &value2, 2);
+}
+
+static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
+{
+       __be32 value2 = cpu_to_be32(value);
+
+       tpm_buf_append(buf, (u8 *) &value2, 4);
+}
+
 extern struct class *tpm_class;
 extern dev_t tpm_devt;
 extern const struct file_operations tpm_fops;
@@ -412,15 +524,9 @@ void tpm_sysfs_del_device(struct tpm_chip *chip);
 int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
 
 #ifdef CONFIG_ACPI
-extern int tpm_add_ppi(struct tpm_chip *chip);
-extern void tpm_remove_ppi(struct tpm_chip *chip);
+extern void tpm_add_ppi(struct tpm_chip *chip);
 #else
-static inline int tpm_add_ppi(struct tpm_chip *chip)
-{
-       return 0;
-}
-
-static inline void tpm_remove_ppi(struct tpm_chip *chip)
+static inline void tpm_add_ppi(struct tpm_chip *chip)
 {
 }
 #endif
@@ -428,6 +534,12 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
 int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
 int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
+int tpm2_seal_trusted(struct tpm_chip *chip,
+                     struct trusted_key_payload *payload,
+                     struct trusted_key_options *options);
+int tpm2_unseal_trusted(struct tpm_chip *chip,
+                       struct trusted_key_payload *payload,
+                       struct trusted_key_options *options);
 ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
                        u32 *value, const char *desc);
 
index 011909a9be9627632bd1d1ec19230d5945d86719..bd7039fafa8aa7c34326e7a2270cd09e42837d81 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Intel Corporation
+ * Copyright (C) 2014, 2015 Intel Corporation
  *
  * Authors:
  * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
  */
 
 #include "tpm.h"
+#include <keys/trusted-type.h>
+
+enum tpm2_object_attributes {
+       TPM2_ATTR_USER_WITH_AUTH        = BIT(6),
+};
 
 struct tpm2_startup_in {
        __be16  startup_type;
@@ -380,6 +385,249 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = {
        .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
 };
 
+/**
+ * Append TPMS_AUTH_COMMAND to the buffer. The buffer must be allocated with
+ * tpm_buf_alloc().
+ *
+ * @param buf: an allocated tpm_buf instance
+ * @param nonce: the session nonce, may be NULL if not used
+ * @param nonce_len: the session nonce length, may be 0 if not used
+ * @param attributes: the session attributes
+ * @param hmac: the session HMAC or password, may be NULL if not used
+ * @param hmac_len: the session HMAC or password length, maybe 0 if not used
+ */
+static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
+                                const u8 *nonce, u16 nonce_len,
+                                u8 attributes,
+                                const u8 *hmac, u16 hmac_len)
+{
+       tpm_buf_append_u32(buf, 9 + nonce_len + hmac_len);
+       tpm_buf_append_u32(buf, session_handle);
+       tpm_buf_append_u16(buf, nonce_len);
+
+       if (nonce && nonce_len)
+               tpm_buf_append(buf, nonce, nonce_len);
+
+       tpm_buf_append_u8(buf, attributes);
+       tpm_buf_append_u16(buf, hmac_len);
+
+       if (hmac && hmac_len)
+               tpm_buf_append(buf, hmac, hmac_len);
+}
+
+/**
+ * tpm2_seal_trusted() - seal a trusted key
+ * @chip_num: A specific chip number for the request or TPM_ANY_NUM
+ * @options: authentication values and other options
+ * @payload: the key data in clear and encrypted form
+ *
+ * Returns < 0 on error and 0 on success.
+ */
+int tpm2_seal_trusted(struct tpm_chip *chip,
+                     struct trusted_key_payload *payload,
+                     struct trusted_key_options *options)
+{
+       unsigned int blob_len;
+       struct tpm_buf buf;
+       int rc;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
+       if (rc)
+               return rc;
+
+       tpm_buf_append_u32(&buf, options->keyhandle);
+       tpm2_buf_append_auth(&buf, TPM2_RS_PW,
+                            NULL /* nonce */, 0,
+                            0 /* session_attributes */,
+                            options->keyauth /* hmac */,
+                            TPM_DIGEST_SIZE);
+
+       /* sensitive */
+       tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len);
+
+       tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
+       tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
+       tpm_buf_append_u16(&buf, payload->key_len);
+       tpm_buf_append(&buf, payload->key, payload->key_len);
+
+       /* public */
+       tpm_buf_append_u16(&buf, 14);
+
+       tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
+       tpm_buf_append_u16(&buf, TPM2_ALG_SHA256);
+       tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
+       tpm_buf_append_u16(&buf, 0); /* policy digest size */
+       tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
+       tpm_buf_append_u16(&buf, 0);
+
+       /* outside info */
+       tpm_buf_append_u16(&buf, 0);
+
+       /* creation PCR */
+       tpm_buf_append_u32(&buf, 0);
+
+       if (buf.flags & TPM_BUF_OVERFLOW) {
+               rc = -E2BIG;
+               goto out;
+       }
+
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "sealing data");
+       if (rc)
+               goto out;
+
+       blob_len = be32_to_cpup((__be32 *) &buf.data[TPM_HEADER_SIZE]);
+       if (blob_len > MAX_BLOB_SIZE) {
+               rc = -E2BIG;
+               goto out;
+       }
+
+       memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len);
+       payload->blob_len = blob_len;
+
+out:
+       tpm_buf_destroy(&buf);
+
+       if (rc > 0)
+               rc = -EPERM;
+
+       return rc;
+}
+
+static int tpm2_load(struct tpm_chip *chip,
+                    struct trusted_key_payload *payload,
+                    struct trusted_key_options *options,
+                    u32 *blob_handle)
+{
+       struct tpm_buf buf;
+       unsigned int private_len;
+       unsigned int public_len;
+       unsigned int blob_len;
+       int rc;
+
+       private_len = be16_to_cpup((__be16 *) &payload->blob[0]);
+       if (private_len > (payload->blob_len - 2))
+               return -E2BIG;
+
+       public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]);
+       blob_len = private_len + public_len + 4;
+       if (blob_len > payload->blob_len)
+               return -E2BIG;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
+       if (rc)
+               return rc;
+
+       tpm_buf_append_u32(&buf, options->keyhandle);
+       tpm2_buf_append_auth(&buf, TPM2_RS_PW,
+                            NULL /* nonce */, 0,
+                            0 /* session_attributes */,
+                            options->keyauth /* hmac */,
+                            TPM_DIGEST_SIZE);
+
+       tpm_buf_append(&buf, payload->blob, blob_len);
+
+       if (buf.flags & TPM_BUF_OVERFLOW) {
+               rc = -E2BIG;
+               goto out;
+       }
+
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "loading blob");
+       if (!rc)
+               *blob_handle = be32_to_cpup(
+                       (__be32 *) &buf.data[TPM_HEADER_SIZE]);
+
+out:
+       tpm_buf_destroy(&buf);
+
+       if (rc > 0)
+               rc = -EPERM;
+
+       return rc;
+}
+
+static void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
+{
+       struct tpm_buf buf;
+       int rc;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
+       if (rc) {
+               dev_warn(chip->pdev, "0x%08x was not flushed, out of memory\n",
+                        handle);
+               return;
+       }
+
+       tpm_buf_append_u32(&buf, handle);
+
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "flushing context");
+       if (rc)
+               dev_warn(chip->pdev, "0x%08x was not flushed, rc=%d\n", handle,
+                        rc);
+
+       tpm_buf_destroy(&buf);
+}
+
+static int tpm2_unseal(struct tpm_chip *chip,
+                      struct trusted_key_payload *payload,
+                      struct trusted_key_options *options,
+                      u32 blob_handle)
+{
+       struct tpm_buf buf;
+       int rc;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
+       if (rc)
+               return rc;
+
+       tpm_buf_append_u32(&buf, blob_handle);
+       tpm2_buf_append_auth(&buf, TPM2_RS_PW,
+                            NULL /* nonce */, 0,
+                            0 /* session_attributes */,
+                            options->blobauth /* hmac */,
+                            TPM_DIGEST_SIZE);
+
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "unsealing");
+       if (rc > 0)
+               rc = -EPERM;
+
+       if (!rc) {
+               payload->key_len = be16_to_cpup(
+                       (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
+
+               memcpy(payload->key, &buf.data[TPM_HEADER_SIZE + 6],
+                      payload->key_len);
+       }
+
+       tpm_buf_destroy(&buf);
+       return rc;
+}
+
+/**
+ * tpm_unseal_trusted() - unseal a trusted key
+ * @chip_num: A specific chip number for the request or TPM_ANY_NUM
+ * @options: authentication values and other options
+ * @payload: the key data in clear and encrypted form
+ *
+ * Returns < 0 on error and 0 on success.
+ */
+int tpm2_unseal_trusted(struct tpm_chip *chip,
+                       struct trusted_key_payload *payload,
+                       struct trusted_key_options *options)
+{
+       u32 blob_handle;
+       int rc;
+
+       rc = tpm2_load(chip, payload, options, &blob_handle);
+       if (rc)
+               return rc;
+
+       rc = tpm2_unseal(chip, payload, options, blob_handle);
+
+       tpm2_flush_context(chip, blob_handle);
+
+       return rc;
+}
+
 /**
  * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
  * @chip:              TPM chip to use.
index 1267322595da0ec0a53bd10a8ba93531a036f483..4bb9727c1047172f70b77db1649729597da1ce52 100644 (file)
@@ -34,12 +34,6 @@ enum crb_defaults {
        CRB_ACPI_START_INDEX = 1,
 };
 
-enum crb_start_method {
-       CRB_SM_ACPI_START = 2,
-       CRB_SM_CRB = 7,
-       CRB_SM_CRB_WITH_ACPI_START = 8,
-};
-
 struct acpi_tpm2 {
        struct acpi_table_header hdr;
        u16 platform_class;
@@ -74,7 +68,8 @@ struct crb_control_area {
        u32 int_enable;
        u32 int_sts;
        u32 cmd_size;
-       u64 cmd_pa;
+       u32 cmd_pa_low;
+       u32 cmd_pa_high;
        u32 rsp_size;
        u64 rsp_pa;
 } __packed;
@@ -220,12 +215,6 @@ static int crb_acpi_add(struct acpi_device *device)
        u64 pa;
        int rc;
 
-       chip = tpmm_chip_alloc(dev, &tpm_crb);
-       if (IS_ERR(chip))
-               return PTR_ERR(chip);
-
-       chip->flags = TPM_CHIP_FLAG_TPM2;
-
        status = acpi_get_table(ACPI_SIG_TPM2, 1,
                                (struct acpi_table_header **) &buf);
        if (ACPI_FAILURE(status)) {
@@ -233,13 +222,15 @@ static int crb_acpi_add(struct acpi_device *device)
                return -ENODEV;
        }
 
-       /* At least some versions of AMI BIOS have a bug that TPM2 table has
-        * zero address for the control area and therefore we must fail.
-       */
-       if (!buf->control_area_pa) {
-               dev_err(dev, "TPM2 ACPI table has a zero address for the control area\n");
-               return -EINVAL;
-       }
+       /* Should the FIFO driver handle this? */
+       if (buf->start_method == TPM2_START_FIFO)
+               return -ENODEV;
+
+       chip = tpmm_chip_alloc(dev, &tpm_crb);
+       if (IS_ERR(chip))
+               return PTR_ERR(chip);
+
+       chip->flags = TPM_CHIP_FLAG_TPM2;
 
        if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
                dev_err(dev, "TPM2 ACPI table has wrong size");
@@ -259,11 +250,11 @@ static int crb_acpi_add(struct acpi_device *device)
         * report only ACPI start but in practice seems to require both
         * ACPI start and CRB start.
         */
-       if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START ||
+       if (sm == TPM2_START_CRB || sm == TPM2_START_FIFO ||
            !strcmp(acpi_device_hid(device), "MSFT0101"))
                priv->flags |= CRB_FL_CRB_START;
 
-       if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
+       if (sm == TPM2_START_ACPI || sm == TPM2_START_CRB_WITH_ACPI)
                priv->flags |= CRB_FL_ACPI_START;
 
        priv->cca = (struct crb_control_area __iomem *)
@@ -273,8 +264,8 @@ static int crb_acpi_add(struct acpi_device *device)
                return -ENOMEM;
        }
 
-       memcpy_fromio(&pa, &priv->cca->cmd_pa, 8);
-       pa = le64_to_cpu(pa);
+       pa = ((u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_high)) << 32) |
+               (u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_low));
        priv->cmd = devm_ioremap_nocache(dev, pa,
                                         ioread32(&priv->cca->cmd_size));
        if (!priv->cmd) {
index 3a56a131586c824f97e2cc2310c496a91378fd3d..bd72fb04225e43f8ae21acba1cc5ddb351701c5d 100644 (file)
@@ -76,15 +76,25 @@ static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
        void *addr = log->bios_event_log;
        void *limit = log->bios_event_log_end;
        struct tcpa_event *event;
+       u32 converted_event_size;
+       u32 converted_event_type;
+
 
        /* read over *pos measurements */
        for (i = 0; i < *pos; i++) {
                event = addr;
 
+               converted_event_size =
+                   do_endian_conversion(event->event_size);
+               converted_event_type =
+                   do_endian_conversion(event->event_type);
+
                if ((addr + sizeof(struct tcpa_event)) < limit) {
-                       if (event->event_type == 0 && event->event_size == 0)
+                       if ((converted_event_type == 0) &&
+                           (converted_event_size == 0))
                                return NULL;
-                       addr += sizeof(struct tcpa_event) + event->event_size;
+                       addr += (sizeof(struct tcpa_event) +
+                                converted_event_size);
                }
        }
 
@@ -94,8 +104,12 @@ static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
 
        event = addr;
 
-       if ((event->event_type == 0 && event->event_size == 0) ||
-           ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
+       converted_event_size = do_endian_conversion(event->event_size);
+       converted_event_type = do_endian_conversion(event->event_type);
+
+       if (((converted_event_type == 0) && (converted_event_size == 0))
+           || ((addr + sizeof(struct tcpa_event) + converted_event_size)
+               >= limit))
                return NULL;
 
        return addr;
@@ -107,8 +121,12 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
        struct tcpa_event *event = v;
        struct tpm_bios_log *log = m->private;
        void *limit = log->bios_event_log_end;
+       u32 converted_event_size;
+       u32 converted_event_type;
 
-       v += sizeof(struct tcpa_event) + event->event_size;
+       converted_event_size = do_endian_conversion(event->event_size);
+
+       v += sizeof(struct tcpa_event) + converted_event_size;
 
        /* now check if current entry is valid */
        if ((v + sizeof(struct tcpa_event)) >= limit)
@@ -116,11 +134,11 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
 
        event = v;
 
-       if (event->event_type == 0 && event->event_size == 0)
-               return NULL;
+       converted_event_size = do_endian_conversion(event->event_size);
+       converted_event_type = do_endian_conversion(event->event_type);
 
-       if ((event->event_type == 0 && event->event_size == 0) ||
-           ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
+       if (((converted_event_type == 0) && (converted_event_size == 0)) ||
+           ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
                return NULL;
 
        (*pos)++;
@@ -140,7 +158,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
        int i, n_len = 0, d_len = 0;
        struct tcpa_pc_event *pc_event;
 
-       switch(event->event_type) {
+       switch (do_endian_conversion(event->event_type)) {
        case PREBOOT:
        case POST_CODE:
        case UNUSED:
@@ -156,14 +174,16 @@ static int get_event_name(char *dest, struct tcpa_event *event,
        case NONHOST_CODE:
        case NONHOST_CONFIG:
        case NONHOST_INFO:
-               name = tcpa_event_type_strings[event->event_type];
+               name = tcpa_event_type_strings[do_endian_conversion
+                                               (event->event_type)];
                n_len = strlen(name);
                break;
        case SEPARATOR:
        case ACTION:
-               if (MAX_TEXT_EVENT > event->event_size) {
+               if (MAX_TEXT_EVENT >
+                   do_endian_conversion(event->event_size)) {
                        name = event_entry;
-                       n_len = event->event_size;
+                       n_len = do_endian_conversion(event->event_size);
                }
                break;
        case EVENT_TAG:
@@ -171,7 +191,7 @@ static int get_event_name(char *dest, struct tcpa_event *event,
 
                /* ToDo Row data -> Base64 */
 
-               switch (pc_event->event_id) {
+               switch (do_endian_conversion(pc_event->event_id)) {
                case SMBIOS:
                case BIS_CERT:
                case CMOS:
@@ -179,7 +199,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
                case OPTION_ROM_EXEC:
                case OPTION_ROM_CONFIG:
                case S_CRTM_VERSION:
-                       name = tcpa_pc_event_id_strings[pc_event->event_id];
+                       name = tcpa_pc_event_id_strings[do_endian_conversion
+                                                       (pc_event->event_id)];
                        n_len = strlen(name);
                        break;
                /* hash data */
@@ -188,7 +209,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
                case OPTION_ROM_MICROCODE:
                case S_CRTM_CONTENTS:
                case POST_CONTENTS:
-                       name = tcpa_pc_event_id_strings[pc_event->event_id];
+                       name = tcpa_pc_event_id_strings[do_endian_conversion
+                                                       (pc_event->event_id)];
                        n_len = strlen(name);
                        for (i = 0; i < 20; i++)
                                d_len += sprintf(&data[2*i], "%02x",
@@ -209,13 +231,24 @@ static int get_event_name(char *dest, struct tcpa_event *event,
 static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
 {
        struct tcpa_event *event = v;
-       char *data = v;
+       struct tcpa_event temp_event;
+       char *tempPtr;
        int i;
 
-       for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
-               seq_putc(m, data[i]);
+       memcpy(&temp_event, event, sizeof(struct tcpa_event));
+
+       /* convert raw integers for endianness */
+       temp_event.pcr_index = do_endian_conversion(event->pcr_index);
+       temp_event.event_type = do_endian_conversion(event->event_type);
+       temp_event.event_size = do_endian_conversion(event->event_size);
+
+       tempPtr = (char *)&temp_event;
+
+       for (i = 0; i < sizeof(struct tcpa_event) + temp_event.event_size; i++)
+               seq_putc(m, tempPtr[i]);
 
        return 0;
+
 }
 
 static int tpm_bios_measurements_release(struct inode *inode,
@@ -238,7 +271,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
        char *eventname;
        struct tcpa_event *event = v;
        unsigned char *event_entry =
-           (unsigned char *) (v + sizeof(struct tcpa_event));
+           (unsigned char *)(v + sizeof(struct tcpa_event));
 
        eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
        if (!eventname) {
@@ -247,13 +280,14 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
                return -EFAULT;
        }
 
-       seq_printf(m, "%2d ", event->pcr_index);
+       /* 1st: PCR */
+       seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
 
        /* 2nd: SHA1 */
        seq_printf(m, "%20phN", event->pcr_value);
 
        /* 3rd: event type identifier */
-       seq_printf(m, " %02x", event->event_type);
+       seq_printf(m, " %02x", do_endian_conversion(event->event_type));
 
        len += get_event_name(eventname, event, event_entry);
 
index e7da086d6928814b0ae04a015d534f6804f40c82..267bfbd1b7bbe7addf4dcd029e8c21df3a731859 100644 (file)
@@ -6,6 +6,12 @@
 #define MAX_TEXT_EVENT         1000    /* Max event string length */
 #define ACPI_TCPA_SIG          "TCPA"  /* 0x41504354 /'TCPA' */
 
+#ifdef CONFIG_PPC64
+#define do_endian_conversion(x) be32_to_cpu(x)
+#else
+#define do_endian_conversion(x) x
+#endif
+
 enum bios_platform_class {
        BIOS_CLIENT = 0x00,
        BIOS_SERVER = 0x01,
index 7a0ca78ad3c68a879e8e1546a88c1d30b5223268..8dfb88b9739c197f01eb538157e450c67323debc 100644 (file)
@@ -217,7 +217,6 @@ static struct i2c_driver i2c_atmel_driver = {
        .remove = i2c_atmel_remove,
        .driver = {
                .name = I2C_DRIVER_NAME,
-               .owner = THIS_MODULE,
                .pm = &i2c_atmel_pm_ops,
                .of_match_table = of_match_ptr(i2c_atmel_of_match),
        },
index 33c5f360ab01e9c2adc687f88be912bd50513f43..63d5d22e9e600c2e7dd1b4b0e83df61f36b6a2e5 100644 (file)
@@ -711,7 +711,6 @@ static struct i2c_driver tpm_tis_i2c_driver = {
        .remove = tpm_tis_i2c_remove,
        .driver = {
                   .name = "tpm_i2c_infineon",
-                  .owner = THIS_MODULE,
                   .pm = &tpm_tis_i2c_ops,
                   .of_match_table = of_match_ptr(tpm_tis_i2c_of_match),
                   },
index 9d42b7d78e501d3d48bc31c1258d73525bf0f943..847f1597fe9b283557e45f5598da955a2dbb7f8f 100644 (file)
@@ -641,7 +641,6 @@ static struct i2c_driver i2c_nuvoton_driver = {
        .remove = i2c_nuvoton_remove,
        .driver = {
                .name = I2C_DRIVER_NAME,
-               .owner = THIS_MODULE,
                .pm = &i2c_nuvoton_pm_ops,
                .of_match_table = of_match_ptr(i2c_nuvoton_of_match),
        },
index 27ebf9511cb41cdf5e26fc1f82a65ecab9a60d33..3e6a22658b63b46acfcdd58f7f9bbe2df31e1498 100644 (file)
@@ -491,7 +491,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
                        }
                        ibmvtpm->rtce_size = be16_to_cpu(crq->len);
                        ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
-                                                   GFP_KERNEL);
+                                                   GFP_ATOMIC);
                        if (!ibmvtpm->rtce_buf) {
                                dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
                                return;
index eebe6256918f31f07e999f3ecf8e3a9fc0caa648..1141456a4b1f1b974192e89574af9e165051922b 100644 (file)
@@ -24,14 +24,14 @@ int read_log(struct tpm_bios_log *log)
 {
        struct device_node *np;
        const u32 *sizep;
-       const __be64 *basep;
+       const u64 *basep;
 
        if (log->bios_event_log != NULL) {
                pr_err("%s: ERROR - Eventlog already initialized\n", __func__);
                return -EFAULT;
        }
 
-       np = of_find_node_by_name(NULL, "ibm,vtpm");
+       np = of_find_node_by_name(NULL, "vtpm");
        if (!np) {
                pr_err("%s: ERROR - IBMVTPM not supported\n", __func__);
                return -ENODEV;
@@ -63,7 +63,7 @@ int read_log(struct tpm_bios_log *log)
 
        log->bios_event_log_end = log->bios_event_log + *sizep;
 
-       memcpy(log->bios_event_log, __va(be64_to_cpup(basep)), *sizep);
+       memcpy(log->bios_event_log, __va(*basep), *sizep);
 
        return 0;
 
index 6ca9b5d78144bbd8302c84fa9af593b12bf3aa67..692a2c6ae036635da19ce4427aa86aacf6bef8d5 100644 (file)
@@ -53,7 +53,7 @@ tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
 static ssize_t tpm_show_ppi_version(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
-       struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_chip *chip = to_tpm_chip(dev);
 
        return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
 }
@@ -63,7 +63,7 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
 {
        ssize_t size = -EINVAL;
        union acpi_object *obj;
-       struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_chip *chip = to_tpm_chip(dev);
 
        obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
                           ACPI_TYPE_PACKAGE, NULL);
@@ -100,7 +100,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
        int func = TPM_PPI_FN_SUBREQ;
        union acpi_object *obj, tmp;
        union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
-       struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_chip *chip = to_tpm_chip(dev);
 
        /*
         * the function to submit TPM operation request to pre-os environment
@@ -156,7 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
                .buffer.length = 0,
                .buffer.pointer = NULL
        };
-       struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_chip *chip = to_tpm_chip(dev);
 
        static char *info[] = {
                "None",
@@ -197,7 +197,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
        acpi_status status = -EINVAL;
        union acpi_object *obj, *ret_obj;
        u64 req, res;
-       struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_chip *chip = to_tpm_chip(dev);
 
        obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
                           ACPI_TYPE_PACKAGE, NULL);
@@ -296,7 +296,7 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
                                           struct device_attribute *attr,
                                           char *buf)
 {
-       struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_chip *chip = to_tpm_chip(dev);
 
        return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
                                   PPI_TPM_REQ_MAX);
@@ -306,7 +306,7 @@ static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
 {
-       struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_chip *chip = to_tpm_chip(dev);
 
        return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
                                   PPI_VS_REQ_END);
@@ -334,17 +334,16 @@ static struct attribute_group ppi_attr_grp = {
        .attrs = ppi_attrs
 };
 
-int tpm_add_ppi(struct tpm_chip *chip)
+void tpm_add_ppi(struct tpm_chip *chip)
 {
        union acpi_object *obj;
-       int rc;
 
        if (!chip->acpi_dev_handle)
-               return 0;
+               return;
 
        if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
                            TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
-               return 0;
+               return;
 
        /* Cache PPI version string. */
        obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
@@ -356,16 +355,5 @@ int tpm_add_ppi(struct tpm_chip *chip)
                ACPI_FREE(obj);
        }
 
-       rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp);
-
-       if (!rc)
-               chip->flags |= TPM_CHIP_FLAG_PPI;
-
-       return rc;
-}
-
-void tpm_remove_ppi(struct tpm_chip *chip)
-{
-       if (chip->flags & TPM_CHIP_FLAG_PPI)
-               sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp);
+       chip->groups[chip->groups_cnt++] = &ppi_attr_grp;
 }
index f2dffa770b8e93496e2b5c339992ede80b95142b..696ef1d56b4f5830682bc1227b72686c2906eefb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005, 2006 IBM Corporation
- * Copyright (C) 2014 Intel Corporation
+ * Copyright (C) 2014, 2015 Intel Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -28,6 +28,7 @@
 #include <linux/wait.h>
 #include <linux/acpi.h>
 #include <linux/freezer.h>
+#include <acpi/actbl2.h>
 #include "tpm.h"
 
 enum tis_access {
@@ -65,6 +66,17 @@ enum tis_defaults {
        TIS_LONG_TIMEOUT = 2000,        /* 2 sec */
 };
 
+struct tpm_info {
+       unsigned long start;
+       unsigned long len;
+       unsigned int irq;
+};
+
+static struct tpm_info tis_default_info = {
+       .start = TIS_MEM_BASE,
+       .len = TIS_MEM_LEN,
+       .irq = 0,
+};
 
 /* Some timeout values are needed before it is known whether the chip is
  * TPM 1.0 or TPM 2.0.
@@ -91,26 +103,54 @@ struct priv_data {
 };
 
 #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
-static int is_itpm(struct pnp_dev *dev)
+static int has_hid(struct acpi_device *dev, const char *hid)
 {
-       struct acpi_device *acpi = pnp_acpi_device(dev);
        struct acpi_hardware_id *id;
 
-       if (!acpi)
-               return 0;
-
-       list_for_each_entry(id, &acpi->pnp.ids, list) {
-               if (!strcmp("INTC0102", id->id))
+       list_for_each_entry(id, &dev->pnp.ids, list)
+               if (!strcmp(hid, id->id))
                        return 1;
-       }
 
        return 0;
 }
+
+static inline int is_itpm(struct acpi_device *dev)
+{
+       return has_hid(dev, "INTC0102");
+}
+
+static inline int is_fifo(struct acpi_device *dev)
+{
+       struct acpi_table_tpm2 *tbl;
+       acpi_status st;
+
+       /* TPM 1.2 FIFO */
+       if (!has_hid(dev, "MSFT0101"))
+               return 1;
+
+       st = acpi_get_table(ACPI_SIG_TPM2, 1,
+                           (struct acpi_table_header **) &tbl);
+       if (ACPI_FAILURE(st)) {
+               dev_err(&dev->dev, "failed to get TPM2 ACPI table\n");
+               return 0;
+       }
+
+       if (le32_to_cpu(tbl->start_method) != TPM2_START_FIFO)
+               return 0;
+
+       /* TPM 2.0 FIFO */
+       return 1;
+}
 #else
-static inline int is_itpm(struct pnp_dev *dev)
+static inline int is_itpm(struct acpi_device *dev)
 {
        return 0;
 }
+
+static inline int is_fifo(struct acpi_device *dev)
+{
+       return 1;
+}
 #endif
 
 /* Before we attempt to access the TPM we must see that the valid bit is set.
@@ -600,9 +640,8 @@ static void tpm_tis_remove(struct tpm_chip *chip)
        release_locality(chip, chip->vendor.locality, 1);
 }
 
-static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
-                       resource_size_t start, resource_size_t len,
-                       unsigned int irq)
+static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
+                       acpi_handle acpi_dev_handle)
 {
        u32 vendor, intfcaps, intmask;
        int rc, i, irq_s, irq_e, probe;
@@ -622,7 +661,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
        chip->acpi_dev_handle = acpi_dev_handle;
 #endif
 
-       chip->vendor.iobase = devm_ioremap(dev, start, len);
+       chip->vendor.iobase = devm_ioremap(dev, tpm_info->start, tpm_info->len);
        if (!chip->vendor.iobase)
                return -EIO;
 
@@ -707,7 +746,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
                  chip->vendor.iobase +
                  TPM_INT_ENABLE(chip->vendor.locality));
        if (interrupts)
-               chip->vendor.irq = irq;
+               chip->vendor.irq = tpm_info->irq;
        if (interrupts && !chip->vendor.irq) {
                irq_s =
                    ioread8(chip->vendor.iobase +
@@ -890,27 +929,27 @@ static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
 static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
                                      const struct pnp_device_id *pnp_id)
 {
-       resource_size_t start, len;
-       unsigned int irq = 0;
+       struct tpm_info tpm_info = tis_default_info;
        acpi_handle acpi_dev_handle = NULL;
 
-       start = pnp_mem_start(pnp_dev, 0);
-       len = pnp_mem_len(pnp_dev, 0);
+       tpm_info.start = pnp_mem_start(pnp_dev, 0);
+       tpm_info.len = pnp_mem_len(pnp_dev, 0);
 
        if (pnp_irq_valid(pnp_dev, 0))
-               irq = pnp_irq(pnp_dev, 0);
+               tpm_info.irq = pnp_irq(pnp_dev, 0);
        else
                interrupts = false;
 
-       if (is_itpm(pnp_dev))
-               itpm = true;
-
 #ifdef CONFIG_ACPI
-       if (pnp_acpi_device(pnp_dev))
+       if (pnp_acpi_device(pnp_dev)) {
+               if (is_itpm(pnp_acpi_device(pnp_dev)))
+                       itpm = true;
+
                acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
+       }
 #endif
 
-       return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq);
+       return tpm_tis_init(&pnp_dev->dev, &tpm_info, acpi_dev_handle);
 }
 
 static struct pnp_device_id tpm_pnp_tbl[] = {
@@ -930,6 +969,7 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
 static void tpm_tis_pnp_remove(struct pnp_dev *dev)
 {
        struct tpm_chip *chip = pnp_get_drvdata(dev);
+
        tpm_chip_unregister(chip);
        tpm_tis_remove(chip);
 }
@@ -950,6 +990,79 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 #endif
 
+#ifdef CONFIG_ACPI
+static int tpm_check_resource(struct acpi_resource *ares, void *data)
+{
+       struct tpm_info *tpm_info = (struct tpm_info *) data;
+       struct resource res;
+
+       if (acpi_dev_resource_interrupt(ares, 0, &res)) {
+               tpm_info->irq = res.start;
+       } else if (acpi_dev_resource_memory(ares, &res)) {
+               tpm_info->start = res.start;
+               tpm_info->len = resource_size(&res);
+       }
+
+       return 1;
+}
+
+static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
+{
+       struct list_head resources;
+       struct tpm_info tpm_info = tis_default_info;
+       int ret;
+
+       if (!is_fifo(acpi_dev))
+               return -ENODEV;
+
+       INIT_LIST_HEAD(&resources);
+       ret = acpi_dev_get_resources(acpi_dev, &resources, tpm_check_resource,
+                                    &tpm_info);
+       if (ret < 0)
+               return ret;
+
+       acpi_dev_free_resource_list(&resources);
+
+       if (!tpm_info.irq)
+               interrupts = false;
+
+       if (is_itpm(acpi_dev))
+               itpm = true;
+
+       return tpm_tis_init(&acpi_dev->dev, &tpm_info, acpi_dev->handle);
+}
+
+static int tpm_tis_acpi_remove(struct acpi_device *dev)
+{
+       struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
+
+       tpm_chip_unregister(chip);
+       tpm_tis_remove(chip);
+
+       return 0;
+}
+
+static struct acpi_device_id tpm_acpi_tbl[] = {
+       {"MSFT0101", 0},        /* TPM 2.0 */
+       /* Add new here */
+       {"", 0},                /* User Specified */
+       {"", 0}                 /* Terminator */
+};
+MODULE_DEVICE_TABLE(acpi, tpm_acpi_tbl);
+
+static struct acpi_driver tis_acpi_driver = {
+       .name = "tpm_tis",
+       .ids = tpm_acpi_tbl,
+       .ops = {
+               .add = tpm_tis_acpi_init,
+               .remove = tpm_tis_acpi_remove,
+       },
+       .drv = {
+               .pm = &tpm_tis_pm,
+       },
+};
+#endif
+
 static struct platform_driver tis_drv = {
        .driver = {
                .name           = "tpm_tis",
@@ -966,9 +1079,25 @@ static int __init init_tis(void)
 {
        int rc;
 #ifdef CONFIG_PNP
-       if (!force)
-               return pnp_register_driver(&tis_pnp_driver);
+       if (!force) {
+               rc = pnp_register_driver(&tis_pnp_driver);
+               if (rc)
+                       return rc;
+       }
+#endif
+#ifdef CONFIG_ACPI
+       if (!force) {
+               rc = acpi_bus_register_driver(&tis_acpi_driver);
+               if (rc) {
+#ifdef CONFIG_PNP
+                       pnp_unregister_driver(&tis_pnp_driver);
 #endif
+                       return rc;
+               }
+       }
+#endif
+       if (!force)
+               return 0;
 
        rc = platform_driver_register(&tis_drv);
        if (rc < 0)
@@ -978,7 +1107,7 @@ static int __init init_tis(void)
                rc = PTR_ERR(pdev);
                goto err_dev;
        }
-       rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0);
+       rc = tpm_tis_init(&pdev->dev, &tis_default_info, NULL);
        if (rc)
                goto err_init;
        return 0;
@@ -992,9 +1121,14 @@ err_dev:
 static void __exit cleanup_tis(void)
 {
        struct tpm_chip *chip;
-#ifdef CONFIG_PNP
+#if defined(CONFIG_PNP) || defined(CONFIG_ACPI)
        if (!force) {
+#ifdef CONFIG_ACPI
+               acpi_bus_unregister_driver(&tis_acpi_driver);
+#endif
+#ifdef CONFIG_PNP
                pnp_unregister_driver(&tis_pnp_driver);
+#endif
                return;
        }
 #endif
index f4cf200b3c76714ca5a059b1ecdcca6f2e77b338..6908080e9b6d889f323d21da24892046f7fd16a0 100644 (file)
@@ -42,7 +42,7 @@ cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
                goto error;
 
        /* attach the data */
-       key->payload.data = payload;
+       key->payload.data[0] = payload;
        ret = 0;
 
 error:
@@ -52,7 +52,7 @@ error:
 static void
 cifs_spnego_key_destroy(struct key *key)
 {
-       kfree(key->payload.data);
+       kfree(key->payload.data[0]);
 }
 
 
@@ -167,7 +167,7 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
 
 #ifdef CONFIG_CIFS_DEBUG2
        if (cifsFYI && !IS_ERR(spnego_key)) {
-               struct cifs_spnego_msg *msg = spnego_key->payload.data;
+               struct cifs_spnego_msg *msg = spnego_key->payload.data[0];
                cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024U,
                                msg->secblob_len + msg->sesskey_len));
        }
index 1ea780bc6376ed00fe39d211b82ea01c30f2ad57..3f93125916bf041e824e0d98df07c7b8195abdf3 100644 (file)
@@ -58,16 +58,15 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
         * dereference payload.data!
         */
        if (prep->datalen <= sizeof(key->payload)) {
-               key->payload.value = 0;
-               memcpy(&key->payload.value, prep->data, prep->datalen);
-               key->datalen = prep->datalen;
-               return 0;
+               key->payload.data[0] = NULL;
+               memcpy(&key->payload, prep->data, prep->datalen);
+       } else {
+               payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
+               if (!payload)
+                       return -ENOMEM;
+               key->payload.data[0] = payload;
        }
-       payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
-       if (!payload)
-               return -ENOMEM;
 
-       key->payload.data = payload;
        key->datalen = prep->datalen;
        return 0;
 }
@@ -76,7 +75,7 @@ static inline void
 cifs_idmap_key_destroy(struct key *key)
 {
        if (key->datalen > sizeof(key->payload))
-               kfree(key->payload.data);
+               kfree(key->payload.data[0]);
 }
 
 static struct key_type cifs_idmap_key_type = {
@@ -233,8 +232,8 @@ id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
         * it could be.
         */
        ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
-               (struct cifs_sid *)&sidkey->payload.value :
-               (struct cifs_sid *)sidkey->payload.data;
+               (struct cifs_sid *)&sidkey->payload :
+               (struct cifs_sid *)sidkey->payload.data[0];
 
        ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
        if (ksid_size > sidkey->datalen) {
@@ -307,14 +306,14 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
        if (sidtype == SIDOWNER) {
                kuid_t uid;
                uid_t id;
-               memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
+               memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
                uid = make_kuid(&init_user_ns, id);
                if (uid_valid(uid))
                        fuid = uid;
        } else {
                kgid_t gid;
                gid_t id;
-               memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
+               memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
                gid = make_kgid(&init_user_ns, id);
                if (gid_valid(gid))
                        fgid = gid;
index 773f4dc776305284f4df53e4d4e44741a74b467f..3f2228570d441840b7e6d11c10a3b814a2b60962 100644 (file)
@@ -2325,13 +2325,14 @@ static int
 cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
 {
        int rc = 0;
-       char *desc, *delim, *payload;
+       const char *delim, *payload;
+       char *desc;
        ssize_t len;
        struct key *key;
        struct TCP_Server_Info *server = ses->server;
        struct sockaddr_in *sa;
        struct sockaddr_in6 *sa6;
-       struct user_key_payload *upayload;
+       const struct user_key_payload *upayload;
 
        desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
        if (!desc)
@@ -2374,14 +2375,14 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
        }
 
        down_read(&key->sem);
-       upayload = key->payload.data;
+       upayload = user_key_payload(key);
        if (IS_ERR_OR_NULL(upayload)) {
                rc = upayload ? PTR_ERR(upayload) : -EINVAL;
                goto out_key_put;
        }
 
        /* find first : in payload */
-       payload = (char *)upayload->data;
+       payload = upayload->data;
        delim = strnchr(payload, upayload->datalen, ':');
        cifs_dbg(FYI, "payload=%s\n", payload);
        if (!delim) {
index bce6fdcd5d480c8b7acb30e8f4bb329f61900151..59727e32ed0f68871785b17b0df0f41bf9e4f378 100644 (file)
@@ -988,7 +988,7 @@ sess_auth_kerberos(struct sess_data *sess_data)
                goto out;
        }
 
-       msg = spnego_key->payload.data;
+       msg = spnego_key->payload.data[0];
        /*
         * check version field to make sure that cifs.upcall is
         * sending us a response in an expected form
index 597a417ba94d3bb910f52e3f14119a197ff2d090..61276929d139f64d1309481e69f2dfce2c8f1fe5 100644 (file)
@@ -660,7 +660,7 @@ ssetup_ntlmssp_authenticate:
                        goto ssetup_exit;
                }
 
-               msg = spnego_key->payload.data;
+               msg = spnego_key->payload.data[0];
                /*
                 * check version field to make sure that cifs.upcall is
                 * sending us a response in an expected form
index 5ba029e627cc22db0648317a619685e545977316..7b39260c7bbaa18fda583426a101a95124639dc5 100644 (file)
@@ -86,7 +86,7 @@ ecryptfs_get_encrypted_key_payload_data(struct key *key)
 {
        if (key->type == &key_type_encrypted)
                return (struct ecryptfs_auth_tok *)
-                       (&((struct encrypted_key_payload *)key->payload.data)->payload_data);
+                       (&((struct encrypted_key_payload *)key->payload.data[0])->payload_data);
        else
                return NULL;
 }
@@ -117,8 +117,7 @@ ecryptfs_get_key_payload_data(struct key *key)
 
        auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
        if (!auth_tok)
-               return (struct ecryptfs_auth_tok *)
-                       (((struct user_key_payload *)key->payload.data)->data);
+               return (struct ecryptfs_auth_tok *)user_key_payload(key)->data;
        else
                return auth_tok;
 }
index 1d510c11b100cf3eb8a1cdcafa9131a94e3841bb..5c52c79dea4625c4a73d7d6195da9c1e39d6f02b 100644 (file)
@@ -121,7 +121,7 @@ int _ext4_get_encryption_info(struct inode *inode)
        struct key *keyring_key = NULL;
        struct ext4_encryption_key *master_key;
        struct ext4_encryption_context ctx;
-       struct user_key_payload *ukp;
+       const struct user_key_payload *ukp;
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        struct crypto_ablkcipher *ctfm;
        const char *cipher_str;
@@ -209,7 +209,7 @@ retry:
        }
        crypt_info->ci_keyring_key = keyring_key;
        BUG_ON(keyring_key->type != &key_type_logon);
-       ukp = ((struct user_key_payload *)keyring_key->payload.data);
+       ukp = user_key_payload(keyring_key);
        if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
                res = -EINVAL;
                goto out;
index 9f77de2ef317e538ced76d5472c62df4de29fcaf..5de2d866a25c282fecb2bdf4592bc53fafa0ca85 100644 (file)
@@ -122,7 +122,7 @@ int _f2fs_get_encryption_info(struct inode *inode)
        struct key *keyring_key = NULL;
        struct f2fs_encryption_key *master_key;
        struct f2fs_encryption_context ctx;
-       struct user_key_payload *ukp;
+       const struct user_key_payload *ukp;
        struct crypto_ablkcipher *ctfm;
        const char *cipher_str;
        char raw_key[F2FS_MAX_KEY_SIZE];
@@ -199,7 +199,7 @@ retry:
        }
        crypt_info->ci_keyring_key = keyring_key;
        BUG_ON(keyring_key->type != &key_type_logon);
-       ukp = ((struct user_key_payload *)keyring_key->payload.data);
+       ukp = user_key_payload(keyring_key);
        if (ukp->datalen != sizeof(struct f2fs_encryption_key)) {
                res = -EINVAL;
                goto out;
index 51dde817e1f24aadc445d17ef19f8256879cf0cf..6b028b7c42509b6cdf319ea3513679c33cf57fc4 100644 (file)
@@ -316,7 +316,7 @@ static const struct seq_operations fscache_objlist_ops = {
 static void fscache_objlist_config(struct fscache_objlist_data *data)
 {
 #ifdef CONFIG_KEYS
-       struct user_key_payload *confkey;
+       const struct user_key_payload *confkey;
        unsigned long config;
        struct key *key;
        const char *buf;
@@ -329,7 +329,7 @@ static void fscache_objlist_config(struct fscache_objlist_data *data)
        config = 0;
        rcu_read_lock();
 
-       confkey = key->payload.data;
+       confkey = user_key_payload(key);
        buf = confkey->data;
 
        for (len = confkey->datalen - 1; len >= 0; len--) {
index 2e4902203c358c46344338ee2efcfb7db7aba7f7..5ba22c6b0ffa6d8bafb302c2660b56f1992fd792 100644 (file)
@@ -297,7 +297,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
 {
        const struct cred *saved_cred;
        struct key *rkey;
-       struct user_key_payload *payload;
+       const struct user_key_payload *payload;
        ssize_t ret;
 
        saved_cred = override_creds(id_resolver_cache);
@@ -316,7 +316,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
        if (ret < 0)
                goto out_up;
 
-       payload = rcu_dereference(rkey->payload.rcudata);
+       payload = user_key_payload(rkey);
        if (IS_ERR_OR_NULL(payload)) {
                ret = PTR_ERR(payload);
                goto out_up;
index 39a01993676864e56b55f8125155646f808f4f40..e1236594fffec8d50b79eada956fdaadba663aff 100644 (file)
@@ -352,3 +352,47 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
        }
 }
 EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group);
+
+/**
+ * __compat_only_sysfs_link_entry_to_kobj - add a symlink to a kobject pointing
+ * to a group or an attribute
+ * @kobj:              The kobject containing the group.
+ * @target_kobj:       The target kobject.
+ * @target_name:       The name of the target group or attribute.
+ */
+int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
+                                     struct kobject *target_kobj,
+                                     const char *target_name)
+{
+       struct kernfs_node *target;
+       struct kernfs_node *entry;
+       struct kernfs_node *link;
+
+       /*
+        * We don't own @target_kobj and it may be removed at any time.
+        * Synchronize using sysfs_symlink_target_lock. See sysfs_remove_dir()
+        * for details.
+        */
+       spin_lock(&sysfs_symlink_target_lock);
+       target = target_kobj->sd;
+       if (target)
+               kernfs_get(target);
+       spin_unlock(&sysfs_symlink_target_lock);
+       if (!target)
+               return -ENOENT;
+
+       entry = kernfs_find_and_get(target_kobj->sd, target_name);
+       if (!entry) {
+               kernfs_put(target);
+               return -ENOENT;
+       }
+
+       link = kernfs_create_link(kobj->sd, target_name, entry);
+       if (IS_ERR(link) && PTR_ERR(link) == -EEXIST)
+               sysfs_warn_dup(kobj->sd, target_name);
+
+       kernfs_put(entry);
+       kernfs_put(target);
+       return IS_ERR(link) ? PTR_ERR(link) : 0;
+}
+EXPORT_SYMBOL_GPL(__compat_only_sysfs_link_entry_to_kobj);
index 067c242b1e152d013f746424ceebd417112154a7..cc2516df0efac72d43ddde2a055fa88c38f2ece5 100644 (file)
@@ -15,7 +15,6 @@
 #define _LINUX_PUBLIC_KEY_H
 
 #include <linux/mpi.h>
-#include <keys/asymmetric-type.h>
 #include <crypto/hash_info.h>
 
 enum pkey_algo {
index 4b840e822209d7d6894f81476267655498d530f2..4915d40d3c3cf9d5c44a6c0663f277c01eaf8eaa 100644 (file)
@@ -49,7 +49,7 @@ struct asymmetric_key_subtype {
 static inline
 struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key)
 {
-       return key->type_data.p[0];
+       return key->payload.data[asym_subtype];
 }
 
 #endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */
index c0754abb2f5676b8d8df7c0df4d44efdc3767d48..59c1df9cf922dfd7f3da0ad251dea1a8c0494866 100644 (file)
 
 extern struct key_type key_type_asymmetric;
 
+/*
+ * The key payload is four words.  The asymmetric-type key uses them as
+ * follows:
+ */
+enum asymmetric_payload_bits {
+       asym_crypto,
+       asym_subtype,
+       asym_key_ids,
+};
+
 /*
  * Identifiers for an asymmetric key ID.  We have three ways of looking up a
  * key derived from an X.509 certificate:
@@ -58,6 +68,11 @@ 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);
+static inline
+const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
+{
+       return key->payload.data[asym_key_ids];
+}
 
 /*
  * The payload is at the discretion of the subtype.
index 56f82e5c99757f159ceb74203d88d723add1ff6d..f91ecd9d1bb19c2c241af39137521432492bff48 100644 (file)
 
 #include <linux/key.h>
 #include <linux/rcupdate.h>
+#include <linux/tpm.h>
 
 #define MIN_KEY_SIZE                   32
 #define MAX_KEY_SIZE                   128
-#define MAX_BLOB_SIZE                  320
+#define MAX_BLOB_SIZE                  512
+#define MAX_PCRINFO_SIZE               64
 
 struct trusted_key_payload {
        struct rcu_head rcu;
@@ -26,6 +28,16 @@ struct trusted_key_payload {
        unsigned char blob[MAX_BLOB_SIZE];
 };
 
+struct trusted_key_options {
+       uint16_t keytype;
+       uint32_t keyhandle;
+       unsigned char keyauth[TPM_DIGEST_SIZE];
+       unsigned char blobauth[TPM_DIGEST_SIZE];
+       uint32_t pcrinfo_len;
+       unsigned char pcrinfo[MAX_PCRINFO_SIZE];
+       int pcrlock;
+};
+
 extern struct key_type key_type_trusted;
 
 #endif /* _KEYS_TRUSTED_TYPE_H */
index cebefb069c44a51bed96e7fc671f0e839bf94d6a..c56fef40f53efa474a57303f46f773863e2fa4b9 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/key.h>
 #include <linux/rcupdate.h>
 
+#ifdef CONFIG_KEYS
+
 /*****************************************************************************/
 /*
  * the payload for a key of type "user" or "logon"
@@ -46,5 +48,11 @@ extern void user_describe(const struct key *user, struct seq_file *m);
 extern long user_read(const struct key *key,
                      char __user *buffer, size_t buflen);
 
+static inline const struct user_key_payload *user_key_payload(const struct key *key)
+{
+       return (struct user_key_payload *)rcu_dereference_key(key);
+}
+
+#endif /* CONFIG_KEYS */
 
 #endif /* _KEYS_USER_TYPE_H */
index ff9f1d3942356ffd1f16ab777cb8c7ed201b35e8..7463355a198b2326ce8c0b2aecd72baa8cd6f956 100644 (file)
@@ -40,8 +40,7 @@ struct key_construction {
  */
 struct key_preparsed_payload {
        char            *description;   /* Proposed key description (or NULL) */
-       void            *type_data[2];  /* Private key-type data */
-       void            *payload[2];    /* Proposed payload */
+       union key_payload payload;      /* Proposed payload */
        const void      *data;          /* Raw data */
        size_t          datalen;        /* Raw datalen */
        size_t          quotalen;       /* Quota length for proposed payload */
index e1d4715f322251591d7261a77e57f7e659c06881..66f70524398594598fb721cf284ebdf1403d8566 100644 (file)
@@ -89,6 +89,11 @@ struct keyring_index_key {
        size_t                  desc_len;
 };
 
+union key_payload {
+       void __rcu              *rcu_data0;
+       void                    *data[4];
+};
+
 /*****************************************************************************/
 /*
  * key reference with possession attribute handling
@@ -186,28 +191,18 @@ struct key {
                };
        };
 
-       /* type specific data
-        * - this is used by the keyring type to index the name
-        */
-       union {
-               struct list_head        link;
-               unsigned long           x[2];
-               void                    *p[2];
-               int                     reject_error;
-       } type_data;
-
        /* key data
         * - this is used to hold the data actually used in cryptography or
         *   whatever
         */
        union {
-               union {
-                       unsigned long           value;
-                       void __rcu              *rcudata;
-                       void                    *data;
-                       void                    *data2[2];
-               } payload;
-               struct assoc_array keys;
+               union key_payload payload;
+               struct {
+                       /* Keyring bits */
+                       struct list_head name_link;
+                       struct assoc_array keys;
+               };
+               int reject_error;
        };
 };
 
@@ -336,12 +331,12 @@ static inline bool key_is_instantiated(const struct key *key)
 }
 
 #define rcu_dereference_key(KEY)                                       \
-       (rcu_dereference_protected((KEY)->payload.rcudata,              \
+       (rcu_dereference_protected((KEY)->payload.rcu_data0,            \
                                   rwsem_is_locked(&((struct key *)(KEY))->sem)))
 
 #define rcu_assign_keypointer(KEY, PAYLOAD)                            \
 do {                                                                   \
-       rcu_assign_pointer((KEY)->payload.rcudata, (PAYLOAD));          \
+       rcu_assign_pointer((KEY)->payload.rcu_data0, (PAYLOAD));        \
 } while (0)
 
 #ifdef CONFIG_SYSCTL
index 9f65758311a4efff6a325f0baeb33f86ec68e06f..ea090eaf468c6337b5ad29685b0d4919e44d2fab 100644 (file)
@@ -268,6 +268,9 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
                            struct kobject *target, const char *link_name);
 void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
                                  const char *link_name);
+int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
+                                     struct kobject *target_kobj,
+                                     const char *target_name);
 
 void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
 
@@ -451,6 +454,14 @@ static inline void sysfs_remove_link_from_group(struct kobject *kobj,
 {
 }
 
+static inline int __compat_only_sysfs_link_entry_to_kobj(
+       struct kobject *kobj,
+       struct kobject *target_kobj,
+       const char *target_name)
+{
+       return 0;
+}
+
 static inline void sysfs_notify(struct kobject *kobj, const char *dir,
                                const char *attr)
 {
index 8350c538b486cd217da6a067f4d008cbd3cdd8f2..706e63eea0800123d50dae79cfae327f6dacaa51 100644 (file)
@@ -30,6 +30,8 @@
 #define        TPM_ANY_NUM 0xFFFF
 
 struct tpm_chip;
+struct trusted_key_payload;
+struct trusted_key_options;
 
 struct tpm_class_ops {
        const u8 req_complete_mask;
@@ -46,11 +48,22 @@ struct tpm_class_ops {
 
 #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
 
+extern int tpm_is_tpm2(u32 chip_num);
 extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
 extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
 extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
 extern int tpm_get_random(u32 chip_num, u8 *data, size_t max);
+extern int tpm_seal_trusted(u32 chip_num,
+                           struct trusted_key_payload *payload,
+                           struct trusted_key_options *options);
+extern int tpm_unseal_trusted(u32 chip_num,
+                             struct trusted_key_payload *payload,
+                             struct trusted_key_options *options);
 #else
+static inline int tpm_is_tpm2(u32 chip_num)
+{
+       return -ENODEV;
+}
 static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
        return -ENODEV;
 }
@@ -63,5 +76,18 @@ static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
 static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) {
        return -ENODEV;
 }
+
+static inline int tpm_seal_trusted(u32 chip_num,
+                                  struct trusted_key_payload *payload,
+                                  struct trusted_key_options *options)
+{
+       return -ENODEV;
+}
+static inline int tpm_unseal_trusted(u32 chip_num,
+                                    struct trusted_key_payload *payload,
+                                    struct trusted_key_options *options)
+{
+       return -ENODEV;
+}
 #endif
 #endif
index 790d83c7d16071ffb96827fc4a372fd9b8eb4c5f..b3097bde4e9cbc999e5d09205db8014e0da27632 100644 (file)
@@ -5,4 +5,3 @@ config_data.h
 config_data.gz
 timeconst.h
 hz.bc
-x509_certificate_list
index bd62f5cda74673377ef080c718163917387ddde0..6528a79d998d08120e9e80524164e5c759d911f3 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/errno.h>
 #include <keys/system_keyring.h>
 #include <crypto/public_key.h>
 #include "module-internal.h"
index ae05ea393fc8c10f5cd25f88a9c39e3d3f866680..07be6c1ef4e2564c321b7bda1669fc1e9d84f8cf 100644 (file)
@@ -79,12 +79,13 @@ static int digsig_verify_rsa(struct key *key,
        unsigned char *out1 = NULL;
        const char *m;
        MPI in = NULL, res = NULL, pkey[2];
-       uint8_t *p, *datap, *endp;
-       struct user_key_payload *ukp;
+       uint8_t *p, *datap;
+       const uint8_t *endp;
+       const struct user_key_payload *ukp;
        struct pubkey_hdr *pkh;
 
        down_read(&key->sem);
-       ukp = key->payload.data;
+       ukp = user_key_payload(key);
 
        if (ukp->datalen < sizeof(*pkh))
                goto err1;
index 54a00d66509e748d47068a664bc14585166cbd97..78f098a20796d7dd0d71b364c5de3d99239dc4ac 100644 (file)
@@ -318,7 +318,7 @@ static int get_secret(struct ceph_crypto_key *dst, const char *name) {
                goto out;
        }
 
-       ckey = ukey->payload.data;
+       ckey = ukey->payload.data[0];
        err = ceph_crypto_key_clone(dst, ckey);
        if (err)
                goto out_key;
index 4440edcce0d6c0fd427fe5e5b456dd67de7e8e52..42e8649c6e79b4950531f0027f2e67820377c066 100644 (file)
@@ -537,7 +537,7 @@ static int ceph_key_preparse(struct key_preparsed_payload *prep)
        if (ret < 0)
                goto err_ckey;
 
-       prep->payload[0] = ckey;
+       prep->payload.data[0] = ckey;
        prep->quotalen = datalen;
        return 0;
 
@@ -549,14 +549,14 @@ err:
 
 static void ceph_key_free_preparse(struct key_preparsed_payload *prep)
 {
-       struct ceph_crypto_key *ckey = prep->payload[0];
+       struct ceph_crypto_key *ckey = prep->payload.data[0];
        ceph_crypto_key_destroy(ckey);
        kfree(ckey);
 }
 
 static void ceph_key_destroy(struct key *key)
 {
-       struct ceph_crypto_key *ckey = key->payload.data;
+       struct ceph_crypto_key *ckey = key->payload.data[0];
 
        ceph_crypto_key_destroy(ckey);
        kfree(ckey);
index 31cd4fd754869b8e621f0c5ecbfa5bca855684a7..c79b85eb4d4ca4712465b6bbeda7ed74d2624344 100644 (file)
@@ -122,7 +122,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
                                        goto bad_option_value;
 
                                kdebug("dns error no. = %lu", derrno);
-                               prep->type_data[0] = ERR_PTR(-derrno);
+                               prep->payload.data[dns_key_error] = ERR_PTR(-derrno);
                                continue;
                        }
 
@@ -137,8 +137,8 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
 
        /* don't cache the result if we're caching an error saying there's no
         * result */
-       if (prep->type_data[0]) {
-               kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0]));
+       if (prep->payload.data[dns_key_error]) {
+               kleave(" = 0 [h_error %ld]", PTR_ERR(prep->payload.data[dns_key_error]));
                return 0;
        }
 
@@ -155,7 +155,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
        memcpy(upayload->data, data, result_len);
        upayload->data[result_len] = '\0';
 
-       prep->payload[0] = upayload;
+       prep->payload.data[dns_key_data] = upayload;
        kleave(" = 0");
        return 0;
 }
@@ -167,7 +167,7 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
 {
        pr_devel("==>%s()\n", __func__);
 
-       kfree(prep->payload[0]);
+       kfree(prep->payload.data[dns_key_data]);
 }
 
 /*
@@ -223,10 +223,10 @@ static int dns_resolver_match_preparse(struct key_match_data *match_data)
  */
 static void dns_resolver_describe(const struct key *key, struct seq_file *m)
 {
-       int err = key->type_data.x[0];
-
        seq_puts(m, key->description);
        if (key_is_instantiated(key)) {
+               int err = PTR_ERR(key->payload.data[dns_key_error]);
+
                if (err)
                        seq_printf(m, ": %d", err);
                else
@@ -241,8 +241,10 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
 static long dns_resolver_read(const struct key *key,
                              char __user *buffer, size_t buflen)
 {
-       if (key->type_data.x[0])
-               return key->type_data.x[0];
+       int err = PTR_ERR(key->payload.data[dns_key_error]);
+
+       if (err)
+               return err;
 
        return user_read(key, buffer, buflen);
 }
index 39d2c39bdf872713e890792914597f29a4ef53ae..4677b6fa6dda2c71ace9d97536a450684d18d3ef 100644 (file)
@@ -70,7 +70,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
              const char *options, char **_result, time_t *_expiry)
 {
        struct key *rkey;
-       struct user_key_payload *upayload;
+       const struct user_key_payload *upayload;
        const struct cred *saved_cred;
        size_t typelen, desclen;
        char *desc, *cp;
@@ -137,12 +137,11 @@ int dns_query(const char *type, const char *name, size_t namelen,
                goto put;
 
        /* If the DNS server gave an error, return that to the caller */
-       ret = rkey->type_data.x[0];
+       ret = PTR_ERR(rkey->payload.data[dns_key_error]);
        if (ret)
                goto put;
 
-       upayload = rcu_dereference_protected(rkey->payload.data,
-                                            lockdep_is_held(&rkey->sem));
+       upayload = user_key_payload(rkey);
        len = upayload->datalen;
 
        ret = -ENOMEM;
index 7af1ed39c0091de232f5b487ac557ba76e3e9b59..0c570d40e4d63283c25b9fb5c51b8879765b4aae 100644 (file)
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
+/*
+ * Layout of key payload words.
+ */
+enum {
+       dns_key_data,
+       dns_key_error,
+};
+
 /*
  * dns_key.c
  */
index 25d60ed15284a56b1a2f6b9bc8c680f0c9f567c0..1f8a144a5dc2c7b15a2f7f9724758b38ab4146d9 100644 (file)
@@ -305,7 +305,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 
        if (!key)
                key = rx->key;
-       if (key && !key->payload.data)
+       if (key && !key->payload.data[0])
                key = NULL; /* a no-security key */
 
        bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
index db0f39f5ef96dcff51e10f09f6eebf4490be8d1e..da3cc09f683e982a43269d166acfad0e05575020 100644 (file)
@@ -148,10 +148,10 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
                       token->kad->ticket[6], token->kad->ticket[7]);
 
        /* count the number of tokens attached */
-       prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
+       prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
 
        /* attach the data */
-       for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
+       for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
             *pptoken;
             pptoken = &(*pptoken)->next)
                continue;
@@ -522,7 +522,7 @@ static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
                goto inval;
 
        /* attach the payload */
-       for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
+       for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
             *pptoken;
             pptoken = &(*pptoken)->next)
                continue;
@@ -764,10 +764,10 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)
        memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
 
        /* count the number of tokens attached */
-       prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
+       prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
 
        /* attach the data */
-       pp = (struct rxrpc_key_token **)&prep->payload[0];
+       pp = (struct rxrpc_key_token **)&prep->payload.data[0];
        while (*pp)
                pp = &(*pp)->next;
        *pp = token;
@@ -814,7 +814,7 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)
  */
 static void rxrpc_free_preparse(struct key_preparsed_payload *prep)
 {
-       rxrpc_free_token_list(prep->payload[0]);
+       rxrpc_free_token_list(prep->payload.data[0]);
 }
 
 /*
@@ -831,7 +831,7 @@ static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
        if (prep->datalen != 8)
                return -EINVAL;
 
-       memcpy(&prep->type_data, prep->data, 8);
+       memcpy(&prep->payload.data[2], prep->data, 8);
 
        ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
        if (IS_ERR(ci)) {
@@ -842,7 +842,7 @@ static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
        if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
                BUG();
 
-       prep->payload[0] = ci;
+       prep->payload.data[0] = ci;
        _leave(" = 0");
        return 0;
 }
@@ -852,8 +852,8 @@ static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
  */
 static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
 {
-       if (prep->payload[0])
-               crypto_free_blkcipher(prep->payload[0]);
+       if (prep->payload.data[0])
+               crypto_free_blkcipher(prep->payload.data[0]);
 }
 
 /*
@@ -861,7 +861,7 @@ static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
  */
 static void rxrpc_destroy(struct key *key)
 {
-       rxrpc_free_token_list(key->payload.data);
+       rxrpc_free_token_list(key->payload.data[0]);
 }
 
 /*
@@ -869,9 +869,9 @@ static void rxrpc_destroy(struct key *key)
  */
 static void rxrpc_destroy_s(struct key *key)
 {
-       if (key->payload.data) {
-               crypto_free_blkcipher(key->payload.data);
-               key->payload.data = NULL;
+       if (key->payload.data[0]) {
+               crypto_free_blkcipher(key->payload.data[0]);
+               key->payload.data[0] = NULL;
        }
 }
 
@@ -1070,7 +1070,7 @@ static long rxrpc_read(const struct key *key,
        size += 1 * 4;  /* token count */
 
        ntoks = 0;
-       for (token = key->payload.data; token; token = token->next) {
+       for (token = key->payload.data[0]; token; token = token->next) {
                toksize = 4;    /* sec index */
 
                switch (token->security_index) {
@@ -1163,7 +1163,7 @@ static long rxrpc_read(const struct key *key,
        ENCODE(ntoks);
 
        tok = 0;
-       for (token = key->payload.data; token; token = token->next) {
+       for (token = key->payload.data[0]; token; token = token->next) {
                toksize = toksizes[tok++];
                ENCODE(toksize);
                oldxdr = xdr;
index c0042807bfc6a5e2b6e03d70fbcffe097be73326..a40d3afe93b7f3ee657985753c320210815f62a9 100644 (file)
@@ -158,7 +158,7 @@ int rxrpc_client_sendmsg(struct rxrpc_sock *rx, struct rxrpc_transport *trans,
                        service_id = htons(srx->srx_service);
                }
                key = rx->key;
-               if (key && !rx->key->payload.data)
+               if (key && !rx->key->payload.data[0])
                        key = NULL;
                bundle = rxrpc_get_bundle(rx, trans, key, service_id,
                                          GFP_KERNEL);
index 49b3cc31ee1f505b65bf21f6042e6727e2d2ed93..8334474eb26c773664ae56bc8c064e9aa9249b45 100644 (file)
@@ -137,9 +137,9 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
        if (ret < 0)
                return ret;
 
-       if (!key->payload.data)
+       token = key->payload.data[0];
+       if (!token)
                return -EKEYREJECTED;
-       token = key->payload.data;
 
        sec = rxrpc_security_lookup(token->security_index);
        if (!sec)
index f226709ebd8f159b4fef700307728accb4d2bf66..d7a9ab5a9d9ce8c95d60b5230c476e41740db607 100644 (file)
@@ -67,7 +67,7 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn)
 
        _enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
 
-       token = conn->key->payload.data;
+       token = conn->key->payload.data[0];
        conn->security_ix = token->security_index;
 
        ci = crypto_alloc_blkcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
@@ -125,7 +125,7 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
        if (!conn->key)
                return;
 
-       token = conn->key->payload.data;
+       token = conn->key->payload.data[0];
        memcpy(&iv, token->kad->session_key, sizeof(iv));
 
        desc.tfm = conn->cipher;
@@ -221,7 +221,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
        rxkhdr.checksum = 0;
 
        /* encrypt from the session key */
-       token = call->conn->key->payload.data;
+       token = call->conn->key->payload.data[0];
        memcpy(&iv, token->kad->session_key, sizeof(iv));
        desc.tfm = call->conn->cipher;
        desc.info = iv.x;
@@ -433,7 +433,7 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
        skb_to_sgvec(skb, sg, 0, skb->len);
 
        /* decrypt from the session key */
-       token = call->conn->key->payload.data;
+       token = call->conn->key->payload.data[0];
        memcpy(&iv, token->kad->session_key, sizeof(iv));
        desc.tfm = call->conn->cipher;
        desc.info = iv.x;
@@ -780,7 +780,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
        if (conn->security_level < min_level)
                goto protocol_error;
 
-       token = conn->key->payload.data;
+       token = conn->key->payload.data[0];
 
        /* build the response packet */
        memset(&resp, 0, sizeof(resp));
@@ -848,12 +848,12 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
                }
        }
 
-       ASSERT(conn->server_key->payload.data != NULL);
+       ASSERT(conn->server_key->payload.data[0] != NULL);
        ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
 
-       memcpy(&iv, &conn->server_key->type_data, sizeof(iv));
+       memcpy(&iv, &conn->server_key->payload.data[2], sizeof(iv));
 
-       desc.tfm = conn->server_key->payload.data;
+       desc.tfm = conn->server_key->payload.data[0];
        desc.info = iv.x;
        desc.flags = 0;
 
diff --git a/scripts/extract-module-sig.pl b/scripts/extract-module-sig.pl
new file mode 100755 (executable)
index 0000000..faac6f2
--- /dev/null
@@ -0,0 +1,136 @@
+#!/usr/bin/perl -w
+#
+# extract-mod-sig <part> <module-file>
+#
+# Reads the module file and writes out some or all of the signature
+# section to stdout.  Part is the bit to be written and is one of:
+#
+#  -0: The unsigned module, no signature data at all
+#  -a: All of the signature data, including magic number
+#  -d: Just the descriptor values as a sequence of numbers
+#  -n: Just the signer's name
+#  -k: Just the key ID
+#  -s: Just the crypto signature or PKCS#7 message
+#
+use strict;
+
+die "Format: $0 -[0adnks] module-file >out\n"
+    if ($#ARGV != 1);
+
+my $part = $ARGV[0];
+my $modfile = $ARGV[1];
+
+my $magic_number = "~Module signature appended~\n";
+
+#
+# Read the module contents
+#
+open FD, "<$modfile" || die $modfile;
+binmode(FD);
+my @st = stat(FD);
+die "$modfile" unless (@st);
+my $buf = "";
+my $len = sysread(FD, $buf, $st[7]);
+die "$modfile" unless (defined($len));
+die "Short read on $modfile\n" unless ($len == $st[7]);
+close(FD) || die $modfile;
+
+print STDERR "Read ", $len, " bytes from module file\n";
+
+die "The file is too short to have a sig magic number and descriptor\n"
+    if ($len < 12 + length($magic_number));
+
+#
+# Check for the magic number and extract the information block
+#
+my $p = $len - length($magic_number);
+my $raw_magic = substr($buf, $p);
+
+die "Magic number not found at $len\n"
+    if ($raw_magic ne $magic_number);
+print STDERR "Found magic number at $len\n";
+
+$p -= 12;
+my $raw_info = substr($buf, $p, 12);
+
+my @info = unpack("CCCCCxxxN", $raw_info);
+my ($algo, $hash, $id_type, $name_len, $kid_len, $sig_len) = @info;
+
+if ($id_type == 0) {
+    print STDERR "Found PGP key identifier\n";
+} elsif ($id_type == 1) {
+    print STDERR "Found X.509 cert identifier\n";
+} elsif ($id_type == 2) {
+    print STDERR "Found PKCS#7/CMS encapsulation\n";
+} else {
+    print STDERR "Found unsupported identifier type $id_type\n";
+}
+
+#
+# Extract the three pieces of info data
+#
+die "Insufficient name+kid+sig data in file\n"
+    unless ($p >= $name_len + $kid_len + $sig_len);
+
+$p -= $sig_len;
+my $raw_sig = substr($buf, $p, $sig_len);
+$p -= $kid_len;
+my $raw_kid = substr($buf, $p, $kid_len);
+$p -= $name_len;
+my $raw_name = substr($buf, $p, $name_len);
+
+my $module_len = $p;
+
+if ($sig_len > 0) {
+    print STDERR "Found $sig_len bytes of signature [";
+    my $n = $sig_len > 16 ? 16 : $sig_len;
+    foreach my $i (unpack("C" x $n, substr($raw_sig, 0, $n))) {
+       printf STDERR "%02x", $i;
+    }
+    print STDERR "]\n";
+}
+
+if ($kid_len > 0) {
+    print STDERR "Found $kid_len bytes of key identifier [";
+    my $n = $kid_len > 16 ? 16 : $kid_len;
+    foreach my $i (unpack("C" x $n, substr($raw_kid, 0, $n))) {
+       printf STDERR "%02x", $i;
+    }
+    print STDERR "]\n";
+}
+
+if ($name_len > 0) {
+    print STDERR "Found $name_len bytes of signer's name [$raw_name]\n";
+}
+
+#
+# Produce the requested output
+#
+if ($part eq "-0") {
+    # The unsigned module, no signature data at all
+    binmode(STDOUT);
+    print substr($buf, 0, $module_len);
+} elsif ($part eq "-a") {
+    # All of the signature data, including magic number
+    binmode(STDOUT);
+    print substr($buf, $module_len);
+} elsif ($part eq "-d") {
+    # Just the descriptor values as a sequence of numbers
+    print join(" ", @info), "\n";
+} elsif ($part eq "-n") {
+    # Just the signer's name
+    print STDERR "No signer's name for PKCS#7 message type sig\n"
+       if ($id_type == 2);
+    binmode(STDOUT);
+    print $raw_name;
+} elsif ($part eq "-k") {
+    # Just the key identifier
+    print STDERR "No key ID for PKCS#7 message type sig\n"
+       if ($id_type == 2);
+    binmode(STDOUT);
+    print $raw_kid;
+} elsif ($part eq "-s") {
+    # Just the crypto signature or PKCS#7 message
+    binmode(STDOUT);
+    print $raw_sig;
+}
diff --git a/scripts/extract-sys-certs.pl b/scripts/extract-sys-certs.pl
new file mode 100755 (executable)
index 0000000..d476e7d
--- /dev/null
@@ -0,0 +1,144 @@
+#!/usr/bin/perl -w
+#
+use strict;
+use Math::BigInt;
+use Fcntl "SEEK_SET";
+
+die "Format: $0 [-s <systemmap-file>] <vmlinux-file> <keyring-file>\n"
+    if ($#ARGV != 1 && $#ARGV != 3 ||
+       $#ARGV == 3 && $ARGV[0] ne "-s");
+
+my $sysmap = "";
+if ($#ARGV == 3) {
+    shift;
+    $sysmap = $ARGV[0];
+    shift;
+}
+
+my $vmlinux = $ARGV[0];
+my $keyring = $ARGV[1];
+
+#
+# Parse the vmlinux section table
+#
+open FD, "objdump -h $vmlinux |" || die $vmlinux;
+my @lines = <FD>;
+close(FD) || die $vmlinux;
+
+my @sections = ();
+
+foreach my $line (@lines) {
+    chomp($line);
+    if ($line =~ /\s*([0-9]+)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+2[*][*]([0-9]+)/
+       ) {
+       my $seg  = $1;
+       my $name = $2;
+       my $len  = Math::BigInt->new("0x" . $3);
+       my $vma  = Math::BigInt->new("0x" . $4);
+       my $lma  = Math::BigInt->new("0x" . $5);
+       my $foff = Math::BigInt->new("0x" . $6);
+       my $align = 2 ** $7;
+
+       push @sections, { name => $name,
+                         vma => $vma,
+                         len => $len,
+                         foff => $foff };
+    }
+}
+
+print "Have $#sections sections\n";
+
+#
+# Try and parse the vmlinux symbol table.  If the vmlinux file has been created
+# from a vmlinuz file with extract-vmlinux then the symbol table will be empty.
+#
+open FD, "nm $vmlinux 2>/dev/null |" || die $vmlinux;
+@lines = <FD>;
+close(FD) || die $vmlinux;
+
+my %symbols = ();
+my $nr_symbols = 0;
+
+sub parse_symbols(@) {
+    foreach my $line (@_) {
+       chomp($line);
+       if ($line =~ /([0-9a-f]+)\s([a-zA-Z])\s(\S+)/
+           ) {
+           my $addr = "0x" . $1;
+           my $type = $2;
+           my $name = $3;
+
+           $symbols{$name} = $addr;
+           $nr_symbols++;
+       }
+    }
+}
+parse_symbols(@lines);
+
+if ($nr_symbols == 0 && $sysmap ne "") {
+    print "No symbols in vmlinux, trying $sysmap\n";
+
+    open FD, "<$sysmap" || die $sysmap;
+    @lines = <FD>;
+    close(FD) || die $sysmap;
+    parse_symbols(@lines);
+}
+
+die "No symbols available\n"
+    if ($nr_symbols == 0);
+
+print "Have $nr_symbols symbols\n";
+
+die "Can't find system certificate list"
+    unless (exists($symbols{"__cert_list_start"}) &&
+           exists($symbols{"__cert_list_end"}));
+
+my $start = Math::BigInt->new($symbols{"__cert_list_start"});
+my $end = Math::BigInt->new($symbols{"__cert_list_end"});
+my $size = $end - $start;
+
+printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start;
+
+my $s = undef;
+foreach my $sec (@sections) {
+    my $s_name = $sec->{name};
+    my $s_vma = $sec->{vma};
+    my $s_len = $sec->{len};
+    my $s_foff = $sec->{foff};
+    my $s_vend = $s_vma + $s_len;
+
+    next unless ($start >= $s_vma);
+    next if ($start >= $s_vend);
+
+    die "Cert object partially overflows section $s_name\n"
+       if ($end > $s_vend);
+
+    die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n"
+       if ($s);
+    $s = $sec;
+}
+
+die "Cert object not inside a section\n"
+    unless ($s);
+
+print "Certificate list in section ", $s->{name}, "\n";
+
+my $foff = $start - $s->{vma} + $s->{foff};
+
+printf "Certificate list at file offset 0x%x\n", $foff;
+
+open FD, "<$vmlinux" || die $vmlinux;
+binmode(FD);
+die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET)));
+my $buf = "";
+my $len = sysread(FD, $buf, $size);
+die "$vmlinux" if (!defined($len));
+die "Short read on $vmlinux\n" if ($len != $size);
+close(FD) || die $vmlinux;
+
+open FD, ">$keyring" || die $keyring;
+binmode(FD);
+$len = syswrite(FD, $buf, $size);
+die "$keyring" if (!defined($len));
+die "Short write on $keyring\n" if ($len != $size);
+close(FD) || die $keyring;
index d49c53960b60c5010d314022d3e58d255ffac204..232469baa94f2f17e686f2cf702a56424eda8176 100644 (file)
@@ -33,7 +33,7 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
 config SECURITY_APPARMOR_HASH
        bool "SHA1 hash of loaded profiles"
        depends on SECURITY_APPARMOR
-       depends on CRYPTO
+       select CRYPTO
        select CRYPTO_SHA1
        default y
 
index 36fb6b527829cead887c28828f9d3c83115568a7..5be9ffbe90bad1511d12b65345064dec22bac00a 100644 (file)
@@ -105,7 +105,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
                                   rc,
                                   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
                                    KEY_USR_VIEW | KEY_USR_READ),
-                                  KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED);
+                                  KEY_ALLOC_NOT_IN_QUOTA);
        if (IS_ERR(key)) {
                rc = PTR_ERR(key);
                pr_err("Problem loading X.509 certificate (%d): %s\n",
index 159ef3ea41308dbb2ef44e2c491d44083c27d72f..461f8d89157948510fda91e3286eab12d2e456ab 100644 (file)
@@ -247,7 +247,7 @@ int evm_init_key(void)
                return -ENOENT;
 
        down_read(&evm_key->sem);
-       ekp = evm_key->payload.data;
+       ekp = evm_key->payload.data[0];
        if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
                rc = -EINVAL;
                goto out;
index b6adb94f6d52573aecf2e38a16724e06895dded6..907c1522ee469b05d42bcf9a839c0a80bf7eff6c 100644 (file)
 
 MODULE_LICENSE("GPL");
 
+/*
+ * Layout of key payload words.
+ */
+enum {
+       big_key_data,
+       big_key_path,
+       big_key_path_2nd_part,
+       big_key_len,
+};
+
 /*
  * If the data is under this limit, there's no point creating a shm file to
  * hold it as the permanently resident metadata for the shmem fs will be at
@@ -47,7 +57,7 @@ struct key_type key_type_big_key = {
  */
 int big_key_preparse(struct key_preparsed_payload *prep)
 {
-       struct path *path = (struct path *)&prep->payload;
+       struct path *path = (struct path *)&prep->payload.data[big_key_path];
        struct file *file;
        ssize_t written;
        size_t datalen = prep->datalen;
@@ -60,7 +70,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
        /* Set an arbitrary quota */
        prep->quotalen = 16;
 
-       prep->type_data[1] = (void *)(unsigned long)datalen;
+       prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
 
        if (datalen > BIG_KEY_FILE_THRESHOLD) {
                /* Create a shmem file to store the data in.  This will permit the data
@@ -94,7 +104,8 @@ int big_key_preparse(struct key_preparsed_payload *prep)
                if (!data)
                        return -ENOMEM;
 
-               prep->payload[0] = memcpy(data, prep->data, prep->datalen);
+               prep->payload.data[big_key_data] = data;
+               memcpy(data, prep->data, prep->datalen);
        }
        return 0;
 
@@ -110,10 +121,10 @@ error:
 void big_key_free_preparse(struct key_preparsed_payload *prep)
 {
        if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
-               struct path *path = (struct path *)&prep->payload;
+               struct path *path = (struct path *)&prep->payload.data[big_key_path];
                path_put(path);
        } else {
-               kfree(prep->payload[0]);
+               kfree(prep->payload.data[big_key_data]);
        }
 }
 
@@ -123,11 +134,12 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
  */
 void big_key_revoke(struct key *key)
 {
-       struct path *path = (struct path *)&key->payload.data2;
+       struct path *path = (struct path *)&key->payload.data[big_key_path];
 
        /* clear the quota */
        key_payload_reserve(key, 0);
-       if (key_is_instantiated(key) && key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD)
+       if (key_is_instantiated(key) &&
+           (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
                vfs_truncate(path, 0);
 }
 
@@ -136,14 +148,16 @@ void big_key_revoke(struct key *key)
  */
 void big_key_destroy(struct key *key)
 {
-       if (key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD) {
-               struct path *path = (struct path *)&key->payload.data2;
+       size_t datalen = (size_t)key->payload.data[big_key_len];
+
+       if (datalen) {
+               struct path *path = (struct path *)&key->payload.data[big_key_path];
                path_put(path);
                path->mnt = NULL;
                path->dentry = NULL;
        } else {
-               kfree(key->payload.data);
-               key->payload.data = NULL;
+               kfree(key->payload.data[big_key_data]);
+               key->payload.data[big_key_data] = NULL;
        }
 }
 
@@ -152,12 +166,12 @@ void big_key_destroy(struct key *key)
  */
 void big_key_describe(const struct key *key, struct seq_file *m)
 {
-       unsigned long datalen = key->type_data.x[1];
+       size_t datalen = (size_t)key->payload.data[big_key_len];
 
        seq_puts(m, key->description);
 
        if (key_is_instantiated(key))
-               seq_printf(m, ": %lu [%s]",
+               seq_printf(m, ": %zu [%s]",
                           datalen,
                           datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
 }
@@ -168,14 +182,14 @@ void big_key_describe(const struct key *key, struct seq_file *m)
  */
 long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
 {
-       unsigned long datalen = key->type_data.x[1];
+       size_t datalen = (size_t)key->payload.data[big_key_len];
        long ret;
 
        if (!buffer || buflen < datalen)
                return datalen;
 
        if (datalen > BIG_KEY_FILE_THRESHOLD) {
-               struct path *path = (struct path *)&key->payload.data2;
+               struct path *path = (struct path *)&key->payload.data[big_key_path];
                struct file *file;
                loff_t pos;
 
@@ -190,7 +204,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
                        ret = -EIO;
        } else {
                ret = datalen;
-               if (copy_to_user(buffer, key->payload.data, datalen) != 0)
+               if (copy_to_user(buffer, key->payload.data[big_key_data],
+                                datalen) != 0)
                        ret = -EFAULT;
        }
 
index 7bed4ad7cd764a9fb9560282da63d93eeab6076b..927db9f35ad6f1bddeb51169e84c1bb526f85f21 100644 (file)
@@ -303,10 +303,10 @@ out:
  *
  * Use a user provided key to encrypt/decrypt an encrypted-key.
  */
-static struct key *request_user_key(const char *master_desc, u8 **master_key,
+static struct key *request_user_key(const char *master_desc, const u8 **master_key,
                                    size_t *master_keylen)
 {
-       struct user_key_payload *upayload;
+       const struct user_key_payload *upayload;
        struct key *ukey;
 
        ukey = request_key(&key_type_user, master_desc, NULL);
@@ -314,7 +314,7 @@ static struct key *request_user_key(const char *master_desc, u8 **master_key,
                goto error;
 
        down_read(&ukey->sem);
-       upayload = ukey->payload.data;
+       upayload = user_key_payload(ukey);
        *master_key = upayload->data;
        *master_keylen = upayload->datalen;
 error:
@@ -426,7 +426,7 @@ static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
 }
 
 static struct key *request_master_key(struct encrypted_key_payload *epayload,
-                                     u8 **master_key, size_t *master_keylen)
+                                     const u8 **master_key, size_t *master_keylen)
 {
        struct key *mkey = NULL;
 
@@ -653,7 +653,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
 {
        struct key *mkey;
        u8 derived_key[HASH_SIZE];
-       u8 *master_key;
+       const u8 *master_key;
        u8 *hmac;
        const char *hex_encoded_data;
        unsigned int encrypted_datalen;
@@ -837,7 +837,7 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
  */
 static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
 {
-       struct encrypted_key_payload *epayload = key->payload.data;
+       struct encrypted_key_payload *epayload = key->payload.data[0];
        struct encrypted_key_payload *new_epayload;
        char *buf;
        char *new_master_desc = NULL;
@@ -896,7 +896,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
 {
        struct encrypted_key_payload *epayload;
        struct key *mkey;
-       u8 *master_key;
+       const u8 *master_key;
        size_t master_keylen;
        char derived_key[HASH_SIZE];
        char *ascii_buf;
@@ -957,13 +957,13 @@ out:
  */
 static void encrypted_destroy(struct key *key)
 {
-       struct encrypted_key_payload *epayload = key->payload.data;
+       struct encrypted_key_payload *epayload = key->payload.data[0];
 
        if (!epayload)
                return;
 
        memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
-       kfree(key->payload.data);
+       kfree(key->payload.data[0]);
 }
 
 struct key_type key_type_encrypted = {
index 8136a2d44c63ddb3a76f30f35b6780ff19b74ae9..47802c0de73567015743e26bebc4af71b3638a02 100644 (file)
@@ -5,10 +5,10 @@
 #if defined(CONFIG_TRUSTED_KEYS) || \
   (defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
 extern struct key *request_trusted_key(const char *trusted_desc,
-                                      u8 **master_key, size_t *master_keylen);
+                                      const u8 **master_key, size_t *master_keylen);
 #else
 static inline struct key *request_trusted_key(const char *trusted_desc,
-                                             u8 **master_key,
+                                             const u8 **master_key,
                                              size_t *master_keylen)
 {
        return ERR_PTR(-EOPNOTSUPP);
index 013f7e5d3a2fce42d026fd87a4a0d6e94af1d53f..b5b4812dbc87bbaba9f2c00812ca770d82a9bd29 100644 (file)
@@ -29,7 +29,7 @@
  * data, trusted key type data is not visible decrypted from userspace.
  */
 struct key *request_trusted_key(const char *trusted_desc,
-                               u8 **master_key, size_t *master_keylen)
+                               const u8 **master_key, size_t *master_keylen)
 {
        struct trusted_key_payload *tpayload;
        struct key *tkey;
@@ -39,7 +39,7 @@ struct key *request_trusted_key(const char *trusted_desc,
                goto error;
 
        down_read(&tkey->sem);
-       tpayload = tkey->payload.data;
+       tpayload = tkey->payload.data[0];
        *master_key = tpayload->key;
        *master_keylen = tpayload->key_len;
 error:
index aee2ec5a18fcafc02e5e9088b9b55b9276bbcdd9..ab7997ded7255258365169abaf820e811e0a7768 100644 (file)
@@ -278,7 +278,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 
        key->index_key.desc_len = desclen;
        key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
-       if (!key->description)
+       if (!key->index_key.description)
                goto no_memory_3;
 
        atomic_set(&key->usage, 1);
@@ -554,7 +554,7 @@ int key_reject_and_link(struct key *key,
        if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
                /* mark the key as being negatively instantiated */
                atomic_inc(&key->user->nikeys);
-               key->type_data.reject_error = -error;
+               key->reject_error = -error;
                smp_wmb();
                set_bit(KEY_FLAG_NEGATIVE, &key->flags);
                set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
@@ -1046,14 +1046,14 @@ int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 
        ret = key_payload_reserve(key, prep->quotalen);
        if (ret == 0) {
-               key->type_data.p[0] = prep->type_data[0];
-               key->type_data.p[1] = prep->type_data[1];
-               rcu_assign_keypointer(key, prep->payload[0]);
-               key->payload.data2[1] = prep->payload[1];
-               prep->type_data[0] = NULL;
-               prep->type_data[1] = NULL;
-               prep->payload[0] = NULL;
-               prep->payload[1] = NULL;
+               rcu_assign_keypointer(key, prep->payload.data[0]);
+               key->payload.data[1] = prep->payload.data[1];
+               key->payload.data[2] = prep->payload.data[2];
+               key->payload.data[3] = prep->payload.data[3];
+               prep->payload.data[0] = NULL;
+               prep->payload.data[1] = NULL;
+               prep->payload.data[2] = NULL;
+               prep->payload.data[3] = NULL;
        }
        pr_devel("<==%s() = %d\n", __func__, ret);
        return ret;
index 0b9ec78a7a7ad2b14af1ef0407e051e6dcef29ff..fb111eafcb893e4f5146c74a84f8499d4e1553c4 100644 (file)
@@ -67,7 +67,6 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
        char type[32], *description;
        void *payload;
        long ret;
-       bool vm;
 
        ret = -EINVAL;
        if (plen > 1024 * 1024 - 1)
@@ -98,14 +97,12 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
        /* pull the payload in if one was supplied */
        payload = NULL;
 
-       vm = false;
        if (_payload) {
                ret = -ENOMEM;
                payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
                if (!payload) {
                        if (plen <= PAGE_SIZE)
                                goto error2;
-                       vm = true;
                        payload = vmalloc(plen);
                        if (!payload)
                                goto error2;
@@ -138,10 +135,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
 
        key_ref_put(keyring_ref);
  error3:
-       if (!vm)
-               kfree(payload);
-       else
-               vfree(payload);
+       kvfree(payload);
  error2:
        kfree(description);
  error:
@@ -1033,7 +1027,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
        if (!instkey)
                goto error;
 
-       rka = instkey->payload.data;
+       rka = instkey->payload.data[0];
        if (rka->target_key->serial != id)
                goto error;
 
@@ -1200,7 +1194,7 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
        if (!instkey)
                goto error;
 
-       rka = instkey->payload.data;
+       rka = instkey->payload.data[0];
        if (rka->target_key->serial != id)
                goto error;
 
index d33437007ad229313a5ef483826e427a74350876..f931ccfeefb01b34b7067caa2fe58774d0274edc 100644 (file)
@@ -118,7 +118,7 @@ static void keyring_publish_name(struct key *keyring)
                if (!keyring_name_hash[bucket].next)
                        INIT_LIST_HEAD(&keyring_name_hash[bucket]);
 
-               list_add_tail(&keyring->type_data.link,
+               list_add_tail(&keyring->name_link,
                              &keyring_name_hash[bucket]);
 
                write_unlock(&keyring_name_lock);
@@ -387,9 +387,9 @@ static void keyring_destroy(struct key *keyring)
        if (keyring->description) {
                write_lock(&keyring_name_lock);
 
-               if (keyring->type_data.link.next != NULL &&
-                   !list_empty(&keyring->type_data.link))
-                       list_del(&keyring->type_data.link);
+               if (keyring->name_link.next != NULL &&
+                   !list_empty(&keyring->name_link))
+                       list_del(&keyring->name_link);
 
                write_unlock(&keyring_name_lock);
        }
@@ -572,7 +572,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
                /* we set a different error code if we pass a negative key */
                if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
                        smp_rmb();
-                       ctx->result = ERR_PTR(key->type_data.reject_error);
+                       ctx->result = ERR_PTR(key->reject_error);
                        kleave(" = %d [neg]", ctx->skipped_ret);
                        goto skipped;
                }
@@ -990,7 +990,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
                 * that's readable and that hasn't been revoked */
                list_for_each_entry(keyring,
                                    &keyring_name_hash[bucket],
-                                   type_data.link
+                                   name_link
                                    ) {
                        if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
                                continue;
index 43b4cddbf2b39ebd838e3849a1e59e9c7c22c945..a3f85d2a00bb469391fc9a9a504c949e653d4a16 100644 (file)
@@ -457,7 +457,7 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
                down_read(&cred->request_key_auth->sem);
 
                if (key_validate(ctx->cred->request_key_auth) == 0) {
-                       rka = ctx->cred->request_key_auth->payload.data;
+                       rka = ctx->cred->request_key_auth->payload.data[0];
 
                        ctx->cred = rka->cred;
                        key_ref = search_process_keyrings(ctx);
@@ -647,7 +647,7 @@ try_again:
                        key_ref = ERR_PTR(-EKEYREVOKED);
                        key = NULL;
                } else {
-                       rka = ctx.cred->request_key_auth->payload.data;
+                       rka = ctx.cred->request_key_auth->payload.data[0];
                        key = rka->dest_keyring;
                        __key_get(key);
                }
index 0d625312427831b63ed18784719cd0b424f03a41..c7a117c9a8f3030d66afc6cbf5767ce5069c813b 100644 (file)
@@ -271,7 +271,7 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
                        if (cred->request_key_auth) {
                                authkey = cred->request_key_auth;
                                down_read(&authkey->sem);
-                               rka = authkey->payload.data;
+                               rka = authkey->payload.data[0];
                                if (!test_bit(KEY_FLAG_REVOKED,
                                              &authkey->flags))
                                        dest_keyring =
@@ -596,7 +596,7 @@ int wait_for_key_construction(struct key *key, bool intr)
                return -ERESTARTSYS;
        if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
                smp_rmb();
-               return key->type_data.reject_error;
+               return key->reject_error;
        }
        return key_validate(key);
 }
index 5d672f7580dd5330516dd62f7d705cac46c319fb..4f0f112fe276fd7da1714e65113753394b5453e0 100644 (file)
@@ -59,7 +59,7 @@ static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
 static int request_key_auth_instantiate(struct key *key,
                                        struct key_preparsed_payload *prep)
 {
-       key->payload.data = (struct request_key_auth *)prep->data;
+       key->payload.data[0] = (struct request_key_auth *)prep->data;
        return 0;
 }
 
@@ -69,7 +69,7 @@ static int request_key_auth_instantiate(struct key *key,
 static void request_key_auth_describe(const struct key *key,
                                      struct seq_file *m)
 {
-       struct request_key_auth *rka = key->payload.data;
+       struct request_key_auth *rka = key->payload.data[0];
 
        seq_puts(m, "key:");
        seq_puts(m, key->description);
@@ -84,7 +84,7 @@ static void request_key_auth_describe(const struct key *key,
 static long request_key_auth_read(const struct key *key,
                                  char __user *buffer, size_t buflen)
 {
-       struct request_key_auth *rka = key->payload.data;
+       struct request_key_auth *rka = key->payload.data[0];
        size_t datalen;
        long ret;
 
@@ -110,7 +110,7 @@ static long request_key_auth_read(const struct key *key,
  */
 static void request_key_auth_revoke(struct key *key)
 {
-       struct request_key_auth *rka = key->payload.data;
+       struct request_key_auth *rka = key->payload.data[0];
 
        kenter("{%d}", key->serial);
 
@@ -125,7 +125,7 @@ static void request_key_auth_revoke(struct key *key)
  */
 static void request_key_auth_destroy(struct key *key)
 {
-       struct request_key_auth *rka = key->payload.data;
+       struct request_key_auth *rka = key->payload.data[0];
 
        kenter("{%d}", key->serial);
 
@@ -179,7 +179,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
                if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
                        goto auth_key_revoked;
 
-               irka = cred->request_key_auth->payload.data;
+               irka = cred->request_key_auth->payload.data[0];
                rka->cred = get_cred(irka->cred);
                rka->pid = irka->pid;
 
index c0594cb07adab14f1efeb970a8c0dd85d86a7931..903dace648a1731b2afbb2dc8b40b8169a05aba2 100644 (file)
@@ -862,12 +862,19 @@ static int datablob_parse(char *datablob, struct trusted_key_payload *p,
 static struct trusted_key_options *trusted_options_alloc(void)
 {
        struct trusted_key_options *options;
+       int tpm2;
+
+       tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+       if (tpm2 < 0)
+               return NULL;
 
        options = kzalloc(sizeof *options, GFP_KERNEL);
        if (options) {
                /* set any non-zero defaults */
                options->keytype = SRK_keytype;
-               options->keyhandle = SRKHANDLE;
+
+               if (!tpm2)
+                       options->keyhandle = SRKHANDLE;
        }
        return options;
 }
@@ -905,6 +912,11 @@ static int trusted_instantiate(struct key *key,
        int ret = 0;
        int key_cmd;
        size_t key_len;
+       int tpm2;
+
+       tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+       if (tpm2 < 0)
+               return tpm2;
 
        if (datalen <= 0 || datalen > 32767 || !prep->data)
                return -EINVAL;
@@ -932,12 +944,20 @@ static int trusted_instantiate(struct key *key,
                goto out;
        }
 
+       if (!options->keyhandle) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        dump_payload(payload);
        dump_options(options);
 
        switch (key_cmd) {
        case Opt_load:
-               ret = key_unseal(payload, options);
+               if (tpm2)
+                       ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options);
+               else
+                       ret = key_unseal(payload, options);
                dump_payload(payload);
                dump_options(options);
                if (ret < 0)
@@ -950,7 +970,10 @@ static int trusted_instantiate(struct key *key,
                        pr_info("trusted_key: key_create failed (%d)\n", ret);
                        goto out;
                }
-               ret = key_seal(payload, options);
+               if (tpm2)
+                       ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options);
+               else
+                       ret = key_seal(payload, options);
                if (ret < 0)
                        pr_info("trusted_key: key_seal failed (%d)\n", ret);
                break;
@@ -984,7 +1007,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
  */
 static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
 {
-       struct trusted_key_payload *p = key->payload.data;
+       struct trusted_key_payload *p = key->payload.data[0];
        struct trusted_key_payload *new_p;
        struct trusted_key_options *new_o;
        size_t datalen = prep->datalen;
@@ -1018,6 +1041,13 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
                kfree(new_p);
                goto out;
        }
+
+       if (!new_o->keyhandle) {
+               ret = -EINVAL;
+               kfree(new_p);
+               goto out;
+       }
+
        /* copy old key values, and reseal with new pcrs */
        new_p->migratable = p->migratable;
        new_p->key_len = p->key_len;
@@ -1084,12 +1114,12 @@ static long trusted_read(const struct key *key, char __user *buffer,
  */
 static void trusted_destroy(struct key *key)
 {
-       struct trusted_key_payload *p = key->payload.data;
+       struct trusted_key_payload *p = key->payload.data[0];
 
        if (!p)
                return;
        memset(p->key, 0, p->key_len);
-       kfree(key->payload.data);
+       kfree(key->payload.data[0]);
 }
 
 struct key_type key_type_trusted = {
index 3249fbd2b6531f9fb661c1f62849f4f4e322c183..ff001a5dcb2479af78108a0e2451b6ff965cda90 100644 (file)
@@ -2,7 +2,6 @@
 #define __TRUSTED_KEY_H
 
 /* implementation specific TPM constants */
-#define MAX_PCRINFO_SIZE               64
 #define MAX_BUF_SIZE                   512
 #define TPM_GETRANDOM_SIZE             14
 #define TPM_OSAP_SIZE                  36
@@ -36,16 +35,6 @@ enum {
        SRK_keytype = 4
 };
 
-struct trusted_key_options {
-       uint16_t keytype;
-       uint32_t keyhandle;
-       unsigned char keyauth[SHA1_DIGEST_SIZE];
-       unsigned char blobauth[SHA1_DIGEST_SIZE];
-       uint32_t pcrinfo_len;
-       unsigned char pcrinfo[MAX_PCRINFO_SIZE];
-       int pcrlock;
-};
-
 #define TPM_DEBUG 0
 
 #if TPM_DEBUG
index 36b47bbd3d8cc277de55e0c0cdd722618ca13231..28cb30f80256911cf9ee41631659b9e8f5a6b5dd 100644 (file)
@@ -74,7 +74,7 @@ int user_preparse(struct key_preparsed_payload *prep)
 
        /* attach the data */
        prep->quotalen = datalen;
-       prep->payload[0] = upayload;
+       prep->payload.data[0] = upayload;
        upayload->datalen = datalen;
        memcpy(upayload->data, prep->data, datalen);
        return 0;
@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(user_preparse);
  */
 void user_free_preparse(struct key_preparsed_payload *prep)
 {
-       kfree(prep->payload[0]);
+       kfree(prep->payload.data[0]);
 }
 EXPORT_SYMBOL_GPL(user_free_preparse);
 
@@ -120,7 +120,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
 
        if (ret == 0) {
                /* attach the new data, displacing the old */
-               zap = key->payload.data;
+               zap = key->payload.data[0];
                rcu_assign_keypointer(key, upayload);
                key->expiry = 0;
        }
@@ -140,7 +140,7 @@ EXPORT_SYMBOL_GPL(user_update);
  */
 void user_revoke(struct key *key)
 {
-       struct user_key_payload *upayload = key->payload.data;
+       struct user_key_payload *upayload = key->payload.data[0];
 
        /* clear the quota */
        key_payload_reserve(key, 0);
@@ -158,7 +158,7 @@ EXPORT_SYMBOL(user_revoke);
  */
 void user_destroy(struct key *key)
 {
-       struct user_key_payload *upayload = key->payload.data;
+       struct user_key_payload *upayload = key->payload.data[0];
 
        kfree(upayload);
 }
@@ -183,10 +183,10 @@ EXPORT_SYMBOL_GPL(user_describe);
  */
 long user_read(const struct key *key, char __user *buffer, size_t buflen)
 {
-       struct user_key_payload *upayload;
+       const struct user_key_payload *upayload;
        long ret;
 
-       upayload = rcu_dereference_key(key);
+       upayload = user_key_payload(key);
        ret = upayload->datalen;
 
        /* we can return the data as is */
index bca1b74a4a2f254df4dca4d4aea52c364ee53818..8691e92f27e584dcf26f35628c61e408c08a77cb 100644 (file)
@@ -78,7 +78,7 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
        int "NSA SELinux checkreqprot default value"
        depends on SECURITY_SELINUX
        range 0 1
-       default 1
+       default 0
        help
          This option sets the default value for the 'checkreqprot' flag
          that determines whether SELinux checks the protection requested
@@ -92,7 +92,7 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
          'checkreqprot=' boot parameter.  It may also be changed at runtime
          via /selinux/checkreqprot if authorized by policy.
 
-         If you are unsure how to answer this question, answer 1.
+         If you are unsure how to answer this question, answer 0.
 
 config SECURITY_SELINUX_POLICYDB_VERSION_MAX
        bool "NSA SELinux maximum supported policy format version"
index 26f4039d54b8f6bd8dd0aba99837835ba13c871b..9e591e5989bef8db6369d2afb4354b0a1e96efa4 100644 (file)
@@ -126,6 +126,7 @@ int selinux_enabled = 1;
 #endif
 
 static struct kmem_cache *sel_inode_cache;
+static struct kmem_cache *file_security_cache;
 
 /**
  * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
@@ -287,7 +288,7 @@ static int file_alloc_security(struct file *file)
        struct file_security_struct *fsec;
        u32 sid = current_sid();
 
-       fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
+       fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
        if (!fsec)
                return -ENOMEM;
 
@@ -302,7 +303,7 @@ static void file_free_security(struct file *file)
 {
        struct file_security_struct *fsec = file->f_security;
        file->f_security = NULL;
-       kfree(fsec);
+       kmem_cache_free(file_security_cache, fsec);
 }
 
 static int superblock_alloc_security(struct super_block *sb)
@@ -674,10 +675,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 
                if (flags[i] == SBLABEL_MNT)
                        continue;
-               rc = security_context_to_sid(mount_options[i],
-                                            strlen(mount_options[i]), &sid, GFP_KERNEL);
+               rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
                if (rc) {
-                       printk(KERN_WARNING "SELinux: security_context_to_sid"
+                       printk(KERN_WARNING "SELinux: security_context_str_to_sid"
                               "(%s) failed for (dev %s, type %s) errno=%d\n",
                               mount_options[i], sb->s_id, name, rc);
                        goto out;
@@ -2617,15 +2617,12 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
 
        for (i = 0; i < opts.num_mnt_opts; i++) {
                u32 sid;
-               size_t len;
 
                if (flags[i] == SBLABEL_MNT)
                        continue;
-               len = strlen(mount_options[i]);
-               rc = security_context_to_sid(mount_options[i], len, &sid,
-                                            GFP_KERNEL);
+               rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
                if (rc) {
-                       printk(KERN_WARNING "SELinux: security_context_to_sid"
+                       printk(KERN_WARNING "SELinux: security_context_str_to_sid"
                               "(%s) failed for (dev %s, type %s) errno=%d\n",
                               mount_options[i], sb->s_id, sb->s_type->name, rc);
                        goto out_free_opts;
@@ -2946,7 +2943,8 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
                        ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
                return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-       if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE))
+       if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)
+                       && !(ia_valid & ATTR_FILE))
                av |= FILE__OPEN;
 
        return dentry_has_perm(cred, dentry, av);
@@ -3166,7 +3164,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
        if (!value || !size)
                return -EACCES;
 
-       rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
+       rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
        if (rc)
                return rc;
 
@@ -3238,7 +3236,7 @@ static void selinux_file_free_security(struct file *file)
  * Check whether a task has the ioctl permission and cmd
  * operation to an inode.
  */
-int ioctl_has_perm(const struct cred *cred, struct file *file,
+static int ioctl_has_perm(const struct cred *cred, struct file *file,
                u32 requested, u16 cmd)
 {
        struct common_audit_data ad;
@@ -6093,6 +6091,9 @@ static __init int selinux_init(void)
        sel_inode_cache = kmem_cache_create("selinux_inode_security",
                                            sizeof(struct inode_security_struct),
                                            0, SLAB_PANIC, NULL);
+       file_security_cache = kmem_cache_create("selinux_file_security",
+                                           sizeof(struct file_security_struct),
+                                           0, SLAB_PANIC, NULL);
        avc_init();
 
        security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
index 6a681d26bf20a609aacbc65f508a85ce8d517861..223e9fd15d6651f16a776fcc19fee232ae802129 100644 (file)
@@ -166,6 +166,8 @@ int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
 int security_context_to_sid(const char *scontext, u32 scontext_len,
                            u32 *out_sid, gfp_t gfp);
 
+int security_context_str_to_sid(const char *scontext, u32 *out_sid, gfp_t gfp);
+
 int security_context_to_sid_default(const char *scontext, u32 scontext_len,
                                    u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
 
index 5bed7716f8ab61b6f13a97ec8548c9559ad42b96..c02da25d7b631992aa7841ca98250b08b48d8477 100644 (file)
@@ -731,13 +731,11 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -819,13 +817,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
                objname = namebuf;
        }
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -882,13 +878,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -940,7 +934,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s", con, user) != 2)
                goto out;
 
-       length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
+       length = security_context_str_to_sid(con, &sid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -1000,13 +994,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
-                                        GFP_KERNEL);
+       length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
        if (length)
                goto out;
 
index b7df12ba61d839c45789f762e6138aae1cc15ca9..ebb5eb3c318c789922da4851b1b0507f28e7f831 100644 (file)
@@ -1218,13 +1218,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
        /*
         * Copy the user name, role name and type name into the context.
         */
-       sprintf(scontextp, "%s:%s:%s",
+       scontextp += sprintf(scontextp, "%s:%s:%s",
                sym_name(&policydb, SYM_USERS, context->user - 1),
                sym_name(&policydb, SYM_ROLES, context->role - 1),
                sym_name(&policydb, SYM_TYPES, context->type - 1));
-       scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
-                    1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
-                    1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
 
        mls_sid_to_context(context, &scontextp);
 
@@ -1259,12 +1256,12 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
                        *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
                        if (!scontext)
                                goto out;
-                       scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
+                       scontextp = kmemdup(initial_sid_to_string[sid],
+                                           *scontext_len, GFP_ATOMIC);
                        if (!scontextp) {
                                rc = -ENOMEM;
                                goto out;
                        }
-                       strcpy(scontextp, initial_sid_to_string[sid]);
                        *scontext = scontextp;
                        goto out;
                }
@@ -1476,6 +1473,11 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
                                            sid, SECSID_NULL, gfp, 0);
 }
 
+int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
+{
+       return security_context_to_sid(scontext, strlen(scontext), sid, gfp);
+}
+
 /**
  * security_context_to_sid_default - Obtain a SID for a given security context,
  * falling back to specified default if needed.
@@ -2604,18 +2606,12 @@ int security_get_bools(int *len, char ***names, int **values)
                goto err;
 
        for (i = 0; i < *len; i++) {
-               size_t name_len;
-
                (*values)[i] = policydb.bool_val_to_struct[i]->state;
-               name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
 
                rc = -ENOMEM;
-               (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
+               (*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC);
                if (!(*names)[i])
                        goto err;
-
-               strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
-               (*names)[i][name_len - 1] = 0;
        }
        rc = 0;
 out:
index fff0c612bbb77be9f84254753c6b11a7572e4626..6c91156ae2256798e59fb54518efa6d056094d7d 100644 (file)
@@ -115,6 +115,7 @@ struct task_smack {
        struct smack_known      *smk_forked;    /* label when forked */
        struct list_head        smk_rules;      /* per task access rules */
        struct mutex            smk_rules_lock; /* lock for the rules */
+       struct list_head        smk_relabel;    /* transit allowed labels */
 };
 
 #define        SMK_INODE_INSTANT       0x01    /* inode is instantiated */
@@ -169,7 +170,7 @@ struct smk_port_label {
 };
 #endif /* SMACK_IPV6_PORT_LABELING */
 
-struct smack_onlycap {
+struct smack_known_list_elem {
        struct list_head        list;
        struct smack_known      *smk_label;
 };
@@ -301,6 +302,7 @@ 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 *);
 int smack_privileged(int cap);
+void smk_destroy_label_list(struct list_head *list);
 
 /*
  * Shared data.
index bc1053fb5d1d062a165b0b91c6553428aab653cf..a283f9e796c114465dc969a1224e72b328a1c927 100644 (file)
@@ -637,7 +637,7 @@ DEFINE_MUTEX(smack_onlycap_lock);
 int smack_privileged(int cap)
 {
        struct smack_known *skp = smk_of_current();
-       struct smack_onlycap *sop;
+       struct smack_known_list_elem *sklep;
 
        /*
         * All kernel tasks are privileged
@@ -654,8 +654,8 @@ int smack_privileged(int cap)
                return 1;
        }
 
-       list_for_each_entry_rcu(sop, &smack_onlycap_list, list) {
-               if (sop->smk_label == skp) {
+       list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
+               if (sklep->smk_label == skp) {
                        rcu_read_unlock();
                        return 1;
                }
index 996c889564383a4725e57a769b24abb53225cd50..ff81026f6ddbae7de368a1ae4bfbfeb1a66a9ae6 100644 (file)
@@ -52,7 +52,7 @@
 #define SMK_SENDING    2
 
 #ifdef SMACK_IPV6_PORT_LABELING
-LIST_HEAD(smk_ipv6_port_list);
+static LIST_HEAD(smk_ipv6_port_list);
 #endif
 static struct kmem_cache *smack_inode_cache;
 int smack_enabled;
@@ -326,6 +326,7 @@ static struct task_smack *new_task_smack(struct smack_known *task,
        tsp->smk_task = task;
        tsp->smk_forked = forked;
        INIT_LIST_HEAD(&tsp->smk_rules);
+       INIT_LIST_HEAD(&tsp->smk_relabel);
        mutex_init(&tsp->smk_rules_lock);
 
        return tsp;
@@ -360,6 +361,35 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
        return rc;
 }
 
+/**
+ * smk_copy_relabel - copy smk_relabel labels list
+ * @nhead: new rules header pointer
+ * @ohead: old rules header pointer
+ * @gfp: type of the memory for the allocation
+ *
+ * Returns 0 on success, -ENOMEM on error
+ */
+static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead,
+                               gfp_t gfp)
+{
+       struct smack_known_list_elem *nklep;
+       struct smack_known_list_elem *oklep;
+
+       INIT_LIST_HEAD(nhead);
+
+       list_for_each_entry(oklep, ohead, list) {
+               nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp);
+               if (nklep == NULL) {
+                       smk_destroy_label_list(nhead);
+                       return -ENOMEM;
+               }
+               nklep->smk_label = oklep->smk_label;
+               list_add(&nklep->list, nhead);
+       }
+
+       return 0;
+}
+
 /**
  * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_*
  * @mode - input mode in form of PTRACE_MODE_*
@@ -1922,6 +1952,8 @@ static void smack_cred_free(struct cred *cred)
                return;
        cred->security = NULL;
 
+       smk_destroy_label_list(&tsp->smk_relabel);
+
        list_for_each_safe(l, n, &tsp->smk_rules) {
                rp = list_entry(l, struct smack_rule, list);
                list_del(&rp->list);
@@ -1953,6 +1985,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
        if (rc != 0)
                return rc;
 
+       rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
+                               gfp);
+       if (rc != 0)
+               return rc;
+
        new->security = new_tsp;
        return 0;
 }
@@ -3354,6 +3391,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                         */
                        isp->smk_inode = smk_of_current();
                        break;
+               case PIPEFS_MAGIC:
+                       isp->smk_inode = smk_of_current();
+                       break;
                default:
                        isp->smk_inode = sbsp->smk_root;
                        break;
@@ -3549,9 +3589,11 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 static int smack_setprocattr(struct task_struct *p, char *name,
                             void *value, size_t size)
 {
-       struct task_smack *tsp;
+       struct task_smack *tsp = current_security();
        struct cred *new;
        struct smack_known *skp;
+       struct smack_known_list_elem *sklep;
+       int rc;
 
        /*
         * Changing another process' Smack value is too dangerous
@@ -3560,7 +3602,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
        if (p != current)
                return -EPERM;
 
-       if (!smack_privileged(CAP_MAC_ADMIN))
+       if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
                return -EPERM;
 
        if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
@@ -3579,12 +3621,27 @@ static int smack_setprocattr(struct task_struct *p, char *name,
        if (skp == &smack_known_web)
                return -EPERM;
 
+       if (!smack_privileged(CAP_MAC_ADMIN)) {
+               rc = -EPERM;
+               list_for_each_entry(sklep, &tsp->smk_relabel, list)
+                       if (sklep->smk_label == skp) {
+                               rc = 0;
+                               break;
+                       }
+               if (rc)
+                       return rc;
+       }
+
        new = prepare_creds();
        if (new == NULL)
                return -ENOMEM;
 
        tsp = new->security;
        tsp->smk_task = skp;
+       /*
+        * process can change its label only once
+        */
+       smk_destroy_label_list(&tsp->smk_relabel);
 
        commit_creds(new);
        return size;
@@ -4708,8 +4765,6 @@ static __init int smack_init(void)
        if (!security_module_enable("smack"))
                return 0;
 
-       smack_enabled = 1;
-
        smack_inode_cache = KMEM_CACHE(inode_smack, 0);
        if (!smack_inode_cache)
                return -ENOMEM;
@@ -4721,6 +4776,8 @@ static __init int smack_init(void)
                return -ENOMEM;
        }
 
+       smack_enabled = 1;
+
        pr_info("Smack:  Initializing.\n");
 #ifdef CONFIG_SECURITY_SMACK_NETFILTER
        pr_info("Smack:  Netfilter enabled.\n");
index c20b154a33f22f9eba932268d733b41110b5a038..94bd9e41c9ecb39ce3d432f9c3734a5db7e1b353 100644 (file)
@@ -61,6 +61,7 @@ enum smk_inos {
 #if IS_ENABLED(CONFIG_IPV6)
        SMK_NET6ADDR    = 23,   /* single label IPv6 hosts */
 #endif /* CONFIG_IPV6 */
+       SMK_RELABEL_SELF = 24, /* relabel possible without CAP_MAC_ADMIN */
 };
 
 /*
@@ -1501,8 +1502,8 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
         */
        if (smack[0] != '-') {
                skp = smk_import_entry(smack, 0);
-               if (skp == NULL) {
-                       rc = -EINVAL;
+               if (IS_ERR(skp)) {
+                       rc = PTR_ERR(skp);
                        goto free_out;
                }
        } else {
@@ -1914,10 +1915,10 @@ static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
 static int onlycap_seq_show(struct seq_file *s, void *v)
 {
        struct list_head *list = v;
-       struct smack_onlycap *sop =
-               list_entry_rcu(list, struct smack_onlycap, list);
+       struct smack_known_list_elem *sklep =
+               list_entry_rcu(list, struct smack_known_list_elem, list);
 
-       seq_puts(s, sop->smk_label->smk_known);
+       seq_puts(s, sklep->smk_label->smk_known);
        seq_putc(s, ' ');
 
        return 0;
@@ -1973,6 +1974,54 @@ static void smk_list_swap_rcu(struct list_head *public,
        }
 }
 
+/**
+ * smk_parse_label_list - parse list of Smack labels, separated by spaces
+ *
+ * @data: the string to parse
+ * @private: destination list
+ *
+ * Returns zero on success or error code, as appropriate
+ */
+static int smk_parse_label_list(char *data, struct list_head *list)
+{
+       char *tok;
+       struct smack_known *skp;
+       struct smack_known_list_elem *sklep;
+
+       while ((tok = strsep(&data, " ")) != NULL) {
+               if (!*tok)
+                       continue;
+
+               skp = smk_import_entry(tok, 0);
+               if (IS_ERR(skp))
+                       return PTR_ERR(skp);
+
+               sklep = kzalloc(sizeof(*sklep), GFP_KERNEL);
+               if (sklep == NULL)
+                       return -ENOMEM;
+
+               sklep->smk_label = skp;
+               list_add(&sklep->list, list);
+       }
+
+       return 0;
+}
+
+/**
+ * smk_destroy_label_list - destroy a list of smack_known_list_elem
+ * @head: header pointer of the list to destroy
+ */
+void smk_destroy_label_list(struct list_head *list)
+{
+       struct smack_known_list_elem *sklep;
+       struct smack_known_list_elem *sklep2;
+
+       list_for_each_entry_safe(sklep, sklep2, list, list)
+               kfree(sklep);
+
+       INIT_LIST_HEAD(list);
+}
+
 /**
  * smk_write_onlycap - write() for smackfs/onlycap
  * @file: file pointer, not actually used
@@ -1986,13 +2035,8 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        char *data;
-       char *data_parse;
-       char *tok;
-       struct smack_known *skp;
-       struct smack_onlycap *sop;
-       struct smack_onlycap *sop2;
        LIST_HEAD(list_tmp);
-       int rc = count;
+       int rc;
 
        if (!smack_privileged(CAP_MAC_ADMIN))
                return -EPERM;
@@ -2006,26 +2050,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
                return -EFAULT;
        }
 
-       data_parse = data;
-       while ((tok = strsep(&data_parse, " ")) != NULL) {
-               if (!*tok)
-                       continue;
-
-               skp = smk_import_entry(tok, 0);
-               if (IS_ERR(skp)) {
-                       rc = PTR_ERR(skp);
-                       break;
-               }
-
-               sop = kzalloc(sizeof(*sop), GFP_KERNEL);
-               if (sop == NULL) {
-                       rc = -ENOMEM;
-                       break;
-               }
-
-               sop->smk_label = skp;
-               list_add_rcu(&sop->list, &list_tmp);
-       }
+       rc = smk_parse_label_list(data, &list_tmp);
        kfree(data);
 
        /*
@@ -2038,17 +2063,14 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
         * But do so only on invalid label, not on system errors.
         * The invalid label must be first to count as clearing attempt.
         */
-       if (rc == -EINVAL && list_empty(&list_tmp))
-               rc = count;
-
-       if (rc >= 0) {
+       if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
                mutex_lock(&smack_onlycap_lock);
                smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
                mutex_unlock(&smack_onlycap_lock);
+               rc = count;
        }
 
-       list_for_each_entry_safe(sop, sop2, &list_tmp, list)
-               kfree(sop);
+       smk_destroy_label_list(&list_tmp);
 
        return rc;
 }
@@ -2698,6 +2720,113 @@ static const struct file_operations smk_syslog_ops = {
        .llseek         = default_llseek,
 };
 
+/*
+ * Seq_file read operations for /smack/relabel-self
+ */
+
+static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct task_smack *tsp = current_security();
+
+       return smk_seq_start(s, pos, &tsp->smk_relabel);
+}
+
+static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct task_smack *tsp = current_security();
+
+       return smk_seq_next(s, v, pos, &tsp->smk_relabel);
+}
+
+static int relabel_self_seq_show(struct seq_file *s, void *v)
+{
+       struct list_head *list = v;
+       struct smack_known_list_elem *sklep =
+               list_entry(list, struct smack_known_list_elem, list);
+
+       seq_puts(s, sklep->smk_label->smk_known);
+       seq_putc(s, ' ');
+
+       return 0;
+}
+
+static const struct seq_operations relabel_self_seq_ops = {
+       .start = relabel_self_seq_start,
+       .next  = relabel_self_seq_next,
+       .show  = relabel_self_seq_show,
+       .stop  = smk_seq_stop,
+};
+
+/**
+ * smk_open_relabel_self - open() for /smack/relabel-self
+ * @inode: inode structure representing file
+ * @file: "relabel-self" file pointer
+ *
+ * Connect our relabel_self_seq_* operations with /smack/relabel-self
+ * file_operations
+ */
+static int smk_open_relabel_self(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &relabel_self_seq_ops);
+}
+
+/**
+ * smk_write_relabel_self - write() for /smack/relabel-self
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ *
+ */
+static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       struct task_smack *tsp = current_security();
+       char *data;
+       int rc;
+       LIST_HEAD(list_tmp);
+
+       /*
+        * Must have privilege.
+        */
+       if (!smack_privileged(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       /*
+        * Enough data must be present.
+        */
+       if (*ppos != 0)
+               return -EINVAL;
+
+       data = kzalloc(count + 1, GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(data, buf, count) != 0) {
+               kfree(data);
+               return -EFAULT;
+       }
+
+       rc = smk_parse_label_list(data, &list_tmp);
+       kfree(data);
+
+       if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
+               smk_destroy_label_list(&tsp->smk_relabel);
+               list_splice(&list_tmp, &tsp->smk_relabel);
+               return count;
+       }
+
+       smk_destroy_label_list(&list_tmp);
+       return rc;
+}
+
+static const struct file_operations smk_relabel_self_ops = {
+       .open           = smk_open_relabel_self,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .write          = smk_write_relabel_self,
+       .release        = seq_release,
+};
 
 /**
  * smk_read_ptrace - read() for /smack/ptrace
@@ -2824,6 +2953,9 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
                [SMK_NET6ADDR] = {
                        "ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR},
 #endif /* CONFIG_IPV6 */
+               [SMK_RELABEL_SELF] = {
+                       "relabel-self", &smk_relabel_self_ops,
+                               S_IRUGO|S_IWUGO},
                /* last one */
                        {""}
        };
@@ -2892,7 +3024,7 @@ static int __init init_smk_fs(void)
        int err;
        int rc;
 
-       if (!security_module_enable("smack"))
+       if (smack_enabled == 0)
                return 0;
 
        err = smk_init_sysfs();