Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2012 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 #include "sandbox/win/src/process_mitigations.h"
      6 
      7 #include "base/win/windows_version.h"
      8 #include "sandbox/win/src/nt_internals.h"
      9 #include "sandbox/win/src/sandbox_utils.h"
     10 #include "sandbox/win/src/win_utils.h"
     11 
     12 namespace {
     13 
     14 // Functions for enabling policies.
     15 typedef BOOL (WINAPI *SetProcessDEPPolicyFunction)(DWORD dwFlags);
     16 
     17 typedef BOOL (WINAPI *SetProcessMitigationPolicyFunction)(
     18     PROCESS_MITIGATION_POLICY mitigation_policy,
     19     PVOID buffer,
     20     SIZE_T length);
     21 
     22 typedef BOOL (WINAPI *SetDefaultDllDirectoriesFunction)(
     23     DWORD DirectoryFlags);
     24 
     25 }  // namespace
     26 
     27 namespace sandbox {
     28 
     29 bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) {
     30   if (!CanSetProcessMitigationsPostStartup(flags))
     31     return false;
     32 
     33   // We can't apply anything before Win XP, so just return cleanly.
     34   if (!IsXPSP2OrLater())
     35     return true;
     36 
     37   base::win::Version version = base::win::GetVersion();
     38   HMODULE module = ::GetModuleHandleA("kernel32.dll");
     39 
     40   if (version >= base::win::VERSION_VISTA &&
     41       (flags & MITIGATION_DLL_SEARCH_ORDER)) {
     42     SetDefaultDllDirectoriesFunction set_default_dll_directories =
     43         reinterpret_cast<SetDefaultDllDirectoriesFunction>(
     44             ::GetProcAddress(module, "SetDefaultDllDirectories"));
     45 
     46     // Check for SetDefaultDllDirectories since it requires KB2533623.
     47     if (set_default_dll_directories) {
     48       if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) &&
     49           ERROR_ACCESS_DENIED != ::GetLastError()) {
     50         return false;
     51       }
     52     }
     53   }
     54 
     55   // Set the heap to terminate on corruption
     56   if (version >= base::win::VERSION_VISTA &&
     57       (flags & MITIGATION_HEAP_TERMINATE)) {
     58     if (!::HeapSetInformation(NULL, HeapEnableTerminationOnCorruption,
     59                               NULL, 0) &&
     60         ERROR_ACCESS_DENIED != ::GetLastError()) {
     61       return false;
     62     }
     63   }
     64 
     65 #if !defined(_WIN64)  // DEP is always enabled on 64-bit.
     66   if (flags & MITIGATION_DEP) {
     67     DWORD dep_flags = PROCESS_DEP_ENABLE;
     68     // DEP support is quirky on XP, so don't force a failure in that case.
     69     const bool return_on_fail = version >= base::win::VERSION_VISTA;
     70 
     71     if (flags & MITIGATION_DEP_NO_ATL_THUNK)
     72       dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
     73 
     74     SetProcessDEPPolicyFunction set_process_dep_policy =
     75         reinterpret_cast<SetProcessDEPPolicyFunction>(
     76             ::GetProcAddress(module, "SetProcessDEPPolicy"));
     77     if (set_process_dep_policy) {
     78       if (!set_process_dep_policy(dep_flags) &&
     79           ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) {
     80         return false;
     81       }
     82     } else {
     83       // We're on XP sp2, so use the less standard approach.
     84       // For reference: http://www.uninformed.org/?v=2&a=4
     85       const int MEM_EXECUTE_OPTION_ENABLE = 1;
     86       const int MEM_EXECUTE_OPTION_DISABLE = 2;
     87       const int MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION = 4;
     88       const int MEM_EXECUTE_OPTION_PERMANENT = 8;
     89 
     90       NtSetInformationProcessFunction set_information_process = NULL;
     91       ResolveNTFunctionPtr("NtSetInformationProcess",
     92                            &set_information_process);
     93       if (!set_information_process)
     94         return false;
     95       ULONG dep = MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT;
     96       if (!(dep_flags & PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION))
     97         dep |= MEM_EXECUTE_OPTION_ATL7_THUNK_EMULATION;
     98       if (!SUCCEEDED(set_information_process(GetCurrentProcess(),
     99                                              ProcessExecuteFlags,
    100                                              &dep, sizeof(dep))) &&
    101           ERROR_ACCESS_DENIED != ::GetLastError() && return_on_fail) {
    102         return false;
    103       }
    104     }
    105   }
    106 #endif
    107 
    108   // This is all we can do in Win7 and below.
    109   if (version < base::win::VERSION_WIN8)
    110     return true;
    111 
    112   SetProcessMitigationPolicyFunction set_process_mitigation_policy =
    113       reinterpret_cast<SetProcessMitigationPolicyFunction>(
    114           ::GetProcAddress(module, "SetProcessMitigationPolicy"));
    115   if (!set_process_mitigation_policy)
    116     return false;
    117 
    118   // Enable ASLR policies.
    119   if (flags & MITIGATION_RELOCATE_IMAGE) {
    120     PROCESS_MITIGATION_ASLR_POLICY policy = { 0 };
    121     policy.EnableForceRelocateImages = true;
    122     policy.DisallowStrippedImages = (flags &
    123         MITIGATION_RELOCATE_IMAGE_REQUIRED) ==
    124         MITIGATION_RELOCATE_IMAGE_REQUIRED;
    125 
    126     if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy,
    127                                        sizeof(policy)) &&
    128         ERROR_ACCESS_DENIED != ::GetLastError()) {
    129       return false;
    130     }
    131   }
    132 
    133   // Enable strict handle policies.
    134   if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
    135     PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = { 0 };
    136     policy.HandleExceptionsPermanentlyEnabled =
    137         policy.RaiseExceptionOnInvalidHandleReference = true;
    138 
    139     if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy,
    140                                        sizeof(policy)) &&
    141         ERROR_ACCESS_DENIED != ::GetLastError()) {
    142       return false;
    143     }
    144   }
    145 
    146   // Enable system call policies.
    147   if (flags & MITIGATION_WIN32K_DISABLE) {
    148     PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = { 0 };
    149     policy.DisallowWin32kSystemCalls = true;
    150 
    151     if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
    152                                        sizeof(policy)) &&
    153         ERROR_ACCESS_DENIED != ::GetLastError()) {
    154       return false;
    155     }
    156   }
    157 
    158   // Enable system call policies.
    159   if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
    160     PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = { 0 };
    161     policy.DisableExtensionPoints = true;
    162 
    163     if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
    164                                        &policy, sizeof(policy)) &&
    165         ERROR_ACCESS_DENIED != ::GetLastError()) {
    166       return false;
    167     }
    168   }
    169 
    170   return true;
    171 }
    172 
    173 void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
    174                                        DWORD64* policy_flags, size_t* size) {
    175   base::win::Version version = base::win::GetVersion();
    176 
    177   *policy_flags = 0;
    178 #if defined(_WIN64)
    179   *size = sizeof(*policy_flags);
    180 #elif defined(_M_IX86)
    181   // A 64-bit flags attribute is illegal on 32-bit Win 7 and below.
    182   if (version < base::win::VERSION_WIN8)
    183     *size = sizeof(DWORD);
    184   else
    185     *size = sizeof(*policy_flags);
    186 #else
    187 #error This platform is not supported.
    188 #endif
    189 
    190   // Nothing for Win XP or Vista.
    191   if (version <= base::win::VERSION_VISTA)
    192     return;
    193 
    194   // DEP and SEHOP are not valid for 64-bit Windows
    195 #if !defined(_WIN64)
    196   if (flags & MITIGATION_DEP) {
    197     *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE;
    198     if (!(flags & MITIGATION_DEP_NO_ATL_THUNK))
    199       *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE;
    200   }
    201 
    202   if (flags & MITIGATION_SEHOP)
    203     *policy_flags |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE;
    204 #endif
    205 
    206   // Win 7
    207   if (version < base::win::VERSION_WIN8)
    208     return;
    209 
    210   if (flags & MITIGATION_RELOCATE_IMAGE) {
    211     *policy_flags |=
    212         PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON;
    213     if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) {
    214       *policy_flags |=
    215           PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS;
    216     }
    217   }
    218 
    219   if (flags & MITIGATION_HEAP_TERMINATE) {
    220     *policy_flags |=
    221         PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON;
    222   }
    223 
    224   if (flags & MITIGATION_BOTTOM_UP_ASLR) {
    225     *policy_flags |=
    226         PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON;
    227   }
    228 
    229   if (flags & MITIGATION_HIGH_ENTROPY_ASLR) {
    230     *policy_flags |=
    231         PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON;
    232   }
    233 
    234   if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
    235     *policy_flags |=
    236         PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON;
    237   }
    238 
    239   if (flags & MITIGATION_WIN32K_DISABLE) {
    240     *policy_flags |=
    241         PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
    242   }
    243 
    244   if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
    245     *policy_flags |=
    246         PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
    247   }
    248 }
    249 
    250 MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
    251   // Anything prior to XP SP2.
    252   if (!IsXPSP2OrLater())
    253     return 0;
    254 
    255   base::win::Version version = base::win::GetVersion();
    256 
    257   // Windows XP SP2+.
    258   if (version < base::win::VERSION_VISTA) {
    259     return flags & (MITIGATION_DEP |
    260                     MITIGATION_DEP_NO_ATL_THUNK);
    261 
    262   // Windows Vista
    263   if (version < base::win::VERSION_WIN7) {
    264     return flags & (MITIGATION_DEP |
    265                     MITIGATION_DEP_NO_ATL_THUNK |
    266                     MITIGATION_BOTTOM_UP_ASLR |
    267                     MITIGATION_DLL_SEARCH_ORDER |
    268                     MITIGATION_HEAP_TERMINATE);
    269   }
    270 
    271   // Windows 7 and Vista.
    272   } else if (version < base::win::VERSION_WIN8) {
    273     return flags & (MITIGATION_BOTTOM_UP_ASLR |
    274                     MITIGATION_DLL_SEARCH_ORDER |
    275                     MITIGATION_HEAP_TERMINATE);
    276   }
    277 
    278   // Windows 8 and above.
    279   return flags & (MITIGATION_BOTTOM_UP_ASLR |
    280                   MITIGATION_DLL_SEARCH_ORDER);
    281 }
    282 
    283 bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
    284                                                MitigationFlags flags) {
    285 // This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
    286 #if !defined(_WIN64)
    287   if (flags & MITIGATION_BOTTOM_UP_ASLR) {
    288     unsigned int limit;
    289     rand_s(&limit);
    290     char* ptr = 0;
    291     const size_t kMask64k = 0xFFFF;
    292     // Random range (512k-16.5mb) in 64k steps.
    293     const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k);
    294     while (ptr < end) {
    295       MEMORY_BASIC_INFORMATION memory_info;
    296       if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info)))
    297         break;
    298       size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k,
    299                              static_cast<SIZE_T>(end - ptr));
    300       if (ptr && memory_info.State == MEM_FREE)
    301         ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS);
    302       ptr += size;
    303     }
    304   }
    305 #endif
    306 
    307   return true;
    308 }
    309 
    310 bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) {
    311   // All of these mitigations can be enabled after startup.
    312   return !(flags & ~(MITIGATION_HEAP_TERMINATE |
    313                      MITIGATION_DEP |
    314                      MITIGATION_DEP_NO_ATL_THUNK |
    315                      MITIGATION_RELOCATE_IMAGE |
    316                      MITIGATION_RELOCATE_IMAGE_REQUIRED |
    317                      MITIGATION_BOTTOM_UP_ASLR |
    318                      MITIGATION_STRICT_HANDLE_CHECKS |
    319                      MITIGATION_WIN32K_DISABLE |
    320                      MITIGATION_EXTENSION_DLL_DISABLE |
    321                      MITIGATION_DLL_SEARCH_ORDER));
    322 }
    323 
    324 bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) {
    325   // These mitigations cannot be enabled prior to startup.
    326   return !(flags & (MITIGATION_STRICT_HANDLE_CHECKS |
    327                     MITIGATION_WIN32K_DISABLE |
    328                     MITIGATION_DLL_SEARCH_ORDER));
    329 }
    330 
    331 }  // namespace sandbox
    332 
    333