Index: dll/ntdll/rtl/libsupp.c =================================================================== --- dll/ntdll/rtl/libsupp.c (revision 67059) +++ dll/ntdll/rtl/libsupp.c (working copy) @@ -16,6 +16,7 @@ SIZE_T RtlpAllocDeallocQueryBufferSize = PAGE_SIZE; PTEB LdrpTopLevelDllBeingLoadedTeb = NULL; +PVOID MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS; /* FUNCTIONS ***************************************************************/ Index: include/ndk/amd64/mmtypes.h =================================================================== --- include/ndk/amd64/mmtypes.h (revision 67059) +++ include/ndk/amd64/mmtypes.h (working copy) @@ -38,6 +38,11 @@ #define MM_PAGE_FRAME_NUMBER_SIZE 52 // +// User space range limit +// +#define MI_HIGHEST_USER_ADDRESS (PVOID)0x000007FFFFFEFFFFULL + +// // Address of the shared user page // #define MM_SHARED_USER_DATA_VA 0x7FFE0000ULL Index: include/ndk/i386/mmtypes.h =================================================================== --- include/ndk/i386/mmtypes.h (revision 67059) +++ include/ndk/i386/mmtypes.h (working copy) @@ -37,6 +37,11 @@ #define MM_PAGE_FRAME_NUMBER_SIZE 20 // +// User space range limit +// +#define MI_HIGHEST_USER_ADDRESS (PVOID)0x7FFEFFFF + +// // Address of the shared user page // #define MM_SHARED_USER_DATA_VA 0x7FFE0000 Index: lib/rtl/image.c =================================================================== --- lib/rtl/image.c (revision 67059) +++ lib/rtl/image.c (working copy) @@ -137,23 +137,29 @@ */ NTSTATUS NTAPI -RtlImageNtHeaderEx(IN ULONG Flags, - IN PVOID Base, - IN ULONG64 Size, - OUT PIMAGE_NT_HEADERS *OutHeaders) +RtlImageNtHeaderEx( + _In_ ULONG Flags, + _In_ PVOID Base, + _In_ ULONG64 Size, + _Out_ PIMAGE_NT_HEADERS *OutHeaders) { PIMAGE_NT_HEADERS NtHeaders; PIMAGE_DOS_HEADER DosHeader; BOOLEAN WantsRangeCheck; + ULONG NtHeaderOffset; /* You must want NT Headers, no? */ - if (!OutHeaders) return STATUS_INVALID_PARAMETER; + if (!OutHeaders) + { + DPRINT1("OutHeaders is NULL\n"); + return STATUS_INVALID_PARAMETER; + } /* Assume failure */ *OutHeaders = NULL; /* Validate Flags */ - if (Flags &~ RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK) + if (Flags & ~RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK) { DPRINT1("Invalid flag combination... check for new API flags?\n"); return STATUS_INVALID_PARAMETER; @@ -160,7 +166,11 @@ } /* Validate base */ - if (!(Base) || (Base == (PVOID)-1)) return STATUS_INVALID_PARAMETER; + if ((Base == NULL) || (Base == (PVOID)-1)) + { + DPRINT1("Invalid base address: %p\n", Base); + return STATUS_INVALID_PARAMETER; + } /* Check if the caller wants validation */ WantsRangeCheck = !(Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK); @@ -183,47 +193,47 @@ return STATUS_INVALID_IMAGE_FORMAT; } + /* Get the offset to the NT headers (and copy from LONG to ULONG) */ + NtHeaderOffset = DosHeader->e_lfanew; + + /* The offset also can't be larger than 256MB, as a hard-coded check. + In Windows this check is only done in user mode, not in kernel mode, + but it doesn't harm to have it anyway. Note that without this check, + other overflow checks would become necessary! */ + if (NtHeaderOffset >= (256 * 1024 * 1024)) + { + /* Fail */ + DPRINT1("PE offset is larger than 256MB\n"); + return STATUS_INVALID_IMAGE_FORMAT; + } + /* Check if the caller wants validation */ if (WantsRangeCheck) { - /* The offset should fit in the passsed-in size */ - if (DosHeader->e_lfanew >= Size) + /* Make sure the file header fits into the size */ + if ((NtHeaderOffset + + RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS, FileHeader)) >= Size) { /* Fail */ - DPRINT1("e_lfanew is larger than PE file\n"); + DPRINT1("PE is larger than 4GB\n"); return STATUS_INVALID_IMAGE_FORMAT; } + } - /* It shouldn't be past 4GB either */ - if (DosHeader->e_lfanew >= - (MAXULONG - sizeof(IMAGE_DOS_SIGNATURE) - sizeof(IMAGE_FILE_HEADER))) - { - /* Fail */ - DPRINT1("e_lfanew is larger than 4GB\n"); - return STATUS_INVALID_IMAGE_FORMAT; - } + /* Now it's safe to get the NT Headers */ + NtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)Base + NtHeaderOffset); - /* And the whole file shouldn't overflow past 4GB */ - if ((DosHeader->e_lfanew + - sizeof(IMAGE_DOS_SIGNATURE) - sizeof(IMAGE_FILE_HEADER)) >= Size) + /* Check if the mapping is in user space */ + if (Base <= MmHighestUserAddress) + { + /* Make sure we don't overflow into kernel space */ + if ((PVOID)(NtHeaders + 1) > MmHighestUserAddress) { - /* Fail */ - DPRINT1("PE is larger than 4GB\n"); + DPRINT1("Image overflows from user space into kernel space!\n"); return STATUS_INVALID_IMAGE_FORMAT; } } - /* The offset also can't be larger than 256MB, as a hard-coded check */ - if (DosHeader->e_lfanew >= (256 * 1024 * 1024)) - { - /* Fail */ - DPRINT1("PE offset is larger than 256MB\n"); - return STATUS_INVALID_IMAGE_FORMAT; - } - - /* Now it's safe to get the NT Headers */ - NtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)Base + DosHeader->e_lfanew); - /* Verify the PE Signature */ if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) { Index: lib/rtl/rtlp.h =================================================================== --- lib/rtl/rtlp.h (revision 67059) +++ lib/rtl/rtlp.h (working copy) @@ -34,6 +34,8 @@ #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m))) +extern PVOID MmHighestUserAddress; + NTSTATUS NTAPI RtlpSafeCopyMemory( Index: ntoskrnl/include/internal/amd64/mm.h =================================================================== --- ntoskrnl/include/internal/amd64/mm.h (revision 67059) +++ ntoskrnl/include/internal/amd64/mm.h (working copy) @@ -5,7 +5,6 @@ /* Memory layout base addresses */ #define MI_LOWEST_VAD_ADDRESS (PVOID)0x000000007FF00000ULL -#define MI_HIGHEST_USER_ADDRESS (PVOID)0x000007FFFFFEFFFFULL #define MI_USER_PROBE_ADDRESS (PVOID)0x000007FFFFFF0000ULL #define MI_DEFAULT_SYSTEM_RANGE_START (PVOID)0xFFFF080000000000ULL #define MI_REAL_SYSTEM_RANGE_START 0xFFFF800000000000ULL Index: ntoskrnl/mm/ARM3/miarm.h =================================================================== --- ntoskrnl/mm/ARM3/miarm.h (revision 67059) +++ ntoskrnl/mm/ARM3/miarm.h (working copy) @@ -29,7 +29,6 @@ #define MI_SYSTEM_VIEW_SIZE (32 * _1MB) -#define MI_HIGHEST_USER_ADDRESS (PVOID)0x7FFEFFFF #define MI_USER_PROBE_ADDRESS (PVOID)0x7FFF0000 #define MI_DEFAULT_SYSTEM_RANGE_START (PVOID)0x80000000 #define MI_SYSTEM_CACHE_WS_START (PVOID)0xC0C00000