From bfbefa346a895c7e3ccc994f503d0f3f02e0fdc9 Mon Sep 17 00:00:00 2001
From: Las <las@protonmail.ch>
Date: Sat, 2 Mar 2019 12:28:26 +0100
Subject: [PATCH v2 3/5] Don't use ZeroBits argument in NtAllocateVirtualMemory
 as alignment

This usage is incorrect, as the ZeroBits argument is used to specify
the size of the pointer returned. This patch replaces internal ntdll
uses of NtAllocateVirtualMemory which depend on this behavior with
a new function virtual_alloc, which NtAllocateVirtualMemory is now a wrapper
for.

Signed-off-by: Las <las@protonmail.ch>
---
 dlls/kernel32/tests/virtual.c |  1 +
 dlls/ntdll/directory.c        |  4 +--
 dlls/ntdll/heap.c             |  6 ++--
 dlls/ntdll/ntdll_misc.h       |  2 ++
 dlls/ntdll/signal_arm.c       |  4 +--
 dlls/ntdll/signal_arm64.c     |  4 +--
 dlls/ntdll/signal_i386.c      |  4 +--
 dlls/ntdll/signal_powerpc.c   |  4 +--
 dlls/ntdll/signal_x86_64.c    |  4 +--
 dlls/ntdll/thread.c           |  4 +--
 dlls/ntdll/virtual.c          | 62 ++++++++++++++++++++---------------
 11 files changed, 55 insertions(+), 44 deletions(-)

diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c
index 78bc17a09c..1ce83bb3ec 100644
--- a/dlls/kernel32/tests/virtual.c
+++ b/dlls/kernel32/tests/virtual.c
@@ -461,6 +461,7 @@ static void test_VirtualAlloc(void)
     addr2 = NULL;
     status = pNtAllocateVirtualMemory(GetCurrentProcess(), &addr2, 21, &size,
                                       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+    todo_wine
     ok(status == STATUS_SUCCESS || status == STATUS_NO_MEMORY,
        "NtAllocateVirtualMemory returned %08x\n", status);
     if (status == STATUS_SUCCESS) ok(VirtualFree(addr2, 0, MEM_RELEASE), "VirtualFree failed\n");
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index b46c2a6736..9833409fe6 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -1603,14 +1603,14 @@ static KERNEL_DIRENT *start_vfat_ioctl( int fd )
         SIZE_T size = 2 * sizeof(*de) + page_size;
         void *addr = NULL;
 
-        if (NtAllocateVirtualMemory( GetCurrentProcess(), &addr, 1, &size, MEM_RESERVE, PAGE_READWRITE ))
+        if (virtual_alloc( GetCurrentProcess(), &addr, 0, &size, MEM_RESERVE, PAGE_READWRITE, 1 ))
             return NULL;
         /* commit only the size needed for the dir entries */
         /* this leaves an extra unaccessible page, which should make the kernel */
         /* fail with -EFAULT before it stomps all over our memory */
         de = addr;
         size = 2 * sizeof(*de);
-        NtAllocateVirtualMemory( GetCurrentProcess(), &addr, 1, &size, MEM_COMMIT, PAGE_READWRITE );
+        virtual_alloc( GetCurrentProcess(), &addr, 0, &size, MEM_COMMIT, PAGE_READWRITE, 1 );
     }
 
     /* set d_reclen to 65535 to work around an AFS kernel bug */
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
index bdadc7932d..af1e67a4e3 100644
--- a/dlls/ntdll/heap.c
+++ b/dlls/ntdll/heap.c
@@ -726,8 +726,8 @@ static void *allocate_large_block( HEAP *heap, DWORD flags, SIZE_T size )
     LPVOID address = NULL;
 
     if (block_size < size) return NULL;  /* overflow */
-    if (NtAllocateVirtualMemory( NtCurrentProcess(), &address, 5,
-                                 &block_size, MEM_COMMIT, get_protection_type( flags ) ))
+    if (virtual_alloc( NtCurrentProcess(), &address, 0,
+                       &block_size, MEM_COMMIT, get_protection_type( flags ), 5 ))
     {
         WARN("Could not allocate block for %08lx bytes\n", size );
         return NULL;
@@ -1521,7 +1521,7 @@ void heap_set_debug_flags( HANDLE handle )
         void *ptr = NULL;
         SIZE_T size = MAX_FREE_PENDING * sizeof(*heap->pending_free);
 
-        if (!NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 4, &size, MEM_COMMIT, PAGE_READWRITE ))
+        if (!virtual_alloc( NtCurrentProcess(), &ptr, 0, &size, MEM_COMMIT, PAGE_READWRITE, 4 ))
         {
             heap->pending_free = ptr;
             heap->pending_pos = 0;
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 2692c43224..08b7925abd 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -167,6 +167,8 @@ extern NTSTATUS nt_to_unix_file_name_attr( const OBJECT_ATTRIBUTES *attr, ANSI_S
                                            UINT disposition ) DECLSPEC_HIDDEN;
 
 /* virtual memory */
+extern NTSTATUS virtual_alloc( HANDLE process, PVOID *ret, ULONG zero_bits,
+                               SIZE_T *size_ptr, ULONG type, ULONG protect, ULONG alignment ) DECLSPEC_HIDDEN;
 extern NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, SIZE_T commit_size,
                                      const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG protect,
                                      pe_image_info_t *image_info ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index 75a1133b4f..802e6104e1 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -966,8 +966,8 @@ NTSTATUS signal_alloc_thread( TEB **teb )
 
     size = 1 << sigstack_zero_bits;
     *teb = NULL;
-    if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
-                                            &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
+    if (!(status = virtual_alloc( NtCurrentProcess(), (void **)teb, 0, &size,
+                                  MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE, sigstack_zero_bits )))
     {
         (*teb)->Tib.Self = &(*teb)->Tib;
         (*teb)->Tib.ExceptionList = (void *)~0UL;
diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c
index 1d26125209..746fe20e77 100644
--- a/dlls/ntdll/signal_arm64.c
+++ b/dlls/ntdll/signal_arm64.c
@@ -887,8 +887,8 @@ NTSTATUS signal_alloc_thread( TEB **teb )
 
     size = 1 << sigstack_zero_bits;
     *teb = NULL;
-    if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
-                                            &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
+    if (!(status = virtual_alloc( NtCurrentProcess(), (void **)teb, 0, &size,
+                                  MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE, sigstack_zero_bits )))
     {
         (*teb)->Tib.Self = &(*teb)->Tib;
         (*teb)->Tib.ExceptionList = (void *)~0UL;
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 0274a7d26d..590410b8d8 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -2311,8 +2311,8 @@ NTSTATUS signal_alloc_thread( TEB **teb )
     }
 
     size = signal_stack_mask + 1;
-    if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, sigstack_zero_bits,
-                                            &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
+    if (!(status = virtual_alloc( NtCurrentProcess(), &addr, 0, &size,
+                                  MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE, sigstack_zero_bits )))
     {
         *teb = addr;
         (*teb)->Tib.Self = &(*teb)->Tib;
diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c
index 86398d8f54..e1430565fe 100644
--- a/dlls/ntdll/signal_powerpc.c
+++ b/dlls/ntdll/signal_powerpc.c
@@ -1032,8 +1032,8 @@ NTSTATUS signal_alloc_thread( TEB **teb )
 
     size = 1 << sigstack_zero_bits;
     *teb = NULL;
-    if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
-                                            &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
+    if (!(status = virtual_alloc( NtCurrentProcess(), (void **)teb, 0, &size,
+                                  MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE, sigstack_zero_bits )))
     {
         (*teb)->Tib.Self = &(*teb)->Tib;
         (*teb)->Tib.ExceptionList = (void *)~0UL;
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 54871b8302..17c6ad7e43 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -3276,8 +3276,8 @@ NTSTATUS signal_alloc_thread( TEB **teb )
 
     size = 1 << sigstack_zero_bits;
     *teb = NULL;
-    if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
-                                            &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
+    if (!(status = virtual_alloc( NtCurrentProcess(), (void **)teb, 0, &size,
+                                  MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE, sigstack_zero_bits )))
     {
         (*teb)->Tib.Self = &(*teb)->Tib;
         (*teb)->Tib.ExceptionList = (void *)~0UL;
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 9f4a08fdb9..32977d4b53 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -185,8 +185,8 @@ void thread_init(void)
 
     addr = NULL;
     size = sizeof(*peb);
-    NtAllocateVirtualMemory( NtCurrentProcess(), &addr, 1, &size,
-                             MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE );
+    virtual_alloc( NtCurrentProcess(), &addr, 0, &size,
+                   MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE, 1 );
     peb = addr;
 
     peb->FastPebLock        = &peb_lock;
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index 76dc6c284d..0fd751ed9d 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -119,6 +119,8 @@ static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
 };
 static RTL_CRITICAL_SECTION csVirtual = { &critsect_debug, -1, 0, 0, 0, 0 };
 
+static const UINT default_alignment = 16;
+static const UINT_PTR default_alignment_mask = 0xffff;
 #ifdef __i386__
 static const UINT page_shift = 12;
 static const UINT_PTR page_mask = 0xfff;
@@ -406,18 +408,6 @@ static struct file_view *VIRTUAL_FindView( const void *addr, size_t size )
 }
 
 
-/***********************************************************************
- *           get_mask
- */
-static inline UINT_PTR get_mask( ULONG zero_bits )
-{
-    if (!zero_bits) return 0xffff;  /* allocations are aligned to 64K by default */
-    if (zero_bits < page_shift) zero_bits = page_shift;
-    if (zero_bits > 21) return 0;
-    return (1 << zero_bits) - 1;
-}
-
-
 /***********************************************************************
  *           is_write_watch_range
  */
@@ -1614,7 +1604,7 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, S
     NTSTATUS res;
     mem_size_t full_size;
     ACCESS_MASK access;
-    SIZE_T size, mask = get_mask( zero_bits );
+    SIZE_T size;
     int unix_handle = -1, needs_close;
     unsigned int vprot, sec_flags;
     struct file_view *view;
@@ -1669,14 +1659,14 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, S
 
             if ((res = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA,
                                            &shared_fd, &shared_needs_close, NULL, NULL ))) goto done;
-            res = map_image( handle, access, unix_handle, mask, image_info,
+            res = map_image( handle, access, unix_handle, default_alignment_mask, image_info,
                              shared_fd, needs_close, addr_ptr );
             if (shared_needs_close) close( shared_fd );
             close_handle( shared_file );
         }
         else
         {
-            res = map_image( handle, access, unix_handle, mask, image_info, -1, needs_close, addr_ptr );
+            res = map_image( handle, access, unix_handle, default_alignment_mask, image_info, -1, needs_close, addr_ptr );
         }
         if (needs_close) close( unix_handle );
         if (res >= 0) *size_ptr = image_info->map_size;
@@ -1713,7 +1703,7 @@ NTSTATUS virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG zero_bits, S
     get_vprot_flags( protect, &vprot, sec_flags & SEC_IMAGE );
     vprot |= sec_flags;
     if (!(sec_flags & SEC_RESERVE)) vprot |= VPROT_COMMITTED;
-    res = map_view( &view, *addr_ptr, size, mask, FALSE, vprot );
+    res = map_view( &view, *addr_ptr, size, default_alignment_mask, FALSE, vprot );
     if (res)
     {
         server_leave_uninterrupted_section( &csVirtual, &sigset );
@@ -1870,7 +1860,7 @@ void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info )
     }
 #endif
     info->MmNumberOfPhysicalPages = info->MmHighestPhysicalPage - info->MmLowestPhysicalPage;
-    info->AllocationGranularity   = get_mask(0) + 1;
+    info->AllocationGranularity   = 1 << default_alignment;
     info->LowestUserAddress       = (void *)0x10000;
     info->HighestUserAddress      = (char *)user_space_limit - 1;
     info->ActiveProcessorsAffinityMask = get_system_affinity_mask();
@@ -2455,25 +2445,32 @@ void virtual_set_large_address_space(void)
 
 
 /***********************************************************************
- *             NtAllocateVirtualMemory   (NTDLL.@)
- *             ZwAllocateVirtualMemory   (NTDLL.@)
+ *             virtual_alloc
+ *
+ * Allocate virtual memory at address given with the given alignment
+ * and pointer size restrictions.
  */
-NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_bits,
-                                         SIZE_T *size_ptr, ULONG type, ULONG protect )
+NTSTATUS virtual_alloc( HANDLE process, PVOID *ret, ULONG zero_bits,
+                        SIZE_T *size_ptr, ULONG type, ULONG protect, ULONG alignment )
 {
     void *base;
     unsigned int vprot;
     SIZE_T size = *size_ptr;
-    SIZE_T mask = get_mask( zero_bits );
+    SIZE_T mask;
     NTSTATUS status = STATUS_SUCCESS;
     BOOL is_dos_memory = FALSE;
     struct file_view *view;
     sigset_t sigset;
 
-    TRACE("%p %p %08lx %x %08x\n", process, *ret, size, type, protect );
+    TRACE("%p %p %i %08lx %x %08x %i\n", process, *ret, zero_bits, size, type, protect, alignment );
+
+    alignment = max( alignment, page_shift );
+    mask = (1 << alignment) - 1;
 
     if (!size) return STATUS_INVALID_PARAMETER;
-    if (!mask) return STATUS_INVALID_PARAMETER_3;
+    /* Unimplemented */
+    if (zero_bits)
+        return STATUS_INVALID_PARAMETER_3;
 
     if (process != NtCurrentProcess())
     {
@@ -2505,7 +2502,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
 
     if (*ret)
     {
-        if (type & MEM_RESERVE) /* Round down to 64k boundary */
+        if (type & MEM_RESERVE)
             base = ROUND_ADDR( *ret, mask );
         else
             base = ROUND_ADDR( *ret, page_mask );
@@ -2589,6 +2586,16 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_
     return status;
 }
 
+/***********************************************************************
+ *             NtAllocateVirtualMemory   (NTDLL.@)
+ *             ZwAllocateVirtualMemory   (NTDLL.@)
+ */
+NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG zero_bits,
+                                         SIZE_T *size_ptr, ULONG type, ULONG protect )
+{
+	return virtual_alloc(process, ret, zero_bits, size_ptr, type, protect, default_alignment);
+}
+
 
 /***********************************************************************
  *             NtFreeVirtualMemory   (NTDLL.@)
@@ -3079,7 +3086,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
                                     SECTION_INHERIT inherit, ULONG alloc_type, ULONG protect )
 {
     NTSTATUS res;
-    SIZE_T mask = get_mask( zero_bits );
+    SIZE_T mask = default_alignment_mask;
     pe_image_info_t image_info;
     LARGE_INTEGER offset;
 
@@ -3090,7 +3097,8 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
 
     /* Check parameters */
 
-    if ((*addr_ptr && zero_bits) || !mask)
+    /* Unimplemented */
+    if (zero_bits)
         return STATUS_INVALID_PARAMETER_4;
 
 #ifndef _WIN64
-- 
2.19.2

