From b19dc8a9b61fc88ed9abfd6d0f82c308350eff59 Mon Sep 17 00:00:00 2001 From: Liav A Date: Wed, 22 Feb 2023 20:11:03 +0200 Subject: [PATCH] Kernel: Prevent out-of-bounds read/write in VirtIO GPU3DDevice::ioctl Before doing a check if offset_in_region + num_bytes of the transfer descriptor are together more than NUM_TRANSFER_REGION_PAGES * PAGE_SIZE, check that addition of both of these parameters will not simply overflow which could lead to out-of-bounds read/write. Fixes #17518. --- Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp b/Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp index 5d66a92c9d..c1fc61fccb 100644 --- a/Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp +++ b/Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp @@ -73,16 +73,16 @@ ErrorOr VirtIOGPU3DDevice::ioctl(OpenFileDescription& description, unsigne auto& transfer_buffer_region = TRY(get_context_for_description(description))->transfer_buffer_region(); auto user_transfer_descriptor = static_ptr_cast(arg); auto transfer_descriptor = TRY(copy_typed_from_user(user_transfer_descriptor)); + if (Checked::addition_would_overflow(transfer_descriptor.offset_in_region, transfer_descriptor.num_bytes)) { + return EOVERFLOW; + } + if (transfer_descriptor.offset_in_region + transfer_descriptor.num_bytes > NUM_TRANSFER_REGION_PAGES * PAGE_SIZE) { + return EOVERFLOW; + } if (transfer_descriptor.direction == VIRGL_DATA_DIR_GUEST_TO_HOST) { - if (transfer_descriptor.offset_in_region + transfer_descriptor.num_bytes > NUM_TRANSFER_REGION_PAGES * PAGE_SIZE) { - return EOVERFLOW; - } auto target = transfer_buffer_region.vaddr().offset(transfer_descriptor.offset_in_region).as_ptr(); return copy_from_user(target, transfer_descriptor.data, transfer_descriptor.num_bytes); } else if (transfer_descriptor.direction == VIRGL_DATA_DIR_HOST_TO_GUEST) { - if (transfer_descriptor.offset_in_region + transfer_descriptor.num_bytes > NUM_TRANSFER_REGION_PAGES * PAGE_SIZE) { - return EOVERFLOW; - } auto source = transfer_buffer_region.vaddr().offset(transfer_descriptor.offset_in_region).as_ptr(); return copy_to_user(transfer_descriptor.data, source, transfer_descriptor.num_bytes); } else {