OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 // | |
5 // Implementation of NtMapViewOfSection intercept for 32 bit builds. | |
6 // | |
7 // TODO(robertshield): Implement the 64 bit intercept. | |
8 | |
9 #include "chrome_elf/blacklist/blacklist_interceptions.h" | |
10 | |
11 #include <stddef.h> | |
12 #include <stdint.h> | |
13 | |
14 #include <string> | |
15 #include <vector> | |
16 | |
17 // Note that only #includes from base that are either header-only or built into | |
18 // base_static (see base/base.gyp) are allowed here. | |
19 #include "base/strings/string16.h" | |
20 #include "base/win/pe_image.h" | |
21 #include "chrome_elf/blacklist/blacklist.h" | |
22 #include "chrome_elf/breakpad.h" | |
23 #include "sandbox/win/src/internal_types.h" | |
24 #include "sandbox/win/src/nt_internals.h" | |
25 #include "sandbox/win/src/sandbox_nt_util.h" | |
26 #include "sandbox/win/src/sandbox_types.h" | |
27 | |
28 namespace { | |
29 | |
30 NtQuerySectionFunction g_nt_query_section_func = NULL; | |
31 NtQueryVirtualMemoryFunction g_nt_query_virtual_memory_func = NULL; | |
32 NtUnmapViewOfSectionFunction g_nt_unmap_view_of_section_func = NULL; | |
33 | |
34 // TODO(robertshield): Merge with ntdll exports cache. | |
35 FARPROC GetNtDllExportByName(const char* export_name) { | |
36 HMODULE ntdll = ::GetModuleHandle(sandbox::kNtdllName); | |
37 return ::GetProcAddress(ntdll, export_name); | |
38 } | |
39 | |
40 int DllMatch(const base::string16& module_name) { | |
41 if (module_name.empty()) | |
42 return -1; | |
43 | |
44 for (int i = 0; blacklist::g_troublesome_dlls[i] != NULL; ++i) { | |
45 if (_wcsicmp(module_name.c_str(), blacklist::g_troublesome_dlls[i]) == 0) | |
46 return i; | |
47 } | |
48 return -1; | |
49 } | |
50 | |
51 // TODO(robertshield): Some of the helper functions below overlap somewhat with | |
52 // code in sandbox_nt_util.cc. See if they can be unified. | |
53 | |
54 // Native reimplementation of PSAPIs GetMappedFileName. | |
55 base::string16 GetBackingModuleFilePath(PVOID address) { | |
56 DCHECK_NT(g_nt_query_virtual_memory_func); | |
57 | |
58 // We'll start with something close to max_path characters for the name. | |
59 SIZE_T buffer_bytes = MAX_PATH * 2; | |
60 std::vector<BYTE> buffer_data(buffer_bytes); | |
61 | |
62 for (;;) { | |
63 MEMORY_SECTION_NAME* section_name = | |
64 reinterpret_cast<MEMORY_SECTION_NAME*>(&buffer_data[0]); | |
65 | |
66 if (!section_name) | |
67 break; | |
68 | |
69 SIZE_T returned_bytes; | |
70 NTSTATUS ret = g_nt_query_virtual_memory_func( | |
71 NtCurrentProcess, address, MemorySectionName, section_name, | |
72 buffer_bytes, &returned_bytes); | |
73 | |
74 if (STATUS_BUFFER_OVERFLOW == ret) { | |
75 // Retry the call with the given buffer size. | |
76 buffer_bytes = returned_bytes + 1; | |
77 buffer_data.resize(buffer_bytes); | |
78 section_name = NULL; | |
79 continue; | |
80 } | |
81 if (!NT_SUCCESS(ret)) | |
82 break; | |
83 | |
84 UNICODE_STRING* section_string = | |
85 reinterpret_cast<UNICODE_STRING*>(section_name); | |
86 return base::string16(section_string->Buffer, | |
87 section_string->Length / sizeof(wchar_t)); | |
88 } | |
89 | |
90 return base::string16(); | |
91 } | |
92 | |
93 bool IsModuleValidImageSection(HANDLE section, | |
94 PVOID *base, | |
95 PLARGE_INTEGER offset, | |
96 PSIZE_T view_size) { | |
97 DCHECK_NT(g_nt_query_section_func); | |
98 | |
99 if (!section || !base || !view_size || offset) | |
100 return false; | |
101 | |
102 SECTION_BASIC_INFORMATION basic_info; | |
103 SIZE_T bytes_returned; | |
104 NTSTATUS ret = g_nt_query_section_func(section, SectionBasicInformation, | |
105 &basic_info, sizeof(basic_info), | |
106 &bytes_returned); | |
107 | |
108 if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned) | |
109 return false; | |
110 | |
111 if (!(basic_info.Attributes & SEC_IMAGE)) | |
112 return false; | |
113 | |
114 return true; | |
115 } | |
116 | |
117 base::string16 ExtractLoadedModuleName(const base::string16& module_path) { | |
118 if (module_path.empty() || module_path[module_path.size() - 1] == L'\\') | |
119 return base::string16(); | |
120 | |
121 size_t sep = module_path.find_last_of(L'\\'); | |
122 if (sep == base::string16::npos) | |
123 return module_path; | |
124 else | |
125 return module_path.substr(sep+1); | |
126 } | |
127 | |
128 // Fills |out_name| with the image name from the given |pe| image and |flags| | |
129 // with additional info about the image. | |
130 void SafeGetImageInfo(const base::win::PEImage& pe, | |
131 std::string* out_name, | |
132 uint32_t* flags) { | |
133 out_name->clear(); | |
134 out_name->reserve(MAX_PATH); | |
135 *flags = 0; | |
136 __try { | |
137 if (pe.VerifyMagic()) { | |
138 *flags |= sandbox::MODULE_IS_PE_IMAGE; | |
139 | |
140 PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory(); | |
141 if (exports) { | |
142 const char* image_name = reinterpret_cast<const char*>( | |
143 pe.RVAToAddr(exports->Name)); | |
144 size_t i = 0; | |
145 for (; i < MAX_PATH && *image_name; ++i, ++image_name) | |
146 out_name->push_back(*image_name); | |
147 } | |
148 | |
149 PIMAGE_NT_HEADERS headers = pe.GetNTHeaders(); | |
150 if (headers) { | |
151 if (headers->OptionalHeader.AddressOfEntryPoint) | |
152 *flags |= sandbox::MODULE_HAS_ENTRY_POINT; | |
153 if (headers->OptionalHeader.SizeOfCode) | |
154 *flags |= sandbox::MODULE_HAS_CODE; | |
155 } | |
156 } | |
157 } __except((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || | |
158 GetExceptionCode() == EXCEPTION_GUARD_PAGE || | |
159 GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR) ? | |
160 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { | |
161 out_name->clear(); | |
162 } | |
163 } | |
164 | |
165 base::string16 GetImageInfoFromLoadedModule(HMODULE module, uint32_t* flags) { | |
166 std::string out_name; | |
167 base::win::PEImage pe(module); | |
168 SafeGetImageInfo(pe, &out_name, flags); | |
169 return base::string16(out_name.begin(), out_name.end()); | |
170 } | |
171 | |
172 bool IsSameAsCurrentProcess(HANDLE process) { | |
173 return (NtCurrentProcess == process) || | |
174 (::GetProcessId(process) == ::GetCurrentProcessId()); | |
175 } | |
176 | |
177 NTSTATUS BlNtMapViewOfSectionImpl( | |
178 NtMapViewOfSectionFunction orig_MapViewOfSection, | |
179 HANDLE section, | |
180 HANDLE process, | |
181 PVOID *base, | |
182 ULONG_PTR zero_bits, | |
183 SIZE_T commit_size, | |
184 PLARGE_INTEGER offset, | |
185 PSIZE_T view_size, | |
186 SECTION_INHERIT inherit, | |
187 ULONG allocation_type, | |
188 ULONG protect) { | |
189 NTSTATUS ret = orig_MapViewOfSection(section, process, base, zero_bits, | |
190 commit_size, offset, view_size, inherit, | |
191 allocation_type, protect); | |
192 | |
193 if (!NT_SUCCESS(ret) || !IsSameAsCurrentProcess(process) || | |
194 !IsModuleValidImageSection(section, base, offset, view_size)) { | |
195 return ret; | |
196 } | |
197 | |
198 HMODULE module = reinterpret_cast<HMODULE>(*base); | |
199 if (module) { | |
200 UINT image_flags; | |
201 | |
202 base::string16 module_name_from_image(GetImageInfoFromLoadedModule( | |
203 reinterpret_cast<HMODULE>(*base), &image_flags)); | |
204 | |
205 int blocked_index = DllMatch(module_name_from_image); | |
206 | |
207 // If the module name isn't blacklisted, see if the file name is different | |
208 // and blacklisted. | |
209 if (blocked_index == -1) { | |
210 base::string16 file_name(GetBackingModuleFilePath(*base)); | |
211 base::string16 module_name_from_file = ExtractLoadedModuleName(file_name); | |
212 | |
213 if (module_name_from_image != module_name_from_file) | |
214 blocked_index = DllMatch(module_name_from_file); | |
215 } | |
216 | |
217 if (blocked_index != -1) { | |
218 DCHECK_NT(g_nt_unmap_view_of_section_func); | |
219 g_nt_unmap_view_of_section_func(process, *base); | |
220 ret = STATUS_UNSUCCESSFUL; | |
221 | |
222 blacklist::BlockedDll(blocked_index); | |
223 } | |
224 } | |
225 | |
226 return ret; | |
227 } | |
228 | |
229 } // namespace | |
230 | |
231 namespace blacklist { | |
232 | |
233 bool InitializeInterceptImports() { | |
234 g_nt_query_section_func = | |
235 reinterpret_cast<NtQuerySectionFunction>( | |
236 GetNtDllExportByName("NtQuerySection")); | |
237 g_nt_query_virtual_memory_func = | |
238 reinterpret_cast<NtQueryVirtualMemoryFunction>( | |
239 GetNtDllExportByName("NtQueryVirtualMemory")); | |
240 g_nt_unmap_view_of_section_func = | |
241 reinterpret_cast<NtUnmapViewOfSectionFunction>( | |
242 GetNtDllExportByName("NtUnmapViewOfSection")); | |
243 | |
244 return (g_nt_query_section_func && g_nt_query_virtual_memory_func && | |
245 g_nt_unmap_view_of_section_func); | |
246 } | |
247 | |
248 SANDBOX_INTERCEPT NTSTATUS WINAPI BlNtMapViewOfSection( | |
249 NtMapViewOfSectionFunction orig_MapViewOfSection, | |
250 HANDLE section, | |
251 HANDLE process, | |
252 PVOID *base, | |
253 ULONG_PTR zero_bits, | |
254 SIZE_T commit_size, | |
255 PLARGE_INTEGER offset, | |
256 PSIZE_T view_size, | |
257 SECTION_INHERIT inherit, | |
258 ULONG allocation_type, | |
259 ULONG protect) { | |
260 NTSTATUS ret = STATUS_UNSUCCESSFUL; | |
261 | |
262 __try { | |
263 ret = BlNtMapViewOfSectionImpl(orig_MapViewOfSection, section, process, | |
264 base, zero_bits, commit_size, offset, | |
265 view_size, inherit, allocation_type, | |
266 protect); | |
267 } __except(GenerateCrashDump(GetExceptionInformation())) { | |
268 } | |
269 | |
270 return ret; | |
271 } | |
272 | |
273 #if defined(_WIN64) | |
274 NTSTATUS WINAPI BlNtMapViewOfSection64( | |
275 HANDLE section, HANDLE process, PVOID *base, ULONG_PTR zero_bits, | |
276 SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size, | |
277 SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect) { | |
278 return BlNtMapViewOfSection(g_nt_map_view_of_section_func, section, process, | |
279 base, zero_bits, commit_size, offset, view_size, | |
280 inherit, allocation_type, protect); | |
281 } | |
282 #endif | |
283 } // namespace blacklist | |
OLD | NEW |