lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <58AC85F2.5000406@linux.vnet.ibm.com>
Date:   Tue, 21 Feb 2017 23:54:50 +0530
From:   Nayna <nayna@...ux.vnet.ibm.com>
To:     Jarkko Sakkinen <jarkko.sakkinen@...ux.intel.com>,
        tpmdd-devel@...ts.sourceforge.net
Cc:     dhowells@...hat.com, open list <linux-kernel@...r.kernel.org>,
        James.Bottomley@...senPartnership.com,
        linux-security-module@...r.kernel.org
Subject: Re: [tpmdd-devel] [PATCH v2 4/7] tpm: infrastructure for TPM spaces



On 02/17/2017 12:55 AM, Jarkko Sakkinen wrote:
> Added an ability to virtualize TPM commands into an isolated context
> that we call a TPM space because the word context is already heavily
> used in the TPM specification. Both the handle areas and bodies (where
> necessary) are virtualized.
>
> The mechanism works by adding a new parameter struct tpm_space to the
> tpm_transmit() function. This new structure contains the list of virtual
> handles and a buffer of page size (currently) for backing storage.
>
> When tpm_transmit() is called with a struct tpm_space instance it will
> execute the following sequence:
>
> 1. Take locks.
> 2. Load transient objects from the backing storage by using ContextLoad
>     and map virtual handles to physical handles.
> 3. Perform the transaction.
> 4. Save transient objects to backing storage by using ContextSave and
>     map resulting physical handle to virtual handle if there is such.
>
> This commit does not implement virtualization support for hmac and
> policy sessions.
>

If I have understood discussions correctly, I assume, that kernel TPM 
operations will also be routed via RM. And I think that is not happening 
now with these patches.

Am I missing something ?

Thanks & Regards,
    - Nayna


> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@...ux.intel.com>
> ---
>   drivers/char/tpm/Makefile        |   2 +-
>   drivers/char/tpm/tpm-chip.c      |   7 +
>   drivers/char/tpm/tpm-dev.c       |   2 +-
>   drivers/char/tpm/tpm-interface.c |  68 +++---
>   drivers/char/tpm/tpm-sysfs.c     |   2 +-
>   drivers/char/tpm/tpm.h           |  26 ++-
>   drivers/char/tpm/tpm2-cmd.c      |  33 +--
>   drivers/char/tpm/tpm2-space.c    | 431 +++++++++++++++++++++++++++++++++++++++
>   8 files changed, 520 insertions(+), 51 deletions(-)
>   create mode 100644 drivers/char/tpm/tpm2-space.c
>
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index 3d386a8..8f07fcf 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -3,7 +3,7 @@
>   #
>   obj-$(CONFIG_TCG_TPM) += tpm.o
>   tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
> -		tpm1_eventlog.o tpm2_eventlog.o
> +	 tpm1_eventlog.o tpm2_eventlog.o tpm2-space.o
>   tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
>   tpm-$(CONFIG_OF) += tpm_of.o
>   obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index c406343..993b9ae 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -128,6 +128,7 @@ static void tpm_dev_release(struct device *dev)
>   	mutex_unlock(&idr_lock);
>
>   	kfree(chip->log.bios_event_log);
> +	kfree(chip->work_space.context_buf);
>   	kfree(chip);
>   }
>
> @@ -189,6 +190,12 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>   	chip->cdev.owner = THIS_MODULE;
>   	chip->cdev.kobj.parent = &chip->dev.kobj;
>
> +	chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
> +	if (!chip->work_space.context_buf) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
>   	return chip;
>
>   out:
> diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
> index 02a8850..414553b 100644
> --- a/drivers/char/tpm/tpm-dev.c
> +++ b/drivers/char/tpm/tpm-dev.c
> @@ -147,7 +147,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf,
>   		mutex_unlock(&priv->buffer_mutex);
>   		return -EPIPE;
>   	}
> -	out_size = tpm_transmit(priv->chip, priv->data_buffer,
> +	out_size = tpm_transmit(priv->chip, NULL, priv->data_buffer,
>   				sizeof(priv->data_buffer), 0);
>
>   	tpm_put_ops(priv->chip);
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 20b1fe3..db5ffe9 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -376,11 +376,12 @@ static bool tpm_validate_command(struct tpm_chip *chip, const u8 *cmd,
>    *     0 when the operation is successful.
>    *     A negative number for system errors (errno).
>    */
> -ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
> -		     unsigned int flags)
> +ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
> +		     u8 *buf, size_t bufsiz, unsigned int flags)
>   {
> -	const struct tpm_output_header *header = (void *)buf;
> -	ssize_t rc;
> +	struct tpm_output_header *header = (void *)buf;
> +	int rc;
> +	ssize_t len = 0;
>   	u32 count, ordinal;
>   	unsigned long stop;
>
> @@ -406,10 +407,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
>   	if (chip->dev.parent)
>   		pm_runtime_get_sync(chip->dev.parent);
>
> +	rc = tpm2_prepare_space(chip, space, ordinal, buf);
> +	if (rc)
> +		goto out;
> +
>   	rc = chip->ops->send(chip, (u8 *) buf, count);
>   	if (rc < 0) {
>   		dev_err(&chip->dev,
> -			"tpm_transmit: tpm_send: error %zd\n", rc);
> +			"tpm_transmit: tpm_send: error %d\n", rc);
>   		goto out;
>   	}
>
> @@ -442,18 +447,23 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
>   	goto out;
>
>   out_recv:
> -	rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
> -	if (rc < 0) {
> +	len = chip->ops->recv(chip, (u8 *) buf, bufsiz);
> +	if (len < 0) {
>   		dev_err(&chip->dev,
> -			"tpm_transmit: tpm_recv: error %zd\n", rc);
> +			"tpm_transmit: tpm_recv: error %d\n", rc);
> +		rc = len;
>   		goto out;
> -	} else if (rc < TPM_HEADER_SIZE) {
> +	} else if (len < TPM_HEADER_SIZE) {
>   		rc = -EFAULT;
>   		goto out;
>   	}
>
> -	if (rc != be32_to_cpu(header->length))
> +	if (len != be32_to_cpu(header->length)) {
> +		rc = -EFAULT;
>   		goto out;
> +	}
> +
> +	rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
>
>   out:
>   	if (chip->dev.parent)
> @@ -461,7 +471,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
>
>   	if (!(flags & TPM_TRANSMIT_UNLOCKED))
>   		mutex_unlock(&chip->tpm_mutex);
> -	return rc;
> +	return rc ? rc : len;
>   }
>
>   /**
> @@ -480,15 +490,16 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
>    *     A negative number for system errors (errno).
>    *     A positive number for a TPM error.
>    */
> -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const 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_space *space,
> +			 const void *buf, size_t bufsiz,
> +			 size_t min_rsp_body_length, unsigned int flags,
> +			 const char *desc)
>   {
>   	const struct tpm_output_header *header = buf;
>   	int err;
>   	ssize_t len;
>
> -	len = tpm_transmit(chip, (const u8 *)buf, bufsiz, flags);
> +	len = tpm_transmit(chip, space, (u8 *)buf, bufsiz, flags);
>   	if (len <  0)
>   		return len;
>
> @@ -541,7 +552,7 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
>   		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>   		tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id);
>   	}
> -	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> +	rc = tpm_transmit_cmd(chip, NULL, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
>   			      min_cap_length, 0, desc);
>   	if (!rc)
>   		*cap = tpm_cmd.params.getcap_out.cap;
> @@ -565,7 +576,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
>   	start_cmd.header.in = tpm_startup_header;
>
>   	start_cmd.params.startup_in.startup_type = startup_type;
> -	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
> +	return tpm_transmit_cmd(chip, NULL, &start_cmd,
> +				TPM_INTERNAL_RESULT_SIZE, 0,
>   				0, "attempting to start the TPM");
>   }
>
> @@ -722,8 +734,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
>   	struct tpm_cmd_t cmd;
>
>   	cmd.header.in = continue_selftest_header;
> -	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, 0,
> -			      "continue selftest");
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
> +			      0, 0, "continue selftest");
>   	return rc;
>   }
>
> @@ -743,7 +755,7 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
>
>   	cmd.header.in = pcrread_header;
>   	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
> -	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, READ_PCR_RESULT_SIZE,
>   			      READ_PCR_RESULT_BODY_SIZE, 0,
>   			      "attempting to read a pcr value");
>
> @@ -855,7 +867,7 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
>   	cmd.header.in = pcrextend_header;
>   	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
>   	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> -	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, EXTEND_PCR_RESULT_SIZE,
>   			      EXTEND_PCR_RESULT_BODY_SIZE, 0,
>   			      "attempting extend a PCR value");
>
> @@ -960,8 +972,8 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
>   	if (chip == NULL)
>   		return -ENODEV;
>
> -	rc = tpm_transmit_cmd(chip, cmd, buflen, 0, 0, "attempting tpm_cmd");
> -
> +	rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0,
> +			      "attempting tpm_cmd");
>   	tpm_put_ops(chip);
>   	return rc;
>   }
> @@ -1062,16 +1074,16 @@ int tpm_pm_suspend(struct device *dev)
>   		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
>   		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
>   		       TPM_DIGEST_SIZE);
> -		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> -				     EXTEND_PCR_RESULT_BODY_SIZE, 0,
> +		rc = tpm_transmit_cmd(chip, NULL, &cmd, EXTEND_PCR_RESULT_SIZE,
> +				      EXTEND_PCR_RESULT_BODY_SIZE, 0,
>   				      "extending dummy pcr before suspend");
>   	}
>
>   	/* now do the actual savestate */
>   	for (try = 0; try < TPM_RETRY; try++) {
>   		cmd.header.in = savestate_header;
> -		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0,
> -				      0, NULL);
> +		rc = tpm_transmit_cmd(chip, NULL, &cmd, SAVESTATE_RESULT_SIZE,
> +				      0, 0, NULL);
>
>   		/*
>   		 * If the TPM indicates that it is too busy to respond to
> @@ -1154,7 +1166,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   		tpm_cmd.header.in = tpm_getrandom_header;
>   		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
>
> -		err = tpm_transmit_cmd(chip, &tpm_cmd,
> +		err = tpm_transmit_cmd(chip, NULL, &tpm_cmd,
>   				       TPM_GETRANDOM_RESULT_SIZE + num_bytes,
>   				       offsetof(struct tpm_getrandom_out,
>   						rng_data),
> diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> index 2f596d7..55405db 100644
> --- a/drivers/char/tpm/tpm-sysfs.c
> +++ b/drivers/char/tpm/tpm-sysfs.c
> @@ -40,7 +40,7 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
>   	struct tpm_chip *chip = to_tpm_chip(dev);
>
>   	tpm_cmd.header.in = tpm_readpubek_header;
> -	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
> +	err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
>   			       READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
>   			       "attempting to read the PUBEK");
>   	if (err)
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 0ec1cf0..97e48a4 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -89,10 +89,13 @@ enum tpm2_structures {
>   };
>
>   enum tpm2_return_codes {
> +	TPM2_RC_SUCCESS		= 0x0000,
>   	TPM2_RC_HASH		= 0x0083, /* RC_FMT1 */
> +	TPM2_RC_HANDLE		= 0x008B,
>   	TPM2_RC_INITIALIZE	= 0x0100, /* RC_VER1 */
>   	TPM2_RC_DISABLED	= 0x0120,
>   	TPM2_RC_TESTING		= 0x090A, /* RC_WARN */
> +	TPM2_RC_REFERENCE_H0	= 0x0910,
>   };
>
>   enum tpm2_algorithms {
> @@ -114,6 +117,7 @@ enum tpm2_command_codes {
>   	TPM2_CC_CREATE		= 0x0153,
>   	TPM2_CC_LOAD		= 0x0157,
>   	TPM2_CC_UNSEAL		= 0x015E,
> +	TPM2_CC_CONTEXT_LOAD	= 0x0161,
>   	TPM2_CC_CONTEXT_SAVE	= 0x0162,
>   	TPM2_CC_FLUSH_CONTEXT	= 0x0165,
>   	TPM2_CC_GET_CAPABILITY	= 0x017A,
> @@ -128,6 +132,7 @@ enum tpm2_permanent_handles {
>   };
>
>   enum tpm2_capabilities {
> +	TPM2_CAP_HANDLES	= 1,
>   	TPM2_CAP_COMMANDS	= 2,
>   	TPM2_CAP_PCRS		= 5,
>   	TPM2_CAP_TPM_PROPERTIES = 6,
> @@ -153,6 +158,11 @@ enum tpm2_cc_attrs {
>
>   #define TPM_PPI_VERSION_LEN		3
>
> +struct tpm_space {
> +	u32 context_tbl[3];
> +	u8 *context_buf;
> +};
> +
>   enum tpm_chip_flags {
>   	TPM_CHIP_FLAG_TPM2		= BIT(1),
>   	TPM_CHIP_FLAG_IRQ		= BIT(2),
> @@ -211,6 +221,7 @@ struct tpm_chip {
>   	char ppi_version[TPM_PPI_VERSION_LEN + 1];
>   #endif /* CONFIG_ACPI */
>
> +	struct tpm_space work_space;
>   	u32 nr_commands;
>   	u32 *cc_attrs_tbl;
>   };
> @@ -507,10 +518,11 @@ enum tpm_transmit_flags {
>   	TPM_TRANSMIT_UNLOCKED	= BIT(0),
>   };
>
> -ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
> -		     unsigned int flags);
> -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, size_t bufsiz,
> -			 size_t min_rsp_body_len, unsigned int flags,
> +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,
> +			 const void *buf, size_t bufsiz,
> +			 size_t min_rsp_body_length, unsigned int flags,
>   			 const char *desc);
>   ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
>   		   const char *desc, size_t min_cap_length);
> @@ -572,4 +584,10 @@ unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
>   int tpm2_probe(struct tpm_chip *chip);
>   ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip);
>   int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
> +int tpm2_init_space(struct tpm_space *space);
> +void tpm2_del_space(struct tpm_space *space);
> +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);
>   #endif
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> index 897902a..96121b3 100644
> --- a/drivers/char/tpm/tpm2-cmd.c
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -266,7 +266,7 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
>   	       sizeof(cmd.params.pcrread_in.pcr_select));
>   	cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
>
> -	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd),
>   			      TPM2_PCR_READ_RESP_BODY_SIZE,
>   			      0, "attempting to read a pcr value");
>   	if (rc == 0) {
> @@ -333,7 +333,7 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
>   		}
>   	}
>
> -	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, 0,
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
>   			      "attempting extend a PCR value");
>
>   	tpm_buf_destroy(&buf);
> @@ -382,7 +382,7 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
>   		cmd.header.in = tpm2_getrandom_header;
>   		cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
>
> -		err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
> +		err = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd),
>   				       offsetof(struct tpm2_get_random_out,
>   						buffer),
>   				       0, "attempting get random");
> @@ -441,7 +441,7 @@ void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
>
>   	tpm_buf_append_u32(&buf, handle);
>
> -	(void) tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags,
> +	(void) tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, flags,
>   				"flushing context");
>
>   	tpm_buf_destroy(&buf);
> @@ -557,7 +557,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
>   		goto out;
>   	}
>
> -	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, 0,
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, 0,
>   			      "sealing data");
>   	if (rc)
>   		goto out;
> @@ -641,7 +641,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
>   		goto out;
>   	}
>
> -	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, flags,
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 4, flags,
>   			      "loading blob");
>   	if (!rc)
>   		*blob_handle = be32_to_cpup(
> @@ -693,7 +693,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
>   			     options->blobauth /* hmac */,
>   			     TPM_DIGEST_SIZE);
>
> -	rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 6, flags,
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 6, flags,
>   			      "unsealing");
>   	if (rc > 0)
>   		rc = -EPERM;
> @@ -770,7 +770,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,  u32 *value,
>   	cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
>   	cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
>
> -	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd),
>   			      TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc);
>   	if (!rc)
>   		*value = be32_to_cpu(cmd.params.get_tpm_pt_out.value);
> @@ -805,7 +805,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
>   	cmd.header.in = tpm2_startup_header;
>
>   	cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
> -	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
> +	return tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0,
>   				"attempting to start the TPM");
>   }
>
> @@ -834,7 +834,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
>   	cmd.header.in = tpm2_shutdown_header;
>   	cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
>
> -	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0,
>   			      "stopping the TPM");
>
>   	/* In places where shutdown command is sent there's no much we can do
> @@ -898,7 +898,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
>   	cmd.header.in = tpm2_selftest_header;
>   	cmd.params.selftest_in.full_test = full;
>
> -	rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0,
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0,
>   			      "continue selftest");
>
>   	/* At least some prototype chips seem to give RC_TESTING error
> @@ -949,7 +949,8 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
>   		cmd.params.pcrread_in.pcr_select[1] = 0x00;
>   		cmd.params.pcrread_in.pcr_select[2] = 0x00;
>
> -		rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL);
> +		rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0,
> +				      NULL);
>   		if (rc < 0)
>   			break;
>
> @@ -982,7 +983,7 @@ int tpm2_probe(struct tpm_chip *chip)
>   	cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
>   	cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
>
> -	rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL);
> +	rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0, NULL);
>   	if (rc <  0)
>   		return rc;
>
> @@ -1022,8 +1023,8 @@ 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, buf.data, PAGE_SIZE, 9 + 4 * nr_commands,
> -			      0, NULL);
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
> +			      9 + 4 * nr_commands, 0, NULL);
>   	if (rc) {
>   		tpm_buf_destroy(&buf);
>   		goto out;
> @@ -1136,7 +1137,7 @@ 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, buf.data, PAGE_SIZE, 9, 0,
> +	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 9, 0,
>   			      "get tpm pcr allocation");
>   	if (rc)
>   		goto out;
> diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
> new file mode 100644
> index 0000000..e955548
> --- /dev/null
> +++ b/drivers/char/tpm/tpm2-space.c
> @@ -0,0 +1,431 @@
> +/*
> + * Copyright (C) 2016 Intel Corporation
> + *
> + * Authors:
> + * Jarkko Sakkinen <jarkko.sakkinen@...ux.intel.com>
> + *
> + * Maintained by: <tpmdd-devel@...ts.sourceforge.net>
> + *
> + * This file contains TPM2 protocol implementations of the commands
> + * used by the kernel internally.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2
> + * of the License.
> + */
> +
> +#include <linux/gfp.h>
> +#include <asm/unaligned.h>
> +#include "tpm.h"
> +
> +enum tpm2_handle_types {
> +	TPM2_HT_HMAC_SESSION	= 0x02000000,
> +	TPM2_HT_POLICY_SESSION	= 0x03000000,
> +	TPM2_HT_TRANSIENT	= 0x80000000,
> +};
> +
> +struct tpm2_context {
> +	__be64 sequence;
> +	__be32 saved_handle;
> +	__be32 hierarchy;
> +	__be16 blob_size;
> +} __packed;
> +
> +int tpm2_init_space(struct tpm_space *space)
> +{
> +	space->context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
> +	if (!space->context_buf)
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +void tpm2_del_space(struct tpm_space *space)
> +{
> +	kfree(space->context_buf);
> +}
> +
> +static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> +			     unsigned int *offset, u32 *handle)
> +{
> +	struct tpm_buf tbuf;
> +	struct tpm2_context *ctx;
> +	unsigned int body_size;
> +	int rc;
> +
> +	rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
> +	if (rc)
> +		return rc;
> +
> +	ctx = (struct tpm2_context *)&buf[*offset];
> +	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_UNLOCKED, NULL);
> +	if (rc < 0) {
> +		dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> +			 __func__, rc);
> +		tpm_buf_destroy(&tbuf);
> +		return -EFAULT;
> +	} else if (rc > 0) {
> +		dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> +			 __func__, rc);
> +		tpm_buf_destroy(&tbuf);
> +		return -EFAULT;
> +	}
> +
> +	*handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
> +	*offset += body_size;
> +
> +	tpm_buf_destroy(&tbuf);
> +	return 0;
> +}
> +
> +static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
> +			     unsigned int buf_size, unsigned int *offset)
> +{
> +	struct tpm_buf tbuf;
> +	unsigned int body_size;
> +	int rc;
> +
> +	rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
> +	if (rc)
> +		return rc;
> +
> +	tpm_buf_append_u32(&tbuf, handle);
> +
> +	rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0,
> +			      TPM_TRANSMIT_UNLOCKED, NULL);
> +	if (rc < 0) {
> +		dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> +			 __func__, rc);
> +		tpm_buf_destroy(&tbuf);
> +		return -EFAULT;
> +	} else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
> +		tpm_buf_destroy(&tbuf);
> +		return -ENOENT;
> +	} else if (rc) {
> +		dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> +			 __func__, rc);
> +		tpm_buf_destroy(&tbuf);
> +		return -EFAULT;
> +	}
> +
> +	body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
> +	if ((*offset + body_size) > buf_size) {
> +		dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
> +		tpm_buf_destroy(&tbuf);
> +		return -ENOMEM;
> +	}
> +
> +	memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
> +	tpm2_flush_context_cmd(chip, handle, TPM_TRANSMIT_UNLOCKED);
> +	*offset += body_size;
> +	tpm_buf_destroy(&tbuf);
> +	return 0;
> +}
> +
> +static 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_UNLOCKED);
> +}
> +
> +static int tpm2_load_space(struct tpm_chip *chip)
> +{
> +	struct tpm_space *space = &chip->work_space;
> +	unsigned int offset;
> +	int i;
> +	int rc;
> +
> +	for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
> +		if (!space->context_tbl[i])
> +			continue;
> +
> +		/* sanity check, should never happen */
> +		if (~space->context_tbl[i]) {
> +			dev_err(&chip->dev, "context table is inconsistent");
> +			return -EFAULT;
> +		}
> +
> +		rc = tpm2_load_context(chip, space->context_buf, &offset,
> +				       &space->context_tbl[i]);
> +		if (rc)
> +			return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle)
> +{
> +	u32 vhandle = be32_to_cpup((__be32 *)handle);
> +	u32 phandle;
> +	int i;
> +
> +	i = 0xFFFFFF - (vhandle & 0xFFFFFF);
> +	if (i > ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i])
> +		return false;
> +
> +	phandle = space->context_tbl[i];
> +	*((__be32 *)handle) = cpu_to_be32(phandle);
> +	return true;
> +}
> +
> +static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
> +{
> +	struct tpm_space *space = &chip->work_space;
> +	unsigned int nr_handles;
> +	u32 attrs;
> +	u32 *handle;
> +	int i;
> +
> +	i = tpm2_find_cc(chip, cc);
> +	if (i < 0)
> +		return -EINVAL;
> +
> +	attrs = chip->cc_attrs_tbl[i];
> +	nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
> +
> +	handle = (u32 *)&cmd[TPM_HEADER_SIZE];
> +	for (i = 0; i < nr_handles; i++, handle++) {
> +		if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
> +			if (!tpm2_map_to_phandle(space, handle))
> +				return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
> +		       u8 *cmd)
> +{
> +	int rc;
> +
> +	if (!space)
> +		return 0;
> +
> +	memcpy(&chip->work_space.context_tbl, &space->context_tbl,
> +	       sizeof(space->context_tbl));
> +	memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE);
> +
> +	rc = tpm2_load_space(chip);
> +	if (rc) {
> +		tpm2_flush_space(chip);
> +		return rc;
> +	}
> +
> +	rc = tpm2_map_command(chip, cc, cmd);
> +	if (rc) {
> +		tpm2_flush_space(chip);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
> +		if (alloc) {
> +			if (!space->context_tbl[i]) {
> +				space->context_tbl[i] = phandle;
> +				break;
> +			}
> +		} else if (space->context_tbl[i] == phandle)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(space->context_tbl))
> +		return 0;
> +
> +	return TPM2_HT_TRANSIENT | (0xFFFFFF - i);
> +}
> +
> +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;
> +	u32 phandle;
> +	u32 phandle_type;
> +	u32 vhandle;
> +	u32 attrs;
> +	int i;
> +
> +	if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS)
> +		return 0;
> +
> +	i = tpm2_find_cc(chip, cc);
> +	/* sanity check, should never happen */
> +	if (i < 0)
> +		return -EFAULT;
> +
> +	attrs = chip->cc_attrs_tbl[i];
> +	if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1))
> +		return 0;
> +
> +	phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]);
> +	phandle_type = phandle & 0xFF000000;
> +
> +	switch (phandle_type) {
> +	case TPM2_HT_TRANSIENT:
> +		vhandle = tpm2_map_to_vhandle(space, phandle, true);
> +		if (!vhandle)
> +			goto out_no_slots;
> +
> +		*(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle);
> +		break;
> +	case TPM2_HT_HMAC_SESSION:
> +	case TPM2_HT_POLICY_SESSION:
> +		break;
> +	default:
> +		dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
> +			__func__, phandle);
> +		break;
> +	};
> +
> +	return 0;
> +out_no_slots:
> +	tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_UNLOCKED);
> +	dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
> +		 phandle);
> +	return -ENOMEM;
> +}
> +
> +struct tpm2_cap_handles {
> +	u8 more_data;
> +	__be32 capability;
> +	__be32 count;
> +	__be32 handles[];
> +} __packed;
> +
> +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 tpm2_cap_handles *data;
> +	u32 phandle;
> +	u32 phandle_type;
> +	u32 vhandle;
> +	int i;
> +	int j;
> +
> +	if (cc != TPM2_CC_GET_CAPABILITY ||
> +	    be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) {
> +		return 0;
> +	}
> +
> +	if (len < TPM_HEADER_SIZE + 9)
> +		return -EFAULT;
> +
> +	data = (void *)&rsp[TPM_HEADER_SIZE];
> +	if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES)
> +		return 0;
> +
> +	if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count))
> +		return -EFAULT;
> +
> +	for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) {
> +		phandle = be32_to_cpup((__be32 *)&data->handles[i]);
> +		phandle_type = phandle & 0xFF000000;
> +
> +		switch (phandle_type) {
> +		case TPM2_HT_TRANSIENT:
> +			vhandle = tpm2_map_to_vhandle(space, phandle, false);
> +			if (!vhandle)
> +				break;
> +
> +			data->handles[j] = cpu_to_be32(vhandle);
> +			j++;
> +			break;
> +		case TPM2_HT_HMAC_SESSION:
> +		case TPM2_HT_POLICY_SESSION:
> +			data->handles[j] = cpu_to_be32(phandle);
> +			j++;
> +			break;
> +		default:
> +			dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
> +				__func__, phandle);
> +			break;
> +		}
> +
> +	}
> +
> +	header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j);
> +	data->count = cpu_to_be32(j);
> +	return 0;
> +}
> +
> +static int tpm2_save_space(struct tpm_chip *chip)
> +{
> +	struct tpm_space *space = &chip->work_space;
> +	unsigned int offset;
> +	int i;
> +	int rc;
> +
> +	for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
> +		if (!(space->context_tbl[i] && ~space->context_tbl[i]))
> +			continue;
> +
> +		rc = tpm2_save_context(chip, space->context_tbl[i],
> +				       space->context_buf, PAGE_SIZE,
> +				       &offset);
> +		if (rc == -ENOENT) {
> +			space->context_tbl[i] = 0;
> +			continue;
> +		} else if (rc)
> +			return rc;
> +
> +		space->context_tbl[i] = ~0;
> +	}
> +
> +	return 0;
> +}
> +
> +int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
> +		      u32 cc, u8 *buf, size_t *bufsiz)
> +{
> +	struct tpm_output_header *header = (void *)buf;
> +	int rc;
> +
> +	if (!space)
> +		return 0;
> +
> +	rc = tpm2_map_response_header(chip, cc, buf, *bufsiz);
> +	if (rc) {
> +		tpm2_flush_space(chip);
> +		return rc;
> +	}
> +
> +	rc = tpm2_map_response_body(chip, cc, buf, *bufsiz);
> +	if (rc) {
> +		tpm2_flush_space(chip);
> +		return rc;
> +	}
> +
> +	rc = tpm2_save_space(chip);
> +	if (rc) {
> +		tpm2_flush_space(chip);
> +		return rc;
> +	}
> +
> +	*bufsiz = be32_to_cpu(header->length);
> +
> +	memcpy(&space->context_tbl, &chip->work_space.context_tbl,
> +	       sizeof(space->context_tbl));
> +	memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE);
> +
> +	return 0;
> +}
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ