]> git.ipfire.org Git - thirdparty/pciutils.git/commitdiff
libpci: physmem-windows: Fix check for length param of physmem_unmap()
authorPali Rohár <pali@kernel.org>
Sun, 30 Nov 2025 16:21:57 +0000 (17:21 +0100)
committerMartin Mareš <mj@ucw.cz>
Sun, 28 Dec 2025 20:49:06 +0000 (21:49 +0100)
VirtualQuery() does not have to return whole mapped range, but just region
subset. So call VirtualQuery() multiple times for each region and calculate
the total length of the mapping.

This change fixes unmapping of the BIOS 0xE0000-0x100000 memory for which
Windows creates region of one page and so VirtualQuery() for each region i
at virtual address ptr + i*4096 returns AllocationBase=ptr and RegionSize=4096.

lib/physmem-windows.c

index 075fe57c069d948d8ffaa863eb104326ea2403b2..90f49e34682a33e997939e8a8029e9eeefa7b0ba 100644 (file)
@@ -948,6 +948,7 @@ physmem_unmap(struct physmem *physmem, void *ptr, size_t length)
   long pagesize = physmem_get_pagesize(physmem);
   MEMORY_BASIC_INFORMATION info;
   NTSTATUS status;
+  DWORD region_size;
 
   if (physmem->section_handle != INVALID_HANDLE_VALUE)
     {
@@ -957,17 +958,30 @@ physmem_unmap(struct physmem *physmem, void *ptr, size_t length)
        * point to the beginning of the mapped memory range.
        *
        * So verify that the ptr argument is the beginning of the mapped range
-       * and length argument is the length of mapped range.
+       * and length argument is the total length of mapped range.
+       *
+       * VirtualQuery() does not have to return whole mapped range, but just
+       * some region subset. So call VirtualQuery() multiple times for each
+       * region subset until we receive size of the whole mapped region range.
        */
 
-      if (VirtualQuery(ptr, &info, sizeof(info)) != sizeof(info))
+      for (region_size = 0; region_size < length; region_size += info.RegionSize)
         {
-          errno = EINVAL;
-          return -1;
+          if (VirtualQuery(ptr + region_size, &info, sizeof(info)) != sizeof(info))
+            {
+              errno = EINVAL;
+              return -1;
+            }
+
+          if (info.AllocationBase != ptr)
+            {
+              errno = EINVAL;
+              return -1;
+            }
         }
 
       /* RegionSize is already page aligned, but length does not have to be. */
-      if (info.AllocationBase != ptr || info.RegionSize != ((length + pagesize-1) & ~(pagesize-1)))
+      if (region_size != ((length + pagesize-1) & ~(pagesize-1)))
         {
           errno = EINVAL;
           return -1;