diff mbox

[11/12] tpm: Add check_data handle to tpm_class_ops in order to check data integrity

Message ID 1458502483-16887-12-git-send-email-christophe-h.ricard@st.com (mailing list archive)
State New, archived
Headers show

Commit Message

Christophe Ricard March 20, 2016, 7:34 p.m. UTC
For example, in order to compute crc over the data sent in lower layer
(i2c for instance), provide a specific handle.

The current principles:
- When sending command:
1) Host writes TPM_STS.commandReady
2) Host writes command
3) Host checks TPM received data correctly
4) if not go to step 1

- When receiving data:
1) Host check TPM_STS.dataAvail is set
2) Host get data
3) Host check received data are correct.
4) if not Host write TPM_STS.responseRetry and go to step 1.

Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com>
---
 drivers/char/tpm/tpm_tis_core.c | 81 ++++++++++++++++++++++++++---------------
 include/linux/tpm.h             |  1 +
 2 files changed, 52 insertions(+), 30 deletions(-)

Comments

Jason Gunthorpe March 21, 2016, 1:39 a.m. UTC | #1
On Sun, Mar 20, 2016 at 08:34:42PM +0100, Christophe Ricard wrote:
> @@ -43,6 +43,7 @@ struct tpm_class_ops {
>  	u8 (*status) (struct tpm_chip *chip);
>  	bool (*update_timeouts)(struct tpm_chip *chip,
>  				unsigned long *timeout_cap);
> +	bool (*check_data)(struct tpm_chip *chip, u8 *buf, size_t len);
>  	int (*read_bytes)(struct tpm_chip *chip, u32 addr, size_t len,
>  			  u8 size, u8 *dst);

Don't add tis specific functions to this structure.

Jason

------------------------------------------------------------------------------
Transform Data into Opportunity.
Accelerate data analysis in your applications with
Intel Data Analytics Acceleration Library.
Click to learn more.
http://pubads.g.doubleclick.net/gampad/clk?id=278785351&iu=/4140
Christophe Ricard March 21, 2016, 5:44 p.m. UTC | #2
Hi Jason,

Just trying to understand. How check_data would be more specific than
update_timeouts only used by the tis part as well ?
Do you expect to have a tis_ops specific structure ?

Best Regards
Christophe

2016-03-21 2:39 GMT+01:00 Jason Gunthorpe <jgunthorpe@obsidianresearch.com>:

> On Sun, Mar 20, 2016 at 08:34:42PM +0100, Christophe Ricard wrote:
> > @@ -43,6 +43,7 @@ struct tpm_class_ops {
> >       u8 (*status) (struct tpm_chip *chip);
> >       bool (*update_timeouts)(struct tpm_chip *chip,
> >                               unsigned long *timeout_cap);
> > +     bool (*check_data)(struct tpm_chip *chip, u8 *buf, size_t len);
> >       int (*read_bytes)(struct tpm_chip *chip, u32 addr, size_t len,
> >                         u8 size, u8 *dst);
>
> Don't add tis specific functions to this structure.
>
> Jason
>
------------------------------------------------------------------------------
Transform Data into Opportunity.
Accelerate data analysis in your applications with
Intel Data Analytics Acceleration Library.
Click to learn more.
http://pubads.g.doubleclick.net/gampad/clk?id=278785351&iu=/4140
diff mbox

Patch

diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index baa9ab1..9efb3ac 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -126,6 +126,14 @@  again:
 	return -1;
 }
 
+static bool tpm_tis_check_data(struct tpm_chip *chip, u8 *buf, size_t len)
+{
+	if (chip->ops->check_data)
+		return chip->ops->check_data(chip, buf, len);
+
+	return true;
+}
+
 u8 tpm_tis_status(struct tpm_chip *chip)
 {
 	return tpm_read_byte(chip, TPM_STS(chip->vendor.locality));
@@ -197,7 +205,8 @@  static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
 int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	int size = 0;
-	int expected, status;
+	int expected, status, i;
+	bool check_data = false;
 
 	if (count < TPM_HEADER_SIZE) {
 		size = -EIO;
@@ -206,34 +215,41 @@  int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 
 	tpm_tis_clear_int(chip);
 
-	/* read first 10 bytes, including tag, paramsize, and result */
-	size = recv_data(chip, buf, TPM_HEADER_SIZE);
-	if (size < TPM_HEADER_SIZE) {
-		dev_err(&chip->dev, "Unable to read header\n");
-		goto out;
-	}
+	for (i = 0; i < TPM_RETRY && !check_data; i++) {
+		/* read first 10 bytes, including tag, paramsize, and result */
+		size = recv_data(chip, buf, TPM_HEADER_SIZE);
+		if (size < TPM_HEADER_SIZE) {
+			dev_err(&chip->dev, "Unable to read header\n");
+			goto out;
+		}
 
-	expected = be32_to_cpu(*(__be32 *) (buf + 2));
-	if (expected > count) {
-		size = -EIO;
-		goto out;
-	}
+		expected = be32_to_cpu(*(__be32 *) (buf + 2));
+		if (expected > count) {
+			size = -EIO;
+			goto out;
+		}
 
-	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
-			  expected - TPM_HEADER_SIZE);
-	if (size < expected) {
-		dev_err(&chip->dev, "Unable to read remainder of result\n");
-		size = -ETIME;
-		goto out;
-	}
+		size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+				  expected - TPM_HEADER_SIZE);
+		if (size < expected) {
+			dev_err(&chip->dev, "Unable to read remainder of result\n");
+			size = -ETIME;
+			goto out;
+		}
 
-	wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
-			  &chip->vendor.int_queue, false);
-	status = tpm_tis_status(chip);
-	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
-		dev_err(&chip->dev, "Error left over data\n");
-		size = -EIO;
-		goto out;
+		wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
+				  &chip->vendor.int_queue, false);
+		status = tpm_tis_status(chip);
+		if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
+			dev_err(&chip->dev, "Error left over data\n");
+			size = -EIO;
+			goto out;
+		}
+
+		check_data = tpm_tis_check_data(chip, buf, size);
+		if (!check_data)
+			tpm_write_byte(chip, TPM_STS(chip->vendor.locality),
+				       TPM_STS_RESPONSE_RETRY);
 	}
 
 out:
@@ -323,15 +339,20 @@  static void disable_interrupts(struct tpm_chip *chip)
  */
 static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
 {
-	int rc;
+	int rc, i;
 	u32 ordinal;
 	unsigned long dur;
+	bool data_valid = false;
 
 	tpm_tis_clear_int(chip);
 
-	rc = tpm_tis_send_data(chip, buf, len);
-	if (rc < 0)
-		return rc;
+	for (i = 0; i < TPM_RETRY && !data_valid; i++) {
+		rc = tpm_tis_send_data(chip, buf, len);
+		if (rc < 0)
+			return rc;
+
+		data_valid = tpm_tis_check_data(chip, buf, len);
+	}
 
 	/* go and do it */
 	tpm_write_byte(chip, TPM_STS(chip->vendor.locality), TPM_STS_GO);
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index f78e4fc..8e871dc 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -43,6 +43,7 @@  struct tpm_class_ops {
 	u8 (*status) (struct tpm_chip *chip);
 	bool (*update_timeouts)(struct tpm_chip *chip,
 				unsigned long *timeout_cap);
+	bool (*check_data)(struct tpm_chip *chip, u8 *buf, size_t len);
 
 	int (*read_bytes)(struct tpm_chip *chip, u32 addr, size_t len,
 			  u8 size, u8 *dst);