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