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