From: Allan Vester <vesterallan246@gmail.com> Both bits were missing from the type masks, so any allocation carrying one was refused with STATUS_INVALID_PARAMETER. Windows reserves address space for MEM_PHYSICAL, fails a large page request that does not hold SeLockMemoryPrivilege on the privilege, and accepts the two combined. Neither large pages nor AWE are implemented, so the flags are validated and then dropped. --- dlls/ntdll/tests/virtual.c | 18 +++++++++--------- dlls/ntdll/unix/virtual.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index fb1214aebd9..30a387a6c20 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1136,17 +1136,17 @@ static void test_large_pages(void) /* Reserving an AWE region needs no privilege: MEM_RESERVE on its own, and * PAGE_READWRITE on its own. */ status = alloc_and_free( large_size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE, FALSE ); - todo_wine ok( !status, "MEM_RESERVE|MEM_PHYSICAL returned %08lx\n", status ); + ok( !status, "MEM_RESERVE|MEM_PHYSICAL returned %08lx\n", status ); if (pNtAllocateVirtualMemoryEx) { status_ex = alloc_and_free( large_size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE, TRUE ); - todo_wine ok( !status_ex, "MEM_RESERVE|MEM_PHYSICAL returned %08lx\n", status_ex ); + ok( !status_ex, "MEM_RESERVE|MEM_PHYSICAL returned %08lx\n", status_ex ); } status = alloc_and_free( large_size, MEM_RESERVE | MEM_PHYSICAL, PAGE_EXECUTE_READWRITE, FALSE ); - todo_wine ok( status == STATUS_INVALID_PAGE_PROTECTION || - broken( status == STATUS_INVALID_PARAMETER_6 ) /* <= win10v1507 */, - "MEM_RESERVE|MEM_PHYSICAL returned %08lx\n", status ); + ok( status == STATUS_INVALID_PAGE_PROTECTION || + broken( status == STATUS_INVALID_PARAMETER_6 ) /* <= win10v1507 */, + "MEM_RESERVE|MEM_PHYSICAL returned %08lx\n", status ); status = alloc_and_free( large_size, MEM_COMMIT | MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE, FALSE ); ok( status == STATUS_INVALID_PARAMETER || @@ -1157,16 +1157,16 @@ static void test_large_pages(void) * needing a privilege. */ status = alloc_and_free( large_size, MEM_COMMIT | MEM_RESERVE | MEM_PHYSICAL | MEM_LARGE_PAGES, PAGE_READWRITE, FALSE ); - todo_wine ok( !status || broken( status == STATUS_INVALID_PARAMETER_5 ) /* <= win10v1507 */, - "MEM_COMMIT|MEM_RESERVE|MEM_PHYSICAL|MEM_LARGE_PAGES returned %08lx\n", status ); + ok( !status || broken( status == STATUS_INVALID_PARAMETER_5 ) /* <= win10v1507 */, + "MEM_COMMIT|MEM_RESERVE|MEM_PHYSICAL|MEM_LARGE_PAGES returned %08lx\n", status ); /* Large pages on their own need SeLockMemoryPrivilege. Without it the * failure is about the privilege, not about the arguments. */ if (!have_privilege) { status = alloc_and_free( large_size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE, FALSE ); - todo_wine ok( status == STATUS_PRIVILEGE_NOT_HELD, - "MEM_COMMIT|MEM_RESERVE|MEM_LARGE_PAGES returned %08lx\n", status ); + ok( status == STATUS_PRIVILEGE_NOT_HELD, + "MEM_COMMIT|MEM_RESERVE|MEM_LARGE_PAGES returned %08lx\n", status ); } status = alloc_and_free( large_size, MEM_COMMIT | MEM_RESERVE | MEM_4MB_PAGES, PAGE_READWRITE, FALSE ); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index db820a89525..7aba549d081 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5239,6 +5239,29 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ } +/*********************************************************************** + * check_large_page_type + * + * Validate MEM_LARGE_PAGES and MEM_PHYSICAL and remove them from the type. + * Neither large pages nor AWE are implemented, but an AWE reservation is + * ordinary address space, and MEM_LARGE_PAGES is only a page size request. + */ +static NTSTATUS check_large_page_type( ULONG *type, ULONG protect ) +{ + if (*type & MEM_PHYSICAL) + { + /* the physical pages themselves are not implemented, see AllocateUserPhysicalPages() */ + if (!(*type & MEM_LARGE_PAGES) && (*type & MEM_COMMIT)) return STATUS_INVALID_PARAMETER; + if (protect != PAGE_READWRITE) return STATUS_INVALID_PAGE_PROTECTION; + } + /* large pages require SeLockMemoryPrivilege, which we never grant */ + else if (*type & MEM_LARGE_PAGES) return STATUS_PRIVILEGE_NOT_HELD; + + *type &= ~(MEM_PHYSICAL | MEM_LARGE_PAGES); + return STATUS_SUCCESS; +} + + /*********************************************************************** * NtAllocateVirtualMemory (NTDLL.@) * ZwAllocateVirtualMemory (NTDLL.@) @@ -5246,7 +5269,9 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR zero_bits, SIZE_T *size_ptr, ULONG type, ULONG protect ) { - static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET; + static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH + | MEM_RESET | MEM_PHYSICAL | MEM_LARGE_PAGES; + unsigned int status; ULONG_PTR limit; TRACE("%p %p %08lx %x %08x\n", process, *ret, *size_ptr, type, protect ); @@ -5258,12 +5283,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z if (!is_old_wow64() && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3; #endif if (type & ~type_mask) return STATUS_INVALID_PARAMETER; + if ((status = check_large_page_type( &type, protect ))) return status; if (process != NtCurrentProcess()) { union apc_call call; union apc_result result; - unsigned int status; memset( &call, 0, sizeof(call) ); @@ -5386,7 +5411,8 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s ULONG count ) { static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH - | MEM_RESET | MEM_RESERVE_PLACEHOLDER | MEM_REPLACE_PLACEHOLDER; + | MEM_RESET | MEM_RESERVE_PLACEHOLDER | MEM_REPLACE_PLACEHOLDER + | MEM_PHYSICAL | MEM_LARGE_PAGES; ULONG_PTR limit_low = 0; ULONG_PTR limit_high = 0; ULONG_PTR align = 0; @@ -5402,6 +5428,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s if (status) return status; if (type & ~type_mask) return STATUS_INVALID_PARAMETER; + if ((status = check_large_page_type( &type, protect ))) return status; if (*ret && (align || limit_low || limit_high)) return STATUS_INVALID_PARAMETER; if (!*size_ptr) return STATUS_INVALID_PARAMETER; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11600