Skip to contentSkip to conversation

tpm2: fix TIS locality timeout problems

PATCH Superseded James Bottomley 4 participants 4 messages May 27, 2020 – May 28, 2020

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

James Bottomley

author maintainer
#0 lore raw

PATCH 1/1 tpm2: fix TIS locality timeout problems

It has been reported that some TIS based TPMs are giving unexpected errors when using the O_NONBLOCK path. The problem is that some TPMs don't like it when you get and then relinquish a locality (as the tpm_try_get_ops/tpm_put_ops pair does) without sending a command. This currently happens all the time in the O_NONBLOCK write path. We can fix this by moving the tpm_try_get_ops further down the code to after the O_NONBLOCK determination is made. This is safe because the priv->buffer_mutex still protects the priv state being modified.

Fixes d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode")
---
 drivers/char/tpm/tpm-dev-common.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)
drivers/char/tpm/tpm-dev-common.c +9 -10
index 87f449340202..1784530b8387 100644
@@ -189,15 +189,6 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
 		goto out;
 	}
 
-	/* atomic tpm command send and result receive. We only hold the ops
-	 * lock during this period so that the tpm can be unregistered even if
-	 * the char dev is held open.
-	 */
-	if (tpm_try_get_ops(priv->chip)) {
-		ret = -EPIPE;
-		goto out;
-	}
-
 	priv->response_length = 0;
 	priv->response_read = false;
 	*off = 0;
@@ -211,11 +202,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
 	if (file->f_flags & O_NONBLOCK) {
 		priv->command_enqueued = true;
 		queue_work(tpm_dev_wq, &priv->async_work);
-		tpm_put_ops(priv->chip);
 		mutex_unlock(&priv->buffer_mutex);
 		return size;
 	}
 
+	/* atomic tpm command send and result receive. We only hold the ops
+	 * lock during this period so that the tpm can be unregistered even if
+	 * the char dev is held open.
+	 */
+	if (tpm_try_get_ops(priv->chip)) {
+		ret = -EPIPE;
+		goto out;
+	}
+
 	ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
 			       sizeof(priv->data_buffer));
 	tpm_put_ops(priv->chip);
Signature · 1 line
2.26.2
#1 lore raw
Quoted 21 lines

-----Original Message-----
From: James Bottomley <[email protected]>
Sent: Tuesday, May 26, 2020 7:25 PM
To: [email protected]
Cc: Jarkko Sakkinen; Jason Gunthorpe; Limonciello, Mario; Alex Guzman
Subject: [PATCH] tpm2: fix TIS locality timeout problems

[EXTERNAL EMAIL]

It has been reported that some TIS based TPMs are giving unexpected errors when using the O_NONBLOCK path. The problem is that some TPMs don't like it when you get and then relinquish a locality (as the tpm_try_get_ops/tpm_put_ops pair does) without sending a command. This currently happens all the time in the O_NONBLOCK write path. We can fix this by moving the tpm_try_get_ops further down the code to after the O_NONBLOCK determination is made. This is safe because the priv->buffer_mutex still protects the priv state being modified.

Quoted 4 lines
Fixes d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode")

A few other notes for right here:

* You should probably mention this buglink:

* And add another Reported-by: For Alex probably makes sense , as he is the original reporter to the bug. I just helped to bring it here.

* This should CC stable (as this regression managed to hit the stable kernels too).

Quoted 50 lines
---
 drivers/char/tpm/tpm-dev-common.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)
drivers/char/tpm/tpm-dev- renamed from drivers/char/tpm/tpm-dev-common.c +0 -0

common.c
index 87f449340202..1784530b8387 100644

drivers/char/tpm/tpm-dev-common.c +0 -9
@@ -189,15 +189,6 @@ ssize_t tpm_common_write(struct file *file, const char
 __user *buf,
 		goto out;
 	}
 
-	/* atomic tpm command send and result receive. We only hold the ops
-	 * lock during this period so that the tpm can be unregistered even if
-	 * the char dev is held open.
-	 */
-	if (tpm_try_get_ops(priv->chip)) {
-		ret = -EPIPE;
-		goto out;
-	}
-
 	priv->response_length = 0;
 	priv->response_read = false;
drivers/char/tpm/tpm-dev-common.c +9 -1
 	*off = 0;
@@ -211,11 +202,19 @@ ssize_t tpm_common_write(struct file *file, const char
 __user *buf,
 	if (file->f_flags & O_NONBLOCK) {
 		priv->command_enqueued = true;
 		queue_work(tpm_dev_wq, &priv->async_work);
-		tpm_put_ops(priv->chip);
 		mutex_unlock(&priv->buffer_mutex);
 		return size;
 	}
 
+	/* atomic tpm command send and result receive. We only hold the ops
+	 * lock during this period so that the tpm can be unregistered even if
+	 * the char dev is held open.
+	 */
+	if (tpm_try_get_ops(priv->chip)) {
+		ret = -EPIPE;
+		goto out;
+	}
+
 	ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
 			       sizeof(priv->data_buffer));

tpm_put_ops(priv->chip);
--
2.26.2

Reviewed-by on v1 1/1
#2 lore raw
In reply to James Bottomley
Quoted 9 lines · James Bottomley

It has been reported that some TIS based TPMs are giving unexpected errors when using the O_NONBLOCK path. The problem is that some TPMs don't like it when you get and then relinquish a locality (as the tpm_try_get_ops/tpm_put_ops pair does) without sending a command. This currently happens all the time in the O_NONBLOCK write path. We can fix this by moving the tpm_try_get_ops further down the code to after the O_NONBLOCK determination is made. This is safe because the priv->buffer_mutex still protects the priv state being modified.

Quoted 4 lines
Fixes d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode")
#3 lore raw
In reply to James Bottomley
Quoted 9 lines · James Bottomley

It has been reported that some TIS based TPMs are giving unexpected errors when using the O_NONBLOCK path. The problem is that some TPMs don't like it when you get and then relinquish a locality (as the tpm_try_get_ops/tpm_put_ops pair does) without sending a command. This currently happens all the time in the O_NONBLOCK write path. We can fix this by moving the tpm_try_get_ops further down the code to after the O_NONBLOCK determination is made. This is safe because the priv->buffer_mutex still protects the priv state being modified.

Quoted 4 lines
Fixes d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode")

Subsystem tag is wrong, function name is missing '()' after and sometimes there are spaces after ".". Please fix the commit message and I can look at the code when it is clean.

/Jarkko