Commit 6fdfea11 authored by Will Harris's avatar Will Harris Committed by Commit Bot

Turn on CFG linker config and bitmap generation for DLLs.

Before this CL, only EXE files had CFG bitmap generated
and PE DLL Characteristics "Control Flow Guard" enabled.

This CL enables these for DLLs as well. It is a no-op for
Chrome code as the dispatch guards are not being generated
but will protect indirect calls from e.g. system libraries
from being able to call into arbitrary Chrome code.

This CL also updates checkbins.py to ensure that shipped
binaries always have /guard:CF enabled, and also enables
longjmp support as compiler issues were isolated to MSVC
which we no longer use.

See Comment 30 on bug for size impact analysis.

TEST=Verify by running dumpbin.exe on Chrome DLLs and
checking for "Control Flow Guard" in the "DLL characteristics"
header field, or run tools/checkbins/checkbins.py on
output directory.

BUG=584575

Cq-Include-Trybots: luci.chromium.try:win7-rel,win_archive,win_x64_archive
Change-Id: I4b78b97e93cd81dee70d0b3d1edd3d8e522a5495
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2298284
Commit-Queue: Will Harris <wfh@chromium.org>
Reviewed-by: default avatarBruce Dawson <brucedawson@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Reviewed-by: default avatarScott Graham <scottmg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#789208}
parent dda5ff14
...@@ -519,8 +519,8 @@ default_executable_configs = default_compiler_configs + [ ...@@ -519,8 +519,8 @@ default_executable_configs = default_compiler_configs + [
] + _linker_configs ] + _linker_configs
if (is_win) { if (is_win) {
# Currently only turn on linker CFI for executables, and position it so it can # Turn on linker CFI for executables, and position it so it can be removed
# be removed when needed. # if needed.
default_executable_configs += [ "//build/config/win:cfi_linker" ] default_executable_configs += [ "//build/config/win:cfi_linker" ]
} }
...@@ -534,6 +534,11 @@ default_shared_library_configs = default_compiler_configs + [ ...@@ -534,6 +534,11 @@ default_shared_library_configs = default_compiler_configs + [
"//build/config:default_libs", "//build/config:default_libs",
"//build/config:shared_library_config", "//build/config:shared_library_config",
] + _linker_configs ] + _linker_configs
if (is_win) {
# Turn on linker CFI for DLLs, and position it so it can be removed if needed.
default_shared_library_configs += [ "//build/config/win:cfi_linker" ]
}
if (is_android) { if (is_android) {
# Strip native JNI exports from shared libraries by default. Binaries that # Strip native JNI exports from shared libraries by default. Binaries that
# want this can remove this config. # want this can remove this config.
......
...@@ -352,9 +352,8 @@ config("cfi_linker") { ...@@ -352,9 +352,8 @@ config("cfi_linker") {
# lots of child processes, so this means things are really slow. Disable CFG # lots of child processes, so this means things are really slow. Disable CFG
# for now. https://crbug.com/846966 # for now. https://crbug.com/846966
if (!is_debug && !is_component_build && !is_asan) { if (!is_debug && !is_component_build && !is_asan) {
# Turn on CFG, except for longjmp because it relies on compiler support # Turn on CFG bitmap generation and CFG load config.
# which clang doesn't have yet. ldflags = [ "/guard:cf" ]
ldflags = [ "/guard:cf,nolongjmp" ]
} }
} }
......
...@@ -17,15 +17,20 @@ import os ...@@ -17,15 +17,20 @@ import os
import optparse import optparse
import sys import sys
# Find /third_party/pefile based on current directory and script path. REPO_ROOT = os.path.join(os.path.dirname(__file__), '..', '..')
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', FILES_CFG = os.path.join(REPO_ROOT, 'chrome', 'tools', 'build', 'win',
'third_party', 'pefile')) 'FILES.cfg')
PEFILE_DIR = os.path.join(REPO_ROOT, 'third_party', 'pefile')
sys.path.append(PEFILE_DIR)
import pefile import pefile
PE_FILE_EXTENSIONS = ['.exe', '.dll'] PE_FILE_EXTENSIONS = ['.exe', '.dll']
# https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
DYNAMICBASE_FLAG = 0x0040 DYNAMICBASE_FLAG = 0x0040
NXCOMPAT_FLAG = 0x0100 NXCOMPAT_FLAG = 0x0100
NO_SEH_FLAG = 0x0400 NO_SEH_FLAG = 0x0400
GUARD_CF_FLAG = 0x4000
MACHINE_TYPE_AMD64 = 0x8664 MACHINE_TYPE_AMD64 = 0x8664
# Please do not add your file here without confirming that it indeed doesn't # Please do not add your file here without confirming that it indeed doesn't
...@@ -37,11 +42,13 @@ EXCLUDED_FILES = [ ...@@ -37,11 +42,13 @@ EXCLUDED_FILES = [
'previous_version_mini_installer.exe', 'previous_version_mini_installer.exe',
] ]
def IsPEFile(path): def IsPEFile(path):
return (os.path.isfile(path) and return (os.path.isfile(path) and
os.path.splitext(path)[1].lower() in PE_FILE_EXTENSIONS and os.path.splitext(path)[1].lower() in PE_FILE_EXTENSIONS and
os.path.basename(path) not in EXCLUDED_FILES) os.path.basename(path) not in EXCLUDED_FILES)
def main(options, args): def main(options, args):
directory = args[0] directory = args[0]
pe_total = 0 pe_total = 0
...@@ -49,6 +56,20 @@ def main(options, args): ...@@ -49,6 +56,20 @@ def main(options, args):
failures = [] failures = []
# Load FILES.cfg
exec_globals = {'__builtins__': None}
execfile(FILES_CFG, exec_globals)
files_cfg = exec_globals['FILES']
# Determines whether a specified file is in the 'default'
# filegroup - which means it's shipped with Chrome.
def IsInDefaultFileGroup(path):
for fileobj in files_cfg:
if fileobj['filename'] == os.path.basename(path):
if 'default' in fileobj.get('filegroup', {}):
return True
return False
for file in os.listdir(directory): for file in os.listdir(directory):
path = os.path.abspath(os.path.join(directory, file)) path = os.path.abspath(os.path.join(directory, file))
if not IsPEFile(path): if not IsPEFile(path):
...@@ -105,6 +126,20 @@ def main(options, args): ...@@ -105,6 +126,20 @@ def main(options, args):
print("Checking %s ImageBase (0x%X > 4GB)... PASS" % print("Checking %s ImageBase (0x%X > 4GB)... PASS" %
(path, pe.OPTIONAL_HEADER.ImageBase)) (path, pe.OPTIONAL_HEADER.ImageBase))
# Can only guarantee that files that are built by Chromium
# are protected by /GUARD:CF. Some system libraries are not.
if IsInDefaultFileGroup(path):
# Check for /GUARD:CF.
if pe.OPTIONAL_HEADER.DllCharacteristics & GUARD_CF_FLAG:
if options.verbose:
print("Checking %s for /GUARD:CF... PASS" % path)
else:
success = False
print("Checking %s for /GUARD:CF... FAIL" % path)
else:
if options.verbose:
print("Skipping check for /GUARD:CF for %s." % path)
# Update tally. # Update tally.
if success: if success:
pe_passed = pe_passed + 1 pe_passed = pe_passed + 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment