process_mitigations.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  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. #include "sandbox/win/src/process_mitigations.h"
  5. #include <stddef.h>
  6. #include <windows.h>
  7. #include <wow64apiset.h>
  8. #include <algorithm>
  9. #include <ostream>
  10. #include "base/check_op.h"
  11. #include "base/files/file_path.h"
  12. #include "base/notreached.h"
  13. #include "base/scoped_native_library.h"
  14. #include "base/win/windows_version.h"
  15. #include "build/build_config.h"
  16. #include "sandbox/win/src/nt_internals.h"
  17. #include "sandbox/win/src/restricted_token_utils.h"
  18. #include "sandbox/win/src/sandbox_rand.h"
  19. #include "sandbox/win/src/win_utils.h"
  20. // These are missing in 10.0.19551.0 but are in 10.0.19041.0 and 10.0.20226.0.
  21. #ifndef PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_STRICT_MODE
  22. #define PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_STRICT_MODE \
  23. (0x00000003ui64 << 28)
  24. #define PROCESS_CREATION_MITIGATION_POLICY2_CET_DYNAMIC_APIS_OUT_OF_PROC_ONLY_ALWAYS_OFF \
  25. (0x00000002ui64 << 48)
  26. #endif
  27. namespace {
  28. // API defined in libloaderapi.h >= Win8.
  29. using SetDefaultDllDirectoriesFunction = decltype(&SetDefaultDllDirectories);
  30. // APIs defined in processthreadsapi.h >= Win8.
  31. using SetProcessMitigationPolicyFunction =
  32. decltype(&SetProcessMitigationPolicy);
  33. using GetProcessMitigationPolicyFunction =
  34. decltype(&GetProcessMitigationPolicy);
  35. using SetThreadInformationFunction = decltype(&SetThreadInformation);
  36. // Returns a two-element array of mitigation flags supported on this machine.
  37. // - This function is only useful on >= base::win::Version::WIN8.
  38. const ULONG64* GetSupportedMitigations() {
  39. static ULONG64 mitigations[2] = {};
  40. // This static variable will only be initialized once.
  41. if (!mitigations[0] && !mitigations[1]) {
  42. GetProcessMitigationPolicyFunction get_process_mitigation_policy =
  43. reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
  44. ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy"));
  45. if (get_process_mitigation_policy) {
  46. // NOTE: the two-element-sized input array is only supported on >= Win10
  47. // RS2.
  48. // If an earlier version, the second element will be left 0.
  49. size_t mits_size =
  50. (base::win::GetVersion() >= base::win::Version::WIN10_RS2)
  51. ? (sizeof(mitigations[0]) * 2)
  52. : sizeof(mitigations[0]);
  53. if (!get_process_mitigation_policy(::GetCurrentProcess(),
  54. ProcessMitigationOptionsMask,
  55. &mitigations, mits_size)) {
  56. NOTREACHED();
  57. }
  58. }
  59. }
  60. return &mitigations[0];
  61. }
  62. // Returns true if this is 32-bit Chrome running on ARM64 with emulation.
  63. // Needed because ACG does not work with emulated code.
  64. // See
  65. // https://docs.microsoft.com/en-us/windows/uwp/porting/apps-on-arm-troubleshooting-x86.
  66. // See https://crbug.com/977723.
  67. // TODO(wfh): Move this code into base. See https://crbug.com/978257.
  68. bool IsRunning32bitEmulatedOnArm64() {
  69. #if defined(ARCH_CPU_X86)
  70. using IsWow64Process2Function = decltype(&IsWow64Process2);
  71. IsWow64Process2Function is_wow64_process2 =
  72. reinterpret_cast<IsWow64Process2Function>(::GetProcAddress(
  73. ::GetModuleHandleA("kernel32.dll"), "IsWow64Process2"));
  74. if (!is_wow64_process2)
  75. return false;
  76. USHORT process_machine;
  77. USHORT native_machine;
  78. bool retval = is_wow64_process2(::GetCurrentProcess(), &process_machine,
  79. &native_machine);
  80. if (!retval)
  81. return false;
  82. if (native_machine == IMAGE_FILE_MACHINE_ARM64)
  83. return true;
  84. #endif // defined(ARCH_CPU_X86)
  85. return false;
  86. }
  87. } // namespace
  88. namespace sandbox {
  89. bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) {
  90. if (!CanSetProcessMitigationsPostStartup(flags))
  91. return false;
  92. base::win::Version version = base::win::GetVersion();
  93. HMODULE module = ::GetModuleHandleA("kernel32.dll");
  94. if (flags & MITIGATION_DLL_SEARCH_ORDER) {
  95. SetDefaultDllDirectoriesFunction set_default_dll_directories =
  96. reinterpret_cast<SetDefaultDllDirectoriesFunction>(
  97. ::GetProcAddress(module, "SetDefaultDllDirectories"));
  98. // Check for SetDefaultDllDirectories since it requires KB2533623.
  99. if (set_default_dll_directories) {
  100. #if defined(COMPONENT_BUILD)
  101. const DWORD directory_flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
  102. #else
  103. // In a non-component build, all DLLs will be loaded manually, or via
  104. // manifest definition, so these flags can be stronger. This prevents DLL
  105. // planting in the application directory.
  106. const DWORD directory_flags =
  107. LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS;
  108. #endif
  109. if (!set_default_dll_directories(directory_flags) &&
  110. ERROR_ACCESS_DENIED != ::GetLastError()) {
  111. return false;
  112. }
  113. }
  114. }
  115. // Set the heap to terminate on corruption
  116. if (flags & MITIGATION_HEAP_TERMINATE) {
  117. if (!::HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption,
  118. nullptr, 0) &&
  119. ERROR_ACCESS_DENIED != ::GetLastError()) {
  120. return false;
  121. }
  122. }
  123. if (flags & MITIGATION_HARDEN_TOKEN_IL_POLICY) {
  124. DWORD error = HardenProcessIntegrityLevelPolicy();
  125. if ((error != ERROR_SUCCESS) && (error != ERROR_ACCESS_DENIED))
  126. return false;
  127. }
  128. #if !defined(_WIN64) // DEP is always enabled on 64-bit.
  129. if (flags & MITIGATION_DEP) {
  130. DWORD dep_flags = PROCESS_DEP_ENABLE;
  131. if (flags & MITIGATION_DEP_NO_ATL_THUNK)
  132. dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
  133. if (!::SetProcessDEPPolicy(dep_flags) &&
  134. ERROR_ACCESS_DENIED != ::GetLastError()) {
  135. return false;
  136. }
  137. }
  138. #endif
  139. // This is all we can do in Win7 and below.
  140. if (version < base::win::Version::WIN8)
  141. return true;
  142. SetProcessMitigationPolicyFunction set_process_mitigation_policy =
  143. reinterpret_cast<SetProcessMitigationPolicyFunction>(
  144. ::GetProcAddress(module, "SetProcessMitigationPolicy"));
  145. if (!set_process_mitigation_policy)
  146. return false;
  147. // Enable ASLR policies.
  148. if (flags & MITIGATION_RELOCATE_IMAGE) {
  149. PROCESS_MITIGATION_ASLR_POLICY policy = {};
  150. policy.EnableForceRelocateImages = true;
  151. policy.DisallowStrippedImages =
  152. (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) ==
  153. MITIGATION_RELOCATE_IMAGE_REQUIRED;
  154. if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy,
  155. sizeof(policy)) &&
  156. ERROR_ACCESS_DENIED != ::GetLastError()) {
  157. return false;
  158. }
  159. }
  160. // Enable strict handle policies.
  161. if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
  162. PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {};
  163. policy.HandleExceptionsPermanentlyEnabled =
  164. policy.RaiseExceptionOnInvalidHandleReference = true;
  165. if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy,
  166. sizeof(policy)) &&
  167. ERROR_ACCESS_DENIED != ::GetLastError()) {
  168. return false;
  169. }
  170. }
  171. // Enable system call policies.
  172. if (flags & MITIGATION_WIN32K_DISABLE) {
  173. PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
  174. policy.DisallowWin32kSystemCalls = true;
  175. if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
  176. sizeof(policy)) &&
  177. ERROR_ACCESS_DENIED != ::GetLastError()) {
  178. return false;
  179. }
  180. }
  181. // Enable extension point policies.
  182. if (flags & MITIGATION_EXTENSION_POINT_DISABLE) {
  183. PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
  184. policy.DisableExtensionPoints = true;
  185. if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
  186. &policy, sizeof(policy)) &&
  187. ERROR_ACCESS_DENIED != ::GetLastError()) {
  188. return false;
  189. }
  190. }
  191. if (version < base::win::Version::WIN8_1)
  192. return true;
  193. // Enable dynamic code policies.
  194. if (!IsRunning32bitEmulatedOnArm64() &&
  195. (flags & MITIGATION_DYNAMIC_CODE_DISABLE)) {
  196. // Verify caller is not accidentally setting both mutually exclusive
  197. // policies.
  198. DCHECK(!(flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT));
  199. PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {};
  200. policy.ProhibitDynamicCode = true;
  201. if (!set_process_mitigation_policy(ProcessDynamicCodePolicy, &policy,
  202. sizeof(policy)) &&
  203. ERROR_ACCESS_DENIED != ::GetLastError()) {
  204. return false;
  205. }
  206. }
  207. if (version < base::win::Version::WIN10)
  208. return true;
  209. // Enable font policies.
  210. if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) {
  211. PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {};
  212. policy.DisableNonSystemFonts = true;
  213. if (!set_process_mitigation_policy(ProcessFontDisablePolicy, &policy,
  214. sizeof(policy)) &&
  215. ERROR_ACCESS_DENIED != ::GetLastError()) {
  216. return false;
  217. }
  218. }
  219. if (version < base::win::Version::WIN10_TH2)
  220. return true;
  221. // Enable binary signing policies.
  222. if (flags & MITIGATION_FORCE_MS_SIGNED_BINS) {
  223. PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY policy = {};
  224. // Allow only MS signed binaries.
  225. policy.MicrosoftSignedOnly = true;
  226. // NOTE: there are two other flags available to allow
  227. // 1) Only Windows Store signed.
  228. // 2) MS-signed, Win Store signed, and WHQL signed binaries.
  229. // Support not added at the moment.
  230. if (!set_process_mitigation_policy(ProcessSignaturePolicy, &policy,
  231. sizeof(policy)) &&
  232. ERROR_ACCESS_DENIED != ::GetLastError()) {
  233. return false;
  234. }
  235. }
  236. // Enable image load policies.
  237. if (flags & MITIGATION_IMAGE_LOAD_NO_REMOTE ||
  238. flags & MITIGATION_IMAGE_LOAD_NO_LOW_LABEL ||
  239. flags & MITIGATION_IMAGE_LOAD_PREFER_SYS32) {
  240. PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
  241. if (flags & MITIGATION_IMAGE_LOAD_NO_REMOTE)
  242. policy.NoRemoteImages = true;
  243. if (flags & MITIGATION_IMAGE_LOAD_NO_LOW_LABEL)
  244. policy.NoLowMandatoryLabelImages = true;
  245. // PreferSystem32 is only supported on >= Anniversary.
  246. if (version >= base::win::Version::WIN10_RS1 &&
  247. flags & MITIGATION_IMAGE_LOAD_PREFER_SYS32) {
  248. policy.PreferSystem32Images = true;
  249. }
  250. if (!set_process_mitigation_policy(ProcessImageLoadPolicy, &policy,
  251. sizeof(policy)) &&
  252. ERROR_ACCESS_DENIED != ::GetLastError()) {
  253. return false;
  254. }
  255. }
  256. if (version < base::win::Version::WIN10_RS1)
  257. return true;
  258. // Enable dynamic code policies.
  259. // Per-thread opt-out is only supported on >= Anniversary (RS1).
  260. if (!IsRunning32bitEmulatedOnArm64() &&
  261. (flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT)) {
  262. // Verify caller is not accidentally setting both mutually exclusive
  263. // policies.
  264. DCHECK(!(flags & MITIGATION_DYNAMIC_CODE_DISABLE));
  265. PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {};
  266. policy.ProhibitDynamicCode = true;
  267. policy.AllowThreadOptOut = true;
  268. if (!set_process_mitigation_policy(ProcessDynamicCodePolicy, &policy,
  269. sizeof(policy)) &&
  270. ERROR_ACCESS_DENIED != ::GetLastError()) {
  271. return false;
  272. }
  273. }
  274. return true;
  275. }
  276. bool ApplyMitigationsToCurrentThread(MitigationFlags flags) {
  277. if (!CanSetMitigationsPerThread(flags))
  278. return false;
  279. base::win::Version version = base::win::GetVersion();
  280. if (version < base::win::Version::WIN10_RS1)
  281. return true;
  282. // Enable dynamic code per-thread policies.
  283. if (flags & MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD) {
  284. DWORD thread_policy = THREAD_DYNAMIC_CODE_ALLOW;
  285. // NOTE: SetThreadInformation API only exists on >= Win8. Dynamically
  286. // get function handle.
  287. base::ScopedNativeLibrary dll(base::FilePath(L"kernel32.dll"));
  288. if (!dll.is_valid())
  289. return false;
  290. SetThreadInformationFunction set_thread_info_function =
  291. reinterpret_cast<SetThreadInformationFunction>(
  292. dll.GetFunctionPointer("SetThreadInformation"));
  293. if (!set_thread_info_function)
  294. return false;
  295. // NOTE: Must use the pseudo-handle here, a thread HANDLE won't work.
  296. if (!set_thread_info_function(::GetCurrentThread(), ThreadDynamicCodePolicy,
  297. &thread_policy, sizeof(thread_policy))) {
  298. return false;
  299. }
  300. }
  301. return true;
  302. }
  303. void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
  304. DWORD64* policy_flags,
  305. size_t* size) {
  306. base::win::Version version = base::win::GetVersion();
  307. // |policy_flags| is a two-element array of DWORD64s. Ensure mitigation flags
  308. // from PROCESS_CREATION_MITIGATION_POLICY2_* go into the second value. If
  309. // any flags are set in value 2, update |size| to include both elements.
  310. DWORD64* policy_value_1 = &policy_flags[0];
  311. DWORD64* policy_value_2 = &policy_flags[1];
  312. *policy_value_1 = 0;
  313. *policy_value_2 = 0;
  314. #if defined(_WIN64)
  315. *size = sizeof(*policy_flags);
  316. #elif defined(_M_IX86)
  317. // A 64-bit flags attribute is illegal on 32-bit Win 7.
  318. if (version < base::win::Version::WIN8)
  319. *size = sizeof(DWORD);
  320. else
  321. *size = sizeof(*policy_flags);
  322. #else
  323. #error This platform is not supported.
  324. #endif
  325. // DEP and SEHOP are not valid for 64-bit Windows
  326. #if !defined(_WIN64)
  327. if (flags & MITIGATION_DEP) {
  328. *policy_value_1 |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE;
  329. if (!(flags & MITIGATION_DEP_NO_ATL_THUNK))
  330. *policy_value_1 |=
  331. PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE;
  332. }
  333. if (flags & MITIGATION_SEHOP)
  334. *policy_value_1 |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE;
  335. #endif
  336. // Win 7
  337. if (version < base::win::Version::WIN8)
  338. return;
  339. // Everything >= Win8, do not return before the end of the function where
  340. // the final policy bitmap is sanity checked against what is supported on this
  341. // machine. The API required to do so is only available since Win8.
  342. // Mitigations >= Win8:
  343. //----------------------------------------------------------------------------
  344. if (version >= base::win::Version::WIN8) {
  345. if (flags & MITIGATION_RELOCATE_IMAGE) {
  346. *policy_value_1 |=
  347. PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON;
  348. if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) {
  349. *policy_value_1 |=
  350. PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS;
  351. }
  352. }
  353. if (flags & MITIGATION_HEAP_TERMINATE) {
  354. *policy_value_1 |=
  355. PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON;
  356. }
  357. if (flags & MITIGATION_BOTTOM_UP_ASLR) {
  358. *policy_value_1 |=
  359. PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON;
  360. }
  361. if (flags & MITIGATION_HIGH_ENTROPY_ASLR) {
  362. *policy_value_1 |=
  363. PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON;
  364. }
  365. if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
  366. *policy_value_1 |=
  367. PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON;
  368. }
  369. if (flags & MITIGATION_WIN32K_DISABLE) {
  370. *policy_value_1 |=
  371. PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
  372. }
  373. if (flags & MITIGATION_EXTENSION_POINT_DISABLE) {
  374. *policy_value_1 |=
  375. PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
  376. }
  377. }
  378. // Mitigations >= Win8.1:
  379. //----------------------------------------------------------------------------
  380. if (version >= base::win::Version::WIN8_1) {
  381. if (flags & MITIGATION_DYNAMIC_CODE_DISABLE) {
  382. *policy_value_1 |=
  383. PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON;
  384. }
  385. }
  386. // Mitigations >= Win10:
  387. //----------------------------------------------------------------------------
  388. if (version >= base::win::Version::WIN10) {
  389. if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) {
  390. *policy_value_1 |=
  391. PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON;
  392. }
  393. }
  394. // Mitigations >= Win10 TH2:
  395. //----------------------------------------------------------------------------
  396. if (version >= base::win::Version::WIN10_TH2) {
  397. if (flags & MITIGATION_FORCE_MS_SIGNED_BINS) {
  398. *policy_value_1 |=
  399. PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
  400. }
  401. if (flags & MITIGATION_IMAGE_LOAD_NO_REMOTE) {
  402. *policy_value_1 |=
  403. PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON;
  404. }
  405. if (flags & MITIGATION_IMAGE_LOAD_NO_LOW_LABEL) {
  406. *policy_value_1 |=
  407. PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON;
  408. }
  409. }
  410. // Mitigations >= Win10 RS1 ("Anniversary"):
  411. //----------------------------------------------------------------------------
  412. if (version >= base::win::Version::WIN10_RS1) {
  413. if (flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT) {
  414. *policy_value_1 |=
  415. PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON_ALLOW_OPT_OUT;
  416. }
  417. if (flags & MITIGATION_IMAGE_LOAD_PREFER_SYS32) {
  418. *policy_value_1 |=
  419. PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON;
  420. }
  421. }
  422. // Mitigations >= Win10 RS3 ("Fall Creator's"):
  423. //----------------------------------------------------------------------------
  424. if (version >= base::win::Version::WIN10_RS3) {
  425. // Note: This mitigation requires not only Win10 1709, but also the January
  426. // 2018 security updates and any applicable firmware updates from the
  427. // OEM device manufacturer.
  428. // Note: Applying this mitigation attribute on creation will succeed, even
  429. // if the underlying hardware does not support the implementation.
  430. // Windows just does its best under the hood for the given hardware.
  431. if (flags & MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION) {
  432. *policy_value_2 |=
  433. PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON;
  434. }
  435. }
  436. // Mitigations >= Win10 20H1
  437. //----------------------------------------------------------------------------
  438. if (version >= base::win::Version::WIN10_20H1) {
  439. if (flags & MITIGATION_CET_DISABLED) {
  440. *policy_value_2 |=
  441. PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_ALWAYS_OFF;
  442. }
  443. if (flags & MITIGATION_CET_STRICT_MODE) {
  444. DCHECK(!(flags & MITIGATION_CET_DISABLED))
  445. << "Cannot enable CET strict mode if CET is disabled.";
  446. *policy_value_2 |=
  447. PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_STRICT_MODE;
  448. }
  449. if (flags & MITIGATION_CET_ALLOW_DYNAMIC_APIS) {
  450. DCHECK(!(flags & MITIGATION_CET_DISABLED))
  451. << "Cannot enable in-process CET apis if CET is disabled.";
  452. DCHECK(!(flags & MITIGATION_DYNAMIC_CODE_DISABLE))
  453. << "Cannot enable in-process CET apis if dynamic code is disabled.";
  454. *policy_value_2 |=
  455. PROCESS_CREATION_MITIGATION_POLICY2_CET_DYNAMIC_APIS_OUT_OF_PROC_ONLY_ALWAYS_OFF;
  456. }
  457. }
  458. // When done setting policy flags, sanity check supported policies on this
  459. // machine, and then update |size|.
  460. const ULONG64* supported = GetSupportedMitigations();
  461. *policy_value_1 = *policy_value_1 & supported[0];
  462. *policy_value_2 = *policy_value_2 & supported[1];
  463. // Only include the second element in |size| if it is non-zero. Else,
  464. // UpdateProcThreadAttribute() will return a failure when setting policies.
  465. if (*policy_value_2 && version >= base::win::Version::WIN10_RS2) {
  466. *size = sizeof(*policy_flags) * 2;
  467. }
  468. return;
  469. }
  470. void ConvertProcessMitigationsToComponentFilter(MitigationFlags flags,
  471. COMPONENT_FILTER* filter) {
  472. filter->ComponentFlags = 0;
  473. if (flags & MITIGATION_KTM_COMPONENT) {
  474. filter->ComponentFlags = COMPONENT_KTM;
  475. }
  476. }
  477. MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
  478. base::win::Version version = base::win::GetVersion();
  479. // Windows 7.
  480. if (version < base::win::Version::WIN8) {
  481. return flags & (MITIGATION_BOTTOM_UP_ASLR | MITIGATION_DLL_SEARCH_ORDER |
  482. MITIGATION_HEAP_TERMINATE);
  483. }
  484. // Windows 8 and above.
  485. return flags & (MITIGATION_BOTTOM_UP_ASLR | MITIGATION_DLL_SEARCH_ORDER);
  486. }
  487. bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
  488. MitigationFlags flags) {
  489. // This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
  490. #if !defined(_WIN64)
  491. if (flags & MITIGATION_BOTTOM_UP_ASLR) {
  492. unsigned int limit;
  493. GetRandom(&limit);
  494. char* ptr = 0;
  495. const size_t kMask64k = 0xFFFF;
  496. // Random range (512k-16.5mb) in 64k steps.
  497. const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k);
  498. while (ptr < end) {
  499. MEMORY_BASIC_INFORMATION memory_info;
  500. if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info)))
  501. break;
  502. size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k,
  503. static_cast<SIZE_T>(end - ptr));
  504. if (ptr && memory_info.State == MEM_FREE)
  505. ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS);
  506. ptr += size;
  507. }
  508. }
  509. #endif
  510. return true;
  511. }
  512. MitigationFlags GetAllowedPostStartupProcessMitigations() {
  513. return MITIGATION_HEAP_TERMINATE |
  514. MITIGATION_DEP |
  515. MITIGATION_DEP_NO_ATL_THUNK |
  516. MITIGATION_RELOCATE_IMAGE |
  517. MITIGATION_RELOCATE_IMAGE_REQUIRED |
  518. MITIGATION_BOTTOM_UP_ASLR |
  519. MITIGATION_STRICT_HANDLE_CHECKS |
  520. MITIGATION_EXTENSION_POINT_DISABLE |
  521. MITIGATION_DLL_SEARCH_ORDER |
  522. MITIGATION_HARDEN_TOKEN_IL_POLICY |
  523. MITIGATION_WIN32K_DISABLE |
  524. MITIGATION_DYNAMIC_CODE_DISABLE |
  525. MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT |
  526. MITIGATION_FORCE_MS_SIGNED_BINS |
  527. MITIGATION_NONSYSTEM_FONT_DISABLE |
  528. MITIGATION_IMAGE_LOAD_NO_REMOTE |
  529. MITIGATION_IMAGE_LOAD_NO_LOW_LABEL |
  530. MITIGATION_IMAGE_LOAD_PREFER_SYS32;
  531. }
  532. bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) {
  533. // All of these mitigations can be enabled after startup.
  534. return !(flags & ~GetAllowedPostStartupProcessMitigations());
  535. }
  536. bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) {
  537. // These mitigations cannot be enabled prior to startup.
  538. return !(flags &
  539. (MITIGATION_STRICT_HANDLE_CHECKS | MITIGATION_DLL_SEARCH_ORDER));
  540. }
  541. bool CanSetMitigationsPerThread(MitigationFlags flags) {
  542. // If any flags EXCEPT these are set, fail.
  543. if (flags & ~(MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD))
  544. return false;
  545. return true;
  546. }
  547. } // namespace sandbox