diff options
| author | Kameron Carr <kameroncarr@linux.microsoft.com> | 2026-10-19 16:09:49 -0700 |
|---|---|---|
| committer | Wei Liu <wei.liu@kernel.org> | 2026-10-21 00:00:29 -0700 |
| commit | be0d83e869430232ca56f439eabac9c99758221f (patch) | |
| tree | b58d56ee7f4ec417a2e99b1b551b17632b5e68ef /include/linux | |
| parent | a8e60890cb86a181d8216ac7e60873ba9d7d2ff9 (diff) | |
Drivers: hv: vmbus: Keep the ring byte counts sane for a bad index
The remaining users of the shared indices can't cause a bad memory
access with the channels a CoCo VM accepts today, but an out-of-range
index gives them a nonsense byte count. Give them defined behavior
instead.
hv_pkt_iter_first() bounds its memcpy() by hv_pkt_iter_avail(), which
is derived from write_index, and by pkt_buffer_size, which comes from
max_pkt_size and can exceed ring_datasize. A bad write index can then
make it read past the end of the ring. Only KVP has such a max_pkt_size
(16K on a 12K ring with 4K pages), and vmbus_is_valid_offer() rejects
it in isolated VMs, so this is latent. hv_pkt_iter_avail() now reports
an empty ring for a bad write index and logs it, rate-limited like
hv_ringbuffer_write(). It takes the channel instead of the ring so the
message can include the relid.
hv_get_bytes_to_read() and hv_get_bytes_to_write() now return 0 for a
bad index, so callers see nothing to read and no room to write. This
also stops hv_end_read() from reporting data that hv_pkt_iter_first()
won't return, which would keep a channel rescheduling its callback.
hv_pkt_iter_close() only uses the indices to decide whether to signal
the host, so skip the signal if either is out of range.
Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/hyperv.h | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 09f25ade88b0..216c0b9e9be5 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -250,6 +250,8 @@ static inline u32 hv_get_bytes_to_read(const struct hv_ring_buffer_info *rbi) read_loc = READ_ONCE(rbi->ring_buffer->read_index); write_loc = READ_ONCE(rbi->ring_buffer->write_index); + if (unlikely(hv_ringbuffer_indices_invalid(rbi, read_loc, write_loc))) + return 0; return hv_ringbuffer_avail_read(rbi, read_loc, write_loc); } @@ -260,6 +262,8 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi) read_loc = READ_ONCE(rbi->ring_buffer->read_index); write_loc = READ_ONCE(rbi->ring_buffer->write_index); + if (unlikely(hv_ringbuffer_indices_invalid(rbi, read_loc, write_loc))) + return 0; return hv_ringbuffer_avail_write(rbi, read_loc, write_loc); } |
