Commit 5da10728 authored by James Morris's avatar James Morris

Merge tag 'tpmdd-next-20190213' of git://git.infradead.org/users/jjs/linux-tpmdd into next-tpm

tpmdd updates for Linux v5.1

From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>

Clean up the transmission flow
==============================

Cleaned up the whole transmission flow. Locking of the chip is now done in
the level of tpm_try_get_ops() and tpm_put_ops() instead taking the chip
lock inside tpm_transmit(). The nested calls inside tpm_transmit(), used
with the resource manager, have been refactored out.

Should make easier to perform more complex transactions with the TPM
without making the subsystem a bigger mess (e.g. encrypted channel patches
by James Bottomley).

PPI 1.3 support
===============

TPM PPI 1.3 introduces an additional optional command parameter that may be
needed for some commands. Display the parameter if the command requires
such a parameter. Only command 23 (SetPCRBanks) needs one.

The PPI request file will show output like this then:

   # echo "23 16" > request
   # cat request
   23 16

   # echo "5" > request
   # cat request
   5

Extend all PCR banks in IMA
===========================

Instead of static PCR banks array, the array of available PCR banks is now
allocated dynamically. The digests sizes are determined dynamically using a
probe PCR read without relying crypto's static list of hash algorithms.

This should finally make sealing of measurements in IMA safe and secure.

TPM 2.0 selftests
=================

Added a test suite to tools/testing/selftests/tpm2 previously outside of
the kernel tree: https://github.com/jsakkine-intel/tpm2-scripts.
parents e7a44cfd 50a81b60
...@@ -74,7 +74,7 @@ static const char* tcpa_pc_event_id_strings[] = { ...@@ -74,7 +74,7 @@ static const char* tcpa_pc_event_id_strings[] = {
/* returns pointer to start of pos. entry of tcg log */ /* returns pointer to start of pos. entry of tcg log */
static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos) static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
{ {
loff_t i; loff_t i = 0;
struct tpm_chip *chip = m->private; struct tpm_chip *chip = m->private;
struct tpm_bios_log *log = &chip->log; struct tpm_bios_log *log = &chip->log;
void *addr = log->bios_event_log; void *addr = log->bios_event_log;
...@@ -83,38 +83,29 @@ static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos) ...@@ -83,38 +83,29 @@ static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
u32 converted_event_size; u32 converted_event_size;
u32 converted_event_type; u32 converted_event_type;
/* read over *pos measurements */ /* read over *pos measurements */
for (i = 0; i < *pos; i++) { do {
event = addr; event = addr;
/* check if current entry is valid */
if (addr + sizeof(struct tcpa_event) > limit)
return NULL;
converted_event_size = converted_event_size =
do_endian_conversion(event->event_size); do_endian_conversion(event->event_size);
converted_event_type = converted_event_type =
do_endian_conversion(event->event_type); do_endian_conversion(event->event_type);
if ((addr + sizeof(struct tcpa_event)) < limit) { if (((converted_event_type == 0) && (converted_event_size == 0))
if ((converted_event_type == 0) && || ((addr + sizeof(struct tcpa_event) + converted_event_size)
(converted_event_size == 0)) > limit))
return NULL; return NULL;
addr += (sizeof(struct tcpa_event) +
converted_event_size);
}
}
/* now check if current entry is valid */
if ((addr + sizeof(struct tcpa_event)) >= limit)
return NULL;
event = addr;
converted_event_size = do_endian_conversion(event->event_size); if (i++ == *pos)
converted_event_type = do_endian_conversion(event->event_type); break;
if (((converted_event_type == 0) && (converted_event_size == 0)) addr += (sizeof(struct tcpa_event) + converted_event_size);
|| ((addr + sizeof(struct tcpa_event) + converted_event_size) } while (1);
>= limit))
return NULL;
return addr; return addr;
} }
...@@ -134,7 +125,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, ...@@ -134,7 +125,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
v += sizeof(struct tcpa_event) + converted_event_size; v += sizeof(struct tcpa_event) + converted_event_size;
/* now check if current entry is valid */ /* now check if current entry is valid */
if ((v + sizeof(struct tcpa_event)) >= limit) if ((v + sizeof(struct tcpa_event)) > limit)
return NULL; return NULL;
event = v; event = v;
...@@ -143,7 +134,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v, ...@@ -143,7 +134,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
converted_event_type = do_endian_conversion(event->event_type); converted_event_type = do_endian_conversion(event->event_type);
if (((converted_event_type == 0) && (converted_event_size == 0)) || if (((converted_event_type == 0) && (converted_event_size == 0)) ||
((v + sizeof(struct tcpa_event) + converted_event_size) >= limit)) ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
return NULL; return NULL;
(*pos)++; (*pos)++;
......
...@@ -37,10 +37,10 @@ ...@@ -37,10 +37,10 @@
* *
* Returns size of the event. If it is an invalid event, returns 0. * Returns size of the event. If it is an invalid event, returns 0.
*/ */
static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, static int calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
struct tcg_pcr_event *event_header) struct tcg_pcr_event *event_header)
{ {
struct tcg_efi_specid_event *efispecid; struct tcg_efi_specid_event_head *efispecid;
struct tcg_event_field *event_field; struct tcg_event_field *event_field;
void *marker; void *marker;
void *marker_start; void *marker_start;
...@@ -55,7 +55,7 @@ static int calc_tpm2_event_size(struct tcg_pcr_event2 *event, ...@@ -55,7 +55,7 @@ static int calc_tpm2_event_size(struct tcg_pcr_event2 *event,
marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type) marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
+ sizeof(event->count); + sizeof(event->count);
efispecid = (struct tcg_efi_specid_event *)event_header->event; efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
/* Check if event is malformed. */ /* Check if event is malformed. */
if (event->count > efispecid->num_algs) if (event->count > efispecid->num_algs)
...@@ -95,7 +95,7 @@ static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) ...@@ -95,7 +95,7 @@ static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
void *addr = log->bios_event_log; void *addr = log->bios_event_log;
void *limit = log->bios_event_log_end; void *limit = log->bios_event_log_end;
struct tcg_pcr_event *event_header; struct tcg_pcr_event *event_header;
struct tcg_pcr_event2 *event; struct tcg_pcr_event2_head *event;
size_t size; size_t size;
int i; int i;
...@@ -136,7 +136,7 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, ...@@ -136,7 +136,7 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
loff_t *pos) loff_t *pos)
{ {
struct tcg_pcr_event *event_header; struct tcg_pcr_event *event_header;
struct tcg_pcr_event2 *event; struct tcg_pcr_event2_head *event;
struct tpm_chip *chip = m->private; struct tpm_chip *chip = m->private;
struct tpm_bios_log *log = &chip->log; struct tpm_bios_log *log = &chip->log;
void *limit = log->bios_event_log_end; void *limit = log->bios_event_log_end;
...@@ -180,7 +180,7 @@ static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) ...@@ -180,7 +180,7 @@ static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
struct tpm_chip *chip = m->private; struct tpm_chip *chip = m->private;
struct tpm_bios_log *log = &chip->log; struct tpm_bios_log *log = &chip->log;
struct tcg_pcr_event *event_header = log->bios_event_log; struct tcg_pcr_event *event_header = log->bios_event_log;
struct tcg_pcr_event2 *event = v; struct tcg_pcr_event2_head *event = v;
void *temp_ptr; void *temp_ptr;
size_t size; size_t size;
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
struct st33zp24_i2c_phy { struct st33zp24_i2c_phy {
struct i2c_client *client; struct i2c_client *client;
u8 buf[TPM_BUFSIZE + 1]; u8 buf[ST33ZP24_BUFSIZE + 1];
int io_lpcpd; int io_lpcpd;
}; };
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
* some latency byte before the answer is available (max 15). * some latency byte before the answer is available (max 15).
* We have 2048 + 1024 + 15. * We have 2048 + 1024 + 15.
*/ */
#define ST33ZP24_SPI_BUFFER_SIZE (TPM_BUFSIZE + (TPM_BUFSIZE / 2) +\ #define ST33ZP24_SPI_BUFFER_SIZE (ST33ZP24_BUFSIZE + (ST33ZP24_BUFSIZE / 2) +\
MAX_SPI_LATENCY) MAX_SPI_LATENCY)
......
...@@ -436,7 +436,7 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, ...@@ -436,7 +436,7 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
goto out_err; goto out_err;
} }
return len; return 0;
out_err: out_err:
st33zp24_cancel(chip); st33zp24_cancel(chip);
release_locality(chip); release_locality(chip);
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
#ifndef __LOCAL_ST33ZP24_H__ #ifndef __LOCAL_ST33ZP24_H__
#define __LOCAL_ST33ZP24_H__ #define __LOCAL_ST33ZP24_H__
#define TPM_WRITE_DIRECTION 0x80 #define TPM_WRITE_DIRECTION 0x80
#define TPM_BUFSIZE 2048 #define ST33ZP24_BUFSIZE 2048
struct st33zp24_dev { struct st33zp24_dev {
struct tpm_chip *chip; struct tpm_chip *chip;
......
...@@ -37,6 +37,103 @@ struct class *tpm_class; ...@@ -37,6 +37,103 @@ struct class *tpm_class;
struct class *tpmrm_class; struct class *tpmrm_class;
dev_t tpm_devt; dev_t tpm_devt;
static int tpm_request_locality(struct tpm_chip *chip)
{
int rc;
if (!chip->ops->request_locality)
return 0;
rc = chip->ops->request_locality(chip, 0);
if (rc < 0)
return rc;
chip->locality = rc;
return 0;
}
static void tpm_relinquish_locality(struct tpm_chip *chip)
{
int rc;
if (!chip->ops->relinquish_locality)
return;
rc = chip->ops->relinquish_locality(chip, chip->locality);
if (rc)
dev_err(&chip->dev, "%s: : error %d\n", __func__, rc);
chip->locality = -1;
}
static int tpm_cmd_ready(struct tpm_chip *chip)
{
if (!chip->ops->cmd_ready)
return 0;
return chip->ops->cmd_ready(chip);
}
static int tpm_go_idle(struct tpm_chip *chip)
{
if (!chip->ops->go_idle)
return 0;
return chip->ops->go_idle(chip);
}
/**
* tpm_chip_start() - power on the TPM
* @chip: a TPM chip to use
*
* Return:
* * The response length - OK
* * -errno - A system error
*/
int tpm_chip_start(struct tpm_chip *chip)
{
int ret;
if (chip->ops->clk_enable)
chip->ops->clk_enable(chip, true);
if (chip->locality == -1) {
ret = tpm_request_locality(chip);
if (ret) {
chip->ops->clk_enable(chip, false);
return ret;
}
}
ret = tpm_cmd_ready(chip);
if (ret) {
tpm_relinquish_locality(chip);
if (chip->ops->clk_enable)
chip->ops->clk_enable(chip, false);
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(tpm_chip_start);
/**
* tpm_chip_stop() - power off the TPM
* @chip: a TPM chip to use
*
* Return:
* * The response length - OK
* * -errno - A system error
*/
void tpm_chip_stop(struct tpm_chip *chip)
{
tpm_go_idle(chip);
tpm_relinquish_locality(chip);
if (chip->ops->clk_enable)
chip->ops->clk_enable(chip, false);
}
EXPORT_SYMBOL_GPL(tpm_chip_stop);
/** /**
* tpm_try_get_ops() - Get a ref to the tpm_chip * tpm_try_get_ops() - Get a ref to the tpm_chip
* @chip: Chip to ref * @chip: Chip to ref
...@@ -56,10 +153,17 @@ int tpm_try_get_ops(struct tpm_chip *chip) ...@@ -56,10 +153,17 @@ int tpm_try_get_ops(struct tpm_chip *chip)
down_read(&chip->ops_sem); down_read(&chip->ops_sem);
if (!chip->ops) if (!chip->ops)
goto out_ops;
mutex_lock(&chip->tpm_mutex);
rc = tpm_chip_start(chip);
if (rc)
goto out_lock; goto out_lock;
return 0; return 0;
out_lock: out_lock:
mutex_unlock(&chip->tpm_mutex);
out_ops:
up_read(&chip->ops_sem); up_read(&chip->ops_sem);
put_device(&chip->dev); put_device(&chip->dev);
return rc; return rc;
...@@ -75,6 +179,8 @@ EXPORT_SYMBOL_GPL(tpm_try_get_ops); ...@@ -75,6 +179,8 @@ EXPORT_SYMBOL_GPL(tpm_try_get_ops);
*/ */
void tpm_put_ops(struct tpm_chip *chip) void tpm_put_ops(struct tpm_chip *chip)
{ {
tpm_chip_stop(chip);
mutex_unlock(&chip->tpm_mutex);
up_read(&chip->ops_sem); up_read(&chip->ops_sem);
put_device(&chip->dev); put_device(&chip->dev);
} }
...@@ -160,6 +266,7 @@ static void tpm_dev_release(struct device *dev) ...@@ -160,6 +266,7 @@ static void tpm_dev_release(struct device *dev)
kfree(chip->log.bios_event_log); kfree(chip->log.bios_event_log);
kfree(chip->work_space.context_buf); kfree(chip->work_space.context_buf);
kfree(chip->work_space.session_buf); kfree(chip->work_space.session_buf);
kfree(chip->allocated_banks);
kfree(chip); kfree(chip);
} }
...@@ -189,7 +296,10 @@ static int tpm_class_shutdown(struct device *dev) ...@@ -189,7 +296,10 @@ static int tpm_class_shutdown(struct device *dev)
if (chip->flags & TPM_CHIP_FLAG_TPM2) { if (chip->flags & TPM_CHIP_FLAG_TPM2) {
down_write(&chip->ops_sem); down_write(&chip->ops_sem);
tpm2_shutdown(chip, TPM2_SU_CLEAR); if (!tpm_chip_start(chip)) {
tpm2_shutdown(chip, TPM2_SU_CLEAR);
tpm_chip_stop(chip);
}
chip->ops = NULL; chip->ops = NULL;
up_write(&chip->ops_sem); up_write(&chip->ops_sem);
} }
...@@ -368,8 +478,12 @@ static void tpm_del_char_device(struct tpm_chip *chip) ...@@ -368,8 +478,12 @@ static void tpm_del_char_device(struct tpm_chip *chip)
/* Make the driver uncallable. */ /* Make the driver uncallable. */
down_write(&chip->ops_sem); down_write(&chip->ops_sem);
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2) {
tpm2_shutdown(chip, TPM2_SU_CLEAR); if (!tpm_chip_start(chip)) {
tpm2_shutdown(chip, TPM2_SU_CLEAR);
tpm_chip_stop(chip);
}
}
chip->ops = NULL; chip->ops = NULL;
up_write(&chip->ops_sem); up_write(&chip->ops_sem);
} }
...@@ -451,7 +565,11 @@ int tpm_chip_register(struct tpm_chip *chip) ...@@ -451,7 +565,11 @@ int tpm_chip_register(struct tpm_chip *chip)
{ {
int rc; int rc;
rc = tpm_chip_start(chip);
if (rc)
return rc;
rc = tpm_auto_startup(chip); rc = tpm_auto_startup(chip);
tpm_chip_stop(chip);
if (rc) if (rc)
return rc; return rc;
......
...@@ -27,7 +27,38 @@ ...@@ -27,7 +27,38 @@
static struct workqueue_struct *tpm_dev_wq; static struct workqueue_struct *tpm_dev_wq;
static DEFINE_MUTEX(tpm_dev_wq_lock); static DEFINE_MUTEX(tpm_dev_wq_lock);
static void tpm_async_work(struct work_struct *work) static ssize_t tpm_dev_transmit(struct tpm_chip *chip, struct tpm_space *space,
u8 *buf, size_t bufsiz)
{
struct tpm_header *header = (void *)buf;
ssize_t ret, len;
ret = tpm2_prepare_space(chip, space, buf, bufsiz);
/* If the command is not implemented by the TPM, synthesize a
* response with a TPM2_RC_COMMAND_CODE return for user-space.
*/
if (ret == -EOPNOTSUPP) {
header->length = cpu_to_be32(sizeof(*header));
header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE |
TSS2_RESMGR_TPM_RC_LAYER);
ret = sizeof(*header);
}
if (ret)
goto out_rc;
len = tpm_transmit(chip, buf, bufsiz);
if (len < 0)
ret = len;
if (!ret)
ret = tpm2_commit_space(chip, space, buf, &len);
out_rc:
return ret ? ret : len;
}
static void tpm_dev_async_work(struct work_struct *work)
{ {
struct file_priv *priv = struct file_priv *priv =
container_of(work, struct file_priv, async_work); container_of(work, struct file_priv, async_work);
...@@ -35,9 +66,8 @@ static void tpm_async_work(struct work_struct *work) ...@@ -35,9 +66,8 @@ static void tpm_async_work(struct work_struct *work)
mutex_lock(&priv->buffer_mutex); mutex_lock(&priv->buffer_mutex);
priv->command_enqueued = false; priv->command_enqueued = false;
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer, ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer), 0); sizeof(priv->data_buffer));
tpm_put_ops(priv->chip); tpm_put_ops(priv->chip);
if (ret > 0) { if (ret > 0) {
priv->response_length = ret; priv->response_length = ret;
...@@ -80,7 +110,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip, ...@@ -80,7 +110,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,
mutex_init(&priv->buffer_mutex); mutex_init(&priv->buffer_mutex);
timer_setup(&priv->user_read_timer, user_reader_timeout, 0); timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
INIT_WORK(&priv->timeout_work, tpm_timeout_work); INIT_WORK(&priv->timeout_work, tpm_timeout_work);
INIT_WORK(&priv->async_work, tpm_async_work); INIT_WORK(&priv->async_work, tpm_dev_async_work);
init_waitqueue_head(&priv->async_wait); init_waitqueue_head(&priv->async_wait);
file->private_data = priv; file->private_data = priv;
} }
...@@ -183,8 +213,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, ...@@ -183,8 +213,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
return size; return size;
} }
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer, ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer), 0); sizeof(priv->data_buffer));
tpm_put_ops(priv->chip); tpm_put_ops(priv->chip);
if (ret > 0) { if (ret > 0) {
......
This diff is collapsed.
...@@ -39,7 +39,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, ...@@ -39,7 +39,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
{ {
struct tpm_buf tpm_buf; struct tpm_buf tpm_buf;
struct tpm_readpubek_out *out; struct tpm_readpubek_out *out;
ssize_t rc;
int i; int i;
char *str = buf; char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
...@@ -47,19 +46,17 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, ...@@ -47,19 +46,17 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
memset(&anti_replay, 0, sizeof(anti_replay)); memset(&anti_replay, 0, sizeof(anti_replay));
rc = tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK); if (tpm_try_get_ops(chip))
if (rc) return 0;
return rc;
if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
goto out_ops;
tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay)); tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
rc = tpm_transmit_cmd(chip, NULL, tpm_buf.data, PAGE_SIZE, if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0, "attempting to read the PUBEK"))
"attempting to read the PUBEK"); goto out_buf;
if (rc) {
tpm_buf_destroy(&tpm_buf);
return 0;
}
out = (struct tpm_readpubek_out *)&tpm_buf.data[10]; out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
str += str +=
...@@ -90,9 +87,11 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, ...@@ -90,9 +87,11 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
str += sprintf(str, "\n"); str += sprintf(str, "\n");
} }
rc = str - buf; out_buf:
tpm_buf_destroy(&tpm_buf); tpm_buf_destroy(&tpm_buf);
return rc; out_ops:
tpm_put_ops(chip);
return str - buf;
} }
static DEVICE_ATTR_RO(pubek); static DEVICE_ATTR_RO(pubek);
...@@ -101,27 +100,32 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, ...@@ -101,27 +100,32 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
{ {
cap_t cap; cap_t cap;
u8 digest[TPM_DIGEST_SIZE]; u8 digest[TPM_DIGEST_SIZE];
ssize_t rc;
u32 i, j, num_pcrs; u32 i, j, num_pcrs;
char *str = buf; char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
rc = tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap, if (tpm_try_get_ops(chip))
"attempting to determine the number of PCRS",
sizeof(cap.num_pcrs));
if (rc)
return 0; return 0;
if (tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap,
"attempting to determine the number of PCRS",
sizeof(cap.num_pcrs))) {
tpm_put_ops(chip);
return 0;
}
num_pcrs = be32_to_cpu(cap.num_pcrs); num_pcrs = be32_to_cpu(cap.num_pcrs);
for (i = 0; i < num_pcrs; i++) { for (i = 0; i < num_pcrs; i++) {
rc = tpm1_pcr_read(chip, i, digest); if (tpm1_pcr_read(chip, i, digest)) {
if (rc) str = buf;
break; break;
}
str += sprintf(str, "PCR-%02d: ", i); str += sprintf(str, "PCR-%02d: ", i);
for (j = 0; j < TPM_DIGEST_SIZE; j++) for (j = 0; j < TPM_DIGEST_SIZE; j++)
str += sprintf(str, "%02X ", digest[j]); str += sprintf(str, "%02X ", digest[j]);
str += sprintf(str, "\n"); str += sprintf(str, "\n");
} }
tpm_put_ops(chip);
return str - buf; return str - buf;
} }
static DEVICE_ATTR_RO(pcrs); static DEVICE_ATTR_RO(pcrs);
...@@ -129,16 +133,21 @@ static DEVICE_ATTR_RO(pcrs); ...@@ -129,16 +133,21 @@ static DEVICE_ATTR_RO(pcrs);
static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap; cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, if (tpm_try_get_ops(chip))
"attempting to determine the permanent enabled state",
sizeof(cap.perm_flags));
if (rc)
return 0; return 0;
if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent enabled state",
sizeof(cap.perm_flags)))
goto out_ops;
rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
out_ops:
tpm_put_ops(chip);
return rc; return rc;
} }
static DEVICE_ATTR_RO(enabled); static DEVICE_ATTR_RO(enabled);
...@@ -146,16 +155,21 @@ static DEVICE_ATTR_RO(enabled); ...@@ -146,16 +155,21 @@ static DEVICE_ATTR_RO(enabled);
static ssize_t active_show(struct device *dev, struct device_attribute *attr, static ssize_t active_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap; cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, if (tpm_try_get_ops(chip))
"attempting to determine the permanent active state",
sizeof(cap.perm_flags));
if (rc)
return 0; return 0;
if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent active state",
sizeof(cap.perm_flags)))
goto out_ops;
rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
out_ops:
tpm_put_ops(chip);
return rc; return rc;
} }
static DEVICE_ATTR_RO(active); static DEVICE_ATTR_RO(active);
...@@ -163,16 +177,21 @@ static DEVICE_ATTR_RO(active); ...@@ -163,16 +177,21 @@ static DEVICE_ATTR_RO(active);
static ssize_t owned_show(struct device *dev, struct device_attribute *attr, static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap; cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, if (tpm_try_get_ops(chip))
"attempting to determine the owner state",
sizeof(cap.owned));
if (rc)
return 0; return 0;
if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
"attempting to determine the owner state",
sizeof(cap.owned)))
goto out_ops;
rc = sprintf(buf, "%d\n", cap.owned); rc = sprintf(buf, "%d\n", cap.owned);
out_ops:
tpm_put_ops(chip);
return rc; return rc;
} }
static DEVICE_ATTR_RO(owned); static DEVICE_ATTR_RO(owned);
...@@ -180,16 +199,21 @@ static DEVICE_ATTR_RO(owned); ...@@ -180,16 +199,21 @@ static DEVICE_ATTR_RO(owned);
static ssize_t temp_deactivated_show(struct device *dev, static ssize_t temp_deactivated_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap; cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, if (tpm_try_get_ops(chip))
"attempting to determine the temporary state",
sizeof(cap.stclear_flags));
if (rc)
return 0; return 0;
if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
"attempting to determine the temporary state",
sizeof(cap.stclear_flags)))
goto out_ops;
rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
out_ops:
tpm_put_ops(chip);
return rc; return rc;
} }
static DEVICE_ATTR_RO(temp_deactivated); static DEVICE_ATTR_RO(temp_deactivated);
...@@ -198,15 +222,18 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -198,15 +222,18 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
cap_t cap; ssize_t rc = 0;
ssize_t rc;
char *str = buf; char *str = buf;
cap_t cap;
rc = tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, if (tpm_try_get_ops(chip))
"attempting to determine the manufacturer",
sizeof(cap.manufacturer_id));
if (rc)
return 0; return 0;
if (tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
"attempting to determine the manufacturer",
sizeof(cap.manufacturer_id)))
goto out_ops;
str += sprintf(str, "Manufacturer: 0x%x\n", str += sprintf(str, "Manufacturer: 0x%x\n",
be32_to_cpu(cap.manufacturer_id)); be32_to_cpu(cap.manufacturer_id));
...@@ -223,11 +250,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -223,11 +250,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
cap.tpm_version_1_2.revMinor); cap.tpm_version_1_2.revMinor);
} else { } else {
/* Otherwise just use TPM_STRUCT_VER */ /* Otherwise just use TPM_STRUCT_VER */
rc = tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap, if (tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
"attempting to determine the 1.1 version", "attempting to determine the 1.1 version",
sizeof(cap.tpm_version)); sizeof(cap.tpm_version)))
if (rc) goto out_ops;
return 0;
str += sprintf(str, str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n", "TCG version: %d.%d\nFirmware version: %d.%d\n",
cap.tpm_version.Major, cap.tpm_version.Major,
...@@ -235,8 +261,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -235,8 +261,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
cap.tpm_version.revMajor, cap.tpm_version.revMajor,
cap.tpm_version.revMinor); cap.tpm_version.revMinor);
} }
rc = str - buf;
return str - buf; out_ops:
tpm_put_ops(chip);
return rc;
} }
static DEVICE_ATTR_RO(caps); static DEVICE_ATTR_RO(caps);
...@@ -244,10 +272,12 @@ static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, ...@@ -244,10 +272,12 @@ static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
if (chip == NULL)
if (tpm_try_get_ops(chip))
return 0; return 0;
chip->ops->cancel(chip); chip->ops->cancel(chip);
tpm_put_ops(chip);
return count; return count;
} }
static DEVICE_ATTR_WO(cancel); static DEVICE_ATTR_WO(cancel);
......
...@@ -25,30 +25,22 @@ ...@@ -25,30 +25,22 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fs.h>
#include <linux/hw_random.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/tpm.h> #include <linux/tpm.h>
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/tpm_eventlog.h> #include <linux/tpm_eventlog.h>
#include <crypto/hash_info.h>
#ifdef CONFIG_X86 #ifdef CONFIG_X86
#include <asm/intel-family.h> #include <asm/intel-family.h>
#endif #endif
enum tpm_const { #define TPM_MINOR 224 /* officially assigned */
TPM_MINOR = 224, /* officially assigned */ #define TPM_BUFSIZE 4096
TPM_BUFSIZE = 4096, #define TPM_NUM_DEVICES 65536
TPM_NUM_DEVICES = 65536, #define TPM_RETRY 50
TPM_RETRY = 50, /* 5 seconds */
TPM_NUM_EVENT_LOG_FILES = 3,
};
enum tpm_timeout { enum tpm_timeout {
TPM_TIMEOUT = 5, /* msecs */ TPM_TIMEOUT = 5, /* msecs */
...@@ -65,16 +57,6 @@ enum tpm_addr { ...@@ -65,16 +57,6 @@ enum tpm_addr {
TPM_ADDR = 0x4E, TPM_ADDR = 0x4E,
}; };
/* Indexes the duration array */
enum tpm_duration {
TPM_SHORT = 0,
TPM_MEDIUM = 1,
TPM_LONG = 2,
TPM_LONG_LONG = 3,
TPM_UNDEFINED,
TPM_NUM_DURATIONS = TPM_UNDEFINED,
};
#define TPM_WARN_RETRY 0x800 #define TPM_WARN_RETRY 0x800
#define TPM_WARN_DOING_SELFTEST 0x802 #define TPM_WARN_DOING_SELFTEST 0x802
#define TPM_ERR_DEACTIVATED 0x6 #define TPM_ERR_DEACTIVATED 0x6
...@@ -122,17 +104,6 @@ enum tpm2_return_codes { ...@@ -122,17 +104,6 @@ enum tpm2_return_codes {
TPM2_RC_RETRY = 0x0922, TPM2_RC_RETRY = 0x0922,
}; };
enum tpm2_algorithms {
TPM2_ALG_ERROR = 0x0000,
TPM2_ALG_SHA1 = 0x0004,
TPM2_ALG_KEYEDHASH = 0x0008,
TPM2_ALG_SHA256 = 0x000B,
TPM2_ALG_SHA384 = 0x000C,
TPM2_ALG_SHA512 = 0x000D,
TPM2_ALG_NULL = 0x0010,
TPM2_ALG_SM3_256 = 0x0012,
};
enum tpm2_command_codes { enum tpm2_command_codes {
TPM2_CC_FIRST = 0x011F, TPM2_CC_FIRST = 0x011F,
TPM2_CC_HIERARCHY_CONTROL = 0x0121, TPM2_CC_HIERARCHY_CONTROL = 0x0121,
...@@ -190,15 +161,6 @@ enum tpm2_cc_attrs { ...@@ -190,15 +161,6 @@ enum tpm2_cc_attrs {
#define TPM_VID_WINBOND 0x1050 #define TPM_VID_WINBOND 0x1050
#define TPM_VID_STM 0x104A #define TPM_VID_STM 0x104A
#define TPM_PPI_VERSION_LEN 3
struct tpm_space {
u32 context_tbl[3];
u8 *context_buf;
u32 session_tbl[3];
u8 *session_buf;
};
enum tpm_chip_flags { enum tpm_chip_flags {
TPM_CHIP_FLAG_TPM2 = BIT(1), TPM_CHIP_FLAG_TPM2 = BIT(1),
TPM_CHIP_FLAG_IRQ = BIT(2), TPM_CHIP_FLAG_IRQ = BIT(2),
...@@ -207,82 +169,15 @@ enum tpm_chip_flags { ...@@ -207,82 +169,15 @@ enum tpm_chip_flags {
TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
}; };
struct tpm_bios_log {
void *bios_event_log;
void *bios_event_log_end;
};
struct tpm_chip_seqops {
struct tpm_chip *chip;
const struct seq_operations *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
* when the driver is unregistered, see tpm_try_get_ops.
*/
struct rw_semaphore ops_sem;
const struct tpm_class_ops *ops;
struct tpm_bios_log log;
struct tpm_chip_seqops bin_log_seqops;
struct tpm_chip_seqops ascii_log_seqops;
unsigned int flags;
int dev_num; /* /dev/tpm# */
unsigned long is_open; /* only one allowed */
char hwrng_name[64];
struct hwrng hwrng;
struct mutex tpm_mutex; /* tpm is processing */
unsigned long timeout_a; /* jiffies */
unsigned long timeout_b; /* jiffies */
unsigned long timeout_c; /* jiffies */
unsigned long timeout_d; /* jiffies */
bool timeout_adjusted;
unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */
bool duration_adjusted;
struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES];
const struct attribute_group *groups[3];
unsigned int groups_cnt;
u16 active_banks[7];
#ifdef CONFIG_ACPI
acpi_handle acpi_dev_handle;
char ppi_version[TPM_PPI_VERSION_LEN + 1];
#endif /* CONFIG_ACPI */
struct tpm_space work_space;
u32 nr_commands;
u32 *cc_attrs_tbl;
/* active locality */
int locality;
};
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
struct tpm_input_header { struct tpm_header {
__be16 tag; __be16 tag;
__be32 length; __be32 length;
__be32 ordinal; union {
} __packed; __be32 ordinal;
__be32 return_code;
struct tpm_output_header { };
__be16 tag;
__be32 length;
__be32 return_code;
} __packed; } __packed;
#define TPM_TAG_RQU_COMMAND 193 #define TPM_TAG_RQU_COMMAND 193
...@@ -401,8 +296,8 @@ struct tpm_buf { ...@@ -401,8 +296,8 @@ struct tpm_buf {
static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal) static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
{ {
struct tpm_input_header *head; struct tpm_header *head = (struct tpm_header *)buf->data;
head = (struct tpm_input_header *)buf->data;
head->tag = cpu_to_be16(tag); head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head)); head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal); head->ordinal = cpu_to_be32(ordinal);
...@@ -428,14 +323,14 @@ static inline void tpm_buf_destroy(struct tpm_buf *buf) ...@@ -428,14 +323,14 @@ static inline void tpm_buf_destroy(struct tpm_buf *buf)
static inline u32 tpm_buf_length(struct tpm_buf *buf) static inline u32 tpm_buf_length(struct tpm_buf *buf)
{ {
struct tpm_input_header *head = (struct tpm_input_header *) buf->data; struct tpm_header *head = (struct tpm_header *)buf->data;
return be32_to_cpu(head->length); return be32_to_cpu(head->length);
} }
static inline u16 tpm_buf_tag(struct tpm_buf *buf) static inline u16 tpm_buf_tag(struct tpm_buf *buf)
{ {
struct tpm_input_header *head = (struct tpm_input_header *) buf->data; struct tpm_header *head = (struct tpm_header *)buf->data;
return be16_to_cpu(head->tag); return be16_to_cpu(head->tag);
} }
...@@ -444,7 +339,7 @@ static inline void tpm_buf_append(struct tpm_buf *buf, ...@@ -444,7 +339,7 @@ static inline void tpm_buf_append(struct tpm_buf *buf,
const unsigned char *new_data, const unsigned char *new_data,
unsigned int new_len) unsigned int new_len)
{ {
struct tpm_input_header *head = (struct tpm_input_header *) buf->data; struct tpm_header *head = (struct tpm_header *)buf->data;
u32 len = tpm_buf_length(buf); u32 len = tpm_buf_length(buf);
/* Return silently if overflow has already happened. */ /* Return silently if overflow has already happened. */
...@@ -487,25 +382,9 @@ extern const struct file_operations tpm_fops; ...@@ -487,25 +382,9 @@ extern const struct file_operations tpm_fops;
extern const struct file_operations tpmrm_fops; extern const struct file_operations tpmrm_fops;
extern struct idr dev_nums_idr; extern struct idr dev_nums_idr;
/** ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz);
* enum tpm_transmit_flags - flags for tpm_transmit() ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
* size_t min_rsp_body_length, const char *desc);
* @TPM_TRANSMIT_UNLOCKED: do not lock the chip
* @TPM_TRANSMIT_NESTED: discard setup steps (power management,
* locality) including locking (i.e. implicit
* UNLOCKED)
*/
enum tpm_transmit_flags {
TPM_TRANSMIT_UNLOCKED = BIT(0),
TPM_TRANSMIT_NESTED = BIT(1),
};
ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
u8 *buf, size_t bufsiz, unsigned int flags);
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
void *buf, size_t bufsiz,
size_t min_rsp_body_length, unsigned int flags,
const char *desc);
int tpm_get_timeouts(struct tpm_chip *); int tpm_get_timeouts(struct tpm_chip *);
int tpm_auto_startup(struct tpm_chip *chip); int tpm_auto_startup(struct tpm_chip *chip);
...@@ -530,6 +409,8 @@ static inline void tpm_msleep(unsigned int delay_msec) ...@@ -530,6 +409,8 @@ static inline void tpm_msleep(unsigned int delay_msec)
delay_msec * 1000); delay_msec * 1000);
}; };
int tpm_chip_start(struct tpm_chip *chip);
void tpm_chip_stop(struct tpm_chip *chip);
struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip); struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
__must_check int tpm_try_get_ops(struct tpm_chip *chip); __must_check int tpm_try_get_ops(struct tpm_chip *chip);
void tpm_put_ops(struct tpm_chip *chip); void tpm_put_ops(struct tpm_chip *chip);
...@@ -558,12 +439,12 @@ static inline u32 tpm2_rc_value(u32 rc) ...@@ -558,12 +439,12 @@ static inline u32 tpm2_rc_value(u32 rc)
} }
int tpm2_get_timeouts(struct tpm_chip *chip); int tpm2_get_timeouts(struct tpm_chip *chip);
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf); int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count, struct tpm_digest *digest, u16 *digest_size_ptr);
struct tpm2_digest *digests); int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests);
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max); int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max);
void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, void tpm2_flush_context(struct tpm_chip *chip, u32 handle);
unsigned int flags);
int tpm2_seal_trusted(struct tpm_chip *chip, int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload, struct trusted_key_payload *payload,
struct trusted_key_options *options); struct trusted_key_options *options);
...@@ -580,10 +461,11 @@ int tpm2_probe(struct tpm_chip *chip); ...@@ -580,10 +461,11 @@ int tpm2_probe(struct tpm_chip *chip);
int tpm2_find_cc(struct tpm_chip *chip, u32 cc); int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
int tpm2_init_space(struct tpm_space *space); int tpm2_init_space(struct tpm_space *space);
void tpm2_del_space(struct tpm_chip *chip, 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, void tpm2_flush_space(struct tpm_chip *chip);
u8 *cmd); int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, size_t cmdsiz);
u32 cc, u8 *buf, size_t *bufsiz); int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf,
size_t *bufsiz);
int tpm_bios_log_setup(struct tpm_chip *chip); int tpm_bios_log_setup(struct tpm_chip *chip);
void tpm_bios_log_teardown(struct tpm_chip *chip); void tpm_bios_log_teardown(struct tpm_chip *chip);
......
...@@ -334,11 +334,8 @@ static int tpm1_startup(struct tpm_chip *chip) ...@@ -334,11 +334,8 @@ static int tpm1_startup(struct tpm_chip *chip)
tpm_buf_append_u16(&buf, TPM_ST_CLEAR); tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
"attempting to start the TPM");
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
return rc; return rc;
} }
...@@ -380,8 +377,7 @@ int tpm1_get_timeouts(struct tpm_chip *chip) ...@@ -380,8 +377,7 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
* of misreporting. * of misreporting.
*/ */
if (chip->ops->update_timeouts) if (chip->ops->update_timeouts)
chip->timeout_adjusted = chip->ops->update_timeouts(chip, timeout_eff);
chip->ops->update_timeouts(chip, timeout_eff);
if (!chip->timeout_adjusted) { if (!chip->timeout_adjusted) {
/* Restore default if chip reported 0 */ /* Restore default if chip reported 0 */
...@@ -462,9 +458,7 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash, ...@@ -462,9 +458,7 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
tpm_buf_append_u32(&buf, pcr_idx); tpm_buf_append_u32(&buf, pcr_idx);
tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE); tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
TPM_DIGEST_SIZE, 0, log_msg);
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
return rc; return rc;
} }
...@@ -494,11 +488,9 @@ ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, ...@@ -494,11 +488,9 @@ ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
tpm_buf_append_u32(&buf, 4); tpm_buf_append_u32(&buf, 4);
tpm_buf_append_u32(&buf, subcap_id); tpm_buf_append_u32(&buf, subcap_id);
} }
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
min_cap_length, 0, desc);
if (!rc) if (!rc)
*cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4]; *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
return rc; return rc;
} }
...@@ -537,8 +529,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max) ...@@ -537,8 +529,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
do { do {
tpm_buf_append_u32(&buf, num_bytes); tpm_buf_append_u32(&buf, num_bytes);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
sizeof(out->rng_data_len), 0,
"attempting get random"); "attempting get random");
if (rc) if (rc)
goto out; goto out;
...@@ -583,8 +574,7 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) ...@@ -583,8 +574,7 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
tpm_buf_append_u32(&buf, pcr_idx); tpm_buf_append_u32(&buf, pcr_idx);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
TPM_DIGEST_SIZE, 0,
"attempting to read a pcr value"); "attempting to read a pcr value");
if (rc) if (rc)
goto out; goto out;
...@@ -618,11 +608,8 @@ static int tpm1_continue_selftest(struct tpm_chip *chip) ...@@ -618,11 +608,8 @@ static int tpm1_continue_selftest(struct tpm_chip *chip)
if (rc) if (rc)
return rc; return rc;
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
0, 0, "continue selftest");
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
return rc; return rc;
} }
...@@ -709,6 +696,18 @@ int tpm1_auto_startup(struct tpm_chip *chip) ...@@ -709,6 +696,18 @@ int tpm1_auto_startup(struct tpm_chip *chip)
goto out; goto out;
} }
chip->allocated_banks = kcalloc(1, sizeof(*chip->allocated_banks),
GFP_KERNEL);
if (!chip->allocated_banks) {
rc = -ENOMEM;
goto out;
}
chip->allocated_banks[0].alg_id = TPM_ALG_SHA1;
chip->allocated_banks[0].digest_size = hash_digest_size[HASH_ALGO_SHA1];
chip->allocated_banks[0].crypto_id = HASH_ALGO_SHA1;
chip->nr_allocated_banks = 1;
return rc; return rc;
out: out:
if (rc > 0) if (rc > 0)
...@@ -747,9 +746,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr) ...@@ -747,9 +746,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
return rc; return rc;
/* now do the actual savestate */ /* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) { for (try = 0; try < TPM_RETRY; try++) {
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
0, 0, NULL);
/* /*
* If the TPM indicates that it is too busy to respond to * If the TPM indicates that it is too busy to respond to
* this command then retry before giving up. It can take * this command then retry before giving up. It can take
......
This diff is collapsed.
...@@ -38,8 +38,7 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) ...@@ -38,8 +38,7 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
if (space->session_tbl[i]) if (space->session_tbl[i])
tpm2_flush_context_cmd(chip, space->session_tbl[i], tpm2_flush_context(chip, space->session_tbl[i]);
TPM_TRANSMIT_NESTED);
} }
} }
...@@ -61,7 +60,10 @@ int tpm2_init_space(struct tpm_space *space) ...@@ -61,7 +60,10 @@ int tpm2_init_space(struct tpm_space *space)
void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space) void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
{ {
mutex_lock(&chip->tpm_mutex); mutex_lock(&chip->tpm_mutex);
tpm2_flush_sessions(chip, space); if (!tpm_chip_start(chip)) {
tpm2_flush_sessions(chip, space);
tpm_chip_stop(chip);
}
mutex_unlock(&chip->tpm_mutex); mutex_unlock(&chip->tpm_mutex);
kfree(space->context_buf); kfree(space->context_buf);
kfree(space->session_buf); kfree(space->session_buf);
...@@ -83,8 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, ...@@ -83,8 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size); body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
tpm_buf_append(&tbuf, &buf[*offset], body_size); tpm_buf_append(&tbuf, &buf[*offset], body_size);
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
TPM_TRANSMIT_NESTED, NULL);
if (rc < 0) { if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n", dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc); __func__, rc);
...@@ -132,8 +133,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, ...@@ -132,8 +133,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
tpm_buf_append_u32(&tbuf, handle); tpm_buf_append_u32(&tbuf, handle);
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0, rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
TPM_TRANSMIT_NESTED, NULL);
if (rc < 0) { if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n", dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc); __func__, rc);
...@@ -162,15 +162,14 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, ...@@ -162,15 +162,14 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
return 0; return 0;
} }
static void tpm2_flush_space(struct tpm_chip *chip) void tpm2_flush_space(struct tpm_chip *chip)
{ {
struct tpm_space *space = &chip->work_space; struct tpm_space *space = &chip->work_space;
int i; int i;
for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
if (space->context_tbl[i] && ~space->context_tbl[i]) if (space->context_tbl[i] && ~space->context_tbl[i])
tpm2_flush_context_cmd(chip, space->context_tbl[i], tpm2_flush_context(chip, space->context_tbl[i]);
TPM_TRANSMIT_NESTED);
tpm2_flush_sessions(chip, space); tpm2_flush_sessions(chip, space);
} }
...@@ -264,14 +263,54 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd) ...@@ -264,14 +263,54 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
return 0; return 0;
} }
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, static int tpm_find_and_validate_cc(struct tpm_chip *chip,
u8 *cmd) struct tpm_space *space,
const void *cmd, size_t len)
{
const struct tpm_header *header = (const void *)cmd;
int i;
u32 cc;
u32 attrs;
unsigned int nr_handles;
if (len < TPM_HEADER_SIZE || !chip->nr_commands)
return -EINVAL;
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 -EOPNOTSUPP;
}
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 cc;
err_len:
dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__,
len);
return -EINVAL;
}
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
size_t cmdsiz)
{ {
int rc; int rc;
int cc;
if (!space) if (!space)
return 0; return 0;
cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz);
if (cc < 0)
return cc;
memcpy(&chip->work_space.context_tbl, &space->context_tbl, memcpy(&chip->work_space.context_tbl, &space->context_tbl,
sizeof(space->context_tbl)); sizeof(space->context_tbl));
memcpy(&chip->work_space.session_tbl, &space->session_tbl, memcpy(&chip->work_space.session_tbl, &space->session_tbl,
...@@ -291,6 +330,7 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc, ...@@ -291,6 +330,7 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
return rc; return rc;
} }
chip->last_cc = cc;
return 0; return 0;
} }
...@@ -334,7 +374,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, ...@@ -334,7 +374,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
size_t len) size_t len)
{ {
struct tpm_space *space = &chip->work_space; struct tpm_space *space = &chip->work_space;
struct tpm_output_header *header = (void *)rsp; struct tpm_header *header = (struct tpm_header *)rsp;
u32 phandle; u32 phandle;
u32 phandle_type; u32 phandle_type;
u32 vhandle; u32 vhandle;
...@@ -377,7 +417,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, ...@@ -377,7 +417,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
return 0; return 0;
out_no_slots: out_no_slots:
tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_NESTED); tpm2_flush_context(chip, phandle);
dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
phandle); phandle);
return -ENOMEM; return -ENOMEM;
...@@ -394,7 +434,7 @@ static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp, ...@@ -394,7 +434,7 @@ static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
size_t len) size_t len)
{ {
struct tpm_space *space = &chip->work_space; struct tpm_space *space = &chip->work_space;
struct tpm_output_header *header = (void *)rsp; struct tpm_header *header = (struct tpm_header *)rsp;
struct tpm2_cap_handles *data; struct tpm2_cap_handles *data;
u32 phandle; u32 phandle;
u32 phandle_type; u32 phandle_type;
...@@ -464,8 +504,7 @@ static int tpm2_save_space(struct tpm_chip *chip) ...@@ -464,8 +504,7 @@ static int tpm2_save_space(struct tpm_chip *chip)
} else if (rc) } else if (rc)
return rc; return rc;
tpm2_flush_context_cmd(chip, space->context_tbl[i], tpm2_flush_context(chip, space->context_tbl[i]);
TPM_TRANSMIT_NESTED);
space->context_tbl[i] = ~0; space->context_tbl[i] = ~0;
} }
...@@ -490,30 +529,30 @@ static int tpm2_save_space(struct tpm_chip *chip) ...@@ -490,30 +529,30 @@ static int tpm2_save_space(struct tpm_chip *chip)
} }
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
u32 cc, u8 *buf, size_t *bufsiz) void *buf, size_t *bufsiz)
{ {
struct tpm_output_header *header = (void *)buf; struct tpm_header *header = buf;
int rc; int rc;
if (!space) if (!space)
return 0; return 0;
rc = tpm2_map_response_header(chip, cc, buf, *bufsiz); rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
if (rc) { if (rc) {
tpm2_flush_space(chip); tpm2_flush_space(chip);
return rc; goto out;
} }
rc = tpm2_map_response_body(chip, cc, buf, *bufsiz); rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz);
if (rc) { if (rc) {
tpm2_flush_space(chip); tpm2_flush_space(chip);
return rc; goto out;
} }
rc = tpm2_save_space(chip); rc = tpm2_save_space(chip);
if (rc) { if (rc) {
tpm2_flush_space(chip); tpm2_flush_space(chip);
return rc; goto out;
} }
*bufsiz = be32_to_cpu(header->length); *bufsiz = be32_to_cpu(header->length);
...@@ -526,4 +565,7 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, ...@@ -526,4 +565,7 @@ int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE); memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE);
return 0; return 0;
out:
dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
return rc;
} }
...@@ -105,7 +105,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -105,7 +105,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
iowrite8(buf[i], priv->iobase); iowrite8(buf[i], priv->iobase);
} }
return count; return 0;
} }
static void tpm_atml_cancel(struct tpm_chip *chip) static void tpm_atml_cancel(struct tpm_chip *chip)
......
...@@ -287,19 +287,29 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -287,19 +287,29 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
struct crb_priv *priv = dev_get_drvdata(&chip->dev); struct crb_priv *priv = dev_get_drvdata(&chip->dev);
unsigned int expected; unsigned int expected;
/* sanity check */ /* A sanity check that the upper layer wants to get at least the header
if (count < 6) * as that is the minimum size for any TPM response.
*/
if (count < TPM_HEADER_SIZE)
return -EIO; return -EIO;
/* If this bit is set, according to the spec, the TPM is in
* unrecoverable condition.
*/
if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR) if (ioread32(&priv->regs_t->ctrl_sts) & CRB_CTRL_STS_ERROR)
return -EIO; return -EIO;
memcpy_fromio(buf, priv->rsp, 6); /* Read the first 8 bytes in order to get the length of the response.
expected = be32_to_cpup((__be32 *) &buf[2]); * We read exactly a quad word in order to make sure that the remaining
if (expected > count || expected < 6) * reads will be aligned.
*/
memcpy_fromio(buf, priv->rsp, 8);
expected = be32_to_cpup((__be32 *)&buf[2]);
if (expected > count || expected < TPM_HEADER_SIZE)
return -EIO; return -EIO;
memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6); memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8);
return expected; return expected;
} }
......
...@@ -46,7 +46,7 @@ struct priv_data { ...@@ -46,7 +46,7 @@ struct priv_data {
/* This is the amount we read on the first try. 25 was chosen to fit a /* This is the amount we read on the first try. 25 was chosen to fit a
* fair number of read responses in the buffer so a 2nd retry can be * fair number of read responses in the buffer so a 2nd retry can be
* avoided in small message cases. */ * avoided in small message cases. */
u8 buffer[sizeof(struct tpm_output_header) + 25]; u8 buffer[sizeof(struct tpm_header) + 25];
}; };
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
...@@ -65,15 +65,22 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -65,15 +65,22 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
dev_dbg(&chip->dev, dev_dbg(&chip->dev,
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, "%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
(int)min_t(size_t, 64, len), buf, len, status); (int)min_t(size_t, 64, len), buf, len, status);
return status;
if (status < 0)
return status;
/* The upper layer does not support incomplete sends. */
if (status != len)
return -E2BIG;
return 0;
} }
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{ {
struct priv_data *priv = dev_get_drvdata(&chip->dev); struct priv_data *priv = dev_get_drvdata(&chip->dev);
struct i2c_client *client = to_i2c_client(chip->dev.parent); struct i2c_client *client = to_i2c_client(chip->dev.parent);
struct tpm_output_header *hdr = struct tpm_header *hdr = (struct tpm_header *)priv->buffer;
(struct tpm_output_header *)priv->buffer;
u32 expected_len; u32 expected_len;
int rc; int rc;
......
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include "tpm.h" #include "tpm.h"
/* max. buffer size supported by our TPM */ #define TPM_I2C_INFINEON_BUFSIZE 1260
#define TPM_BUFSIZE 1260
/* max. number of iterations after I2C NAK */ /* max. number of iterations after I2C NAK */
#define MAX_COUNT 3 #define MAX_COUNT 3
...@@ -63,11 +62,13 @@ enum i2c_chip_type { ...@@ -63,11 +62,13 @@ enum i2c_chip_type {
UNKNOWN, UNKNOWN,
}; };
/* Structure to store I2C TPM specific stuff */
struct tpm_inf_dev { struct tpm_inf_dev {
struct i2c_client *client; struct i2c_client *client;
int locality; int locality;
u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ /* In addition to the data itself, the buffer must fit the 7-bit I2C
* address and the direction bit.
*/
u8 buf[TPM_I2C_INFINEON_BUFSIZE + 1];
struct tpm_chip *chip; struct tpm_chip *chip;
enum i2c_chip_type chip_type; enum i2c_chip_type chip_type;
unsigned int adapterlimit; unsigned int adapterlimit;
...@@ -219,7 +220,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, ...@@ -219,7 +220,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
.buf = tpm_dev.buf .buf = tpm_dev.buf
}; };
if (len > TPM_BUFSIZE) if (len > TPM_I2C_INFINEON_BUFSIZE)
return -EINVAL; return -EINVAL;
if (!tpm_dev.client->adapter->algo->master_xfer) if (!tpm_dev.client->adapter->algo->master_xfer)
...@@ -527,8 +528,8 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -527,8 +528,8 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
u8 retries = 0; u8 retries = 0;
u8 sts = TPM_STS_GO; u8 sts = TPM_STS_GO;
if (len > TPM_BUFSIZE) if (len > TPM_I2C_INFINEON_BUFSIZE)
return -E2BIG; /* command is too long for our tpm, sorry */ return -E2BIG;
if (request_locality(chip, 0) < 0) if (request_locality(chip, 0) < 0)
return -EBUSY; return -EBUSY;
...@@ -587,7 +588,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -587,7 +588,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
/* go and do it */ /* go and do it */
iic_tpm_write(TPM_STS(tpm_dev.locality), &sts, 1); iic_tpm_write(TPM_STS(tpm_dev.locality), &sts, 1);
return len; return 0;
out_err: out_err:
tpm_tis_i2c_ready(chip); tpm_tis_i2c_ready(chip);
/* The TPM needs some time to clean up here, /* The TPM needs some time to clean up here,
......
...@@ -35,14 +35,12 @@ ...@@ -35,14 +35,12 @@
#include "tpm.h" #include "tpm.h"
/* I2C interface offsets */ /* I2C interface offsets */
#define TPM_STS 0x00 #define TPM_STS 0x00
#define TPM_BURST_COUNT 0x01 #define TPM_BURST_COUNT 0x01
#define TPM_DATA_FIFO_W 0x20 #define TPM_DATA_FIFO_W 0x20
#define TPM_DATA_FIFO_R 0x40 #define TPM_DATA_FIFO_R 0x40
#define TPM_VID_DID_RID 0x60 #define TPM_VID_DID_RID 0x60
/* TPM command header size */ #define TPM_I2C_RETRIES 5
#define TPM_HEADER_SIZE 10
#define TPM_RETRY 5
/* /*
* I2C bus device maximum buffer size w/o counting I2C address or command * I2C bus device maximum buffer size w/o counting I2C address or command
* i.e. max size required for I2C write is 34 = addr, command, 32 bytes data * i.e. max size required for I2C write is 34 = addr, command, 32 bytes data
...@@ -292,7 +290,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -292,7 +290,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
dev_err(dev, "%s() count < header size\n", __func__); dev_err(dev, "%s() count < header size\n", __func__);
return -EIO; return -EIO;
} }
for (retries = 0; retries < TPM_RETRY; retries++) { for (retries = 0; retries < TPM_I2C_RETRIES; retries++) {
if (retries > 0) { if (retries > 0) {
/* if this is not the first trial, set responseRetry */ /* if this is not the first trial, set responseRetry */
i2c_nuvoton_write_status(client, i2c_nuvoton_write_status(client,
...@@ -467,7 +465,7 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -467,7 +465,7 @@ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
} }
dev_dbg(dev, "%s() -> %zd\n", __func__, len); dev_dbg(dev, "%s() -> %zd\n", __func__, len);
return len; return 0;
} }
static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status) static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status)
......
...@@ -139,14 +139,14 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -139,14 +139,14 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
} }
/** /**
* tpm_ibmvtpm_send - Send tpm request * tpm_ibmvtpm_send() - Send a TPM command
*
* @chip: tpm chip struct * @chip: tpm chip struct
* @buf: buffer contains data to send * @buf: buffer contains data to send
* @count: size of buffer * @count: size of buffer
* *
* Return: * Return:
* Number of bytes sent or < 0 on error. * 0 on success,
* -errno on error
*/ */
static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
{ {
...@@ -192,7 +192,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -192,7 +192,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
rc = 0; rc = 0;
ibmvtpm->tpm_processing_cmd = false; ibmvtpm->tpm_processing_cmd = false;
} else } else
rc = count; rc = 0;
spin_unlock(&ibmvtpm->rtce_lock); spin_unlock(&ibmvtpm->rtce_lock);
return rc; return rc;
......
...@@ -354,7 +354,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) ...@@ -354,7 +354,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
wait_and_send(chip, buf[i]); wait_and_send(chip, buf[i]);
} }
return count; return 0;
} }
static void tpm_inf_cancel(struct tpm_chip *chip) static void tpm_inf_cancel(struct tpm_chip *chip)
......
...@@ -226,7 +226,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) ...@@ -226,7 +226,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
} }
outb(NSC_COMMAND_EOC, priv->base + NSC_COMMAND); outb(NSC_COMMAND_EOC, priv->base + NSC_COMMAND);
return count; return 0;
} }
static void tpm_nsc_cancel(struct tpm_chip *chip) static void tpm_nsc_cancel(struct tpm_chip *chip)
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include "tpm.h" #include "tpm.h"
#define TPM_PPI_REVISION_ID 1 #define TPM_PPI_REVISION_ID_1 1
#define TPM_PPI_REVISION_ID_2 2
#define TPM_PPI_FN_VERSION 1 #define TPM_PPI_FN_VERSION 1
#define TPM_PPI_FN_SUBREQ 2 #define TPM_PPI_FN_SUBREQ 2
#define TPM_PPI_FN_GETREQ 3 #define TPM_PPI_FN_GETREQ 3
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
#define TPM_PPI_FN_GETRSP 5 #define TPM_PPI_FN_GETRSP 5
#define TPM_PPI_FN_SUBREQ2 7 #define TPM_PPI_FN_SUBREQ2 7
#define TPM_PPI_FN_GETOPR 8 #define TPM_PPI_FN_GETOPR 8
#define PPI_TPM_REQ_MAX 22 #define PPI_TPM_REQ_MAX 101 /* PPI 1.3 for TPM 2 */
#define PPI_VS_REQ_START 128 #define PPI_VS_REQ_START 128
#define PPI_VS_REQ_END 255 #define PPI_VS_REQ_END 255
...@@ -36,14 +37,18 @@ static const guid_t tpm_ppi_guid = ...@@ -36,14 +37,18 @@ static const guid_t tpm_ppi_guid =
GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4, GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53); 0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
static bool tpm_ppi_req_has_parameter(u64 req)
{
return req == 23;
}
static inline union acpi_object * static inline union acpi_object *
tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type, tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
union acpi_object *argv4) union acpi_object *argv4, u64 rev)
{ {
BUG_ON(!ppi_handle); BUG_ON(!ppi_handle);
return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid, return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid,
TPM_PPI_REVISION_ID, rev, func, argv4, type);
func, argv4, type);
} }
static ssize_t tpm_show_ppi_version(struct device *dev, static ssize_t tpm_show_ppi_version(struct device *dev,
...@@ -60,9 +65,14 @@ static ssize_t tpm_show_ppi_request(struct device *dev, ...@@ -60,9 +65,14 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
ssize_t size = -EINVAL; ssize_t size = -EINVAL;
union acpi_object *obj; union acpi_object *obj;
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
u64 rev = TPM_PPI_REVISION_ID_2;
u64 req;
if (strcmp(chip->ppi_version, "1.2") < 0)
rev = TPM_PPI_REVISION_ID_1;
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
ACPI_TYPE_PACKAGE, NULL); ACPI_TYPE_PACKAGE, NULL, rev);
if (!obj) if (!obj)
return -ENXIO; return -ENXIO;
...@@ -72,7 +82,23 @@ static ssize_t tpm_show_ppi_request(struct device *dev, ...@@ -72,7 +82,23 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
* error. The second is pending TPM operation requested by the OS, 0 * error. The second is pending TPM operation requested by the OS, 0
* means none and >0 means operation value. * means none and >0 means operation value.
*/ */
if (obj->package.count == 2 && if (obj->package.count == 3 &&
obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
obj->package.elements[1].type == ACPI_TYPE_INTEGER &&
obj->package.elements[2].type == ACPI_TYPE_INTEGER) {
if (obj->package.elements[0].integer.value)
size = -EFAULT;
else {
req = obj->package.elements[1].integer.value;
if (tpm_ppi_req_has_parameter(req))
size = scnprintf(buf, PAGE_SIZE,
"%llu %llu\n", req,
obj->package.elements[2].integer.value);
else
size = scnprintf(buf, PAGE_SIZE,
"%llu\n", req);
}
} else if (obj->package.count == 2 &&
obj->package.elements[0].type == ACPI_TYPE_INTEGER && obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
obj->package.elements[1].type == ACPI_TYPE_INTEGER) { obj->package.elements[1].type == ACPI_TYPE_INTEGER) {
if (obj->package.elements[0].integer.value) if (obj->package.elements[0].integer.value)
...@@ -94,9 +120,10 @@ static ssize_t tpm_store_ppi_request(struct device *dev, ...@@ -94,9 +120,10 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
u32 req; u32 req;
u64 ret; u64 ret;
int func = TPM_PPI_FN_SUBREQ; int func = TPM_PPI_FN_SUBREQ;
union acpi_object *obj, tmp; union acpi_object *obj, tmp[2];
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(2, tmp);
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
u64 rev = TPM_PPI_REVISION_ID_1;
/* /*
* the function to submit TPM operation request to pre-os environment * the function to submit TPM operation request to pre-os environment
...@@ -104,7 +131,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev, ...@@ -104,7 +131,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
* version 1.1 * version 1.1
*/ */
if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2)) TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_SUBREQ2))
func = TPM_PPI_FN_SUBREQ2; func = TPM_PPI_FN_SUBREQ2;
/* /*
...@@ -113,20 +140,29 @@ static ssize_t tpm_store_ppi_request(struct device *dev, ...@@ -113,20 +140,29 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
* string/package type. For PPI version 1.0 and 1.1, use buffer type * string/package type. For PPI version 1.0 and 1.1, use buffer type
* for compatibility, and use package type since 1.2 according to spec. * for compatibility, and use package type since 1.2 according to spec.
*/ */
if (strcmp(chip->ppi_version, "1.2") < 0) { if (strcmp(chip->ppi_version, "1.3") == 0) {
if (sscanf(buf, "%llu %llu", &tmp[0].integer.value,
&tmp[1].integer.value) != 2)
goto ppi12;
rev = TPM_PPI_REVISION_ID_2;
tmp[0].type = ACPI_TYPE_INTEGER;
tmp[1].type = ACPI_TYPE_INTEGER;
} else if (strcmp(chip->ppi_version, "1.2") < 0) {
if (sscanf(buf, "%d", &req) != 1) if (sscanf(buf, "%d", &req) != 1)
return -EINVAL; return -EINVAL;
argv4.type = ACPI_TYPE_BUFFER; argv4.type = ACPI_TYPE_BUFFER;
argv4.buffer.length = sizeof(req); argv4.buffer.length = sizeof(req);
argv4.buffer.pointer = (u8 *)&req; argv4.buffer.pointer = (u8 *)&req;
} else { } else {
tmp.type = ACPI_TYPE_INTEGER; ppi12:
if (sscanf(buf, "%llu", &tmp.integer.value) != 1) argv4.package.count = 1;
tmp[0].type = ACPI_TYPE_INTEGER;
if (sscanf(buf, "%llu", &tmp[0].integer.value) != 1)
return -EINVAL; return -EINVAL;
} }
obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
&argv4); &argv4, rev);
if (!obj) { if (!obj) {
return -ENXIO; return -ENXIO;
} else { } else {
...@@ -170,7 +206,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, ...@@ -170,7 +206,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
if (strcmp(chip->ppi_version, "1.2") < 0) if (strcmp(chip->ppi_version, "1.2") < 0)
obj = &tmp; obj = &tmp;
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
ACPI_TYPE_INTEGER, obj); ACPI_TYPE_INTEGER, obj, TPM_PPI_REVISION_ID_1);
if (!obj) { if (!obj) {
return -ENXIO; return -ENXIO;
} else { } else {
...@@ -196,7 +232,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev, ...@@ -196,7 +232,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
ACPI_TYPE_PACKAGE, NULL); ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1);
if (!obj) if (!obj)
return -ENXIO; return -ENXIO;
...@@ -264,7 +300,7 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, ...@@ -264,7 +300,7 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
"User not required", "User not required",
}; };
if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID, if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1,
1 << TPM_PPI_FN_GETOPR)) 1 << TPM_PPI_FN_GETOPR))
return -EPERM; return -EPERM;
...@@ -272,7 +308,8 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, ...@@ -272,7 +308,8 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
for (i = start; i <= end; i++) { for (i = start; i <= end; i++) {
tmp.integer.value = i; tmp.integer.value = i;
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
ACPI_TYPE_INTEGER, &argv); ACPI_TYPE_INTEGER, &argv,
TPM_PPI_REVISION_ID_1);
if (!obj) { if (!obj) {
return -ENOMEM; return -ENOMEM;
} else { } else {
...@@ -338,12 +375,13 @@ void tpm_add_ppi(struct tpm_chip *chip) ...@@ -338,12 +375,13 @@ void tpm_add_ppi(struct tpm_chip *chip)
return; return;
if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid, if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION)) TPM_PPI_REVISION_ID_1, 1 << TPM_PPI_FN_VERSION))
return; return;
/* Cache PPI version string. */ /* Cache PPI version string. */
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid, obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid,
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, TPM_PPI_REVISION_ID_1,
TPM_PPI_FN_VERSION,
NULL, ACPI_TYPE_STRING); NULL, ACPI_TYPE_STRING);
if (obj) { if (obj) {
strlcpy(chip->ppi_version, obj->string.pointer, strlcpy(chip->ppi_version, obj->string.pointer,
......
...@@ -481,7 +481,7 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len) ...@@ -481,7 +481,7 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
goto out_err; goto out_err;
} }
} }
return len; return 0;
out_err: out_err:
tpm_tis_ready(chip); tpm_tis_ready(chip);
return rc; return rc;
...@@ -521,35 +521,38 @@ static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = { ...@@ -521,35 +521,38 @@ static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = {
(TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } }, (TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } },
}; };
static bool tpm_tis_update_timeouts(struct tpm_chip *chip, static void tpm_tis_update_timeouts(struct tpm_chip *chip,
unsigned long *timeout_cap) unsigned long *timeout_cap)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int i, rc; int i, rc;
u32 did_vid; u32 did_vid;
chip->timeout_adjusted = false;
if (chip->ops->clk_enable != NULL) if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, true); chip->ops->clk_enable(chip, true);
rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid); rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid);
if (rc < 0) if (rc < 0) {
dev_warn(&chip->dev, "%s: failed to read did_vid: %d\n",
__func__, rc);
goto out; goto out;
}
for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) { for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
if (vendor_timeout_overrides[i].did_vid != did_vid) if (vendor_timeout_overrides[i].did_vid != did_vid)
continue; continue;
memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us, memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
sizeof(vendor_timeout_overrides[i].timeout_us)); sizeof(vendor_timeout_overrides[i].timeout_us));
rc = true; chip->timeout_adjusted = true;
} }
rc = false;
out: out:
if (chip->ops->clk_enable != NULL) if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, false); chip->ops->clk_enable(chip, false);
return rc; return;
} }
/* /*
...@@ -913,7 +916,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -913,7 +916,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
intmask &= ~TPM_GLOBAL_INT_ENABLE; intmask &= ~TPM_GLOBAL_INT_ENABLE;
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
rc = tpm_chip_start(chip);
if (rc)
goto out_err;
rc = tpm2_probe(chip); rc = tpm2_probe(chip);
tpm_chip_stop(chip);
if (rc) if (rc)
goto out_err; goto out_err;
......
...@@ -303,9 +303,9 @@ static int vtpm_proxy_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -303,9 +303,9 @@ static int vtpm_proxy_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count)
static int vtpm_proxy_is_driver_command(struct tpm_chip *chip, static int vtpm_proxy_is_driver_command(struct tpm_chip *chip,
u8 *buf, size_t count) u8 *buf, size_t count)
{ {
struct tpm_input_header *hdr = (struct tpm_input_header *)buf; struct tpm_header *hdr = (struct tpm_header *)buf;
if (count < sizeof(struct tpm_input_header)) if (count < sizeof(struct tpm_header))
return 0; return 0;
if (chip->flags & TPM_CHIP_FLAG_TPM2) { if (chip->flags & TPM_CHIP_FLAG_TPM2) {
...@@ -335,7 +335,6 @@ static int vtpm_proxy_is_driver_command(struct tpm_chip *chip, ...@@ -335,7 +335,6 @@ static int vtpm_proxy_is_driver_command(struct tpm_chip *chip,
static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count) static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count)
{ {
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev); struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
int rc = 0;
if (count > sizeof(proxy_dev->buffer)) { if (count > sizeof(proxy_dev->buffer)) {
dev_err(&chip->dev, dev_err(&chip->dev,
...@@ -366,7 +365,7 @@ static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -366,7 +365,7 @@ static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count)
wake_up_interruptible(&proxy_dev->wq); wake_up_interruptible(&proxy_dev->wq);
return rc; return 0;
} }
static void vtpm_proxy_tpm_op_cancel(struct tpm_chip *chip) static void vtpm_proxy_tpm_op_cancel(struct tpm_chip *chip)
...@@ -402,7 +401,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality) ...@@ -402,7 +401,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
{ {
struct tpm_buf buf; struct tpm_buf buf;
int rc; int rc;
const struct tpm_output_header *header; const struct tpm_header *header;
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev); struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
...@@ -417,9 +416,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality) ...@@ -417,9 +416,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
proxy_dev->state |= STATE_DRIVER_COMMAND; proxy_dev->state |= STATE_DRIVER_COMMAND;
rc = tpm_transmit_cmd(chip, NULL, buf.data, tpm_buf_length(&buf), 0, rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
TPM_TRANSMIT_NESTED,
"attempting to set locality");
proxy_dev->state &= ~STATE_DRIVER_COMMAND; proxy_dev->state &= ~STATE_DRIVER_COMMAND;
...@@ -428,7 +425,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality) ...@@ -428,7 +425,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
goto out; goto out;
} }
header = (const struct tpm_output_header *)buf.data; header = (const struct tpm_header *)buf.data;
rc = be32_to_cpu(header->return_code); rc = be32_to_cpu(header->return_code);
if (rc) if (rc)
locality = -1; locality = -1;
......
...@@ -163,7 +163,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -163,7 +163,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
wmb(); wmb();
notify_remote_via_evtchn(priv->evtchn); notify_remote_via_evtchn(priv->evtchn);
ordinal = be32_to_cpu(((struct tpm_input_header*)buf)->ordinal); ordinal = be32_to_cpu(((struct tpm_header *)buf)->ordinal);
duration = tpm_calc_ordinal_duration(chip, ordinal); duration = tpm_calc_ordinal_duration(chip, ordinal);
if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration, if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration,
...@@ -173,7 +173,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -173,7 +173,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
return -ETIME; return -ETIME;
} }
return count; return 0;
} }
static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
......
...@@ -22,12 +22,41 @@ ...@@ -22,12 +22,41 @@
#ifndef __LINUX_TPM_H__ #ifndef __LINUX_TPM_H__
#define __LINUX_TPM_H__ #define __LINUX_TPM_H__
#include <linux/hw_random.h>
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <crypto/hash_info.h>
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */ #define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
struct tpm_chip; struct tpm_chip;
struct trusted_key_payload; struct trusted_key_payload;
struct trusted_key_options; struct trusted_key_options;
enum tpm_algorithms {
TPM_ALG_ERROR = 0x0000,
TPM_ALG_SHA1 = 0x0004,
TPM_ALG_KEYEDHASH = 0x0008,
TPM_ALG_SHA256 = 0x000B,
TPM_ALG_SHA384 = 0x000C,
TPM_ALG_SHA512 = 0x000D,
TPM_ALG_NULL = 0x0010,
TPM_ALG_SM3_256 = 0x0012,
};
struct tpm_digest {
u16 alg_id;
u8 digest[TPM_MAX_DIGEST_SIZE];
} __packed;
struct tpm_bank_info {
u16 alg_id;
u16 digest_size;
u16 crypto_id;
};
enum TPM_OPS_FLAGS { enum TPM_OPS_FLAGS {
TPM_OPS_AUTO_STARTUP = BIT(0), TPM_OPS_AUTO_STARTUP = BIT(0),
}; };
...@@ -41,7 +70,7 @@ struct tpm_class_ops { ...@@ -41,7 +70,7 @@ struct tpm_class_ops {
int (*send) (struct tpm_chip *chip, u8 *buf, size_t len); int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
void (*cancel) (struct tpm_chip *chip); void (*cancel) (struct tpm_chip *chip);
u8 (*status) (struct tpm_chip *chip); u8 (*status) (struct tpm_chip *chip);
bool (*update_timeouts)(struct tpm_chip *chip, void (*update_timeouts)(struct tpm_chip *chip,
unsigned long *timeout_cap); unsigned long *timeout_cap);
int (*go_idle)(struct tpm_chip *chip); int (*go_idle)(struct tpm_chip *chip);
int (*cmd_ready)(struct tpm_chip *chip); int (*cmd_ready)(struct tpm_chip *chip);
...@@ -50,11 +79,100 @@ struct tpm_class_ops { ...@@ -50,11 +79,100 @@ struct tpm_class_ops {
void (*clk_enable)(struct tpm_chip *chip, bool value); void (*clk_enable)(struct tpm_chip *chip, bool value);
}; };
#define TPM_NUM_EVENT_LOG_FILES 3
/* Indexes the duration array */
enum tpm_duration {
TPM_SHORT = 0,
TPM_MEDIUM = 1,
TPM_LONG = 2,
TPM_LONG_LONG = 3,
TPM_UNDEFINED,
TPM_NUM_DURATIONS = TPM_UNDEFINED,
};
#define TPM_PPI_VERSION_LEN 3
struct tpm_space {
u32 context_tbl[3];
u8 *context_buf;
u32 session_tbl[3];
u8 *session_buf;
};
struct tpm_bios_log {
void *bios_event_log;
void *bios_event_log_end;
};
struct tpm_chip_seqops {
struct tpm_chip *chip;
const struct seq_operations *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
* when the driver is unregistered, see tpm_try_get_ops.
*/
struct rw_semaphore ops_sem;
const struct tpm_class_ops *ops;
struct tpm_bios_log log;
struct tpm_chip_seqops bin_log_seqops;
struct tpm_chip_seqops ascii_log_seqops;
unsigned int flags;
int dev_num; /* /dev/tpm# */
unsigned long is_open; /* only one allowed */
char hwrng_name[64];
struct hwrng hwrng;
struct mutex tpm_mutex; /* tpm is processing */
unsigned long timeout_a; /* jiffies */
unsigned long timeout_b; /* jiffies */
unsigned long timeout_c; /* jiffies */
unsigned long timeout_d; /* jiffies */
bool timeout_adjusted;
unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */
bool duration_adjusted;
struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES];
const struct attribute_group *groups[3];
unsigned int groups_cnt;
u32 nr_allocated_banks;
struct tpm_bank_info *allocated_banks;
#ifdef CONFIG_ACPI
acpi_handle acpi_dev_handle;
char ppi_version[TPM_PPI_VERSION_LEN + 1];
#endif /* CONFIG_ACPI */
struct tpm_space work_space;
u32 last_cc;
u32 nr_commands;
u32 *cc_attrs_tbl;
/* active locality */
int locality;
};
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
extern int tpm_is_tpm2(struct tpm_chip *chip); extern int tpm_is_tpm2(struct tpm_chip *chip);
extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf); extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash); struct tpm_digest *digest);
extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests);
extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen); extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen);
extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max);
extern int tpm_seal_trusted(struct tpm_chip *chip, extern int tpm_seal_trusted(struct tpm_chip *chip,
...@@ -70,13 +188,14 @@ static inline int tpm_is_tpm2(struct tpm_chip *chip) ...@@ -70,13 +188,14 @@ static inline int tpm_is_tpm2(struct tpm_chip *chip)
return -ENODEV; return -ENODEV;
} }
static inline int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx,
struct tpm_digest *digest)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, static inline int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
const u8 *hash) struct tpm_digest *digests)
{ {
return -ENODEV; return -ENODEV;
} }
......
...@@ -3,12 +3,11 @@ ...@@ -3,12 +3,11 @@
#ifndef __LINUX_TPM_EVENTLOG_H__ #ifndef __LINUX_TPM_EVENTLOG_H__
#define __LINUX_TPM_EVENTLOG_H__ #define __LINUX_TPM_EVENTLOG_H__
#include <crypto/hash_info.h> #include <linux/tpm.h>
#define TCG_EVENT_NAME_LEN_MAX 255 #define TCG_EVENT_NAME_LEN_MAX 255
#define MAX_TEXT_EVENT 1000 /* Max event string length */ #define MAX_TEXT_EVENT 1000 /* Max event string length */
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
#define TPM2_ACTIVE_PCR_BANKS 3
#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x1 #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x1
#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x2 #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x2
...@@ -82,7 +81,7 @@ struct tcg_efi_specid_event_algs { ...@@ -82,7 +81,7 @@ struct tcg_efi_specid_event_algs {
u16 digest_size; u16 digest_size;
} __packed; } __packed;
struct tcg_efi_specid_event { struct tcg_efi_specid_event_head {
u8 signature[16]; u8 signature[16];
u32 platform_class; u32 platform_class;
u8 spec_version_minor; u8 spec_version_minor;
...@@ -90,9 +89,7 @@ struct tcg_efi_specid_event { ...@@ -90,9 +89,7 @@ struct tcg_efi_specid_event {
u8 spec_errata; u8 spec_errata;
u8 uintnsize; u8 uintnsize;
u32 num_algs; u32 num_algs;
struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS]; struct tcg_efi_specid_event_algs digest_sizes[];
u8 vendor_info_size;
u8 vendor_info[0];
} __packed; } __packed;
struct tcg_pcr_event { struct tcg_pcr_event {
...@@ -108,17 +105,11 @@ struct tcg_event_field { ...@@ -108,17 +105,11 @@ struct tcg_event_field {
u8 event[0]; u8 event[0];
} __packed; } __packed;
struct tpm2_digest { struct tcg_pcr_event2_head {
u16 alg_id;
u8 digest[SHA512_DIGEST_SIZE];
} __packed;
struct tcg_pcr_event2 {
u32 pcr_idx; u32 pcr_idx;
u32 event_type; u32 event_type;
u32 count; u32 count;
struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS]; struct tpm_digest digests[];
struct tcg_event_field event;
} __packed; } __packed;
#endif #endif
...@@ -153,6 +153,7 @@ int ima_measurements_show(struct seq_file *m, void *v); ...@@ -153,6 +153,7 @@ int ima_measurements_show(struct seq_file *m, void *v);
unsigned long ima_get_binary_runtime_size(void); unsigned long ima_get_binary_runtime_size(void);
int ima_init_template(void); int ima_init_template(void);
void ima_init_template_list(void); void ima_init_template_list(void);
int __init ima_init_digests(void);
/* /*
* used to protect h_table and sha_table * used to protect h_table and sha_table
......
...@@ -643,12 +643,12 @@ int ima_calc_buffer_hash(const void *buf, loff_t len, ...@@ -643,12 +643,12 @@ int ima_calc_buffer_hash(const void *buf, loff_t len,
return calc_buffer_shash(buf, len, hash); return calc_buffer_shash(buf, len, hash);
} }
static void __init ima_pcrread(u32 idx, u8 *pcr) static void __init ima_pcrread(u32 idx, struct tpm_digest *d)
{ {
if (!ima_tpm_chip) if (!ima_tpm_chip)
return; return;
if (tpm_pcr_read(ima_tpm_chip, idx, pcr) != 0) if (tpm_pcr_read(ima_tpm_chip, idx, d) != 0)
pr_err("Error Communicating to TPM chip\n"); pr_err("Error Communicating to TPM chip\n");
} }
...@@ -658,7 +658,7 @@ static void __init ima_pcrread(u32 idx, u8 *pcr) ...@@ -658,7 +658,7 @@ static void __init ima_pcrread(u32 idx, u8 *pcr)
static int __init ima_calc_boot_aggregate_tfm(char *digest, static int __init ima_calc_boot_aggregate_tfm(char *digest,
struct crypto_shash *tfm) struct crypto_shash *tfm)
{ {
u8 pcr_i[TPM_DIGEST_SIZE]; struct tpm_digest d = { .alg_id = TPM_ALG_SHA1, .digest = {0} };
int rc; int rc;
u32 i; u32 i;
SHASH_DESC_ON_STACK(shash, tfm); SHASH_DESC_ON_STACK(shash, tfm);
...@@ -672,9 +672,9 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest, ...@@ -672,9 +672,9 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest,
/* cumulative sha1 over tpm registers 0-7 */ /* cumulative sha1 over tpm registers 0-7 */
for (i = TPM_PCR0; i < TPM_PCR8; i++) { for (i = TPM_PCR0; i < TPM_PCR8; i++) {
ima_pcrread(i, pcr_i); ima_pcrread(i, &d);
/* now accumulate with current aggregate */ /* now accumulate with current aggregate */
rc = crypto_shash_update(shash, pcr_i, TPM_DIGEST_SIZE); rc = crypto_shash_update(shash, d.digest, TPM_DIGEST_SIZE);
} }
if (!rc) if (!rc)
crypto_shash_final(shash, digest); crypto_shash_final(shash, digest);
......
...@@ -123,8 +123,12 @@ int __init ima_init(void) ...@@ -123,8 +123,12 @@ int __init ima_init(void)
if (rc != 0) if (rc != 0)
return rc; return rc;
/* It can be called before ima_init_digests(), it does not use TPM. */
ima_load_kexec_buffer(); ima_load_kexec_buffer();
rc = ima_init_digests();
if (rc != 0)
return rc;
rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */ rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */
if (rc != 0) if (rc != 0)
return rc; return rc;
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#define AUDIT_CAUSE_LEN_MAX 32 #define AUDIT_CAUSE_LEN_MAX 32
/* pre-allocated array of tpm_digest structures to extend a PCR */
static struct tpm_digest *digests;
LIST_HEAD(ima_measurements); /* list of all measurements */ LIST_HEAD(ima_measurements); /* list of all measurements */
#ifdef CONFIG_IMA_KEXEC #ifdef CONFIG_IMA_KEXEC
static unsigned long binary_runtime_size; static unsigned long binary_runtime_size;
...@@ -140,11 +143,15 @@ unsigned long ima_get_binary_runtime_size(void) ...@@ -140,11 +143,15 @@ unsigned long ima_get_binary_runtime_size(void)
static int ima_pcr_extend(const u8 *hash, int pcr) static int ima_pcr_extend(const u8 *hash, int pcr)
{ {
int result = 0; int result = 0;
int i;
if (!ima_tpm_chip) if (!ima_tpm_chip)
return result; return result;
result = tpm_pcr_extend(ima_tpm_chip, pcr, hash); for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
memcpy(digests[i].digest, hash, TPM_DIGEST_SIZE);
result = tpm_pcr_extend(ima_tpm_chip, pcr, digests);
if (result != 0) if (result != 0)
pr_err("Error Communicating to TPM chip, result: %d\n", result); pr_err("Error Communicating to TPM chip, result: %d\n", result);
return result; return result;
...@@ -211,3 +218,21 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry) ...@@ -211,3 +218,21 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry)
mutex_unlock(&ima_extend_list_mutex); mutex_unlock(&ima_extend_list_mutex);
return result; return result;
} }
int __init ima_init_digests(void)
{
int i;
if (!ima_tpm_chip)
return 0;
digests = kcalloc(ima_tpm_chip->nr_allocated_banks, sizeof(*digests),
GFP_NOFS);
if (!digests)
return -ENOMEM;
for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
return 0;
}
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
static const char hmac_alg[] = "hmac(sha1)"; static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1"; static const char hash_alg[] = "sha1";
static struct tpm_chip *chip;
static struct tpm_digest *digests;
struct sdesc { struct sdesc {
struct shash_desc shash; struct shash_desc shash;
...@@ -362,7 +364,7 @@ int trusted_tpm_send(unsigned char *cmd, size_t buflen) ...@@ -362,7 +364,7 @@ int trusted_tpm_send(unsigned char *cmd, size_t buflen)
int rc; int rc;
dump_tpm_buf(cmd); dump_tpm_buf(cmd);
rc = tpm_send(NULL, cmd, buflen); rc = tpm_send(chip, cmd, buflen);
dump_tpm_buf(cmd); dump_tpm_buf(cmd);
if (rc > 0) if (rc > 0)
/* Can't return positive return codes values to keyctl */ /* Can't return positive return codes values to keyctl */
...@@ -379,15 +381,10 @@ EXPORT_SYMBOL_GPL(trusted_tpm_send); ...@@ -379,15 +381,10 @@ EXPORT_SYMBOL_GPL(trusted_tpm_send);
*/ */
static int pcrlock(const int pcrnum) static int pcrlock(const int pcrnum)
{ {
unsigned char hash[SHA1_DIGEST_SIZE];
int ret;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);
if (ret != SHA1_DIGEST_SIZE) return tpm_pcr_extend(chip, pcrnum, digests) ? -EINVAL : 0;
return ret;
return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;
} }
/* /*
...@@ -400,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s, ...@@ -400,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
unsigned char ononce[TPM_NONCE_SIZE]; unsigned char ononce[TPM_NONCE_SIZE];
int ret; int ret;
ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE); ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE) if (ret != TPM_NONCE_SIZE)
return ret; return ret;
...@@ -496,7 +493,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype, ...@@ -496,7 +493,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE); ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE) if (ret != TPM_NONCE_SIZE)
goto out; goto out;
ordinal = htonl(TPM_ORD_SEAL); ordinal = htonl(TPM_ORD_SEAL);
...@@ -606,7 +603,7 @@ static int tpm_unseal(struct tpm_buf *tb, ...@@ -606,7 +603,7 @@ static int tpm_unseal(struct tpm_buf *tb,
ordinal = htonl(TPM_ORD_UNSEAL); ordinal = htonl(TPM_ORD_UNSEAL);
keyhndl = htonl(SRKHANDLE); keyhndl = htonl(SRKHANDLE);
ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE); ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE) { if (ret != TPM_NONCE_SIZE) {
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret); pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
return ret; return ret;
...@@ -751,7 +748,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay, ...@@ -751,7 +748,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
int i; int i;
int tpm2; int tpm2;
tpm2 = tpm_is_tpm2(NULL); tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0) if (tpm2 < 0)
return tpm2; return tpm2;
...@@ -920,7 +917,7 @@ static struct trusted_key_options *trusted_options_alloc(void) ...@@ -920,7 +917,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
struct trusted_key_options *options; struct trusted_key_options *options;
int tpm2; int tpm2;
tpm2 = tpm_is_tpm2(NULL); tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0) if (tpm2 < 0)
return NULL; return NULL;
...@@ -970,7 +967,7 @@ static int trusted_instantiate(struct key *key, ...@@ -970,7 +967,7 @@ static int trusted_instantiate(struct key *key,
size_t key_len; size_t key_len;
int tpm2; int tpm2;
tpm2 = tpm_is_tpm2(NULL); tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0) if (tpm2 < 0)
return tpm2; return tpm2;
...@@ -1011,7 +1008,7 @@ static int trusted_instantiate(struct key *key, ...@@ -1011,7 +1008,7 @@ static int trusted_instantiate(struct key *key,
switch (key_cmd) { switch (key_cmd) {
case Opt_load: case Opt_load:
if (tpm2) if (tpm2)
ret = tpm_unseal_trusted(NULL, payload, options); ret = tpm_unseal_trusted(chip, payload, options);
else else
ret = key_unseal(payload, options); ret = key_unseal(payload, options);
dump_payload(payload); dump_payload(payload);
...@@ -1021,13 +1018,13 @@ static int trusted_instantiate(struct key *key, ...@@ -1021,13 +1018,13 @@ static int trusted_instantiate(struct key *key,
break; break;
case Opt_new: case Opt_new:
key_len = payload->key_len; key_len = payload->key_len;
ret = tpm_get_random(NULL, payload->key, key_len); ret = tpm_get_random(chip, payload->key, key_len);
if (ret != key_len) { if (ret != key_len) {
pr_info("trusted_key: key_create failed (%d)\n", ret); pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out; goto out;
} }
if (tpm2) if (tpm2)
ret = tpm_seal_trusted(NULL, payload, options); ret = tpm_seal_trusted(chip, payload, options);
else else
ret = key_seal(payload, options); ret = key_seal(payload, options);
if (ret < 0) if (ret < 0)
...@@ -1221,21 +1218,59 @@ static int __init trusted_shash_alloc(void) ...@@ -1221,21 +1218,59 @@ static int __init trusted_shash_alloc(void)
return ret; return ret;
} }
static int __init init_digests(void)
{
u8 digest[TPM_MAX_DIGEST_SIZE];
int ret;
int i;
ret = tpm_get_random(chip, digest, TPM_MAX_DIGEST_SIZE);
if (ret < 0)
return ret;
if (ret < TPM_MAX_DIGEST_SIZE)
return -EFAULT;
digests = kcalloc(chip->nr_allocated_banks, sizeof(*digests),
GFP_KERNEL);
if (!digests)
return -ENOMEM;
for (i = 0; i < chip->nr_allocated_banks; i++)
memcpy(digests[i].digest, digest, TPM_MAX_DIGEST_SIZE);
return 0;
}
static int __init init_trusted(void) static int __init init_trusted(void)
{ {
int ret; int ret;
chip = tpm_default_chip();
if (!chip)
return -ENOENT;
ret = init_digests();
if (ret < 0)
goto err_put;
ret = trusted_shash_alloc(); ret = trusted_shash_alloc();
if (ret < 0) if (ret < 0)
return ret; goto err_free;
ret = register_key_type(&key_type_trusted); ret = register_key_type(&key_type_trusted);
if (ret < 0) if (ret < 0)
trusted_shash_release(); goto err_release;
return 0;
err_release:
trusted_shash_release();
err_free:
kfree(digests);
err_put:
put_device(&chip->dev);
return ret; return ret;
} }
static void __exit cleanup_trusted(void) static void __exit cleanup_trusted(void)
{ {
put_device(&chip->dev);
kfree(digests);
trusted_shash_release(); trusted_shash_release();
unregister_key_type(&key_type_trusted); unregister_key_type(&key_type_trusted);
} }
......
...@@ -47,6 +47,7 @@ TARGETS += sysctl ...@@ -47,6 +47,7 @@ TARGETS += sysctl
ifneq (1, $(quicktest)) ifneq (1, $(quicktest))
TARGETS += timers TARGETS += timers
endif endif
TARGETS += tpm2
TARGETS += user TARGETS += user
TARGETS += vm TARGETS += vm
TARGETS += x86 TARGETS += x86
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
include ../lib.mk
TEST_PROGS := test_smoke.sh test_space.sh
#!/bin/bash
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
python -m unittest -v tpm2_tests.SmokeTest
#!/bin/bash
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
python -m unittest -v tpm2_tests.SpaceTest
This diff is collapsed.
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
from argparse import ArgumentParser
from argparse import FileType
import os
import sys
import tpm2
from tpm2 import ProtocolError
import unittest
import logging
import struct
class SmokeTest(unittest.TestCase):
def setUp(self):
self.client = tpm2.Client()
self.root_key = self.client.create_root_key()
def tearDown(self):
self.client.flush_context(self.root_key)
self.client.close()
def test_seal_with_auth(self):
data = 'X' * 64
auth = 'A' * 15
blob = self.client.seal(self.root_key, data, auth, None)
result = self.client.unseal(self.root_key, blob, auth, None)
self.assertEqual(data, result)
def test_seal_with_policy(self):
handle = self.client.start_auth_session(tpm2.TPM2_SE_TRIAL)
data = 'X' * 64
auth = 'A' * 15
pcrs = [16]
try:
self.client.policy_pcr(handle, pcrs)
self.client.policy_password(handle)
policy_dig = self.client.get_policy_digest(handle)
finally:
self.client.flush_context(handle)
blob = self.client.seal(self.root_key, data, auth, policy_dig)
handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
try:
self.client.policy_pcr(handle, pcrs)
self.client.policy_password(handle)
result = self.client.unseal(self.root_key, blob, auth, handle)
except:
self.client.flush_context(handle)
raise
self.assertEqual(data, result)
def test_unseal_with_wrong_auth(self):
data = 'X' * 64
auth = 'A' * 20
rc = 0
blob = self.client.seal(self.root_key, data, auth, None)
try:
result = self.client.unseal(self.root_key, blob, auth[:-1] + 'B', None)
except ProtocolError, e:
rc = e.rc
self.assertEqual(rc, tpm2.TPM2_RC_AUTH_FAIL)
def test_unseal_with_wrong_policy(self):
handle = self.client.start_auth_session(tpm2.TPM2_SE_TRIAL)
data = 'X' * 64
auth = 'A' * 17
pcrs = [16]
try:
self.client.policy_pcr(handle, pcrs)
self.client.policy_password(handle)
policy_dig = self.client.get_policy_digest(handle)
finally:
self.client.flush_context(handle)
blob = self.client.seal(self.root_key, data, auth, policy_dig)
# Extend first a PCR that is not part of the policy and try to unseal.
# This should succeed.
ds = tpm2.get_digest_size(tpm2.TPM2_ALG_SHA1)
self.client.extend_pcr(1, 'X' * ds)
handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
try:
self.client.policy_pcr(handle, pcrs)
self.client.policy_password(handle)
result = self.client.unseal(self.root_key, blob, auth, handle)
except:
self.client.flush_context(handle)
raise
self.assertEqual(data, result)
# Then, extend a PCR that is part of the policy and try to unseal.
# This should fail.
self.client.extend_pcr(16, 'X' * ds)
handle = self.client.start_auth_session(tpm2.TPM2_SE_POLICY)
rc = 0
try:
self.client.policy_pcr(handle, pcrs)
self.client.policy_password(handle)
result = self.client.unseal(self.root_key, blob, auth, handle)
except ProtocolError, e:
rc = e.rc
self.client.flush_context(handle)
except:
self.client.flush_context(handle)
raise
self.assertEqual(rc, tpm2.TPM2_RC_POLICY_FAIL)
def test_seal_with_too_long_auth(self):
ds = tpm2.get_digest_size(tpm2.TPM2_ALG_SHA1)
data = 'X' * 64
auth = 'A' * (ds + 1)
rc = 0
try:
blob = self.client.seal(self.root_key, data, auth, None)
except ProtocolError, e:
rc = e.rc
self.assertEqual(rc, tpm2.TPM2_RC_SIZE)
def test_too_short_cmd(self):
rejected = False
try:
fmt = '>HIII'
cmd = struct.pack(fmt,
tpm2.TPM2_ST_NO_SESSIONS,
struct.calcsize(fmt) + 1,
tpm2.TPM2_CC_FLUSH_CONTEXT,
0xDEADBEEF)
self.client.send_cmd(cmd)
except IOError, e:
rejected = True
except:
pass
self.assertEqual(rejected, True)
class SpaceTest(unittest.TestCase):
def setUp(self):
logging.basicConfig(filename='SpaceTest.log', level=logging.DEBUG)
def test_make_two_spaces(self):
log = logging.getLogger(__name__)
log.debug("test_make_two_spaces")
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
root1 = space1.create_root_key()
space2 = tpm2.Client(tpm2.Client.FLAG_SPACE)
root2 = space2.create_root_key()
root3 = space2.create_root_key()
log.debug("%08x" % (root1))
log.debug("%08x" % (root2))
log.debug("%08x" % (root3))
def test_flush_context(self):
log = logging.getLogger(__name__)
log.debug("test_flush_context")
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
root1 = space1.create_root_key()
log.debug("%08x" % (root1))
space1.flush_context(root1)
def test_get_handles(self):
log = logging.getLogger(__name__)
log.debug("test_get_handles")
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
space1.create_root_key()
space2 = tpm2.Client(tpm2.Client.FLAG_SPACE)
space2.create_root_key()
space2.create_root_key()
handles = space2.get_cap(tpm2.TPM2_CAP_HANDLES, tpm2.HR_TRANSIENT)
self.assertEqual(len(handles), 2)
log.debug("%08x" % (handles[0]))
log.debug("%08x" % (handles[1]))
def test_invalid_cc(self):
log = logging.getLogger(__name__)
log.debug(sys._getframe().f_code.co_name)
TPM2_CC_INVALID = tpm2.TPM2_CC_FIRST - 1
space1 = tpm2.Client(tpm2.Client.FLAG_SPACE)
root1 = space1.create_root_key()
log.debug("%08x" % (root1))
fmt = '>HII'
cmd = struct.pack(fmt, tpm2.TPM2_ST_NO_SESSIONS, struct.calcsize(fmt),
TPM2_CC_INVALID)
rc = 0
try:
space1.send_cmd(cmd)
except ProtocolError, e:
rc = e.rc
self.assertEqual(rc, tpm2.TPM2_RC_COMMAND_CODE |
tpm2.TSS2_RESMGR_TPM_RC_LAYER)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment