Commit 5af7f115 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull tpm updates from James Morris:

 - 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

* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (37 commits)
  tpm/ppi: Enable submission of optional command parameter for PPI 1.3
  tpm/ppi: Possibly show command parameter if TPM PPI 1.3 is used
  tpm/ppi: Display up to 101 operations as define for version 1.3
  tpm/ppi: rename TPM_PPI_REVISION_ID to TPM_PPI_REVISION_ID_1
  tpm/ppi: pass function revision ID to tpm_eval_dsm()
  tpm: pass an array of tpm_extend_digest structures to tpm_pcr_extend()
  KEYS: trusted: explicitly use tpm_chip structure from tpm_default_chip()
  tpm: move tpm_chip definition to include/linux/tpm.h
  tpm: retrieve digest size of unknown algorithms with PCR read
  tpm: rename and export tpm2_digest and tpm2_algorithms
  tpm: dynamically allocate the allocated_banks array
  tpm: remove @flags from tpm_transmit()
  tpm: take TPM chip power gating out of tpm_transmit()
  tpm: introduce tpm_chip_start() and tpm_chip_stop()
  tpm: remove TPM_TRANSMIT_UNLOCKED flag
  tpm: use tpm_try_get_ops() in tpm-sysfs.c.
  tpm: remove @space from tpm_transmit()
  tpm: move TPM space code out of tpm_transmit()
  tpm: move tpm_validate_commmand() to tpm2-space.c
  tpm: clean up tpm_try_transmit() error handling flow
  ...
parents c3665a6b 5da10728
......@@ -74,7 +74,7 @@ static const char* tcpa_pc_event_id_strings[] = {
/* returns pointer to start of pos. entry of tcg log */
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_bios_log *log = &chip->log;
void *addr = log->bios_event_log;
......@@ -83,38 +83,29 @@ static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
u32 converted_event_size;
u32 converted_event_type;
/* read over *pos measurements */
for (i = 0; i < *pos; i++) {
do {
event = addr;
/* check if current entry is valid */
if (addr + sizeof(struct tcpa_event) > limit)
return NULL;
converted_event_size =
do_endian_conversion(event->event_size);
converted_event_type =
do_endian_conversion(event->event_type);
if ((addr + sizeof(struct tcpa_event)) < limit) {
if ((converted_event_type == 0) &&
(converted_event_size == 0))
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;
if (((converted_event_type == 0) && (converted_event_size == 0))
|| ((addr + sizeof(struct tcpa_event) + converted_event_size)
> limit))
return NULL;
converted_event_size = do_endian_conversion(event->event_size);
converted_event_type = do_endian_conversion(event->event_type);
if (i++ == *pos)
break;
if (((converted_event_type == 0) && (converted_event_size == 0))
|| ((addr + sizeof(struct tcpa_event) + converted_event_size)
>= limit))
return NULL;
addr += (sizeof(struct tcpa_event) + converted_event_size);
} while (1);
return addr;
}
......@@ -134,7 +125,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
v += sizeof(struct tcpa_event) + converted_event_size;
/* now check if current entry is valid */
if ((v + sizeof(struct tcpa_event)) >= limit)
if ((v + sizeof(struct tcpa_event)) > limit)
return NULL;
event = 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);
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;
(*pos)++;
......
......@@ -37,10 +37,10 @@
*
* 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_efi_specid_event *efispecid;
struct tcg_efi_specid_event_head *efispecid;
struct tcg_event_field *event_field;
void *marker;
void *marker_start;
......@@ -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)
+ 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. */
if (event->count > efispecid->num_algs)
......@@ -95,7 +95,7 @@ static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
void *addr = log->bios_event_log;
void *limit = log->bios_event_log_end;
struct tcg_pcr_event *event_header;
struct tcg_pcr_event2 *event;
struct tcg_pcr_event2_head *event;
size_t size;
int i;
......@@ -136,7 +136,7 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
loff_t *pos)
{
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_bios_log *log = &chip->log;
void *limit = log->bios_event_log_end;
......@@ -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_bios_log *log = &chip->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;
size_t size;
......
......@@ -33,7 +33,7 @@
struct st33zp24_i2c_phy {
struct i2c_client *client;
u8 buf[TPM_BUFSIZE + 1];
u8 buf[ST33ZP24_BUFSIZE + 1];
int io_lpcpd;
};
......
......@@ -63,7 +63,7 @@
* some latency byte before the answer is available (max 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)
......
......@@ -436,7 +436,7 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
goto out_err;
}
return len;
return 0;
out_err:
st33zp24_cancel(chip);
release_locality(chip);
......
......@@ -18,8 +18,8 @@
#ifndef __LOCAL_ST33ZP24_H__
#define __LOCAL_ST33ZP24_H__
#define TPM_WRITE_DIRECTION 0x80
#define TPM_BUFSIZE 2048
#define TPM_WRITE_DIRECTION 0x80
#define ST33ZP24_BUFSIZE 2048
struct st33zp24_dev {
struct tpm_chip *chip;
......
......@@ -37,6 +37,103 @@ struct class *tpm_class;
struct class *tpmrm_class;
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
* @chip: Chip to ref
......@@ -56,10 +153,17 @@ int tpm_try_get_ops(struct tpm_chip *chip)
down_read(&chip->ops_sem);
if (!chip->ops)
goto out_ops;
mutex_lock(&chip->tpm_mutex);
rc = tpm_chip_start(chip);
if (rc)
goto out_lock;
return 0;
out_lock:
mutex_unlock(&chip->tpm_mutex);
out_ops:
up_read(&chip->ops_sem);
put_device(&chip->dev);
return rc;
......@@ -75,6 +179,8 @@ EXPORT_SYMBOL_GPL(tpm_try_get_ops);
*/
void tpm_put_ops(struct tpm_chip *chip)
{
tpm_chip_stop(chip);
mutex_unlock(&chip->tpm_mutex);
up_read(&chip->ops_sem);
put_device(&chip->dev);
}
......@@ -160,6 +266,7 @@ static void tpm_dev_release(struct device *dev)
kfree(chip->log.bios_event_log);
kfree(chip->work_space.context_buf);
kfree(chip->work_space.session_buf);
kfree(chip->allocated_banks);
kfree(chip);
}
......@@ -189,7 +296,10 @@ static int tpm_class_shutdown(struct device *dev)
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
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;
up_write(&chip->ops_sem);
}
......@@ -368,8 +478,12 @@ static void tpm_del_char_device(struct tpm_chip *chip)
/* Make the driver uncallable. */
down_write(&chip->ops_sem);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_CLEAR);
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
if (!tpm_chip_start(chip)) {
tpm2_shutdown(chip, TPM2_SU_CLEAR);
tpm_chip_stop(chip);
}
}
chip->ops = NULL;
up_write(&chip->ops_sem);
}
......@@ -451,7 +565,11 @@ int tpm_chip_register(struct tpm_chip *chip)
{
int rc;
rc = tpm_chip_start(chip);
if (rc)
return rc;
rc = tpm_auto_startup(chip);
tpm_chip_stop(chip);
if (rc)
return rc;
......
......@@ -27,7 +27,38 @@
static struct workqueue_struct *tpm_dev_wq;
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 =
container_of(work, struct file_priv, async_work);
......@@ -35,9 +66,8 @@ static void tpm_async_work(struct work_struct *work)
mutex_lock(&priv->buffer_mutex);
priv->command_enqueued = false;
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer), 0);
ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer));
tpm_put_ops(priv->chip);
if (ret > 0) {
priv->response_length = ret;
......@@ -80,7 +110,7 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,
mutex_init(&priv->buffer_mutex);
timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
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);
file->private_data = priv;
}
......@@ -183,8 +213,8 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
return size;
}
ret = tpm_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer), 0);
ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer));
tpm_put_ops(priv->chip);
if (ret > 0) {
......
This diff is collapsed.
......@@ -39,7 +39,6 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
{
struct tpm_buf tpm_buf;
struct tpm_readpubek_out *out;
ssize_t rc;
int i;
char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev);
......@@ -47,19 +46,17 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
memset(&anti_replay, 0, sizeof(anti_replay));
rc = tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK);
if (rc)
return rc;
if (tpm_try_get_ops(chip))
return 0;
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));
rc = tpm_transmit_cmd(chip, NULL, tpm_buf.data, PAGE_SIZE,
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
"attempting to read the PUBEK");
if (rc) {
tpm_buf_destroy(&tpm_buf);
return 0;
}
if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
"attempting to read the PUBEK"))
goto out_buf;
out = (struct tpm_readpubek_out *)&tpm_buf.data[10];
str +=
......@@ -90,9 +87,11 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
str += sprintf(str, "\n");
}
rc = str - buf;
out_buf:
tpm_buf_destroy(&tpm_buf);
return rc;
out_ops:
tpm_put_ops(chip);
return str - buf;
}
static DEVICE_ATTR_RO(pubek);
......@@ -101,27 +100,32 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
{
cap_t cap;
u8 digest[TPM_DIGEST_SIZE];
ssize_t rc;
u32 i, j, num_pcrs;
char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev);
rc = tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap,
"attempting to determine the number of PCRS",
sizeof(cap.num_pcrs));
if (rc)
if (tpm_try_get_ops(chip))
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);
for (i = 0; i < num_pcrs; i++) {
rc = tpm1_pcr_read(chip, i, digest);
if (rc)
if (tpm1_pcr_read(chip, i, digest)) {
str = buf;
break;
}
str += sprintf(str, "PCR-%02d: ", i);
for (j = 0; j < TPM_DIGEST_SIZE; j++)
str += sprintf(str, "%02X ", digest[j]);
str += sprintf(str, "\n");
}
tpm_put_ops(chip);
return str - buf;
}
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,
char *buf)
{
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent enabled state",
sizeof(cap.perm_flags));
if (rc)
if (tpm_try_get_ops(chip))
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);
out_ops:
tpm_put_ops(chip);
return rc;
}
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,
char *buf)
{
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent active state",
sizeof(cap.perm_flags));
if (rc)
if (tpm_try_get_ops(chip))
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);
out_ops:
tpm_put_ops(chip);
return rc;
}
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,
char *buf)
{
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
"attempting to determine the owner state",
sizeof(cap.owned));
if (rc)
if (tpm_try_get_ops(chip))
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);
out_ops:
tpm_put_ops(chip);
return rc;
}
static DEVICE_ATTR_RO(owned);
......@@ -180,16 +199,21 @@ static DEVICE_ATTR_RO(owned);
static ssize_t temp_deactivated_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tpm_chip *chip = to_tpm_chip(dev);
ssize_t rc = 0;
cap_t cap;
ssize_t rc;
rc = tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
"attempting to determine the temporary state",
sizeof(cap.stclear_flags));
if (rc)
if (tpm_try_get_ops(chip))
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);
out_ops:
tpm_put_ops(chip);
return rc;
}
static DEVICE_ATTR_RO(temp_deactivated);
......@@ -198,15 +222,18 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tpm_chip *chip = to_tpm_chip(dev);
cap_t cap;
ssize_t rc;
ssize_t rc = 0;
char *str = buf;
cap_t cap;
rc = tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
"attempting to determine the manufacturer",
sizeof(cap.manufacturer_id));
if (rc)
if (tpm_try_get_ops(chip))
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",
be32_to_cpu(cap.manufacturer_id));
......@@ -223,11 +250,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
cap.tpm_version_1_2.revMinor);
} else {
/* Otherwise just use TPM_STRUCT_VER */
rc = tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
"attempting to determine the 1.1 version",
sizeof(cap.tpm_version));
if (rc)
return 0;
if (tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
"attempting to determine the 1.1 version",
sizeof(cap.tpm_version)))
goto out_ops;
str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n",
cap.tpm_version.Major,
......@@ -235,8 +261,10 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
cap.tpm_version.revMajor,
cap.tpm_version.revMinor);
}
return str - buf;
rc = str - buf;
out_ops:
tpm_put_ops(chip);
return rc;
}
static DEVICE_ATTR_RO(caps);
......@@ -244,10 +272,12 @@ static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct tpm_chip *chip = to_tpm_chip(dev);
if (chip == NULL)
if (tpm_try_get_ops(chip))
return 0;
chip->ops->cancel(chip);
tpm_put_ops(chip);
return count;
}
static DEVICE_ATTR_WO(cancel);
......
......@@ -25,30 +25,22 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/hw_random.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/tpm.h>
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/highmem.h>
#include <linux/tpm_eventlog.h>
#include <crypto/hash_info.h>
#ifdef CONFIG_X86
#include <asm/intel-family.h>
#endif
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_BUFSIZE = 4096,
TPM_NUM_DEVICES = 65536,
TPM_RETRY = 50, /* 5 seconds */
TPM_NUM_EVENT_LOG_FILES = 3,
};
#define TPM_MINOR 224 /* officially assigned */
#define TPM_BUFSIZE 4096
#define TPM_NUM_DEVICES 65536
#define TPM_RETRY 50
enum tpm_timeout {
TPM_TIMEOUT = 5, /* msecs */
......@@ -65,16 +57,6 @@ enum tpm_addr {
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_DOING_SELFTEST 0x802
#define TPM_ERR_DEACTIVATED 0x6
......@@ -122,17 +104,6 @@ enum tpm2_return_codes {
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 {
TPM2_CC_FIRST = 0x011F,
TPM2_CC_HIERARCHY_CONTROL = 0x0121,
......@@ -190,15 +161,6 @@ enum tpm2_cc_attrs {
#define TPM_VID_WINBOND 0x1050
#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 {
TPM_CHIP_FLAG_TPM2 = BIT(1),
TPM_CHIP_FLAG_IRQ = BIT(2),
......@@ -207,82 +169,15 @@ enum tpm_chip_flags {
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)
struct tpm_input_header {
__be16 tag;
__be32 length;
__be32 ordinal;
} __packed;
struct tpm_output_header {
__be16 tag;
__be32 length;
__be32 return_code;
struct tpm_header {
__be16 tag;
__be32 length;
union {
__be32 ordinal;
__be32 return_code;
};
} __packed;
#define TPM_TAG_RQU_COMMAND 193
......@@ -401,8 +296,8 @@ struct tpm_buf {
static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
struct tpm_input_header *head;
head = (struct tpm_input_header *)buf->data;
struct tpm_header *head = (struct tpm_header *)buf->data;
head->tag = cpu_to_be16(tag);
head->length = cpu_to_be32(sizeof(*head));
head->ordinal = cpu_to_be32(ordinal);
......@@ -428,14 +323,14 @@ static inline void tpm_buf_destroy(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);
}
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);
}
......@@ -444,7 +339,7 @@ static inline void tpm_buf_append(struct tpm_buf *buf,
const unsigned char *new_data,
unsigned int new_len)
{
struct tpm_input_header *head = (struct tpm_input_header *) buf->data;
struct tpm_header *head = (struct tpm_header *)buf->data;
u32 len = tpm_buf_length(buf);
/* Return silently if overflow has already happened. */
......@@ -487,25 +382,9 @@ extern const struct file_operations tpm_fops;
extern const struct file_operations tpmrm_fops;
extern struct idr dev_nums_idr;
/**
* enum tpm_transmit_flags - flags for tpm_transmit()
*
* @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);
ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz);
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
size_t min_rsp_body_length, const char *desc);
int tpm_get_timeouts(struct tpm_chip *);
int tpm_auto_startup(struct tpm_chip *chip);
......@@ -530,6 +409,8 @@ static inline void tpm_msleep(unsigned int delay_msec)
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);
__must_check int tpm_try_get_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)
}
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_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
struct tpm2_digest *digests);
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digest, u16 *digest_size_ptr);
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);
void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
unsigned int flags);
void tpm2_flush_context(struct tpm_chip *chip, u32 handle);
int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
......@@ -580,10 +461,11 @@ int tpm2_probe(struct tpm_chip *chip);
int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
int tpm2_init_space(struct tpm_space *space);
void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space);
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
u8 *cmd);
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
u32 cc, u8 *buf, size_t *bufsiz);
void tpm2_flush_space(struct tpm_chip *chip);
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
size_t cmdsiz);
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);
void tpm_bios_log_teardown(struct tpm_chip *chip);
......
......@@ -334,11 +334,8 @@ static int tpm1_startup(struct tpm_chip *chip)
tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
"attempting to start the TPM");
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
tpm_buf_destroy(&buf);
return rc;
}
......@@ -380,8 +377,7 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
* of misreporting.
*/
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) {
/* Restore default if chip reported 0 */
......@@ -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(&buf, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
TPM_DIGEST_SIZE, 0, log_msg);
rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
tpm_buf_destroy(&buf);
return rc;
}
......@@ -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, subcap_id);
}
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
min_cap_length, 0, desc);
rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
if (!rc)
*cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
tpm_buf_destroy(&buf);
return rc;
}
......@@ -537,8 +529,7 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
do {
tpm_buf_append_u32(&buf, num_bytes);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
sizeof(out->rng_data_len), 0,
rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
"attempting get random");
if (rc)
goto out;
......@@ -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);
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
TPM_DIGEST_SIZE, 0,
rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE,
"attempting to read a pcr value");
if (rc)
goto out;
......@@ -618,11 +608,8 @@ static int tpm1_continue_selftest(struct tpm_chip *chip)
if (rc)
return rc;
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
0, 0, "continue selftest");
rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
tpm_buf_destroy(&buf);
return rc;
}
......@@ -709,6 +696,18 @@ int tpm1_auto_startup(struct tpm_chip *chip)
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;
out:
if (rc > 0)
......@@ -747,9 +746,7 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
return rc;
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
0, 0, NULL);
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
* 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)
for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
if (space->session_tbl[i])
tpm2_flush_context_cmd(chip, space->session_tbl[i],
TPM_TRANSMIT_NESTED);
tpm2_flush_context(chip, space->session_tbl[i]);
}
}
......@@ -61,7 +60,10 @@ int tpm2_init_space(struct tpm_space *space)
void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
{
mutex_lock(&chip->tpm_mutex);
tpm2_flush_sessions(chip, space);
if (!tpm_chip_start(chip)) {
tpm2_flush_sessions(chip, space);
tpm_chip_stop(chip);
}
mutex_unlock(&chip->tpm_mutex);
kfree(space->context_buf);
kfree(space->session_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);
tpm_buf_append(&tbuf, &buf[*offset], body_size);
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4,
TPM_TRANSMIT_NESTED, NULL);
rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
......@@ -132,8 +133,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
tpm_buf_append_u32(&tbuf, handle);
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0,
TPM_TRANSMIT_NESTED, NULL);
rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
......@@ -162,15 +162,14 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
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;
int i;
for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
if (space->context_tbl[i] && ~space->context_tbl[i])
tpm2_flush_context_cmd(chip, space->context_tbl[i],
TPM_TRANSMIT_NESTED);
tpm2_flush_context(chip, space->context_tbl[i]);
tpm2_flush_sessions(chip, space);
}
......@@ -264,14 +263,54 @@ static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
return 0;
}
int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
u8 *cmd)
static int tpm_find_and_validate_cc(struct tpm_chip *chip,
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 cc;
if (!space)
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,
sizeof(space->context_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,
return rc;
}
chip->last_cc = cc;
return 0;
}
......@@ -334,7 +374,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
size_t len)
{
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_type;
u32 vhandle;
......@@ -377,7 +417,7 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
return 0;
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__,
phandle);
return -ENOMEM;
......@@ -394,7 +434,7 @@ static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
size_t len)
{
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;
u32 phandle;
u32 phandle_type;
......@@ -464,8 +504,7 @@ static int tpm2_save_space(struct tpm_chip *chip)
} else if (rc)
return rc;
tpm2_flush_context_cmd(chip, space->context_tbl[i],
TPM_TRANSMIT_NESTED);
tpm2_flush_context(chip, space->context_tbl[i]);
space->context_tbl[i] = ~0;
}
......@@ -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,
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;
if (!space)
return 0;
rc = tpm2_map_response_header(chip, cc, buf, *bufsiz);
rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
if (rc) {
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) {
tpm2_flush_space(chip);
return rc;
goto out;
}
rc = tpm2_save_space(chip);
if (rc) {
tpm2_flush_space(chip);
return rc;
goto out;
}
*bufsiz = be32_to_cpu(header->length);
......@@ -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);
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)
iowrite8(buf[i], priv->iobase);
}
return count;
return 0;
}
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)
struct crb_priv *priv = dev_get_drvdata(&chip->dev);
unsigned int expected;
/* sanity check */
if (count < 6)
/* A sanity check that the upper layer wants to get at least the header
* as that is the minimum size for any TPM response.
*/
if (count < TPM_HEADER_SIZE)
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)
return -EIO;
memcpy_fromio(buf, priv->rsp, 6);
expected = be32_to_cpup((__be32 *) &buf[2]);
if (expected > count || expected < 6)
/* Read the first 8 bytes in order to get the length of the response.
* We read exactly a quad word in order to make sure that the remaining
* 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;
memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
memcpy_fromio(&buf[8], &priv->rsp[8], expected - 8);
return expected;
}
......
......@@ -46,7 +46,7 @@ struct priv_data {
/* 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
* 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)
......@@ -65,15 +65,22 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
dev_dbg(&chip->dev,
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
(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)
{
struct priv_data *priv = dev_get_drvdata(&chip->dev);
struct i2c_client *client = to_i2c_client(chip->dev.parent);
struct tpm_output_header *hdr =
(struct tpm_output_header *)priv->buffer;
struct tpm_header *hdr = (struct tpm_header *)priv->buffer;
u32 expected_len;
int rc;
......
......@@ -26,8 +26,7 @@
#include <linux/wait.h>
#include "tpm.h"
/* max. buffer size supported by our TPM */
#define TPM_BUFSIZE 1260
#define TPM_I2C_INFINEON_BUFSIZE 1260
/* max. number of iterations after I2C NAK */
#define MAX_COUNT 3
......@@ -63,11 +62,13 @@ enum i2c_chip_type {
UNKNOWN,
};
/* Structure to store I2C TPM specific stuff */
struct tpm_inf_dev {
struct i2c_client *client;
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;
enum i2c_chip_type chip_type;
unsigned int adapterlimit;
......@@ -219,7 +220,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
.buf = tpm_dev.buf
};
if (len > TPM_BUFSIZE)
if (len > TPM_I2C_INFINEON_BUFSIZE)
return -EINVAL;
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)
u8 retries = 0;
u8 sts = TPM_STS_GO;
if (len > TPM_BUFSIZE)
return -E2BIG; /* command is too long for our tpm, sorry */
if (len > TPM_I2C_INFINEON_BUFSIZE)
return -E2BIG;
if (request_locality(chip, 0) < 0)
return -EBUSY;
......@@ -587,7 +588,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
/* go and do it */
iic_tpm_write(TPM_STS(tpm_dev.locality), &sts, 1);
return len;
return 0;
out_err:
tpm_tis_i2c_ready(chip);
/* The TPM needs some time to clean up here,
......
......@@ -35,14 +35,12 @@
#include "tpm.h"
/* I2C interface offsets */
#define TPM_STS 0x00
#define TPM_BURST_COUNT 0x01
#define TPM_DATA_FIFO_W 0x20
#define TPM_DATA_FIFO_R 0x40
#define TPM_VID_DID_RID 0x60
/* TPM command header size */
#define TPM_HEADER_SIZE 10
#define TPM_RETRY 5
#define TPM_STS 0x00
#define TPM_BURST_COUNT 0x01
#define TPM_DATA_FIFO_W 0x20
#define TPM_DATA_FIFO_R 0x40
#define TPM_VID_DID_RID 0x60
#define TPM_I2C_RETRIES 5
/*
* 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
......@@ -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__);
return -EIO;
}
for (retries = 0; retries < TPM_RETRY; retries++) {
for (retries = 0; retries < TPM_I2C_RETRIES; retries++) {
if (retries > 0) {
/* if this is not the first trial, set responseRetry */
i2c_nuvoton_write_status(client,
......@@ -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);
return len;
return 0;
}
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)
}
/**
* tpm_ibmvtpm_send - Send tpm request
*
* tpm_ibmvtpm_send() - Send a TPM command
* @chip: tpm chip struct
* @buf: buffer contains data to send
* @count: size of buffer
*
* 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)
{
......@@ -192,7 +192,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
rc = 0;
ibmvtpm->tpm_processing_cmd = false;
} else
rc = count;
rc = 0;
spin_unlock(&ibmvtpm->rtce_lock);
return rc;
......
......@@ -354,7 +354,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
for (i = 0; i < count; i++) {
wait_and_send(chip, buf[i]);
}
return count;
return 0;
}
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)
}
outb(NSC_COMMAND_EOC, priv->base + NSC_COMMAND);
return count;
return 0;
}
static void tpm_nsc_cancel(struct tpm_chip *chip)
......
......@@ -20,7 +20,8 @@
#include <linux/acpi.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_SUBREQ 2
#define TPM_PPI_FN_GETREQ 3
......@@ -28,7 +29,7 @@
#define TPM_PPI_FN_GETRSP 5
#define TPM_PPI_FN_SUBREQ2 7
#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_END 255
......@@ -36,14 +37,18 @@ static const guid_t tpm_ppi_guid =
GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
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 *
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);
return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid,
TPM_PPI_REVISION_ID,
func, argv4, type);
rev, func, argv4, type);
}
static ssize_t tpm_show_ppi_version(struct device *dev,
......@@ -60,9 +65,14 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
ssize_t size = -EINVAL;
union acpi_object *obj;
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,
ACPI_TYPE_PACKAGE, NULL);
ACPI_TYPE_PACKAGE, NULL, rev);
if (!obj)
return -ENXIO;
......@@ -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
* 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[1].type == ACPI_TYPE_INTEGER) {
if (obj->package.elements[0].integer.value)
......@@ -94,9 +120,10 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
u32 req;
u64 ret;
int func = TPM_PPI_FN_SUBREQ;
union acpi_object *obj, tmp;
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
union acpi_object *obj, tmp[2];
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(2, tmp);
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
......@@ -104,7 +131,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
* version 1.1
*/
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;
/*
......@@ -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
* 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)
return -EINVAL;
argv4.type = ACPI_TYPE_BUFFER;
argv4.buffer.length = sizeof(req);
argv4.buffer.pointer = (u8 *)&req;
} else {
tmp.type = ACPI_TYPE_INTEGER;
if (sscanf(buf, "%llu", &tmp.integer.value) != 1)
ppi12:
argv4.package.count = 1;
tmp[0].type = ACPI_TYPE_INTEGER;
if (sscanf(buf, "%llu", &tmp[0].integer.value) != 1)
return -EINVAL;
}
obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
&argv4);
&argv4, rev);
if (!obj) {
return -ENXIO;
} else {
......@@ -170,7 +206,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
if (strcmp(chip->ppi_version, "1.2") < 0)
obj = &tmp;
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) {
return -ENXIO;
} else {
......@@ -196,7 +232,7 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
struct tpm_chip *chip = to_tpm_chip(dev);
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
ACPI_TYPE_PACKAGE, NULL);
ACPI_TYPE_PACKAGE, NULL, TPM_PPI_REVISION_ID_1);
if (!obj)
return -ENXIO;
......@@ -264,7 +300,7 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
"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))
return -EPERM;
......@@ -272,7 +308,8 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
for (i = start; i <= end; i++) {
tmp.integer.value = i;
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) {
return -ENOMEM;
} else {
......@@ -338,12 +375,13 @@ void tpm_add_ppi(struct tpm_chip *chip)
return;
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;
/* Cache PPI version string. */
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);
if (obj) {
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)
goto out_err;
}
}
return len;
return 0;
out_err:
tpm_tis_ready(chip);
return rc;
......@@ -521,35 +521,38 @@ static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = {
(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)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int i, rc;
u32 did_vid;
chip->timeout_adjusted = false;
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, true);
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;
}
for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
if (vendor_timeout_overrides[i].did_vid != did_vid)
continue;
memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
sizeof(vendor_timeout_overrides[i].timeout_us));
rc = true;
chip->timeout_adjusted = true;
}
rc = false;
out:
if (chip->ops->clk_enable != NULL)
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,
intmask &= ~TPM_GLOBAL_INT_ENABLE;
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
rc = tpm_chip_start(chip);
if (rc)
goto out_err;
rc = tpm2_probe(chip);
tpm_chip_stop(chip);
if (rc)
goto out_err;
......
......@@ -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,
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;
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
......@@ -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)
{
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
int rc = 0;
if (count > sizeof(proxy_dev->buffer)) {
dev_err(&chip->dev,
......@@ -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);
return rc;
return 0;
}
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)
{
struct tpm_buf buf;
int rc;
const struct tpm_output_header *header;
const struct tpm_header *header;
struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
......@@ -417,9 +416,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
proxy_dev->state |= STATE_DRIVER_COMMAND;
rc = tpm_transmit_cmd(chip, NULL, buf.data, tpm_buf_length(&buf), 0,
TPM_TRANSMIT_NESTED,
"attempting to set locality");
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to set locality");
proxy_dev->state &= ~STATE_DRIVER_COMMAND;
......@@ -428,7 +425,7 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
goto out;
}
header = (const struct tpm_output_header *)buf.data;
header = (const struct tpm_header *)buf.data;
rc = be32_to_cpu(header->return_code);
if (rc)
locality = -1;
......
......@@ -163,7 +163,7 @@ static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
wmb();
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);
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)
return -ETIME;
}
return count;
return 0;
}
static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
......
......@@ -22,12 +22,41 @@
#ifndef __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_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
struct tpm_chip;
struct trusted_key_payload;
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 {
TPM_OPS_AUTO_STARTUP = BIT(0),
};
......@@ -41,7 +70,7 @@ struct tpm_class_ops {
int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
void (*cancel) (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);
int (*go_idle)(struct tpm_chip *chip);
int (*cmd_ready)(struct tpm_chip *chip);
......@@ -50,11 +79,100 @@ struct tpm_class_ops {
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)
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_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash);
extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
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_get_random(struct tpm_chip *chip, u8 *data, size_t max);
extern int tpm_seal_trusted(struct tpm_chip *chip,
......@@ -70,13 +188,14 @@ static inline int tpm_is_tpm2(struct tpm_chip *chip)
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;
}
static inline int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
const u8 *hash)
struct tpm_digest *digests)
{
return -ENODEV;
}
......
......@@ -3,12 +3,11 @@
#ifndef __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 MAX_TEXT_EVENT 1000 /* Max event string length */
#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_2 0x2
......@@ -82,7 +81,7 @@ struct tcg_efi_specid_event_algs {
u16 digest_size;
} __packed;
struct tcg_efi_specid_event {
struct tcg_efi_specid_event_head {
u8 signature[16];
u32 platform_class;
u8 spec_version_minor;
......@@ -90,9 +89,7 @@ struct tcg_efi_specid_event {
u8 spec_errata;
u8 uintnsize;
u32 num_algs;
struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS];
u8 vendor_info_size;
u8 vendor_info[0];
struct tcg_efi_specid_event_algs digest_sizes[];
} __packed;
struct tcg_pcr_event {
......@@ -108,17 +105,11 @@ struct tcg_event_field {
u8 event[0];
} __packed;
struct tpm2_digest {
u16 alg_id;
u8 digest[SHA512_DIGEST_SIZE];
} __packed;
struct tcg_pcr_event2 {
struct tcg_pcr_event2_head {
u32 pcr_idx;
u32 event_type;
u32 count;
struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS];
struct tcg_event_field event;
struct tpm_digest digests[];
} __packed;
#endif
......@@ -153,6 +153,7 @@ int ima_measurements_show(struct seq_file *m, void *v);
unsigned long ima_get_binary_runtime_size(void);
int ima_init_template(void);
void ima_init_template_list(void);
int __init ima_init_digests(void);
/*
* used to protect h_table and sha_table
......
......@@ -643,12 +643,12 @@ int ima_calc_buffer_hash(const void *buf, loff_t len,
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)
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");
}
......@@ -658,7 +658,7 @@ static void __init ima_pcrread(u32 idx, u8 *pcr)
static int __init ima_calc_boot_aggregate_tfm(char *digest,
struct crypto_shash *tfm)
{
u8 pcr_i[TPM_DIGEST_SIZE];
struct tpm_digest d = { .alg_id = TPM_ALG_SHA1, .digest = {0} };
int rc;
u32 i;
SHASH_DESC_ON_STACK(shash, tfm);
......@@ -672,9 +672,9 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest,
/* cumulative sha1 over tpm registers 0-7 */
for (i = TPM_PCR0; i < TPM_PCR8; i++) {
ima_pcrread(i, pcr_i);
ima_pcrread(i, &d);
/* 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)
crypto_shash_final(shash, digest);
......
......@@ -123,8 +123,12 @@ int __init ima_init(void)
if (rc != 0)
return rc;
/* It can be called before ima_init_digests(), it does not use TPM. */
ima_load_kexec_buffer();
rc = ima_init_digests();
if (rc != 0)
return rc;
rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */
if (rc != 0)
return rc;
......
......@@ -27,6 +27,9 @@
#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 */
#ifdef CONFIG_IMA_KEXEC
static unsigned long binary_runtime_size;
......@@ -140,11 +143,15 @@ unsigned long ima_get_binary_runtime_size(void)
static int ima_pcr_extend(const u8 *hash, int pcr)
{
int result = 0;
int i;
if (!ima_tpm_chip)
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)
pr_err("Error Communicating to TPM chip, result: %d\n", result);
return result;
......@@ -211,3 +218,21 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry)
mutex_unlock(&ima_extend_list_mutex);
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 @@
static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1";
static struct tpm_chip *chip;
static struct tpm_digest *digests;
struct sdesc {
struct shash_desc shash;
......@@ -362,7 +364,7 @@ int trusted_tpm_send(unsigned char *cmd, size_t buflen)
int rc;
dump_tpm_buf(cmd);
rc = tpm_send(NULL, cmd, buflen);
rc = tpm_send(chip, cmd, buflen);
dump_tpm_buf(cmd);
if (rc > 0)
/* Can't return positive return codes values to keyctl */
......@@ -379,15 +381,10 @@ EXPORT_SYMBOL_GPL(trusted_tpm_send);
*/
static int pcrlock(const int pcrnum)
{
unsigned char hash[SHA1_DIGEST_SIZE];
int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);
if (ret != SHA1_DIGEST_SIZE)
return ret;
return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;
return tpm_pcr_extend(chip, pcrnum, digests) ? -EINVAL : 0;
}
/*
......@@ -400,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
unsigned char ononce[TPM_NONCE_SIZE];
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)
return ret;
......@@ -496,7 +493,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
if (ret < 0)
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)
goto out;
ordinal = htonl(TPM_ORD_SEAL);
......@@ -606,7 +603,7 @@ static int tpm_unseal(struct tpm_buf *tb,
ordinal = htonl(TPM_ORD_UNSEAL);
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) {
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
return ret;
......@@ -751,7 +748,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
int i;
int tpm2;
tpm2 = tpm_is_tpm2(NULL);
tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0)
return tpm2;
......@@ -920,7 +917,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
struct trusted_key_options *options;
int tpm2;
tpm2 = tpm_is_tpm2(NULL);
tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0)
return NULL;
......@@ -970,7 +967,7 @@ static int trusted_instantiate(struct key *key,
size_t key_len;
int tpm2;
tpm2 = tpm_is_tpm2(NULL);
tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0)
return tpm2;
......@@ -1011,7 +1008,7 @@ static int trusted_instantiate(struct key *key,
switch (key_cmd) {
case Opt_load:
if (tpm2)
ret = tpm_unseal_trusted(NULL, payload, options);
ret = tpm_unseal_trusted(chip, payload, options);
else
ret = key_unseal(payload, options);
dump_payload(payload);
......@@ -1021,13 +1018,13 @@ static int trusted_instantiate(struct key *key,
break;
case Opt_new:
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) {
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
}
if (tpm2)
ret = tpm_seal_trusted(NULL, payload, options);
ret = tpm_seal_trusted(chip, payload, options);
else
ret = key_seal(payload, options);
if (ret < 0)
......@@ -1221,21 +1218,59 @@ static int __init trusted_shash_alloc(void)
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)
{
int ret;
chip = tpm_default_chip();
if (!chip)
return -ENOENT;
ret = init_digests();
if (ret < 0)
goto err_put;
ret = trusted_shash_alloc();
if (ret < 0)
return ret;
goto err_free;
ret = register_key_type(&key_type_trusted);
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;
}
static void __exit cleanup_trusted(void)
{
put_device(&chip->dev);
kfree(digests);
trusted_shash_release();
unregister_key_type(&key_type_trusted);
}
......
......@@ -50,6 +50,7 @@ ifneq (1, $(quicktest))
TARGETS += timers
endif
TARGETS += tmpfs
TARGETS += tpm2
TARGETS += user
TARGETS += vm
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