| From 2e8e4c8f6673247e22efc7985ce5497accd16f88 Mon Sep 17 00:00:00 2001 |
| From: Tadeusz Struk <tstruk@gmail.com> |
| Date: Sat, 15 Jan 2022 17:26:26 -0800 |
| Subject: tpm: Fix error handling in async work |
| |
| From: Tadeusz Struk <tstruk@gmail.com> |
| |
| commit 2e8e4c8f6673247e22efc7985ce5497accd16f88 upstream. |
| |
| When an invalid (non existing) handle is used in a TPM command, |
| that uses the resource manager interface (/dev/tpmrm0) the resource |
| manager tries to load it from its internal cache, but fails and |
| the tpm_dev_transmit returns an -EINVAL error to the caller. |
| The existing async handler doesn't handle these error cases |
| currently and the condition in the poll handler never returns |
| mask with EPOLLIN set. |
| The result is that the poll call blocks and the application gets stuck |
| until the user_read_timer wakes it up after 120 sec. |
| Change the tpm_dev_async_work function to handle error conditions |
| returned from tpm_dev_transmit they are also reflected in the poll mask |
| and a correct error code could passed back to the caller. |
| |
| Cc: Jarkko Sakkinen <jarkko@kernel.org> |
| Cc: Jason Gunthorpe <jgg@ziepe.ca> |
| Cc: <linux-integrity@vger.kernel.org> |
| Cc: <stable@vger.kernel.org> |
| Cc: <linux-kernel@vger.kernel.org> |
| |
| Fixes: 9e1b74a63f77 ("tpm: add support for nonblocking operation") |
| Tested-by: Jarkko Sakkinen<jarkko@kernel.org> |
| Signed-off-by: Tadeusz Struk <tstruk@gmail.com> |
| Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> |
| Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org> |
| Cc: Tadeusz Struk <tadeusz.struk@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/char/tpm/tpm-dev-common.c | 8 +++++++- |
| 1 file changed, 7 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/char/tpm/tpm-dev-common.c |
| +++ b/drivers/char/tpm/tpm-dev-common.c |
| @@ -69,7 +69,13 @@ static void tpm_dev_async_work(struct wo |
| ret = tpm_dev_transmit(priv->chip, priv->space, priv->data_buffer, |
| sizeof(priv->data_buffer)); |
| tpm_put_ops(priv->chip); |
| - if (ret > 0) { |
| + |
| + /* |
| + * If ret is > 0 then tpm_dev_transmit returned the size of the |
| + * response. If ret is < 0 then tpm_dev_transmit failed and |
| + * returned an error code. |
| + */ |
| + if (ret != 0) { |
| priv->response_length = ret; |
| mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); |
| } |