vi->data_avail is decremented on each read, so it holds the remaining
bytes rather than the total length. Subtracting vi->data_idx from it
again in commit e3046eeada29 ("hwrng: virtio: clamp device-reported
used.len at copy_data()") undercounts the bytes left after a partial
read. This can leave vi->data_avail nonzero without queuing a new
request, causing virtio_read() to hang on have_data.
Clamp vi->data_avail to sizeof(vi->data) - vi->data_idx instead.
Fixes: e3046eeada29 ("hwrng: virtio: clamp device-reported used.len at
copy_data()")
Tested-by: Wei Liu <[email protected]>
Cc: [email protected]
Signed-off-by: Xiang Lei <[email protected]>
---
drivers/char/hw_random/virtio-rng.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/char/hw_random/virtio-rng.c
b/drivers/char/hw_random/virtio-rng.c
index f9982217247d..a3392f7e2d8c 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -70,7 +70,7 @@ static void request_entropy(struct virtrng_info *vi)
static unsigned int copy_data(struct virtrng_info *vi, void *buf,
unsigned int size)
{
- unsigned int idx, avail;
+ unsigned int idx;
/*
* vi->data_avail was set from the device-reported used.len and
@@ -81,13 +81,13 @@ static unsigned int copy_data(struct virtrng_info *vi, void
*buf,
* steered into adjacent slab memory, including under
* speculation.
*/
- avail = min(vi->data_avail, sizeof(vi->data));
- if (vi->data_idx >= avail) {
+ if (vi->data_idx >= sizeof(vi->data)) {
vi->data_avail = 0;
request_entropy(vi);
return 0;
}
- size = min(size, avail - vi->data_idx);
+ vi->data_avail = min(vi->data_avail, sizeof(vi->data) - vi->data_idx);
+ size = min(size, vi->data_avail);
idx = array_index_nospec(vi->data_idx, sizeof(vi->data));
memcpy(buf, vi->data + idx, size);
vi->data_idx += size;
--
2.53.0