| 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 <string> |  | 
| 12 #include <vector> |  | 
| 13 |  | 
| 14 // Note that only #includes from base that are either header-only or built into |  | 
| 15 // base_static (see base/base.gyp) are allowed here. |  | 
| 16 #include "base/basictypes.h" |  | 
| 17 #include "base/strings/string16.h" |  | 
| 18 #include "base/win/pe_image.h" |  | 
| 19 #include "chrome_elf/blacklist/blacklist.h" |  | 
| 20 #include "sandbox/win/src/internal_types.h" |  | 
| 21 #include "sandbox/win/src/nt_internals.h" |  | 
| 22 #include "sandbox/win/src/sandbox_nt_util.h" |  | 
| 23 #include "sandbox/win/src/sandbox_types.h" |  | 
| 24 |  | 
| 25 namespace { |  | 
| 26 |  | 
| 27 NtQuerySectionFunction g_nt_query_section_func = NULL; |  | 
| 28 NtQueryVirtualMemoryFunction g_nt_query_virtual_memory_func = NULL; |  | 
| 29 NtUnmapViewOfSectionFunction g_nt_unmap_view_of_section_func = NULL; |  | 
| 30 |  | 
| 31 // TODO(robertshield): Merge with ntdll exports cache. |  | 
| 32 FARPROC GetNtDllExportByName(const char* export_name) { |  | 
| 33   HMODULE ntdll = ::GetModuleHandle(sandbox::kNtdllName); |  | 
| 34   return ::GetProcAddress(ntdll, export_name); |  | 
| 35 } |  | 
| 36 |  | 
| 37 bool DllMatch(const string16& module_name) { |  | 
| 38   for (int i = 0; i < blacklist::g_troublesome_dlls_cur_index; ++i) { |  | 
| 39     if (module_name == blacklist::g_troublesome_dlls[i]) |  | 
| 40       return true; |  | 
| 41   } |  | 
| 42   return false; |  | 
| 43 } |  | 
| 44 |  | 
| 45 // TODO(robertshield): Some of the helper functions below overlap somewhat with |  | 
| 46 // code in sandbox_nt_util.cc. See if they can be unified. |  | 
| 47 |  | 
| 48 // Native reimplementation of PSAPIs GetMappedFileName. |  | 
| 49 string16 GetBackingModuleFilePath(PVOID address) { |  | 
| 50   DCHECK_NT(g_nt_query_virtual_memory_func); |  | 
| 51 |  | 
| 52   // We'll start with something close to max_path characters for the name. |  | 
| 53   ULONG buffer_bytes = MAX_PATH * 2; |  | 
| 54   std::vector<BYTE> buffer_data(buffer_bytes); |  | 
| 55 |  | 
| 56   for (;;) { |  | 
| 57     MEMORY_SECTION_NAME* section_name = |  | 
| 58         reinterpret_cast<MEMORY_SECTION_NAME*>(&buffer_data[0]); |  | 
| 59 |  | 
| 60     if (!section_name) |  | 
| 61       break; |  | 
| 62 |  | 
| 63     ULONG returned_bytes; |  | 
| 64     NTSTATUS ret = g_nt_query_virtual_memory_func( |  | 
| 65         NtCurrentProcess, address, MemorySectionName, section_name, |  | 
| 66         buffer_bytes, &returned_bytes); |  | 
| 67 |  | 
| 68     if (STATUS_BUFFER_OVERFLOW == ret) { |  | 
| 69       // Retry the call with the given buffer size. |  | 
| 70       buffer_bytes = returned_bytes + 1; |  | 
| 71       buffer_data.resize(buffer_bytes); |  | 
| 72       section_name = NULL; |  | 
| 73       continue; |  | 
| 74     } |  | 
| 75     if (!NT_SUCCESS(ret)) |  | 
| 76       break; |  | 
| 77 |  | 
| 78     UNICODE_STRING* section_string = |  | 
| 79         reinterpret_cast<UNICODE_STRING*>(section_name); |  | 
| 80     return string16(section_string->Buffer, |  | 
| 81                         section_string->Length / sizeof(wchar_t)); |  | 
| 82   } |  | 
| 83 |  | 
| 84   return string16(); |  | 
| 85 } |  | 
| 86 |  | 
| 87 bool IsModuleValidImageSection(HANDLE section, |  | 
| 88                                PVOID *base, |  | 
| 89                                PLARGE_INTEGER offset, |  | 
| 90                                PSIZE_T view_size) { |  | 
| 91   DCHECK_NT(g_nt_query_section_func); |  | 
| 92 |  | 
| 93   if (!section || !base || !view_size || offset) |  | 
| 94     return false; |  | 
| 95 |  | 
| 96   SECTION_BASIC_INFORMATION basic_info; |  | 
| 97   SIZE_T bytes_returned; |  | 
| 98   NTSTATUS ret = g_nt_query_section_func(section, SectionBasicInformation, |  | 
| 99                                          &basic_info, sizeof(basic_info), |  | 
| 100                                          &bytes_returned); |  | 
| 101 |  | 
| 102   if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned) |  | 
| 103     return false; |  | 
| 104 |  | 
| 105   if (!(basic_info.Attributes & SEC_IMAGE)) |  | 
| 106     return false; |  | 
| 107 |  | 
| 108   return true; |  | 
| 109 } |  | 
| 110 |  | 
| 111 string16 ExtractLoadedModuleName(const string16& module_path) { |  | 
| 112   if (module_path.empty() || module_path[module_path.size() - 1] == L'\\') |  | 
| 113     return string16(); |  | 
| 114 |  | 
| 115   size_t sep = module_path.find_last_of(L'\\'); |  | 
| 116   if (sep == string16::npos) |  | 
| 117     return module_path; |  | 
| 118   else |  | 
| 119     return module_path.substr(sep+1); |  | 
| 120 } |  | 
| 121 |  | 
| 122 // Fills |out_name| with the image name from the given |pe| image and |flags| |  | 
| 123 // with additional info about the image. |  | 
| 124 void SafeGetImageInfo(const base::win::PEImage& pe, |  | 
| 125                       std::string* out_name, |  | 
| 126                       uint32* flags) { |  | 
| 127   out_name->clear(); |  | 
| 128   out_name->reserve(MAX_PATH); |  | 
| 129   *flags = 0; |  | 
| 130   __try { |  | 
| 131     if (pe.VerifyMagic()) { |  | 
| 132       *flags |= sandbox::MODULE_IS_PE_IMAGE; |  | 
| 133 |  | 
| 134       PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory(); |  | 
| 135       if (exports) { |  | 
| 136         char* image_name = reinterpret_cast<char*>(pe.RVAToAddr(exports->Name)); |  | 
| 137         size_t i = 0; |  | 
| 138         for (; i < MAX_PATH && *image_name; ++i, ++image_name) |  | 
| 139           out_name->push_back(*image_name); |  | 
| 140       } |  | 
| 141 |  | 
| 142       PIMAGE_NT_HEADERS headers = pe.GetNTHeaders(); |  | 
| 143       if (headers) { |  | 
| 144         if (headers->OptionalHeader.AddressOfEntryPoint) |  | 
| 145           *flags |= sandbox::MODULE_HAS_ENTRY_POINT; |  | 
| 146         if (headers->OptionalHeader.SizeOfCode) |  | 
| 147           *flags |= sandbox::MODULE_HAS_CODE; |  | 
| 148       } |  | 
| 149     } |  | 
| 150   } __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? |  | 
| 151              EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { |  | 
| 152     out_name->clear(); |  | 
| 153   } |  | 
| 154 } |  | 
| 155 |  | 
| 156 string16 GetImageInfoFromLoadedModule(HMODULE module, uint32* flags) { |  | 
| 157   std::string out_name; |  | 
| 158   base::win::PEImage pe(module); |  | 
| 159   SafeGetImageInfo(pe, &out_name, flags); |  | 
| 160   return string16(out_name.begin(), out_name.end()); |  | 
| 161 } |  | 
| 162 |  | 
| 163 }  // namespace |  | 
| 164 |  | 
| 165 namespace blacklist { |  | 
| 166 |  | 
| 167 bool InitializeInterceptImports() { |  | 
| 168   g_nt_query_section_func = reinterpret_cast<NtQuerySectionFunction>( |  | 
| 169           GetNtDllExportByName("NtQuerySection")); |  | 
| 170   g_nt_query_virtual_memory_func = |  | 
| 171       reinterpret_cast<NtQueryVirtualMemoryFunction>( |  | 
| 172           GetNtDllExportByName("NtQueryVirtualMemory")); |  | 
| 173   g_nt_unmap_view_of_section_func = |  | 
| 174       reinterpret_cast<NtUnmapViewOfSectionFunction>( |  | 
| 175           GetNtDllExportByName("NtUnmapViewOfSection")); |  | 
| 176 |  | 
| 177   return g_nt_query_section_func && g_nt_query_virtual_memory_func && |  | 
| 178          g_nt_unmap_view_of_section_func; |  | 
| 179 } |  | 
| 180 |  | 
| 181 SANDBOX_INTERCEPT NTSTATUS WINAPI BlNtMapViewOfSection( |  | 
| 182     NtMapViewOfSectionFunction orig_MapViewOfSection, |  | 
| 183     HANDLE section, |  | 
| 184     HANDLE process, |  | 
| 185     PVOID *base, |  | 
| 186     ULONG_PTR zero_bits, |  | 
| 187     SIZE_T commit_size, |  | 
| 188     PLARGE_INTEGER offset, |  | 
| 189     PSIZE_T view_size, |  | 
| 190     SECTION_INHERIT inherit, |  | 
| 191     ULONG allocation_type, |  | 
| 192     ULONG protect) { |  | 
| 193   NTSTATUS ret = orig_MapViewOfSection(section, process, base, zero_bits, |  | 
| 194                                        commit_size, offset, view_size, inherit, |  | 
| 195                                        allocation_type, protect); |  | 
| 196 |  | 
| 197   if (!NT_SUCCESS(ret) || !sandbox::IsSameProcess(process) || |  | 
| 198       !IsModuleValidImageSection(section, base, offset, view_size)) { |  | 
| 199     return ret; |  | 
| 200   } |  | 
| 201 |  | 
| 202   HMODULE module = reinterpret_cast<HMODULE>(*base); |  | 
| 203   if (module) { |  | 
| 204     UINT image_flags; |  | 
| 205 |  | 
| 206     string16 module_name(GetImageInfoFromLoadedModule( |  | 
| 207         reinterpret_cast<HMODULE>(*base), &image_flags)); |  | 
| 208     string16 file_name(GetBackingModuleFilePath(*base)); |  | 
| 209 |  | 
| 210     if (module_name.empty() && (image_flags & sandbox::MODULE_HAS_CODE)) { |  | 
| 211       // If the module has no exports we retrieve the module name from the |  | 
| 212       // full path of the mapped section. |  | 
| 213       module_name = ExtractLoadedModuleName(file_name); |  | 
| 214     } |  | 
| 215 |  | 
| 216     if (!module_name.empty() && DllMatch(module_name)) { |  | 
| 217       DCHECK_NT(g_nt_unmap_view_of_section_func); |  | 
| 218       g_nt_unmap_view_of_section_func(process, *base); |  | 
| 219       ret = STATUS_UNSUCCESSFUL; |  | 
| 220     } |  | 
| 221 |  | 
| 222   } |  | 
| 223   return ret; |  | 
| 224 } |  | 
| 225 |  | 
| 226 }  // namespace blacklist |  | 
| OLD | NEW | 
|---|