Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1592049 > unrolled thread
| Started by | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| First post | 2017-03-03 16:30 +0100 |
| Last post | 2017-03-11 10:00 +0100 |
| Articles | 8 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v3 0/7] in-kernel resource manager Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-03 16:30 +0100
[PATCH v3 6/7] tpm: expose spaces via a device link /dev/tpmrm<n> Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-03 16:30 +0100
[PATCH v3 3/7] tpm: export tpm2_flush_context_cmd Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-03 16:30 +0100
[PATCH v3 2/7] tpm: validate TPM 2.0 commands Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-03 16:30 +0100
[PATCH v3 7/7] tpm2: add session handle context saving and restoring to the space code Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-03 16:30 +0100
[PATCH v3 5/7] tpm: split out tpm-dev.c into tpm-dev.c and tpm-common-dev.c Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-03 16:30 +0100
Re: [PATCH v3 0/7] in-kernel resource manager Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-06 22:10 +0100
Re: [PATCH v3 0/7] in-kernel resource manager Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2017-03-11 10:00 +0100
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-03 16:30 +0100 |
| Subject | [PATCH v3 0/7] in-kernel resource manager |
| Message-ID | <tgXjz-35T-3@gated-at.bofh.it> |
This patch set adds support for TPM spaces that provide an isolated
execution context for transient objects and HMAC and policy sessions. A
space is swapped into TPM volatile memory only when it is used and
swapped out after the use.
There's a test script for trying out TPM spaces in
git://git.infradead.org/users/jjs/tpm2-scripts.git
A simple smoke test suite can be run by
sudo python -m unittest -v tpm2_smoke.SpaceTest
v3:
* Reverted back to /dev/tpmrm0 that was actually James' original
proposal. It's the most pragmatic choice as it cannot be mixed
with other TPM 2.0 and kernel idioms easily.
v2:
* Substitute virtual handle in ContextSave.
* Substitute virtual handles in GetCapability.
* Validate that the real response length and the one reported in the
header match in tpm_transmit().
James Bottomley (3):
tpm: split out tpm-dev.c into tpm-dev.c and tpm-common-dev.c
tpm: expose spaces via a device link /dev/tpmrm<n>
tpm2: add session handle context saving and restoring to the space
code
Jarkko Sakkinen (4):
tpm: move length validation to tpm_transmit()
tpm: validate TPM 2.0 commands
tpm: export tpm2_flush_context_cmd
tpm: infrastructure for TPM spaces
drivers/char/tpm/Makefile | 3 +-
drivers/char/tpm/tpm-chip.c | 71 ++++-
drivers/char/tpm/tpm-dev-common.c | 148 +++++++++++
drivers/char/tpm/tpm-dev.c | 143 +---------
drivers/char/tpm/tpm-dev.h | 27 ++
drivers/char/tpm/tpm-interface.c | 131 +++++++---
drivers/char/tpm/tpm-sysfs.c | 2 +-
drivers/char/tpm/tpm.h | 49 +++-
drivers/char/tpm/tpm2-cmd.c | 173 +++++++++----
drivers/char/tpm/tpm2-space.c | 532 ++++++++++++++++++++++++++++++++++++++
drivers/char/tpm/tpmrm-dev.c | 65 +++++
11 files changed, 1123 insertions(+), 221 deletions(-)
create mode 100644 drivers/char/tpm/tpm-dev-common.c
create mode 100644 drivers/char/tpm/tpm-dev.h
create mode 100644 drivers/char/tpm/tpm2-space.c
create mode 100644 drivers/char/tpm/tpmrm-dev.c
--
2.9.3
[toc] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-03 16:30 +0100 |
| Subject | [PATCH v3 6/7] tpm: expose spaces via a device link /dev/tpmrm<n> |
| Message-ID | <tgXjA-35T-23@gated-at.bofh.it> |
| In reply to | #1592049 |
From: James Bottomley <James.Bottomley@HansenPartnership.com>
Currently the tpm spaces are not exposed to userspace. Make this
exposure via a separate device, which can now be opened multiple times
because each read/write transaction goes separately via the space.
Concurrency is protected by the chip->tpm_mutex for each read/write
transaction separately. The TPM is cleared of all transient objects
by the time the mutex is dropped, so there should be no interference
between the kernel and userspace.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
drivers/char/tpm/Makefile | 3 +-
drivers/char/tpm/tpm-chip.c | 58 ++++++++++++++++++++++++++++++++++-
drivers/char/tpm/tpm-interface.c | 13 ++++++--
drivers/char/tpm/tpm.h | 4 +++
drivers/char/tpm/tpmrm-dev.c | 65 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 139 insertions(+), 4 deletions(-)
create mode 100644 drivers/char/tpm/tpmrm-dev.c
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 10e5827..23681f0 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -3,7 +3,8 @@
#
obj-$(CONFIG_TCG_TPM) += tpm.o
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
- tpm-dev-common.o tpm1_eventlog.o tpm2_eventlog.o tpm2-space.o
+ tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \
+ tpm2-space.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
tpm-$(CONFIG_OF) += tpm_of.o
obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 364d92e..3db38f9 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -33,6 +33,7 @@ DEFINE_IDR(dev_nums_idr);
static DEFINE_MUTEX(idr_lock);
struct class *tpm_class;
+struct class *tpmrm_class;
dev_t tpm_devt;
/**
@@ -132,6 +133,14 @@ static void tpm_dev_release(struct device *dev)
kfree(chip);
}
+static void tpm_devs_release(struct device *dev)
+{
+ struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
+
+ /* release the master device reference */
+ put_device(&chip->dev);
+}
+
/**
* tpm_chip_alloc() - allocate a new struct tpm_chip instance
* @pdev: device to which the chip is associated
@@ -168,27 +177,47 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
chip->dev_num = rc;
device_initialize(&chip->dev);
+ device_initialize(&chip->devs);
chip->dev.class = tpm_class;
chip->dev.release = tpm_dev_release;
chip->dev.parent = pdev;
chip->dev.groups = chip->groups;
+ chip->devs.parent = pdev;
+ chip->devs.class = tpmrm_class;
+ chip->devs.release = tpm_devs_release;
+ /* get extra reference on main device to hold on
+ * behalf of devs. This holds the chip structure
+ * while cdevs is in use. The corresponding put
+ * is in the tpm_devs_release
+ */
+ get_device(&chip->dev);
+
if (chip->dev_num == 0)
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
else
chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
+ chip->devs.devt =
+ MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
+
rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num);
if (rc)
goto out;
+ rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
+ if (rc)
+ goto out;
if (!pdev)
chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
cdev_init(&chip->cdev, &tpm_fops);
+ cdev_init(&chip->cdevs, &tpmrm_fops);
chip->cdev.owner = THIS_MODULE;
+ chip->cdevs.owner = THIS_MODULE;
chip->cdev.kobj.parent = &chip->dev.kobj;
+ chip->cdevs.kobj.parent = &chip->devs.kobj;
chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!chip->work_space.context_buf) {
@@ -199,6 +228,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
return chip;
out:
+ put_device(&chip->devs);
put_device(&chip->dev);
return ERR_PTR(rc);
}
@@ -263,7 +293,6 @@ static int tpm_add_char_device(struct tpm_chip *chip)
"unable to cdev_add() %s, major %d, minor %d, err=%d\n",
dev_name(&chip->dev), MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
-
return rc;
}
@@ -277,6 +306,29 @@ static int tpm_add_char_device(struct tpm_chip *chip)
return rc;
}
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ rc = cdev_add(&chip->cdevs, chip->devs.devt, 1);
+ if (rc) {
+ dev_err(&chip->dev,
+ "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+ dev_name(&chip->devs), MAJOR(chip->devs.devt),
+ MINOR(chip->devs.devt), rc);
+ tpm_del_char_device(chip, true);
+ return rc;
+ }
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ rc = device_add(&chip->devs);
+ if (rc) {
+ dev_err(&chip->dev,
+ "unable to device_register() %s, major %d, minor %d, err=%d\n",
+ dev_name(&chip->devs), MAJOR(chip->devs.devt),
+ MINOR(chip->devs.devt), rc);
+ cdev_del(&chip->cdevs);
+ tpm_del_char_device(chip, true);
+ return rc;
+ }
+
/* Make the chip available. */
mutex_lock(&idr_lock);
idr_replace(&dev_nums_idr, chip, chip->dev_num);
@@ -392,6 +444,10 @@ void tpm_chip_unregister(struct tpm_chip *chip)
{
tpm_del_legacy_sysfs(chip);
tpm_bios_log_teardown(chip);
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ cdev_del(&chip->cdevs);
+ device_del(&chip->devs);
+ }
tpm_del_char_device(chip, true);
}
EXPORT_SYMBOL_GPL(tpm_chip_unregister);
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index db5ffe9..e38c792 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -1257,9 +1257,17 @@ static int __init tpm_init(void)
return PTR_ERR(tpm_class);
}
- rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
+ tpmrm_class = class_create(THIS_MODULE, "tpmrm");
+ if (IS_ERR(tpmrm_class)) {
+ pr_err("couldn't create tpmrm class\n");
+ class_destroy(tpm_class);
+ return PTR_ERR(tpmrm_class);
+ }
+
+ rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm");
if (rc < 0) {
pr_err("tpm: failed to allocate char dev region\n");
+ class_destroy(tpmrm_class);
class_destroy(tpm_class);
return rc;
}
@@ -1271,7 +1279,8 @@ static void __exit tpm_exit(void)
{
idr_destroy(&dev_nums_idr);
class_destroy(tpm_class);
- unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
+ class_destroy(tpmrm_class);
+ unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
}
subsys_initcall(tpm_init);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 023fc02..16dd207 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -182,7 +182,9 @@ struct tpm_chip_seqops {
struct tpm_chip {
struct device dev;
+ struct device devs;
struct cdev cdev;
+ struct cdev cdevs;
/* A driver callback under ops cannot be run unless ops_sem is held
* (sometimes implicitly, eg for the sysfs code). ops becomes null
@@ -510,8 +512,10 @@ static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
}
extern struct class *tpm_class;
+extern struct class *tpmrm_class;
extern dev_t tpm_devt;
extern const struct file_operations tpm_fops;
+extern const struct file_operations tpmrm_fops;
extern struct idr dev_nums_idr;
enum tpm_transmit_flags {
diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c
new file mode 100644
index 0000000..630bddc
--- /dev/null
+++ b/drivers/char/tpm/tpmrm-dev.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 James.Bottomley@HansenPartnership.com
+ *
+ * GPLv2
+ */
+#include <linux/slab.h>
+#include "tpm-dev.h"
+
+struct tpmrm_priv {
+ struct file_priv priv;
+ struct tpm_space space;
+};
+
+static int tpmrm_open(struct inode *inode, struct file *file)
+{
+ struct tpm_chip *chip;
+ struct tpmrm_priv *priv;
+ int rc;
+
+ chip = container_of(inode->i_cdev, struct tpm_chip, cdevs);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ rc = tpm2_init_space(&priv->space);
+ if (rc) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ tpm_common_open(file, chip, &priv->priv);
+
+ return 0;
+}
+
+static int tpmrm_release(struct inode *inode, struct file *file)
+{
+ struct file_priv *fpriv = file->private_data;
+ struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv);
+
+ tpm_common_release(file, fpriv);
+ tpm2_del_space(&priv->space);
+ kfree(priv);
+
+ return 0;
+}
+
+ssize_t tpmrm_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *off)
+{
+ struct file_priv *fpriv = file->private_data;
+ struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv);
+
+ return tpm_common_write(file, buf, size, off, &priv->space);
+}
+
+const struct file_operations tpmrm_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = tpmrm_open,
+ .read = tpm_common_read,
+ .write = tpmrm_write,
+ .release = tpmrm_release,
+};
+
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-03 16:30 +0100 |
| Subject | [PATCH v3 3/7] tpm: export tpm2_flush_context_cmd |
| Message-ID | <tgXjA-35T-25@gated-at.bofh.it> |
| In reply to | #1592049 |
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Reviewed-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
drivers/char/tpm/tpm.h | 2 ++
drivers/char/tpm/tpm2-cmd.c | 62 +++++++++++++++++++++------------------------
2 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 8568dda..dd5f526 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -555,6 +555,8 @@ 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, u32 count,
struct tpm2_digest *digests);
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
+void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
+ unsigned int flags);
int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 5efe9c4..ec05ab3 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -419,6 +419,35 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = {
};
/**
+ * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
+ * @chip: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
+ unsigned int flags)
+{
+ struct tpm_buf buf;
+ int rc;
+
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
+ if (rc) {
+ dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
+ handle);
+ return;
+ }
+
+ tpm_buf_append_u32(&buf, handle);
+
+ (void) tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags,
+ "flushing context");
+
+ tpm_buf_destroy(&buf);
+}
+
+/**
* tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
*
* @buf: an allocated tpm_buf instance
@@ -628,39 +657,6 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
}
/**
- * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
- *
- * @chip: TPM chip to use
- * @handle: the key data in clear and encrypted form
- * @flags: tpm transmit flags
- *
- * Return: Same as with tpm_transmit_cmd.
- */
-static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
- unsigned int flags)
-{
- struct tpm_buf buf;
- int rc;
-
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
- if (rc) {
- dev_warn(&chip->dev, "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, 0, flags,
- "flushing context");
- if (rc)
- dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle,
- rc);
-
- tpm_buf_destroy(&buf);
-}
-
-/**
* tpm2_unseal_cmd() - execute a TPM2_Unload command
*
* @chip: TPM chip to use
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-03 16:30 +0100 |
| Subject | [PATCH v3 2/7] tpm: validate TPM 2.0 commands |
| Message-ID | <tgXjA-35T-31@gated-at.bofh.it> |
| In reply to | #1592049 |
Check for every TPM 2.0 command that the command code is supported and
the command buffer has at least the length that can contain the header
and the handle area.
For ContextSave and FlushContext we mark the body to be part of the
handle area. This gives validation for these commands at zero
cost, including the body of the command.
The more important reason for this is that we can virtualize these
commands in the same way as you would virtualize the handle area of a
command.
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Reviewed-by: James Bottomley <James.Bottomley@HansenPartnership.com>
---
drivers/char/tpm/tpm-interface.c | 38 +++++++++++++++++-
drivers/char/tpm/tpm.h | 15 +++++++
drivers/char/tpm/tpm2-cmd.c | 84 ++++++++++++++++++++++++++++++++++++++--
3 files changed, 132 insertions(+), 5 deletions(-)
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 708d356..20b1fe3 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -328,6 +328,42 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
}
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
+static bool tpm_validate_command(struct tpm_chip *chip, const u8 *cmd,
+ size_t len)
+{
+ const struct tpm_input_header *header = (const void *)cmd;
+ int i;
+ u32 cc;
+ u32 attrs;
+ unsigned int nr_handles;
+
+ if (len < TPM_HEADER_SIZE)
+ return false;
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
+ cc = be32_to_cpu(header->ordinal);
+
+ i = tpm2_find_cc(chip, cc);
+ if (i < 0) {
+ dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
+ cc);
+ return false;
+ }
+
+ attrs = chip->cc_attrs_tbl[i];
+ nr_handles =
+ 4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
+ if (len < TPM_HEADER_SIZE + 4 * nr_handles)
+ goto err_len;
+ }
+
+ return true;
+err_len:
+ dev_dbg(&chip->dev,
+ "%s: insufficient command length %zu", __func__, len);
+ return false;
+}
+
/**
* tmp_transmit - Internal kernel interface to transmit TPM commands.
*
@@ -348,7 +384,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
u32 count, ordinal;
unsigned long stop;
- if (bufsiz < TPM_HEADER_SIZE)
+ if (!tpm_validate_command(chip, buf, bufsiz))
return -EINVAL;
if (bufsiz > TPM_BUFSIZE)
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 4937b56..8568dda 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -114,6 +114,7 @@ enum tpm2_command_codes {
TPM2_CC_CREATE = 0x0153,
TPM2_CC_LOAD = 0x0157,
TPM2_CC_UNSEAL = 0x015E,
+ TPM2_CC_CONTEXT_SAVE = 0x0162,
TPM2_CC_FLUSH_CONTEXT = 0x0165,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
@@ -127,15 +128,25 @@ enum tpm2_permanent_handles {
};
enum tpm2_capabilities {
+ TPM2_CAP_COMMANDS = 2,
TPM2_CAP_PCRS = 5,
TPM2_CAP_TPM_PROPERTIES = 6,
};
+enum tpm2_properties {
+ TPM_PT_TOTAL_COMMANDS = 0x0129,
+};
+
enum tpm2_startup_types {
TPM2_SU_CLEAR = 0x0000,
TPM2_SU_STATE = 0x0001,
};
+enum tpm2_cc_attrs {
+ TPM2_CC_ATTR_CHANDLES = 25,
+ TPM2_CC_ATTR_RHANDLE = 28,
+};
+
#define TPM_VID_INTEL 0x8086
#define TPM_VID_WINBOND 0x1050
#define TPM_VID_STM 0x104A
@@ -199,6 +210,9 @@ struct tpm_chip {
acpi_handle acpi_dev_handle;
char ppi_version[TPM_PPI_VERSION_LEN + 1];
#endif /* CONFIG_ACPI */
+
+ u32 nr_commands;
+ u32 *cc_attrs_tbl;
};
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
@@ -554,4 +568,5 @@ int tpm2_auto_startup(struct tpm_chip *chip);
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
int tpm2_probe(struct tpm_chip *chip);
+int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
#endif
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 881aea9..5efe9c4 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1067,15 +1067,76 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
return rc;
}
+static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
+{
+ struct tpm_buf buf;
+ u32 nr_commands;
+ u32 *attrs;
+ u32 cc;
+ int i;
+ int rc;
+
+ rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
+ if (rc)
+ goto out;
+
+ if (nr_commands > 0xFFFFF) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ chip->cc_attrs_tbl = devm_kzalloc(&chip->dev, 4 * nr_commands,
+ GFP_KERNEL);
+
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+ if (rc)
+ goto out;
+
+ tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
+ tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
+ tpm_buf_append_u32(&buf, nr_commands);
+
+ rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9 + 4 * nr_commands,
+ 0, NULL);
+ if (rc) {
+ tpm_buf_destroy(&buf);
+ goto out;
+ }
+
+ if (nr_commands !=
+ be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
+ tpm_buf_destroy(&buf);
+ goto out;
+ }
+
+ chip->nr_commands = nr_commands;
+
+ attrs = (u32 *)&buf.data[TPM_HEADER_SIZE + 9];
+ for (i = 0; i < nr_commands; i++, attrs++) {
+ chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
+ cc = chip->cc_attrs_tbl[i] & 0xFFFF;
+
+ if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) {
+ chip->cc_attrs_tbl[i] &=
+ ~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES);
+ chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES;
+ }
+ }
+
+ tpm_buf_destroy(&buf);
+
+out:
+ if (rc > 0)
+ rc = -ENODEV;
+ return rc;
+}
+
/**
* tpm2_auto_startup - Perform the standard automatic TPM initialization
* sequence
* @chip: TPM chip to use
*
- * Initializes timeout values for operation and command durations, conducts
- * a self-test and reads the list of active PCR banks.
- *
- * Return: 0 on success. Otherwise, a system error code is returned.
+ * Returns 0 on success, < 0 in case of fatal error.
*/
int tpm2_auto_startup(struct tpm_chip *chip)
{
@@ -1104,9 +1165,24 @@ int tpm2_auto_startup(struct tpm_chip *chip)
}
rc = tpm2_get_pcr_allocation(chip);
+ if (rc)
+ goto out;
+
+ rc = tpm2_get_cc_attrs_tbl(chip);
out:
if (rc > 0)
rc = -ENODEV;
return rc;
}
+
+int tpm2_find_cc(struct tpm_chip *chip, u32 cc)
+{
+ int i;
+
+ for (i = 0; i < chip->nr_commands; i++)
+ if (cc == (chip->cc_attrs_tbl[i] & GENMASK(15, 0)))
+ return i;
+
+ return -1;
+}
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-03 16:30 +0100 |
| Subject | [PATCH v3 7/7] tpm2: add session handle context saving and restoring to the space code |
| Message-ID | <tgXjB-35T-41@gated-at.bofh.it> |
| In reply to | #1592049 |
From: James Bottomley <James.Bottomley@HansenPartnership.com>
Sessions are different from transient objects in that their handles
may not be virtualized (because they're used for some hmac
calculations). Additionally when a session is context saved, a
vestigial memory remains in the TPM and if it is also flushed, that
will be lost and the session context will refuse to load next time, so
the code is updated to flush only transient objects after a context
save. Add a separate array (chip->session_tbl) to save and restore
sessions by handle. Use the failure of a context save or load to
signal that the session has been flushed from the TPM and we can
remove its memory from chip->session_tbl.
Sessions are also isolated during each instance of a tpm space. This
means that spaces shouldn't be able to see each other's sessions and
is enforced by ensuring that a space user may only refer to sessions
handles that are present in their own chip->session_tbl. Finally when
a space is closed, all the sessions belonging to it should be flushed
so the handles may be re-used by other spaces.
Note that if we get a session save or load error, all sessions are
effectively flushed. Even though we restore the session buffer, all
the old sessions will refuse to load after the flush and they'll be
purged from our session memory. This means that while transient
context handling is still soft in the face of errors, session handling
is hard (any failure of the model means all sessions are lost).
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
drivers/char/tpm/tpm-chip.c | 6 +++
drivers/char/tpm/tpm.h | 4 +-
drivers/char/tpm/tpm2-space.c | 105 +++++++++++++++++++++++++++++++++++++++++-
drivers/char/tpm/tpmrm-dev.c | 2 +-
4 files changed, 113 insertions(+), 4 deletions(-)
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 3db38f9..27a76e7 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -130,6 +130,7 @@ static void tpm_dev_release(struct device *dev)
kfree(chip->log.bios_event_log);
kfree(chip->work_space.context_buf);
+ kfree(chip->work_space.session_buf);
kfree(chip);
}
@@ -224,6 +225,11 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
rc = -ENOMEM;
goto out;
}
+ chip->work_space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!chip->work_space.session_buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
return chip;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 16dd207..5eacb3f 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -161,6 +161,8 @@ enum tpm2_cc_attrs {
struct tpm_space {
u32 context_tbl[3];
u8 *context_buf;
+ u32 session_tbl[3];
+ u8 *session_buf;
};
enum tpm_chip_flags {
@@ -588,7 +590,7 @@ unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
int tpm2_probe(struct tpm_chip *chip);
int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
int tpm2_init_space(struct tpm_space *space);
-void tpm2_del_space(struct tpm_space *space);
+void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space);
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
u8 *cmd);
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
index e955548..d36d81e 100644
--- a/drivers/char/tpm/tpm2-space.c
+++ b/drivers/char/tpm/tpm2-space.c
@@ -32,18 +32,39 @@ struct tpm2_context {
__be16 blob_size;
} __packed;
+static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+ if (space->session_tbl[i])
+ tpm2_flush_context_cmd(chip, space->session_tbl[i],
+ TPM_TRANSMIT_UNLOCKED);
+ }
+}
+
int tpm2_init_space(struct tpm_space *space)
{
space->context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!space->context_buf)
return -ENOMEM;
+ space->session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (space->session_buf == NULL) {
+ kfree(space->context_buf);
+ return -ENOMEM;
+ }
+
return 0;
}
-void tpm2_del_space(struct tpm_space *space)
+void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
{
+ mutex_lock(&chip->tpm_mutex);
+ tpm2_flush_sessions(chip, space);
+ mutex_unlock(&chip->tpm_mutex);
kfree(space->context_buf);
+ kfree(space->session_buf);
}
static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
@@ -69,6 +90,20 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
__func__, rc);
tpm_buf_destroy(&tbuf);
return -EFAULT;
+ } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
+ rc == TPM2_RC_REFERENCE_H0) {
+ /*
+ * TPM_RC_HANDLE means that the session context can't
+ * be loaded because of an internal counter mismatch
+ * that makes the TPM think there might have been a
+ * replay. This might happen if the context was saved
+ * and loaded outside the space.
+ *
+ * TPM_RC_REFERENCE_H0 means the session has been
+ * flushed outside the space
+ */
+ rc = -ENOENT;
+ tpm_buf_destroy(&tbuf);
} else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
@@ -121,7 +156,6 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
}
memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
- tpm2_flush_context_cmd(chip, handle, TPM_TRANSMIT_UNLOCKED);
*offset += body_size;
tpm_buf_destroy(&tbuf);
return 0;
@@ -136,6 +170,8 @@ static void tpm2_flush_space(struct tpm_chip *chip)
if (space->context_tbl[i] && ~space->context_tbl[i])
tpm2_flush_context_cmd(chip, space->context_tbl[i],
TPM_TRANSMIT_UNLOCKED);
+
+ tpm2_flush_sessions(chip, space);
}
static int tpm2_load_space(struct tpm_chip *chip)
@@ -161,6 +197,28 @@ static int tpm2_load_space(struct tpm_chip *chip)
return rc;
}
+ for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+ u32 handle;
+
+ if (!space->session_tbl[i])
+ continue;
+
+ rc = tpm2_load_context(chip, space->session_buf,
+ &offset, &handle);
+ if (rc == -ENOENT) {
+ /* load failed, just forget session */
+ space->session_tbl[i] = 0;
+ } else if (rc) {
+ tpm2_flush_space(chip);
+ return rc;
+ }
+ if (handle != space->session_tbl[i]) {
+ dev_warn(&chip->dev, "session restored to wrong handle\n");
+ tpm2_flush_space(chip);
+ return -EFAULT;
+ }
+ }
+
return 0;
}
@@ -215,7 +273,10 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
memcpy(&chip->work_space.context_tbl, &space->context_tbl,
sizeof(space->context_tbl));
+ memcpy(&chip->work_space.session_tbl, &space->session_tbl,
+ sizeof(space->session_tbl));
memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE);
+ memcpy(chip->work_space.session_buf, space->session_buf, PAGE_SIZE);
rc = tpm2_load_space(chip);
if (rc) {
@@ -232,6 +293,22 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
return 0;
}
+static bool tpm2_add_session(struct tpm_chip *chip, u32 handle)
+{
+ struct tpm_space *space = &chip->work_space;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
+ if (space->session_tbl[i] == 0)
+ break;
+
+ if (i == ARRAY_SIZE(space->session_tbl))
+ return false;
+
+ space->session_tbl[i] = handle;
+ return true;
+}
+
static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc)
{
int i;
@@ -288,6 +365,8 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
break;
case TPM2_HT_HMAC_SESSION:
case TPM2_HT_POLICY_SESSION:
+ if (!tpm2_add_session(chip, phandle))
+ goto out_no_slots;
break;
default:
dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
@@ -388,9 +467,28 @@ static int tpm2_save_space(struct tpm_chip *chip)
} else if (rc)
return rc;
+ tpm2_flush_context_cmd(chip, space->context_tbl[i],
+ TPM_TRANSMIT_UNLOCKED);
space->context_tbl[i] = ~0;
}
+ for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
+ if (!space->session_tbl[i])
+ continue;
+
+ rc = tpm2_save_context(chip, space->session_tbl[i],
+ space->session_buf, PAGE_SIZE,
+ &offset);
+
+ if (rc == -ENOENT) {
+ /* handle error saving session, just forget it */
+ space->session_tbl[i] = 0;
+ } else if (rc < 0) {
+ tpm2_flush_space(chip);
+ return rc;
+ }
+ }
+
return 0;
}
@@ -425,7 +523,10 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
memcpy(&space->context_tbl, &chip->work_space.context_tbl,
sizeof(space->context_tbl));
+ memcpy(&space->session_tbl, &chip->work_space.session_tbl,
+ sizeof(space->session_tbl));
memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE);
+ memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE);
return 0;
}
diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c
index 630bddc..c636e7f 100644
--- a/drivers/char/tpm/tpmrm-dev.c
+++ b/drivers/char/tpm/tpmrm-dev.c
@@ -39,7 +39,7 @@ static int tpmrm_release(struct inode *inode, struct file *file)
struct tpmrm_priv *priv = container_of(fpriv, struct tpmrm_priv, priv);
tpm_common_release(file, fpriv);
- tpm2_del_space(&priv->space);
+ tpm2_del_space(fpriv->chip, &priv->space);
kfree(priv);
return 0;
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-03 16:30 +0100 |
| Subject | [PATCH v3 5/7] tpm: split out tpm-dev.c into tpm-dev.c and tpm-common-dev.c |
| Message-ID | <tgXjB-35T-47@gated-at.bofh.it> |
| In reply to | #1592049 |
From: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
drivers/char/tpm/Makefile | 2 +-
drivers/char/tpm/tpm-dev-common.c | 148 ++++++++++++++++++++++++++++++++++++++
drivers/char/tpm/tpm-dev.c | 143 ++++--------------------------------
drivers/char/tpm/tpm-dev.h | 27 +++++++
4 files changed, 190 insertions(+), 130 deletions(-)
create mode 100644 drivers/char/tpm/tpm-dev-common.c
create mode 100644 drivers/char/tpm/tpm-dev.h
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 8f07fcf..10e5827 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -3,7 +3,7 @@
#
obj-$(CONFIG_TCG_TPM) += tpm.o
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
- tpm1_eventlog.o tpm2_eventlog.o tpm2-space.o
+ tpm-dev-common.o tpm1_eventlog.o tpm2_eventlog.o tpm2-space.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
tpm-$(CONFIG_OF) += tpm_of.o
obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c
new file mode 100644
index 0000000..610638a
--- /dev/null
+++ b/drivers/char/tpm/tpm-dev-common.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Copyright (C) 2013 Obsidian Research Corp
+ * Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+ *
+ * Device file system interface to the TPM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include "tpm.h"
+#include "tpm-dev.h"
+
+static void user_reader_timeout(unsigned long ptr)
+{
+ struct file_priv *priv = (struct file_priv *)ptr;
+
+ pr_warn("TPM user space timeout is deprecated (pid=%d)\n",
+ task_tgid_nr(current));
+
+ schedule_work(&priv->work);
+}
+
+static void timeout_work(struct work_struct *work)
+{
+ struct file_priv *priv = container_of(work, struct file_priv, work);
+
+ mutex_lock(&priv->buffer_mutex);
+ atomic_set(&priv->data_pending, 0);
+ memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
+ mutex_unlock(&priv->buffer_mutex);
+}
+
+void tpm_common_open(struct file *file, struct tpm_chip *chip,
+ struct file_priv *priv)
+{
+ priv->chip = chip;
+ atomic_set(&priv->data_pending, 0);
+ mutex_init(&priv->buffer_mutex);
+ setup_timer(&priv->user_read_timer, user_reader_timeout,
+ (unsigned long)priv);
+ INIT_WORK(&priv->work, timeout_work);
+
+ file->private_data = priv;
+}
+
+ssize_t tpm_common_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
+{
+ struct file_priv *priv = file->private_data;
+ ssize_t ret_size;
+ ssize_t orig_ret_size;
+ int rc;
+
+ del_singleshot_timer_sync(&priv->user_read_timer);
+ flush_work(&priv->work);
+ ret_size = atomic_read(&priv->data_pending);
+ if (ret_size > 0) { /* relay data */
+ orig_ret_size = ret_size;
+ if (size < ret_size)
+ ret_size = size;
+
+ mutex_lock(&priv->buffer_mutex);
+ rc = copy_to_user(buf, priv->data_buffer, ret_size);
+ memset(priv->data_buffer, 0, orig_ret_size);
+ if (rc)
+ ret_size = -EFAULT;
+
+ mutex_unlock(&priv->buffer_mutex);
+ }
+
+ atomic_set(&priv->data_pending, 0);
+
+ return ret_size;
+}
+
+ssize_t tpm_common_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *off, struct tpm_space *space)
+{
+ struct file_priv *priv = file->private_data;
+ size_t in_size = size;
+ ssize_t out_size;
+
+ /* Cannot perform a write until the read has cleared either via
+ * tpm_read or a user_read_timer timeout. This also prevents split
+ * buffered writes from blocking here.
+ */
+ if (atomic_read(&priv->data_pending) != 0)
+ return -EBUSY;
+
+ if (in_size > TPM_BUFSIZE)
+ return -E2BIG;
+
+ mutex_lock(&priv->buffer_mutex);
+
+ if (copy_from_user
+ (priv->data_buffer, (void __user *) buf, in_size)) {
+ mutex_unlock(&priv->buffer_mutex);
+ return -EFAULT;
+ }
+
+ /* atomic tpm command send and result receive. We only hold the ops
+ * lock during this period so that the tpm can be unregistered even if
+ * the char dev is held open.
+ */
+ if (tpm_try_get_ops(priv->chip)) {
+ mutex_unlock(&priv->buffer_mutex);
+ return -EPIPE;
+ }
+ out_size = tpm_transmit(priv->chip, space, priv->data_buffer,
+ sizeof(priv->data_buffer), 0);
+
+ tpm_put_ops(priv->chip);
+ if (out_size < 0) {
+ mutex_unlock(&priv->buffer_mutex);
+ return out_size;
+ }
+
+ atomic_set(&priv->data_pending, out_size);
+ mutex_unlock(&priv->buffer_mutex);
+
+ /* Set a timeout by which the reader must come claim the result */
+ mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
+
+ return in_size;
+}
+
+/*
+ * Called on file close
+ */
+void tpm_common_release(struct file *file, struct file_priv *priv)
+{
+ del_singleshot_timer_sync(&priv->user_read_timer);
+ flush_work(&priv->work);
+ file->private_data = NULL;
+ atomic_set(&priv->data_pending, 0);
+}
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index 414553b..ebd74ab 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -18,48 +18,15 @@
*
*/
#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include "tpm.h"
-
-struct file_priv {
- struct tpm_chip *chip;
-
- /* Data passed to and from the tpm via the read/write calls */
- atomic_t data_pending;
- struct mutex buffer_mutex;
-
- struct timer_list user_read_timer; /* user needs to claim result */
- struct work_struct work;
-
- u8 data_buffer[TPM_BUFSIZE];
-};
-
-static void user_reader_timeout(unsigned long ptr)
-{
- struct file_priv *priv = (struct file_priv *)ptr;
-
- pr_warn("TPM user space timeout is deprecated (pid=%d)\n",
- task_tgid_nr(current));
-
- schedule_work(&priv->work);
-}
-
-static void timeout_work(struct work_struct *work)
-{
- struct file_priv *priv = container_of(work, struct file_priv, work);
-
- mutex_lock(&priv->buffer_mutex);
- atomic_set(&priv->data_pending, 0);
- memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
- mutex_unlock(&priv->buffer_mutex);
-}
+#include "tpm-dev.h"
static int tpm_open(struct inode *inode, struct file *file)
{
- struct tpm_chip *chip =
- container_of(inode->i_cdev, struct tpm_chip, cdev);
+ struct tpm_chip *chip;
struct file_priv *priv;
+ chip = container_of(inode->i_cdev, struct tpm_chip, cdev);
+
/* It's assured that the chip will be opened just once,
* by the check of is_open variable, which is protected
* by driver_lock. */
@@ -69,100 +36,22 @@ static int tpm_open(struct inode *inode, struct file *file)
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (priv == NULL) {
- clear_bit(0, &chip->is_open);
- return -ENOMEM;
- }
+ if (priv == NULL)
+ goto out;
- priv->chip = chip;
- atomic_set(&priv->data_pending, 0);
- mutex_init(&priv->buffer_mutex);
- setup_timer(&priv->user_read_timer, user_reader_timeout,
- (unsigned long)priv);
- INIT_WORK(&priv->work, timeout_work);
+ tpm_common_open(file, chip, priv);
- file->private_data = priv;
return 0;
-}
-
-static ssize_t tpm_read(struct file *file, char __user *buf,
- size_t size, loff_t *off)
-{
- struct file_priv *priv = file->private_data;
- ssize_t ret_size;
- int rc;
- del_singleshot_timer_sync(&priv->user_read_timer);
- flush_work(&priv->work);
- ret_size = atomic_read(&priv->data_pending);
- if (ret_size > 0) { /* relay data */
- ssize_t orig_ret_size = ret_size;
- if (size < ret_size)
- ret_size = size;
-
- mutex_lock(&priv->buffer_mutex);
- rc = copy_to_user(buf, priv->data_buffer, ret_size);
- memset(priv->data_buffer, 0, orig_ret_size);
- if (rc)
- ret_size = -EFAULT;
-
- mutex_unlock(&priv->buffer_mutex);
- }
-
- atomic_set(&priv->data_pending, 0);
-
- return ret_size;
+ out:
+ clear_bit(0, &chip->is_open);
+ return -ENOMEM;
}
static ssize_t tpm_write(struct file *file, const char __user *buf,
size_t size, loff_t *off)
{
- struct file_priv *priv = file->private_data;
- size_t in_size = size;
- ssize_t out_size;
-
- /* cannot perform a write until the read has cleared
- either via tpm_read or a user_read_timer timeout.
- This also prevents splitted buffered writes from blocking here.
- */
- if (atomic_read(&priv->data_pending) != 0)
- return -EBUSY;
-
- if (in_size > TPM_BUFSIZE)
- return -E2BIG;
-
- mutex_lock(&priv->buffer_mutex);
-
- if (copy_from_user
- (priv->data_buffer, (void __user *) buf, in_size)) {
- mutex_unlock(&priv->buffer_mutex);
- return -EFAULT;
- }
-
- /* atomic tpm command send and result receive. We only hold the ops
- * lock during this period so that the tpm can be unregistered even if
- * the char dev is held open.
- */
- if (tpm_try_get_ops(priv->chip)) {
- mutex_unlock(&priv->buffer_mutex);
- return -EPIPE;
- }
- out_size = tpm_transmit(priv->chip, NULL, priv->data_buffer,
- sizeof(priv->data_buffer), 0);
-
- tpm_put_ops(priv->chip);
- if (out_size < 0) {
- mutex_unlock(&priv->buffer_mutex);
- return out_size;
- }
-
- atomic_set(&priv->data_pending, out_size);
- mutex_unlock(&priv->buffer_mutex);
-
- /* Set a timeout by which the reader must come claim the result */
- mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
-
- return in_size;
+ return tpm_common_write(file, buf, size, off, NULL);
}
/*
@@ -172,12 +61,10 @@ static int tpm_release(struct inode *inode, struct file *file)
{
struct file_priv *priv = file->private_data;
- del_singleshot_timer_sync(&priv->user_read_timer);
- flush_work(&priv->work);
- file->private_data = NULL;
- atomic_set(&priv->data_pending, 0);
+ tpm_common_release(file, priv);
clear_bit(0, &priv->chip->is_open);
kfree(priv);
+
return 0;
}
@@ -185,9 +72,7 @@ const struct file_operations tpm_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
- .read = tpm_read,
+ .read = tpm_common_read,
.write = tpm_write,
.release = tpm_release,
};
-
-
diff --git a/drivers/char/tpm/tpm-dev.h b/drivers/char/tpm/tpm-dev.h
new file mode 100644
index 0000000..ff15cf7
--- /dev/null
+++ b/drivers/char/tpm/tpm-dev.h
@@ -0,0 +1,27 @@
+#ifndef _TPM_DEV_H
+#define _TPM_DEV_H
+
+#include "tpm.h"
+
+struct file_priv {
+ struct tpm_chip *chip;
+
+ /* Data passed to and from the tpm via the read/write calls */
+ atomic_t data_pending;
+ struct mutex buffer_mutex;
+
+ struct timer_list user_read_timer; /* user needs to claim result */
+ struct work_struct work;
+
+ u8 data_buffer[TPM_BUFSIZE];
+};
+
+void tpm_common_open(struct file *file, struct tpm_chip *chip,
+ struct file_priv *priv);
+ssize_t tpm_common_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off);
+ssize_t tpm_common_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *off, struct tpm_space *space);
+void tpm_common_release(struct file *file, struct file_priv *priv);
+
+#endif
--
2.9.3
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-06 22:10 +0100 |
| Message-ID | <ti83g-5wO-35@gated-at.bofh.it> |
| In reply to | #1592049 |
On Fri, Mar 03, 2017 at 05:19:01PM +0200, Jarkko Sakkinen wrote: > This patch set adds support for TPM spaces that provide an isolated > execution context for transient objects and HMAC and policy sessions. A > space is swapped into TPM volatile memory only when it is used and > swapped out after the use. > > There's a test script for trying out TPM spaces in > > git://git.infradead.org/users/jjs/tpm2-scripts.git > > A simple smoke test suite can be run by > > sudo python -m unittest -v tpm2_smoke.SpaceTest > > v3: > * Reverted back to /dev/tpmrm0 that was actually James' original > proposal. It's the most pragmatic choice as it cannot be mixed > with other TPM 2.0 and kernel idioms easily. > > v2: > * Substitute virtual handle in ContextSave. > * Substitute virtual handles in GetCapability. > * Validate that the real response length and the one reported in the > header match in tpm_transmit(). > > > James Bottomley (3): > tpm: split out tpm-dev.c into tpm-dev.c and tpm-common-dev.c > tpm: expose spaces via a device link /dev/tpmrm<n> > tpm2: add session handle context saving and restoring to the space > code > > Jarkko Sakkinen (4): > tpm: move length validation to tpm_transmit() > tpm: validate TPM 2.0 commands > tpm: export tpm2_flush_context_cmd > tpm: infrastructure for TPM spaces > > drivers/char/tpm/Makefile | 3 +- > drivers/char/tpm/tpm-chip.c | 71 ++++- > drivers/char/tpm/tpm-dev-common.c | 148 +++++++++++ > drivers/char/tpm/tpm-dev.c | 143 +--------- > drivers/char/tpm/tpm-dev.h | 27 ++ > drivers/char/tpm/tpm-interface.c | 131 +++++++--- > drivers/char/tpm/tpm-sysfs.c | 2 +- > drivers/char/tpm/tpm.h | 49 +++- > drivers/char/tpm/tpm2-cmd.c | 173 +++++++++---- > drivers/char/tpm/tpm2-space.c | 532 ++++++++++++++++++++++++++++++++++++++ > drivers/char/tpm/tpmrm-dev.c | 65 +++++ > 11 files changed, 1123 insertions(+), 221 deletions(-) > create mode 100644 drivers/char/tpm/tpm-dev-common.c > create mode 100644 drivers/char/tpm/tpm-dev.h > create mode 100644 drivers/char/tpm/tpm2-space.c > create mode 100644 drivers/char/tpm/tpmrm-dev.c > > -- > 2.9.3 > Should I put this available to linux-next? I would think it would make sense. I'm still looking forward to get more reviewed-by's and tested-by's but that way it might be easier to get those... /Jarkko
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2017-03-11 10:00 +0100 |
| Message-ID | <tjL2x-hd-5@gated-at.bofh.it> |
| In reply to | #1592049 |
On Fri, Mar 03, 2017 at 05:19:01PM +0200, Jarkko Sakkinen wrote: > This patch set adds support for TPM spaces that provide an isolated > execution context for transient objects and HMAC and policy sessions. A > space is swapped into TPM volatile memory only when it is used and > swapped out after the use. > > There's a test script for trying out TPM spaces in > > git://git.infradead.org/users/jjs/tpm2-scripts.git > > A simple smoke test suite can be run by > > sudo python -m unittest -v tpm2_smoke.SpaceTest > > v3: > * Reverted back to /dev/tpmrm0 that was actually James' original > proposal. It's the most pragmatic choice as it cannot be mixed > with other TPM 2.0 and kernel idioms easily. > > v2: > * Substitute virtual handle in ContextSave. > * Substitute virtual handles in GetCapability. > * Validate that the real response length and the one reported in the > header match in tpm_transmit(). > > > James Bottomley (3): > tpm: split out tpm-dev.c into tpm-dev.c and tpm-common-dev.c > tpm: expose spaces via a device link /dev/tpmrm<n> > tpm2: add session handle context saving and restoring to the space > code > > Jarkko Sakkinen (4): > tpm: move length validation to tpm_transmit() > tpm: validate TPM 2.0 commands > tpm: export tpm2_flush_context_cmd > tpm: infrastructure for TPM spaces > > drivers/char/tpm/Makefile | 3 +- > drivers/char/tpm/tpm-chip.c | 71 ++++- > drivers/char/tpm/tpm-dev-common.c | 148 +++++++++++ > drivers/char/tpm/tpm-dev.c | 143 +--------- > drivers/char/tpm/tpm-dev.h | 27 ++ > drivers/char/tpm/tpm-interface.c | 131 +++++++--- > drivers/char/tpm/tpm-sysfs.c | 2 +- > drivers/char/tpm/tpm.h | 49 +++- > drivers/char/tpm/tpm2-cmd.c | 173 +++++++++---- > drivers/char/tpm/tpm2-space.c | 532 ++++++++++++++++++++++++++++++++++++++ > drivers/char/tpm/tpmrm-dev.c | 65 +++++ > 11 files changed, 1123 insertions(+), 221 deletions(-) > create mode 100644 drivers/char/tpm/tpm-dev-common.c > create mode 100644 drivers/char/tpm/tpm-dev.h > create mode 100644 drivers/char/tpm/tpm2-space.c > create mode 100644 drivers/char/tpm/tpmrm-dev.c > > -- > 2.9.3 > These commits are now in my master and next branches. Tested-by's are still most welcome! /Jarkko
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web