[PATCH] hv: hv_balloon: validate unballoon range count
From: Michael Bommarito <hidden>
Date: 2026-07-10 02:29:22
Also in:
lkml, stable
Subsystem:
hyper-v/azure core and drivers, the rest · Maintainers:
"K. Y. Srinivasan", Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Linus Torvalds
The Hyper-V dynamic memory host supplies DM_UNBALLOON_REQUEST messages
with a header size and a range_count field. balloon_down() trusts
range_count and walks req->range_array without checking that the received
message contains that many ranges.
A malformed host or backend message can therefore make the guest read
past the received VMBus packet while freeing balloon ranges. Validate the
received message size and reject range_count values that exceed the
present range array before walking it.
Impact: A malicious Hyper-V host or backend can crash a guest by sending
a short unballoon request with an oversized range_count.
Fixes: 9aa8b50b2b3d ("Drivers: hv: Add Hyper-V balloon driver")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <redacted>
---
drivers/hv/hv_balloon.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index a848400a59a2d..f5bc8c9fea7b9 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c@@ -1337,8 +1337,23 @@ static void balloon_up(struct work_struct *dummy) } } +static bool unballoon_request_valid(struct dm_unballoon_request *req, + u32 msg_size) +{ + u32 max_ranges; + + if (msg_size < sizeof(*req) || req->hdr.size < sizeof(*req) || + req->hdr.size > msg_size) + return false; + + max_ranges = (req->hdr.size - sizeof(*req)) / + sizeof(req->range_array[0]); + + return req->range_count <= max_ranges; +} + static void balloon_down(struct hv_dynmem_device *dm, - struct dm_unballoon_request *req) + struct dm_unballoon_request *req, u32 msg_size) { union dm_mem_page_range *range_array = req->range_array; int range_count = req->range_count;
@@ -1346,6 +1361,12 @@ static void balloon_down(struct hv_dynmem_device *dm, int i; unsigned int prev_pages_ballooned = dm->num_pages_ballooned; + if (!unballoon_request_valid(req, msg_size)) { + pr_warn_ratelimited("Invalid unballoon request: size %u, header size %u, range count %u\n", + msg_size, req->hdr.size, req->range_count); + return; + } + for (i = 0; i < range_count; i++) { free_balloon_pages(dm, &range_array[i]); complete(&dm_device.config_event);
@@ -1527,7 +1548,8 @@ static void balloon_onchannelcallback(void *context) dm->state = DM_BALLOON_DOWN; balloon_down(dm, - (struct dm_unballoon_request *)recv_buffer); + (struct dm_unballoon_request *)recv_buffer, + recvlen); break; case DM_MEM_HOT_ADD_REQUEST:
--
2.53.0