You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# Generated files
|
||||
#
|
||||
x509_certificate_list
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user