Rémi Bernon : ntdll: Check that ptr is in committed blocks in find_subheap.

Alexandre Julliard julliard at winehq.org
Tue May 17 15:37:22 CDT 2022


Module: wine
Branch: master
Commit: 39697a2c007026356f143379c2fe875722e46f7f
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=39697a2c007026356f143379c2fe875722e46f7f

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Wed May  4 21:12:15 2022 +0200

ntdll: Check that ptr is in committed blocks in find_subheap.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/heap.c | 35 ++++++++++++-----------------------
 1 file changed, 12 insertions(+), 23 deletions(-)

diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
index 5174fe99fc3..0142328e978 100644
--- a/dlls/ntdll/heap.c
+++ b/dlls/ntdll/heap.c
@@ -614,15 +614,17 @@ static inline void HEAP_InsertFreeBlock( HEAP *heap, ARENA_FREE *pArena, BOOL la
 }
 
 
-static SUBHEAP *find_subheap( const HEAP *heap, const void *ptr )
+static SUBHEAP *find_subheap( const HEAP *heap, const struct block *block, BOOL heap_walk )
 {
     SUBHEAP *subheap;
 
     LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry )
     {
+        SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap );
         if (!check_subheap( subheap )) return NULL;
-        if (contains( subheap_base( subheap ), subheap_size( subheap ), ptr, sizeof(struct block) ))
-            return subheap;
+        if (contains( first_block( subheap ), blocks_size, block, sizeof(*block) )) return subheap;
+        /* outside of blocks region, possible corruption or heap_walk */
+        if (contains( subheap_base( subheap ), subheap_size( subheap ), block, 0 )) return heap_walk ? subheap : NULL;
     }
 
     return NULL;
@@ -760,7 +762,7 @@ static void HEAP_MakeInUseBlockFree( SUBHEAP *subheap, ARENA_INUSE *pArena )
         mark_block_free( pArena + 1, pArena->size & ARENA_SIZE_MASK, heap->flags );
         if (!prev) return;
         pArena = prev;
-        subheap = find_subheap( heap, pArena );
+        subheap = find_subheap( heap, pArena, FALSE );
     }
 
     /* Check if we can merge with previous block */
@@ -1097,7 +1099,7 @@ static ARENA_FREE *HEAP_FindFreeBlock( HEAP *heap, SIZE_T size,
                             sizeof(ARENA_FREE) - sizeof(ARENA_INUSE);
         if (arena_size >= size)
         {
-            subheap = find_subheap( heap, pArena );
+            subheap = find_subheap( heap, (struct block *)pArena, FALSE );
             if (!HEAP_Commit( subheap, (ARENA_INUSE *)pArena, size )) return NULL;
             *ppSubHeap = subheap;
             return pArena;
@@ -1145,9 +1147,7 @@ static BOOL is_valid_free_block( const HEAP *heap, const struct block *block )
     const SUBHEAP *subheap;
     unsigned int i;
 
-    if (!(subheap = find_subheap( heap, block ))) return FALSE;
-    if ((char *)block >= (char *)subheap->base + subheap->headerSize) return TRUE;
-    if (subheap != &heap->subheap) return FALSE;
+    if ((subheap = find_subheap( heap, block, FALSE ))) return TRUE;
     for (i = 0; i < HEAP_NB_FREE_LISTS; i++) if (block == (struct block *)&heap->freeList[i].arena) return TRUE;
     return FALSE;
 }
@@ -1155,7 +1155,6 @@ static BOOL is_valid_free_block( const HEAP *heap, const struct block *block )
 static BOOL validate_free_block( const SUBHEAP *subheap, const struct block *block )
 {
     const char *err = NULL, *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap );
-    SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap );
     const struct entry *entry = (struct entry *)block;
     const struct block *prev, *next;
     HEAP *heap = subheap->heap;
@@ -1163,8 +1162,6 @@ static BOOL validate_free_block( const SUBHEAP *subheap, const struct block *blo
 
     if ((ULONG_PTR)(block + 1) % ALIGNMENT)
         err = "invalid block alignment";
-    else if (!contains( first_block( subheap ), blocks_size, block, sizeof(*block) ))
-        err = "invalid block pointer";
     else if (block_get_type( block ) != ARENA_FREE_MAGIC)
         err = "invalid block header";
     else if (!(block_get_flags( block ) & ARENA_FLAG_FREE) || (block_get_flags( block ) & ARENA_FLAG_PREV_FREE))
@@ -1211,7 +1208,6 @@ static BOOL validate_free_block( const SUBHEAP *subheap, const struct block *blo
 static BOOL validate_used_block( const SUBHEAP *subheap, const struct block *block )
 {
     const char *err = NULL, *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap );
-    SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap );
     const HEAP *heap = subheap->heap;
     DWORD flags = heap->flags;
     const struct block *next;
@@ -1219,8 +1215,6 @@ static BOOL validate_used_block( const SUBHEAP *subheap, const struct block *blo
 
     if ((ULONG_PTR)(block + 1) % ALIGNMENT)
         err = "invalid block alignment";
-    else if (!contains( first_block( subheap ), blocks_size, block, sizeof(*block) ))
-        err = "invalid block pointer";
     else if (block_get_type( block ) != ARENA_INUSE_MAGIC && block_get_type( block ) != ARENA_PENDING_MAGIC)
         err = "invalid block header";
     else if (block_get_flags( block ) & ARENA_FLAG_FREE)
@@ -1272,12 +1266,11 @@ static BOOL heap_validate_ptr( const HEAP *heap, const void *ptr, SUBHEAP **subh
     const struct block *arena = (struct block *)ptr - 1;
     const ARENA_LARGE *large_arena;
 
-    if (!(*subheap = find_subheap( heap, arena )) ||
-        ((const char *)arena < (char *)(*subheap)->base + (*subheap)->headerSize))
+    if (!(*subheap = find_subheap( heap, arena, FALSE )))
     {
         if (!(large_arena = find_large_block( heap, ptr )))
         {
-            if (WARN_ON(heap)) WARN("heap %p, ptr %p is not inside heap\n", heap, ptr );
+            if (WARN_ON(heap)) WARN("heap %p, ptr %p: block region not found\n", heap, ptr );
             return FALSE;
         }
 
@@ -1325,7 +1318,6 @@ static inline struct block *unsafe_block_from_ptr( const HEAP *heap, const void
 {
     struct block *block = (struct block *)ptr - 1;
     const char *err = NULL, *base, *commit_end;
-    SIZE_T blocks_size;
 
     if (heap->flags & HEAP_VALIDATE)
     {
@@ -1333,11 +1325,10 @@ static inline struct block *unsafe_block_from_ptr( const HEAP *heap, const void
         return block;
     }
 
-    if ((*subheap = find_subheap( heap, block )))
+    if ((*subheap = find_subheap( heap, block, FALSE )))
     {
         base = subheap_base( *subheap );
         commit_end = subheap_commit_end( *subheap );
-        blocks_size = (char *)last_block( *subheap ) - (char *)first_block( *subheap );
     }
 
     if (!*subheap)
@@ -1347,8 +1338,6 @@ static inline struct block *unsafe_block_from_ptr( const HEAP *heap, const void
     }
     else if ((ULONG_PTR)ptr % ALIGNMENT)
         err = "invalid ptr alignment";
-    else if (!contains( first_block( *subheap ), blocks_size, block, sizeof(*block) ))
-        err = "invalid block pointer";
     else if (block_get_type( block ) == ARENA_PENDING_MAGIC || (block_get_flags( block ) & ARENA_FLAG_FREE))
         err = "already freed block";
     else if (block_get_type( block ) != ARENA_INUSE_MAGIC)
@@ -1975,7 +1964,7 @@ static NTSTATUS heap_walk( const HEAP *heap, struct rtl_heap_entry *entry )
 
     if ((large = find_large_block( heap, entry->lpData )))
         next = &large->entry;
-    else if ((subheap = find_subheap( heap, entry->lpData )))
+    else if ((subheap = find_subheap( heap, entry->lpData, TRUE )))
     {
         if (!(status = heap_walk_blocks( heap, subheap, entry ))) return STATUS_SUCCESS;
         else if (status != STATUS_NO_MORE_ENTRIES) return status;




More information about the wine-cvs mailing list