mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
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.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
if (((converted_event_type == 0) && (converted_event_size == 0))
|
||||
|| ((addr + sizeof(struct tcpa_event) + converted_event_size)
|
||||
> limit))
|
||||
return NULL;
|
||||
|
||||
/* now check if current entry is valid */
|
||||
if ((addr + sizeof(struct tcpa_event)) >= limit)
|
||||
return NULL;
|
||||
if (i++ == *pos)
|
||||
break;
|
||||
|
||||
event = addr;
|
||||
|
||||
converted_event_size = do_endian_conversion(event->event_size);
|
||||
converted_event_type = do_endian_conversion(event->event_type);
|
||||
|
||||
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;
|
||||
|
||||
+121
-3
@@ -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) {
|
||||
|
||||
@@ -62,137 +62,22 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
|
||||
|
||||
static int tpm_validate_command(struct tpm_chip *chip,
|
||||
struct tpm_space *space,
|
||||
const u8 *cmd,
|
||||
size_t len)
|
||||
static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
|
||||
{
|
||||
const struct tpm_input_header *header = (const void *)cmd;
|
||||
int i;
|
||||
u32 cc;
|
||||
u32 attrs;
|
||||
unsigned int nr_handles;
|
||||
|
||||
if (len < TPM_HEADER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (!space)
|
||||
return 0;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
|
||||
cc = be32_to_cpu(header->ordinal);
|
||||
|
||||
i = tpm2_find_cc(chip, cc);
|
||||
if (i < 0) {
|
||||
dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
|
||||
cc);
|
||||
return -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 0;
|
||||
err_len:
|
||||
dev_dbg(&chip->dev,
|
||||
"%s: insufficient command length %zu", __func__, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return 0;
|
||||
|
||||
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, unsigned int flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return;
|
||||
|
||||
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, unsigned int flags)
|
||||
{
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return 0;
|
||||
|
||||
if (!chip->ops->cmd_ready)
|
||||
return 0;
|
||||
|
||||
return chip->ops->cmd_ready(chip);
|
||||
}
|
||||
|
||||
static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags)
|
||||
{
|
||||
if (flags & TPM_TRANSMIT_NESTED)
|
||||
return 0;
|
||||
|
||||
if (!chip->ops->go_idle)
|
||||
return 0;
|
||||
|
||||
return chip->ops->go_idle(chip);
|
||||
}
|
||||
|
||||
static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
||||
struct tpm_space *space,
|
||||
u8 *buf, size_t bufsiz,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct tpm_output_header *header = (void *)buf;
|
||||
struct tpm_header *header = buf;
|
||||
int rc;
|
||||
ssize_t len = 0;
|
||||
u32 count, ordinal;
|
||||
unsigned long stop;
|
||||
bool need_locality;
|
||||
|
||||
rc = tpm_validate_command(chip, space, buf, bufsiz);
|
||||
if (rc == -EINVAL)
|
||||
return rc;
|
||||
/*
|
||||
* If the command is not implemented by the TPM, synthesize a
|
||||
* response with a TPM2_RC_COMMAND_CODE return for user-space.
|
||||
*/
|
||||
if (rc == -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);
|
||||
return sizeof(*header);
|
||||
}
|
||||
if (bufsiz < TPM_HEADER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (bufsiz > TPM_BUFSIZE)
|
||||
bufsiz = TPM_BUFSIZE;
|
||||
|
||||
count = be32_to_cpu(*((__be32 *) (buf + 2)));
|
||||
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
|
||||
count = be32_to_cpu(header->length);
|
||||
ordinal = be32_to_cpu(header->ordinal);
|
||||
if (count == 0)
|
||||
return -ENODATA;
|
||||
if (count > bufsiz) {
|
||||
@@ -201,37 +86,21 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
|
||||
if (chip->ops->clk_enable != NULL)
|
||||
chip->ops->clk_enable(chip, true);
|
||||
|
||||
/* Store the decision as chip->locality will be changed. */
|
||||
need_locality = chip->locality == -1;
|
||||
|
||||
if (need_locality) {
|
||||
rc = tpm_request_locality(chip, flags);
|
||||
if (rc < 0) {
|
||||
need_locality = false;
|
||||
goto out_locality;
|
||||
}
|
||||
}
|
||||
|
||||
rc = tpm_cmd_ready(chip, flags);
|
||||
if (rc)
|
||||
goto out_locality;
|
||||
|
||||
rc = tpm2_prepare_space(chip, space, ordinal, buf);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = chip->ops->send(chip, buf, count);
|
||||
if (rc < 0) {
|
||||
if (rc != -EPIPE)
|
||||
dev_err(&chip->dev,
|
||||
"%s: tpm_send: error %d\n", __func__, rc);
|
||||
goto out;
|
||||
"%s: send(): error %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* A sanity check. send() should just return zero on success e.g.
|
||||
* not the command length.
|
||||
*/
|
||||
if (rc > 0) {
|
||||
dev_warn(&chip->dev,
|
||||
"%s: send(): invalid value %d\n", __func__, rc);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_IRQ)
|
||||
@@ -246,8 +115,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
||||
|
||||
if (chip->ops->req_canceled(chip, status)) {
|
||||
dev_err(&chip->dev, "Operation Canceled\n");
|
||||
rc = -ECANCELED;
|
||||
goto out;
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
tpm_msleep(TPM_TIMEOUT_POLL);
|
||||
@@ -256,77 +124,45 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
||||
|
||||
chip->ops->cancel(chip);
|
||||
dev_err(&chip->dev, "Operation Timed out\n");
|
||||
rc = -ETIME;
|
||||
goto out;
|
||||
return -ETIME;
|
||||
|
||||
out_recv:
|
||||
len = chip->ops->recv(chip, buf, bufsiz);
|
||||
if (len < 0) {
|
||||
rc = len;
|
||||
dev_err(&chip->dev,
|
||||
"tpm_transmit: tpm_recv: error %d\n", rc);
|
||||
goto out;
|
||||
} else if (len < TPM_HEADER_SIZE) {
|
||||
dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %d\n", rc);
|
||||
} else if (len < TPM_HEADER_SIZE || len != be32_to_cpu(header->length))
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (len != be32_to_cpu(header->length)) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
|
||||
if (rc)
|
||||
dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc);
|
||||
|
||||
out:
|
||||
/* may fail but do not override previous error value in rc */
|
||||
tpm_go_idle(chip, flags);
|
||||
|
||||
out_locality:
|
||||
if (need_locality)
|
||||
tpm_relinquish_locality(chip, flags);
|
||||
|
||||
if (chip->ops->clk_enable != NULL)
|
||||
chip->ops->clk_enable(chip, false);
|
||||
|
||||
if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
return rc ? rc : len;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_transmit - Internal kernel interface to transmit TPM commands.
|
||||
* @chip: a TPM chip to use
|
||||
* @buf: a TPM command buffer
|
||||
* @bufsiz: length of the TPM command buffer
|
||||
*
|
||||
* @chip: TPM chip to use
|
||||
* @space: tpm space
|
||||
* @buf: TPM command buffer
|
||||
* @bufsiz: length of the TPM command buffer
|
||||
* @flags: tpm transmit flags - bitmap
|
||||
* A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from
|
||||
* the TPM and retransmits the command after a delay up to a maximum wait of
|
||||
* TPM2_DURATION_LONG.
|
||||
*
|
||||
* A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY
|
||||
* returns from the TPM and retransmits the command after a delay up
|
||||
* to a maximum wait of TPM2_DURATION_LONG.
|
||||
*
|
||||
* Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2
|
||||
* only
|
||||
* Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0
|
||||
* only.
|
||||
*
|
||||
* Return:
|
||||
* the length of the return when the operation is successful.
|
||||
* A negative number for system errors (errno).
|
||||
* * The response length - OK
|
||||
* * -errno - A system error
|
||||
*/
|
||||
ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||
u8 *buf, size_t bufsiz, unsigned int flags)
|
||||
ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz)
|
||||
{
|
||||
struct tpm_output_header *header = (struct tpm_output_header *)buf;
|
||||
struct tpm_header *header = (struct tpm_header *)buf;
|
||||
/* space for header and handles */
|
||||
u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)];
|
||||
unsigned int delay_msec = TPM2_DURATION_SHORT;
|
||||
u32 rc = 0;
|
||||
ssize_t ret;
|
||||
const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE,
|
||||
bufsiz);
|
||||
const size_t save_size = min(sizeof(save), bufsiz);
|
||||
/* the command code is where the return code will be */
|
||||
u32 cc = be32_to_cpu(header->return_code);
|
||||
|
||||
@@ -338,7 +174,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||
memcpy(save, buf, save_size);
|
||||
|
||||
for (;;) {
|
||||
ret = tpm_try_transmit(chip, space, buf, bufsiz, flags);
|
||||
ret = tpm_try_transmit(chip, buf, bufsiz);
|
||||
if (ret < 0)
|
||||
break;
|
||||
rc = be32_to_cpu(header->return_code);
|
||||
@@ -365,39 +201,33 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_transmit_cmd - send a tpm command to the device
|
||||
* The function extracts tpm out header return code
|
||||
*
|
||||
* @chip: TPM chip to use
|
||||
* @space: tpm space
|
||||
* @buf: TPM command buffer
|
||||
* @bufsiz: length of the buffer
|
||||
* @min_rsp_body_length: minimum expected length of response body
|
||||
* @flags: tpm transmit flags - bitmap
|
||||
* @desc: command description used in the error message
|
||||
* @chip: a TPM chip to use
|
||||
* @buf: a TPM command buffer
|
||||
* @min_rsp_body_length: minimum expected length of response body
|
||||
* @desc: command description used in the error message
|
||||
*
|
||||
* Return:
|
||||
* 0 when the operation is successful.
|
||||
* A negative number for system errors (errno).
|
||||
* A positive number for a TPM error.
|
||||
* * 0 - OK
|
||||
* * -errno - A system error
|
||||
* * TPM_RC - A TPM error
|
||||
*/
|
||||
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_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||
size_t min_rsp_body_length, const char *desc)
|
||||
{
|
||||
const struct tpm_output_header *header = buf;
|
||||
const struct tpm_header *header = (struct tpm_header *)buf->data;
|
||||
int err;
|
||||
ssize_t len;
|
||||
|
||||
len = tpm_transmit(chip, space, buf, bufsiz, flags);
|
||||
len = tpm_transmit(chip, buf->data, PAGE_SIZE);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
err = be32_to_cpu(header->return_code);
|
||||
if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED
|
||||
&& desc)
|
||||
&& err != TPM2_RC_TESTING && desc)
|
||||
dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
|
||||
desc);
|
||||
if (err)
|
||||
@@ -451,11 +281,12 @@ EXPORT_SYMBOL_GPL(tpm_is_tpm2);
|
||||
* tpm_pcr_read - read a PCR value from SHA1 bank
|
||||
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||
* @pcr_idx: the PCR to be retrieved
|
||||
* @res_buf: the value of the PCR
|
||||
* @digest: the PCR bank and buffer current PCR value is written to
|
||||
*
|
||||
* Return: same as with tpm_transmit_cmd()
|
||||
*/
|
||||
int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
||||
int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digest)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -464,9 +295,9 @@ int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
||||
return -ENODEV;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
|
||||
rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL);
|
||||
else
|
||||
rc = tpm1_pcr_read(chip, pcr_idx, res_buf);
|
||||
rc = tpm1_pcr_read(chip, pcr_idx, digest->digest);
|
||||
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
@@ -477,41 +308,34 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read);
|
||||
* tpm_pcr_extend - extend a PCR value in SHA1 bank.
|
||||
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||
* @pcr_idx: the PCR to be retrieved
|
||||
* @hash: the hash value used to extend the PCR value
|
||||
* @digests: array of tpm_digest structures used to extend PCRs
|
||||
*
|
||||
* Note: with TPM 2.0 extends also those banks with a known digest size to the
|
||||
* cryto subsystem in order to prevent malicious use of those PCR banks. In the
|
||||
* future we should dynamically determine digest sizes.
|
||||
* Note: callers must pass a digest for every allocated PCR bank, in the same
|
||||
* order of the banks in chip->allocated_banks.
|
||||
*
|
||||
* Return: same as with tpm_transmit_cmd()
|
||||
*/
|
||||
int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash)
|
||||
int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digests)
|
||||
{
|
||||
int rc;
|
||||
struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
|
||||
u32 count = 0;
|
||||
int i;
|
||||
|
||||
chip = tpm_find_get_ops(chip);
|
||||
if (!chip)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < chip->nr_allocated_banks; i++)
|
||||
if (digests[i].alg_id != chip->allocated_banks[i].alg_id)
|
||||
return -EINVAL;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
memset(digest_list, 0, sizeof(digest_list));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chip->active_banks) &&
|
||||
chip->active_banks[i] != TPM2_ALG_ERROR; i++) {
|
||||
digest_list[i].alg_id = chip->active_banks[i];
|
||||
memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE);
|
||||
count++;
|
||||
}
|
||||
|
||||
rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list);
|
||||
rc = tpm2_pcr_extend(chip, pcr_idx, digests);
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = tpm1_pcr_extend(chip, pcr_idx, hash,
|
||||
rc = tpm1_pcr_extend(chip, pcr_idx, digests[0].digest,
|
||||
"attempting extend a PCR value");
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
@@ -528,14 +352,21 @@ EXPORT_SYMBOL_GPL(tpm_pcr_extend);
|
||||
*/
|
||||
int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
int rc;
|
||||
|
||||
chip = tpm_find_get_ops(chip);
|
||||
if (!chip)
|
||||
return -ENODEV;
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0,
|
||||
"attempting to a send a command");
|
||||
rc = tpm_buf_init(&buf, 0, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
memcpy(buf.data, cmd, buflen);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to a send a command");
|
||||
tpm_buf_destroy(&buf);
|
||||
out:
|
||||
tpm_put_ops(chip);
|
||||
return rc;
|
||||
}
|
||||
@@ -571,10 +402,16 @@ int tpm_pm_suspend(struct device *dev)
|
||||
if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
|
||||
return 0;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||
else
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_shutdown(chip, TPM2_SU_STATE);
|
||||
tpm_chip_stop(chip);
|
||||
}
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
} else {
|
||||
rc = tpm1_pm_suspend(chip, tpm_suspend_pcr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+31
-149
@@ -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);
|
||||
|
||||
+20
-23
@@ -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
|
||||
|
||||
+121
-85
@@ -33,11 +33,11 @@ struct tpm2_hash {
|
||||
};
|
||||
|
||||
static struct tpm2_hash tpm2_hash_map[] = {
|
||||
{HASH_ALGO_SHA1, TPM2_ALG_SHA1},
|
||||
{HASH_ALGO_SHA256, TPM2_ALG_SHA256},
|
||||
{HASH_ALGO_SHA384, TPM2_ALG_SHA384},
|
||||
{HASH_ALGO_SHA512, TPM2_ALG_SHA512},
|
||||
{HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
|
||||
{HASH_ALGO_SHA1, TPM_ALG_SHA1},
|
||||
{HASH_ALGO_SHA256, TPM_ALG_SHA256},
|
||||
{HASH_ALGO_SHA384, TPM_ALG_SHA384},
|
||||
{HASH_ALGO_SHA512, TPM_ALG_SHA512},
|
||||
{HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
|
||||
};
|
||||
|
||||
int tpm2_get_timeouts(struct tpm_chip *chip)
|
||||
@@ -171,20 +171,36 @@ struct tpm2_pcr_read_out {
|
||||
* tpm2_pcr_read() - read a PCR value
|
||||
* @chip: TPM chip to use.
|
||||
* @pcr_idx: index of the PCR to read.
|
||||
* @res_buf: buffer to store the resulting hash.
|
||||
* @digest: PCR bank and buffer current PCR value is written to.
|
||||
* @digest_size_ptr: pointer to variable that stores the digest size.
|
||||
*
|
||||
* Return: Same as with tpm_transmit_cmd.
|
||||
*/
|
||||
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,
|
||||
struct tpm_digest *digest, u16 *digest_size_ptr)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
struct tpm_buf buf;
|
||||
struct tpm2_pcr_read_out *out;
|
||||
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
|
||||
u16 digest_size;
|
||||
u16 expected_digest_size = 0;
|
||||
|
||||
if (pcr_idx >= TPM2_PLATFORM_PCR)
|
||||
return -EINVAL;
|
||||
|
||||
if (!digest_size_ptr) {
|
||||
for (i = 0; i < chip->nr_allocated_banks &&
|
||||
chip->allocated_banks[i].alg_id != digest->alg_id; i++)
|
||||
;
|
||||
|
||||
if (i == chip->nr_allocated_banks)
|
||||
return -EINVAL;
|
||||
|
||||
expected_digest_size = chip->allocated_banks[i].digest_size;
|
||||
}
|
||||
|
||||
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -192,18 +208,28 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
|
||||
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
|
||||
|
||||
tpm_buf_append_u32(&buf, 1);
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_SHA1);
|
||||
tpm_buf_append_u16(&buf, digest->alg_id);
|
||||
tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
|
||||
tpm_buf_append(&buf, (const unsigned char *)pcr_select,
|
||||
sizeof(pcr_select));
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
res_buf ? "attempting to read a pcr value" : NULL);
|
||||
if (rc == 0 && res_buf) {
|
||||
out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
|
||||
memcpy(res_buf, out->digest, SHA1_DIGEST_SIZE);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
|
||||
digest_size = be16_to_cpu(out->digest_size);
|
||||
if (digest_size > sizeof(digest->digest) ||
|
||||
(!digest_size_ptr && digest_size != expected_digest_size)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (digest_size_ptr)
|
||||
*digest_size_ptr = digest_size;
|
||||
|
||||
memcpy(digest->digest, out->digest, digest_size);
|
||||
out:
|
||||
tpm_buf_destroy(&buf);
|
||||
return rc;
|
||||
}
|
||||
@@ -220,22 +246,17 @@ struct tpm2_null_auth_area {
|
||||
*
|
||||
* @chip: TPM chip to use.
|
||||
* @pcr_idx: index of the PCR.
|
||||
* @count: number of digests passed.
|
||||
* @digests: list of pcr banks and corresponding digest values to extend.
|
||||
*
|
||||
* Return: Same as with tpm_transmit_cmd.
|
||||
*/
|
||||
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
|
||||
struct tpm2_digest *digests)
|
||||
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
|
||||
struct tpm_digest *digests)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
struct tpm2_null_auth_area auth_area;
|
||||
int rc;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (count > ARRAY_SIZE(chip->active_banks))
|
||||
return -EINVAL;
|
||||
|
||||
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
|
||||
if (rc)
|
||||
@@ -251,21 +272,15 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, u32 count,
|
||||
tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area));
|
||||
tpm_buf_append(&buf, (const unsigned char *)&auth_area,
|
||||
sizeof(auth_area));
|
||||
tpm_buf_append_u32(&buf, count);
|
||||
tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) {
|
||||
if (digests[i].alg_id != tpm2_hash_map[j].tpm_id)
|
||||
continue;
|
||||
tpm_buf_append_u16(&buf, digests[i].alg_id);
|
||||
tpm_buf_append(&buf, (const unsigned char
|
||||
*)&digests[i].digest,
|
||||
hash_digest_size[tpm2_hash_map[j].crypto_id]);
|
||||
}
|
||||
for (i = 0; i < chip->nr_allocated_banks; i++) {
|
||||
tpm_buf_append_u16(&buf, digests[i].alg_id);
|
||||
tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest,
|
||||
chip->allocated_banks[i].digest_size);
|
||||
}
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
"attempting extend a PCR value");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
|
||||
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
@@ -309,10 +324,10 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
||||
do {
|
||||
tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM);
|
||||
tpm_buf_append_u16(&buf, num_bytes);
|
||||
err = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
err = tpm_transmit_cmd(chip, &buf,
|
||||
offsetof(struct tpm2_get_random_out,
|
||||
buffer),
|
||||
0, "attempting get random");
|
||||
"attempting get random");
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@@ -341,14 +356,11 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
|
||||
* tpm2_flush_context() - execute a TPM2_FlushContext command
|
||||
* @chip: TPM chip to use
|
||||
* @handle: context handle
|
||||
* @flags: tpm transmit flags - bitmap
|
||||
*
|
||||
*/
|
||||
void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
|
||||
unsigned int flags)
|
||||
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
int rc;
|
||||
@@ -362,9 +374,7 @@ void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
|
||||
|
||||
tpm_buf_append_u32(&buf, handle);
|
||||
|
||||
(void) tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, flags,
|
||||
"flushing context");
|
||||
|
||||
tpm_transmit_cmd(chip, &buf, 0, "flushing context");
|
||||
tpm_buf_destroy(&buf);
|
||||
}
|
||||
|
||||
@@ -449,7 +459,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
||||
|
||||
/* public */
|
||||
tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
|
||||
tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH);
|
||||
tpm_buf_append_u16(&buf, hash);
|
||||
|
||||
/* policy */
|
||||
@@ -464,7 +474,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
||||
}
|
||||
|
||||
/* public parameters */
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
|
||||
tpm_buf_append_u16(&buf, TPM_ALG_NULL);
|
||||
tpm_buf_append_u16(&buf, 0);
|
||||
|
||||
/* outside info */
|
||||
@@ -478,8 +488,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0,
|
||||
"sealing data");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
@@ -516,7 +525,6 @@ out:
|
||||
* @payload: the key data in clear and encrypted form
|
||||
* @options: authentication values and other options
|
||||
* @blob_handle: returned blob handle
|
||||
* @flags: tpm transmit flags
|
||||
*
|
||||
* Return: 0 on success.
|
||||
* -E2BIG on wrong payload size.
|
||||
@@ -526,7 +534,7 @@ out:
|
||||
static int tpm2_load_cmd(struct tpm_chip *chip,
|
||||
struct trusted_key_payload *payload,
|
||||
struct trusted_key_options *options,
|
||||
u32 *blob_handle, unsigned int flags)
|
||||
u32 *blob_handle)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
unsigned int private_len;
|
||||
@@ -561,8 +569,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags,
|
||||
"loading blob");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");
|
||||
if (!rc)
|
||||
*blob_handle = be32_to_cpup(
|
||||
(__be32 *) &buf.data[TPM_HEADER_SIZE]);
|
||||
@@ -583,7 +590,6 @@ out:
|
||||
* @payload: the key data in clear and encrypted form
|
||||
* @options: authentication values and other options
|
||||
* @blob_handle: blob handle
|
||||
* @flags: tpm_transmit_cmd flags
|
||||
*
|
||||
* Return: 0 on success
|
||||
* -EPERM on tpm error status
|
||||
@@ -592,7 +598,7 @@ out:
|
||||
static int tpm2_unseal_cmd(struct tpm_chip *chip,
|
||||
struct trusted_key_payload *payload,
|
||||
struct trusted_key_options *options,
|
||||
u32 blob_handle, unsigned int flags)
|
||||
u32 blob_handle)
|
||||
{
|
||||
struct tpm_buf buf;
|
||||
u16 data_len;
|
||||
@@ -612,8 +618,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
|
||||
options->blobauth /* hmac */,
|
||||
TPM_DIGEST_SIZE);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags,
|
||||
"unsealing");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");
|
||||
if (rc > 0)
|
||||
rc = -EPERM;
|
||||
|
||||
@@ -657,17 +662,12 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
|
||||
u32 blob_handle;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&chip->tpm_mutex);
|
||||
rc = tpm2_load_cmd(chip, payload, options, &blob_handle,
|
||||
TPM_TRANSMIT_UNLOCKED);
|
||||
rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
|
||||
if (rc)
|
||||
goto out;
|
||||
return rc;
|
||||
|
||||
rc = tpm2_unseal_cmd(chip, payload, options, blob_handle,
|
||||
TPM_TRANSMIT_UNLOCKED);
|
||||
tpm2_flush_context_cmd(chip, blob_handle, TPM_TRANSMIT_UNLOCKED);
|
||||
out:
|
||||
mutex_unlock(&chip->tpm_mutex);
|
||||
rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
|
||||
tpm2_flush_context(chip, blob_handle);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -703,7 +703,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
|
||||
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
|
||||
tpm_buf_append_u32(&buf, property_id);
|
||||
tpm_buf_append_u32(&buf, 1);
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
|
||||
if (!rc) {
|
||||
out = (struct tpm2_get_cap_out *)
|
||||
&buf.data[TPM_HEADER_SIZE];
|
||||
@@ -733,8 +733,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
|
||||
if (rc)
|
||||
return;
|
||||
tpm_buf_append_u16(&buf, shutdown_type);
|
||||
tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
"stopping the TPM");
|
||||
tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
|
||||
tpm_buf_destroy(&buf);
|
||||
}
|
||||
|
||||
@@ -763,7 +762,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
|
||||
return rc;
|
||||
|
||||
tpm_buf_append_u8(&buf, full);
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0,
|
||||
"attempting the self test");
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
@@ -790,7 +789,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
|
||||
*/
|
||||
int tpm2_probe(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_output_header *out;
|
||||
struct tpm_header *out;
|
||||
struct tpm_buf buf;
|
||||
int rc;
|
||||
|
||||
@@ -800,10 +799,10 @@ int tpm2_probe(struct tpm_chip *chip)
|
||||
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
|
||||
tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
|
||||
tpm_buf_append_u32(&buf, 1);
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0, NULL);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
|
||||
/* We ignore TPM return codes on purpose. */
|
||||
if (rc >= 0) {
|
||||
out = (struct tpm_output_header *)buf.data;
|
||||
out = (struct tpm_header *)buf.data;
|
||||
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
|
||||
chip->flags |= TPM_CHIP_FLAG_TPM2;
|
||||
}
|
||||
@@ -812,6 +811,30 @@ int tpm2_probe(struct tpm_chip *chip)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm2_probe);
|
||||
|
||||
static int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index)
|
||||
{
|
||||
struct tpm_bank_info *bank = chip->allocated_banks + bank_index;
|
||||
struct tpm_digest digest = { .alg_id = bank->alg_id };
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Avoid unnecessary PCR read operations to reduce overhead
|
||||
* and obtain identifiers of the crypto subsystem.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
|
||||
enum hash_algo crypto_algo = tpm2_hash_map[i].crypto_id;
|
||||
|
||||
if (bank->alg_id != tpm2_hash_map[i].tpm_id)
|
||||
continue;
|
||||
|
||||
bank->digest_size = hash_digest_size[crypto_algo];
|
||||
bank->crypto_id = crypto_algo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size);
|
||||
}
|
||||
|
||||
struct tpm2_pcr_selection {
|
||||
__be16 hash_alg;
|
||||
u8 size_of_select;
|
||||
@@ -825,8 +848,10 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
||||
void *marker;
|
||||
void *end;
|
||||
void *pcr_select_offset;
|
||||
unsigned int count;
|
||||
u32 sizeof_pcr_selection;
|
||||
u32 nr_possible_banks;
|
||||
u32 nr_alloc_banks = 0;
|
||||
u16 hash_alg;
|
||||
u32 rsp_len;
|
||||
int rc;
|
||||
int i = 0;
|
||||
@@ -839,16 +864,18 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
||||
tpm_buf_append_u32(&buf, 0);
|
||||
tpm_buf_append_u32(&buf, 1);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 9, 0,
|
||||
"get tpm pcr allocation");
|
||||
rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
count = be32_to_cpup(
|
||||
nr_possible_banks = be32_to_cpup(
|
||||
(__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
|
||||
|
||||
if (count > ARRAY_SIZE(chip->active_banks)) {
|
||||
rc = -ENODEV;
|
||||
chip->allocated_banks = kcalloc(nr_possible_banks,
|
||||
sizeof(*chip->allocated_banks),
|
||||
GFP_KERNEL);
|
||||
if (!chip->allocated_banks) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -857,7 +884,7 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
||||
rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
|
||||
end = &buf.data[rsp_len];
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
for (i = 0; i < nr_possible_banks; i++) {
|
||||
pcr_select_offset = marker +
|
||||
offsetof(struct tpm2_pcr_selection, size_of_select);
|
||||
if (pcr_select_offset >= end) {
|
||||
@@ -866,17 +893,28 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
|
||||
}
|
||||
|
||||
memcpy(&pcr_selection, marker, sizeof(pcr_selection));
|
||||
chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg);
|
||||
hash_alg = be16_to_cpu(pcr_selection.hash_alg);
|
||||
|
||||
pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0,
|
||||
pcr_selection.size_of_select);
|
||||
if (pcr_select_offset) {
|
||||
chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg;
|
||||
|
||||
rc = tpm2_init_bank_info(chip, nr_alloc_banks);
|
||||
if (rc < 0)
|
||||
break;
|
||||
|
||||
nr_alloc_banks++;
|
||||
}
|
||||
|
||||
sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) +
|
||||
sizeof(pcr_selection.size_of_select) +
|
||||
pcr_selection.size_of_select;
|
||||
marker = marker + sizeof_pcr_selection;
|
||||
}
|
||||
|
||||
chip->nr_allocated_banks = nr_alloc_banks;
|
||||
out:
|
||||
if (i < ARRAY_SIZE(chip->active_banks))
|
||||
chip->active_banks[i] = TPM2_ALG_ERROR;
|
||||
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
return rc;
|
||||
@@ -911,8 +949,7 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
|
||||
tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
|
||||
tpm_buf_append_u32(&buf, nr_commands);
|
||||
|
||||
rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
|
||||
9 + 4 * nr_commands, 0, NULL);
|
||||
rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
|
||||
if (rc) {
|
||||
tpm_buf_destroy(&buf);
|
||||
goto out;
|
||||
@@ -969,8 +1006,7 @@ static int tpm2_startup(struct tpm_chip *chip)
|
||||
return rc;
|
||||
|
||||
tpm_buf_append_u16(&buf, TPM2_SU_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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user