Commit 78628402 authored by James Bottomley's avatar James Bottomley Committed by Jarkko Sakkinen

tpm: Fix TIS locality timeout problems

It has been reported that some TIS based TPMs are giving unexpected
errors when using the O_NONBLOCK path of the TPM device. 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. 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.

BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206275
Fixes: d23d1248 ("tpm: fix invalid locking in NONBLOCKING mode")
Reported-by: default avatarMario Limonciello <Mario.Limonciello@dell.com>
Tested-by: default avatarAlex Guzman <alex@guzman.io>
Cc: stable@vger.kernel.org
Reviewed-by: default avatarJerry Snitselaar <jsnitsel@redhat.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
parent cd77006e
...@@ -189,15 +189,6 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, ...@@ -189,15 +189,6 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
goto out; 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_length = 0;
priv->response_read = false; priv->response_read = false;
*off = 0; *off = 0;
...@@ -211,11 +202,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf, ...@@ -211,11 +202,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
if (file->f_flags & O_NONBLOCK) { if (file->f_flags & O_NONBLOCK) {
priv->command_enqueued = true; priv->command_enqueued = true;
queue_work(tpm_dev_wq, &priv->async_work); queue_work(tpm_dev_wq, &priv->async_work);
tpm_put_ops(priv->chip);
mutex_unlock(&priv->buffer_mutex); mutex_unlock(&priv->buffer_mutex);
return size; 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, ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer,
sizeof(priv->data_buffer)); sizeof(priv->data_buffer));
tpm_put_ops(priv->chip); tpm_put_ops(priv->chip);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment