forked from wine-compholio/wine-staging
-
-
Notifications
You must be signed in to change notification settings - Fork 88
/
0001-ntoskrnl.exe-Avoid-invalid-memory-access-when-reloca.patch
96 lines (90 loc) · 4.24 KB
/
0001-ntoskrnl.exe-Avoid-invalid-memory-access-when-reloca.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
From 77f6fbe85432f4bc61b1b9b27a0992a1f6269344 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 10 Nov 2014 04:05:38 +0100
Subject: ntoskrnl.exe: Avoid invalid memory access when relocation block
addresses memory outside of the current page.
---
dlls/ntoskrnl.exe/ntoskrnl.c | 49 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 43 insertions(+), 6 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 577f5b3..8649863 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -3208,6 +3208,39 @@ static LDR_MODULE *find_ldr_module( HMODULE module )
return ldr;
}
+/* change permissions of a specific memory range, save original permissions */
+static void virtual_protect_save( void *addr, SIZE_T size, ULONG new_prot, ULONG *old_prot )
+{
+ SYSTEM_BASIC_INFORMATION info;
+ UINT i = 0;
+
+ NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL );
+ while (size)
+ {
+ SIZE_T block_size = min( size, info.PageSize - ((UINT_PTR)addr & (info.PageSize - 1)) );
+ VirtualProtect( addr, block_size, new_prot, &old_prot[i++] );
+ addr = (void *)((char *)addr + block_size);
+ size -= block_size;
+ }
+}
+
+/* restore permissions for a specific memory range */
+static void virtual_protect_load( void *addr, SIZE_T size, ULONG *old_prot )
+{
+ SYSTEM_BASIC_INFORMATION info;
+ DWORD dummy;
+ UINT i = 0;
+
+ NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL );
+ while (size)
+ {
+ SIZE_T block_size = min( size, info.PageSize - ((UINT_PTR)addr & (info.PageSize - 1)) );
+ VirtualProtect( addr, block_size, old_prot[i++], &dummy );
+ addr = (void *)((char *)addr + block_size);
+ size -= block_size;
+ }
+}
+
/* load the driver module file */
static HMODULE load_driver_module( const WCHAR *name )
{
@@ -3231,7 +3264,7 @@ static HMODULE load_driver_module( const WCHAR *name )
if (nt->OptionalHeader.SectionAlignment < info.PageSize ||
!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
{
- DWORD old;
+ DWORD old_prot[3];
IMAGE_BASE_RELOCATION *rel, *end;
if ((rel = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size )))
@@ -3239,20 +3272,24 @@ static HMODULE load_driver_module( const WCHAR *name )
WINE_TRACE( "%s: relocating from %p to %p\n",
wine_dbgstr_w(name), (char *)module - delta, module );
end = (IMAGE_BASE_RELOCATION *)((char *)rel + size);
- while (rel < end && rel->SizeOfBlock)
+ while (rel < end - 1 && rel->SizeOfBlock)
{
void *page = (char *)module + rel->VirtualAddress;
- VirtualProtect( page, info.PageSize, PAGE_EXECUTE_READWRITE, &old );
+ /* LdrProcessRelocationBlock can access the memory range from page - (page + 0xfff + 8), so
+ * changing permissions of a single page is not sufficient. We assume here that the minimum
+ * page size is 0x1000, so we have to save/restore two or three pages, depending on the
+ * virtual address. */
+ virtual_protect_save( page, 0xfff + 8, PAGE_EXECUTE_READWRITE, old_prot );
rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
(USHORT *)(rel + 1), delta );
- if (old != PAGE_EXECUTE_READWRITE) VirtualProtect( page, info.PageSize, old, &old );
+ virtual_protect_load( page, 0xfff + 8, old_prot );
if (!rel) goto error;
}
/* make sure we don't try again */
size = FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + nt->FileHeader.SizeOfOptionalHeader;
- VirtualProtect( nt, size, PAGE_READWRITE, &old );
+ VirtualProtect( nt, size, PAGE_READWRITE, &old_prot[0] );
nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
- VirtualProtect( nt, size, old, &old );
+ VirtualProtect( nt, size, old_prot[0], &old_prot[0] );
}
}
--
2.7.4