Message ID | 1590689457.3449.7.camel@HansenPartnership.com (mailing list archive) |
---|---|
State | Accepted, archived |
Headers | show |
Series | [v2] tpm: fix TIS locality timeout problems | expand |
On Thu, May 28, 2020 at 11:10:57AM -0700, James Bottomley wrote: > 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: d23d12484307 ("tpm: fix invalid locking in NONBLOCKING mode") > Reported-by: Mario Limonciello <Mario.Limonciello@dell.com> > Tested-by: Alex Guzman <alex@guzman.io> > Cc: stable@vger.kernel.org > Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com> > Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Thanks a lot! Merging this soon. Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> /Jarko
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index 87f449340202..1784530b8387 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -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);