Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

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
  ...
This commit is contained in:
Linus Torvalds
2015-11-05 15:32:38 -08:00
89 changed files with 1748 additions and 492 deletions
+12 -7
View 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:
+13 -12
View 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.
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 ->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.
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
+10
View 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:
+25 -16
View 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);
+1
View 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)
+30 -10
View 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);
+4
View File
@@ -0,0 +1,4 @@
#
# Generated files
#
x509_certificate_list
-5
View 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];
}
+27 -19
View File
@@ -307,25 +307,34 @@ static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
}
/*
* Clean up the preparse data
* Clean up the key ID list
*/
static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
{
struct asymmetric_key_subtype *subtype = prep->type_data[0];
struct asymmetric_key_ids *kids = prep->type_data[1];
int i;
pr_devel("==>%s()\n", __func__);
if (subtype) {
subtype->destroy(prep->payload[0]);
module_put(subtype->owner);
}
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->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.data[asym_crypto]);
module_put(subtype->owner);
}
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 = {
+2 -2
View 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);
}
+1 -1
View 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;
+1
View 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;
+5 -4
View 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;
+1 -1
View 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
-1
View 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),
+16 -8
View 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);
}
+76
View 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;
+123 -11
View 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);
+249 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Intel Corporation
* Copyright (C) 2014, 2015 Intel Corporation
*
* Authors:
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
@@ -16,6 +16,11 @@
*/
#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.
+15 -24
View 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) {

Some files were not shown because too many files have changed in this diff Show More