Commit 71106292 authored by Tadeusz Struk's avatar Tadeusz Struk Committed by James Morris
Browse files

tpm: fix an invalid condition in tpm_common_poll



The poll condition should only check response_length,
because reads should only be issued if there is data to read.
The response_read flag only prevents double writes.
The problem was that the write set the response_read to false,
enqued a tpm job, and returned. Then application called poll
which checked the response_read flag and returned EPOLLIN.
Then the application called read, but got nothing.
After all that the async_work kicked in.
Added also mutex_lock around the poll check to prevent
other possible race conditions.

Fixes: 9488585b ("tpm: add support for partial reads")
Reported-by: default avatarMantas Mikulėnas <grawity@gmail.com>
Tested-by: default avatarMantas Mikulėnas <grawity@gmail.com>
Signed-off-by: default avatarTadeusz Struk <tadeusz.struk@intel.com>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: default avatarJames Morris <james.morris@microsoft.com>
parent e891db1a
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -233,12 +233,19 @@ __poll_t tpm_common_poll(struct file *file, poll_table *wait)
	__poll_t mask = 0;

	poll_wait(file, &priv->async_wait, wait);
	mutex_lock(&priv->buffer_mutex);

	if (!priv->response_read || priv->response_length)
	/*
	 * The response_length indicates if there is still response
	 * (or part of it) to be consumed. Partial reads decrease it
	 * by the number of bytes read, and write resets it the zero.
	 */
	if (priv->response_length)
		mask = EPOLLIN | EPOLLRDNORM;
	else
		mask = EPOLLOUT | EPOLLWRNORM;

	mutex_unlock(&priv->buffer_mutex);
	return mask;
}