Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ntdll/ntdll.spec | 2 + dlls/ntdll/tests/virtual.c | 149 +++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/loader.c | 1 + dlls/ntdll/unix/virtual.c | 12 +++ dlls/wow64/syscall.h | 1 + dlls/wow64/virtual.c | 34 +++++++++ include/winternl.h | 1 + 7 files changed, 200 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index ba29b21d61d..a7a39a0bce2 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -253,6 +253,7 @@ # @ stub NtMapUserPhysicalPages # @ stub NtMapUserPhysicalPagesScatter @ stdcall -syscall NtMapViewOfSection(long long ptr long long ptr ptr long long long) +@ stdcall -syscall NtMapViewOfSectionEx(long long ptr ptr ptr long long ptr long) # @ stub NtModifyBootEntry @ stdcall -syscall NtNotifyChangeDirectoryFile(long long ptr ptr ptr ptr long long long) @ stdcall -syscall NtNotifyChangeKey(long long ptr ptr ptr long long ptr long long) @@ -1279,6 +1280,7 @@ # @ stub ZwMapUserPhysicalPages # @ stub ZwMapUserPhysicalPagesScatter @ stdcall -private -syscall ZwMapViewOfSection(long long ptr long long ptr ptr long long long) NtMapViewOfSection +@ stdcall -private -syscall ZwMapViewOfSectionEx(long long ptr ptr ptr long long ptr long) NtMapViewOfSectionEx # @ stub ZwModifyBootEntry @ stdcall -private -syscall ZwNotifyChangeDirectoryFile(long long ptr ptr ptr ptr long long long) NtNotifyChangeDirectoryFile @ stdcall -private -syscall ZwNotifyChangeKey(long long ptr ptr ptr long long ptr long long) NtNotifyChangeKey diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 30a97ba9d94..aeef2ed8fb9 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -39,6 +39,9 @@ static void * (WINAPI *pRtlFindExportedRoutineByName)(HMODULE,const char*); static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); static NTSTATUS (WINAPI *pNtAllocateVirtualMemoryEx)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG, MEM_EXTENDED_PARAMETER *, ULONG); +static NTSTATUS (WINAPI *pNtMapViewOfSectionEx)(HANDLE, HANDLE, PVOID *, const LARGE_INTEGER *, SIZE_T *, + ULONG, ULONG, MEM_EXTENDED_PARAMETER *, ULONG); + static const BOOL is_win64 = sizeof(void*) != sizeof(int); static BOOL is_wow64;
@@ -908,6 +911,150 @@ static void test_NtMapViewOfSection(void) CloseHandle(process); }
+static void test_NtMapViewOfSectionEx(void) +{ + static const char testfile[] = "testfile.xxx"; + static const char data[] = "test data for NtMapViewOfSectionEx"; + char buffer[sizeof(data)]; + HANDLE file, mapping, process; + DWORD status, written; + SIZE_T size, result; + LARGE_INTEGER offset; + void *ptr, *ptr2; + BOOL ret; + + if (!pNtMapViewOfSectionEx) + { + win_skip("NtMapViewOfSectionEx() is not supported.\n"); + return; + } + + if (!pIsWow64Process || !pIsWow64Process(NtCurrentProcess(), &is_wow64)) is_wow64 = FALSE; + + file = CreateFileA(testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Failed to create test file\n"); + WriteFile(file, data, sizeof(data), &written, NULL); + SetFilePointer(file, 4096, NULL, FILE_BEGIN); + SetEndOfFile(file); + + /* read/write mapping */ + + mapping = CreateFileMappingA(file, NULL, PAGE_READWRITE, 0, 4096, NULL); + ok(mapping != 0, "CreateFileMapping failed\n"); + + process = create_target_process("sleep"); + ok(process != NULL, "Can't start process\n"); + + ptr = NULL; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr, &offset, &size, 0, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx\n", status); + ok(!((ULONG_PTR)ptr & 0xffff), "returned memory %p is not aligned to 64k\n", ptr); + + ret = ReadProcessMemory(process, ptr, buffer, sizeof(buffer), &result); + ok(ret, "ReadProcessMemory failed\n"); + ok(result == sizeof(buffer), "ReadProcessMemory didn't read all data (%Ix)\n", result); + ok(!memcmp(buffer, data, sizeof(buffer)), "Wrong data read\n"); + + /* mapping at the same page conflicts */ + ptr2 = ptr; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, 0, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx\n", status); + + /* offset has to be aligned */ + ptr2 = ptr; + size = 0; + offset.QuadPart = 1; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, 0, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_MAPPED_ALIGNMENT, "Unexpected status %08lx\n", status); + + /* ptr has to be aligned */ + ptr2 = (char *)ptr + 42; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, 0, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_MAPPED_ALIGNMENT, "Unexpected status %08lx\n", status); + + /* still not 64k aligned */ + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, 0, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_MAPPED_ALIGNMENT, "Unexpected status %08lx\n", status); + + if (!is_win64 && !is_wow64) + { + /* new memory region conflicts with previous mapping */ + ptr2 = ptr; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, AT_ROUND_TO_PAGE, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx\n", status); + + ptr2 = (char *)ptr + 42; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, AT_ROUND_TO_PAGE, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx\n", status); + + /* in contrary to regular NtMapViewOfSection, only 4kb align is enforced */ + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, AT_ROUND_TO_PAGE, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx\n", status); + ok((char *)ptr2 == (char *)ptr + 0x1000, + "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2); + status = NtUnmapViewOfSection(process, ptr2); + ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection returned %08lx\n", status); + + /* the address is rounded down if not on a page boundary */ + ptr2 = (char *)ptr + 0x1001; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, AT_ROUND_TO_PAGE, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx\n", status); + ok((char *)ptr2 == (char *)ptr + 0x1000, + "expected address %p, got %p\n", (char *)ptr + 0x1000, ptr2); + status = NtUnmapViewOfSection(process, ptr2); + ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection returned %08lx\n", status); + + ptr2 = (char *)ptr + 0x2000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, AT_ROUND_TO_PAGE, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx\n", status); + ok((char *)ptr2 == (char *)ptr + 0x2000, + "expected address %p, got %p\n", (char *)ptr + 0x2000, ptr2); + status = NtUnmapViewOfSection(process, ptr2); + ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection returned %08lx\n", status); + } + else + { + ptr2 = (char *)ptr + 0x1000; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, process, &ptr2, &offset, &size, AT_ROUND_TO_PAGE, PAGE_READWRITE, NULL, 0); + todo_wine + ok(status == STATUS_INVALID_PARAMETER_9 || status == STATUS_INVALID_PARAMETER, + "NtMapViewOfSection returned %08lx\n", status); + } + + status = NtUnmapViewOfSection(process, ptr); + ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection returned %08lx\n", status); + + NtClose(mapping); + + CloseHandle(file); + DeleteFileA(testfile); + + TerminateProcess(process, 0); + CloseHandle(process); +} + #define SUPPORTED_XSTATE_FEATURES ((1 << XSTATE_LEGACY_FLOATING_POINT) | (1 << XSTATE_LEGACY_SSE) | (1 << XSTATE_AVX))
static void test_user_shared_data(void) @@ -1160,6 +1307,7 @@ START_TEST(virtual) pRtlFindExportedRoutineByName = (void *)GetProcAddress(mod, "RtlFindExportedRoutineByName"); pRtlGetEnabledExtendedFeatures = (void *)GetProcAddress(mod, "RtlGetEnabledExtendedFeatures"); pNtAllocateVirtualMemoryEx = (void *)GetProcAddress(mod, "NtAllocateVirtualMemoryEx"); + pNtMapViewOfSectionEx = (void *)GetProcAddress(mod, "NtMapViewOfSectionEx");
NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL); trace("system page size %#lx\n", sbi.PageSize); @@ -1169,6 +1317,7 @@ START_TEST(virtual) test_NtAllocateVirtualMemory(); test_RtlCreateUserStack(); test_NtMapViewOfSection(); + test_NtMapViewOfSectionEx(); test_user_shared_data(); test_syscalls(); } diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index d1c42ddc0f3..cad760a1445 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -207,6 +207,7 @@ static void * const syscalls[] = NtLockVirtualMemory, NtMakeTemporaryObject, NtMapViewOfSection, + NtMapViewOfSectionEx, NtNotifyChangeDirectoryFile, NtNotifyChangeKey, NtNotifyChangeMultipleKeys, diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 94b300c5057..02478cceb06 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4536,6 +4536,18 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p offset_ptr, size_ptr, alloc_type, protect ); }
+/*********************************************************************** + * NtMapViewOfSectionEx (NTDLL.@) + * ZwMapViewOfSectionEx (NTDLL.@) + */ +NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr_ptr, const LARGE_INTEGER *offset_ptr, + SIZE_T *size_ptr, ULONG alloc_type, ULONG protect, MEM_EXTENDED_PARAMETER *params, ULONG params_count ) +{ + if (params) + FIXME("Ignoring extended parameters.\n"); + + return NtMapViewOfSection( handle, process, addr_ptr, 0, 0, offset_ptr, size_ptr, ViewShare, alloc_type, protect ); +}
/*********************************************************************** * NtUnmapViewOfSection (NTDLL.@) diff --git a/dlls/wow64/syscall.h b/dlls/wow64/syscall.h index a3af9174c49..3b364d909d7 100644 --- a/dlls/wow64/syscall.h +++ b/dlls/wow64/syscall.h @@ -108,6 +108,7 @@ SYSCALL_ENTRY( NtLockVirtualMemory ) \ SYSCALL_ENTRY( NtMakeTemporaryObject ) \ SYSCALL_ENTRY( NtMapViewOfSection ) \ + SYSCALL_ENTRY( NtMapViewOfSectionEx ) \ SYSCALL_ENTRY( NtNotifyChangeDirectoryFile ) \ SYSCALL_ENTRY( NtNotifyChangeKey ) \ SYSCALL_ENTRY( NtNotifyChangeMultipleKeys ) \ diff --git a/dlls/wow64/virtual.c b/dlls/wow64/virtual.c index e89373f4239..61c84e5d7be 100644 --- a/dlls/wow64/virtual.c +++ b/dlls/wow64/virtual.c @@ -287,6 +287,40 @@ NTSTATUS WINAPI wow64_NtMapViewOfSection( UINT *args ) return status; }
+/********************************************************************** + * wow64_NtMapViewOfSectionEx + */ +NTSTATUS WINAPI wow64_NtMapViewOfSectionEx( UINT *args ) +{ + HANDLE handle = get_handle( &args ); + HANDLE process = get_handle( &args ); + ULONG *addr32 = get_ptr( &args ); + const LARGE_INTEGER *offset = get_ptr( &args ); + ULONG *size32 = get_ptr( &args ); + ULONG alloc = get_ulong( &args ); + ULONG protect = get_ulong( &args ); + MEM_EXTENDED_PARAMETER *params = get_ptr( &args ); + ULONG params_count = get_ulong( &args ); + + void *addr; + SIZE_T size; + NTSTATUS status; + + status = NtMapViewOfSectionEx( handle, process, addr_32to64( &addr, addr32 ), offset, size_32to64( &size, size32 ), alloc, + protect, params, params_count ); + if (NT_SUCCESS(status)) + { + SECTION_IMAGE_INFORMATION info; + + if (!NtQuerySection( handle, SectionImageInformation, &info, sizeof(info), NULL )) + { + if (info.Machine == current_machine) init_image_mapping( addr ); + } + put_addr( addr32, addr ); + put_size( size32, size ); + } + return status; +}
/********************************************************************** * wow64_NtProtectVirtualMemory diff --git a/include/winternl.h b/include/winternl.h index b4942d86b4c..1d358fc0b2d 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4007,6 +4007,7 @@ NTSYSAPI NTSTATUS WINAPI NtLockFile(HANDLE,HANDLE,PIO_APC_ROUTINE,void*,PIO_STA NTSYSAPI NTSTATUS WINAPI NtLockVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG); NTSYSAPI NTSTATUS WINAPI NtMakeTemporaryObject(HANDLE); NTSYSAPI NTSTATUS WINAPI NtMapViewOfSection(HANDLE,HANDLE,PVOID*,ULONG_PTR,SIZE_T,const LARGE_INTEGER*,SIZE_T*,SECTION_INHERIT,ULONG,ULONG); +NTSYSAPI NTSTATUS WINAPI NtMapViewOfSectionEx(HANDLE,HANDLE,PVOID*,const LARGE_INTEGER*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG); NTSYSAPI NTSTATUS WINAPI NtNotifyChangeDirectoryFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,ULONG,BOOLEAN); NTSYSAPI NTSTATUS WINAPI NtNotifyChangeKey(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN); NTSYSAPI NTSTATUS WINAPI NtNotifyChangeMultipleKeys(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/kernelbase/kernelbase.spec | 1 + dlls/kernelbase/memory.c | 18 +++++++++++++++++ dlls/kernelbase/tests/process.c | 35 +++++++++++++++++++++++++++++++++ include/winbase.h | 1 + 4 files changed, 55 insertions(+)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index a651bc20909..9dd166c7b65 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -981,6 +981,7 @@ # @ stub MapPredefinedHandleInternal @ stdcall MapUserPhysicalPages(ptr long ptr) @ stdcall MapViewOfFile(long long long long long) +@ stdcall MapViewOfFile3(long long ptr int64 long long long ptr long) @ stdcall MapViewOfFileEx(long long long long long ptr) @ stdcall MapViewOfFileExNuma(long long long long long ptr long) # @ stub MapViewOfFileFromApp diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index ea223c3986a..49bf71e0aa2 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -234,6 +234,24 @@ LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFileEx( HANDLE handle, DWORD access, DW return addr; }
+/*********************************************************************** + * MapViewOfFile3 (kernelbase.@) + */ +LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFile3( HANDLE handle, HANDLE process, PVOID baseaddr, ULONG64 offset, + SIZE_T size, ULONG alloc_type, ULONG protection, MEM_EXTENDED_PARAMETER *params, ULONG params_count ) +{ + LARGE_INTEGER off; + void *addr; + + addr = baseaddr; + off.QuadPart = offset; + if (!set_ntstatus( NtMapViewOfSectionEx( handle, process, &addr, &off, &size, alloc_type, protection, + params, params_count ))) + { + return NULL; + } + return addr; +}
/*********************************************************************** * ReadProcessMemory (kernelbase.@) diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index d119dca650d..077ee1082dd 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -31,6 +31,8 @@ #include "wine/test.h"
static BOOL (WINAPI *pCompareObjectHandles)(HANDLE, HANDLE); +static LPVOID (WINAPI *pMapViewOfFile3)(HANDLE, HANDLE, PVOID, ULONG64 offset, SIZE_T size, + ULONG, ULONG, MEM_EXTENDED_PARAMETER *, ULONG);
static void test_CompareObjectHandles(void) { @@ -89,6 +91,37 @@ static void test_CompareObjectHandles(void) CloseHandle( h1 ); }
+static void test_MapViewOfFile3(void) +{ + static const char testfile[] = "testfile.xxx"; + HANDLE file, mapping; + void *ptr; + + if (!pMapViewOfFile3) + { + win_skip("MapViewOfFile3() is not supported.\n"); + return; + } + + SetLastError(0xdeadbeef); + file = CreateFileA( testfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "CreateFile error %lu\n", GetLastError() ); + SetFilePointer( file, 12288, NULL, FILE_BEGIN ); + SetEndOfFile( file ); + + SetLastError(0xdeadbeef); + mapping = CreateFileMappingA( file, NULL, PAGE_READWRITE, 0, 4096, NULL ); + ok( mapping != 0, "CreateFileMapping error %lu\n", GetLastError() ); + + SetLastError(0xdeadbeef); + ptr = pMapViewOfFile3( mapping, GetCurrentProcess(), NULL, 0, 4096, 0, PAGE_READONLY, NULL, 0); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %lu\n", GetLastError() ); + UnmapViewOfFile( ptr ); + + CloseHandle( file ); + DeleteFileA( testfile ); +} + START_TEST(process) { HMODULE hmod; @@ -99,6 +132,8 @@ START_TEST(process)
hmod = GetModuleHandleA("kernelbase.dll"); pCompareObjectHandles = (void *)GetProcAddress(hmod, "CompareObjectHandles"); + pMapViewOfFile3 = (void *)GetProcAddress(hmod, "MapViewOfFile3");
test_CompareObjectHandles(); + test_MapViewOfFile3(); } diff --git a/include/winbase.h b/include/winbase.h index a0c62d710b9..55be6dbf62b 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2484,6 +2484,7 @@ WINADVAPI BOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR,PSECURITY_ WINADVAPI VOID WINAPI MapGenericMask(PDWORD,PGENERIC_MAPPING); WINBASEAPI BOOL WINAPI MapUserPhysicalPages(PVOID,ULONG_PTR,PULONG_PTR); WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE,DWORD,DWORD,DWORD,SIZE_T); +WINBASEAPI LPVOID WINAPI MapViewOfFile3(HANDLE,HANDLE,PVOID,ULONG64,SIZE_T,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG); WINBASEAPI LPVOID WINAPI MapViewOfFileEx(HANDLE,DWORD,DWORD,DWORD,SIZE_T,LPVOID); WINBASEAPI BOOL WINAPI MoveFileA(LPCSTR,LPCSTR); WINBASEAPI BOOL WINAPI MoveFileW(LPCWSTR,LPCWSTR);