diff options
author | rmcilroy <rmcilroy@chromium.org> | 2015-01-09 03:31:22 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-01-09 11:32:12 +0000 |
commit | da69cd0f7c2f92640b7d00e59f66eb3b9fabba2e (patch) | |
tree | 27214eb143b0898348defb783b8cd2e7f0337658 | |
parent | 712f1acaf22f225a5eaef28b3dff9aecb7bc5cc8 (diff) | |
download | chromium_src-da69cd0f7c2f92640b7d00e59f66eb3b9fabba2e.zip chromium_src-da69cd0f7c2f92640b7d00e59f66eb3b9fabba2e.tar.gz chromium_src-da69cd0f7c2f92640b7d00e59f66eb3b9fabba2e.tar.bz2 |
[gin] Fingerprint the V8 snapshot files on Windows and verify before loading the snapshot.
Adds code which generates a SHA256 fingerprint of the external V8 snapshot
blob files during the build process, and embeds these values into the
binary. During startup the SHA256 hash of the snapshot blobs are compared
against these fingerprints and Chrome will fail to load if they differ.
BUG=421063,439661
Review URL: https://codereview.chromium.org/832393003
Cr-Commit-Position: refs/heads/master@{#310755}
-rw-r--r-- | content/app/content_main_runner.cc | 8 | ||||
-rw-r--r-- | gin/BUILD.gn | 36 | ||||
-rw-r--r-- | gin/DEPS | 1 | ||||
-rw-r--r-- | gin/fingerprint/fingerprint_v8_snapshot.gypi | 47 | ||||
-rwxr-xr-x | gin/fingerprint/fingerprint_v8_snapshot.py | 86 | ||||
-rw-r--r-- | gin/gin.gyp | 26 | ||||
-rw-r--r-- | gin/isolate_holder.cc | 43 | ||||
-rw-r--r-- | gin/public/isolate_holder.h | 2 |
8 files changed, 235 insertions, 14 deletions
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc index 05e45bd..2da7dc1 100644 --- a/content/app/content_main_runner.cc +++ b/content/app/content_main_runner.cc @@ -721,7 +721,7 @@ class ContentMainRunnerImpl : public ContentMainRunner { else CHECK(base::i18n::InitializeICU()); -#ifdef V8_USE_EXTERNAL_STARTUP_DATA +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) int v8_natives_fd = base::GlobalDescriptors::GetInstance()->MaybeGet( kV8NativesDataDescriptor); int v8_snapshot_fd = base::GlobalDescriptors::GetInstance()->MaybeGet( @@ -736,10 +736,10 @@ class ContentMainRunnerImpl : public ContentMainRunner { #else CHECK(base::i18n::InitializeICU()); -#ifdef V8_USE_EXTERNAL_STARTUP_DATA +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) CHECK(gin::IsolateHolder::LoadV8Snapshot()); -#endif // V8_USE_EXTERNAL_STARTUP_DATA -#endif // OS_ANDROID +#endif // V8_USE_EXTERNAL_STARTUP_DATA +#endif // OS_ANDROID InitializeStatsTable(command_line); diff --git a/gin/BUILD.gn b/gin/BUILD.gn index b352c3a..d389b84 100644 --- a/gin/BUILD.gn +++ b/gin/BUILD.gn @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/module_args/v8.gni") + component("gin") { sources = [ "arguments.cc", @@ -68,6 +70,40 @@ component("gin") { deps = [ "//base/third_party/dynamic_annotations", ] + if (v8_use_external_startup_data && is_win) { + deps += [ + ":gin_v8_snapshot_fingerprint", + "//crypto:crypto", + ] + sources += [ "$target_gen_dir/v8_snapshot_fingerprint.cc" ] + defines += [ "V8_VERIFY_EXTERNAL_STARTUP_DATA" ] + } +} + +if (v8_use_external_startup_data) { + action("gin_v8_snapshot_fingerprint") { + script = "//gin/fingerprint/fingerprint_v8_snapshot.py" + + snapshot_file = "$root_build_dir/snapshot_blob.bin" + natives_file = "$root_build_dir/natives_blob.bin" + output_file = "$target_gen_dir/v8_snapshot_fingerprint.cc" + + args = [ + "--snapshot_file", + rebase_path(snapshot_file, root_build_dir), + "--natives_file", + rebase_path(natives_file, root_build_dir), + "--output_file", + rebase_path(output_file, root_build_dir), + ] + inputs = [ + snapshot_file, + natives_file, + ] + outputs = [ + output_file, + ] + } } executable("gin_shell") { @@ -1,4 +1,5 @@ include_rules = [ "+base", + "+crypto", "+v8", ] diff --git a/gin/fingerprint/fingerprint_v8_snapshot.gypi b/gin/fingerprint/fingerprint_v8_snapshot.gypi new file mode 100644 index 0000000..ede0de3 --- /dev/null +++ b/gin/fingerprint/fingerprint_v8_snapshot.gypi @@ -0,0 +1,47 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is meant to be included into a target to provide a rule that +# fingerprints the v8 snapshot and generates a .cc file which includes this +# fingerprint. +# +# To use this, create a gyp target with the following form: +# { +# 'target_name': 'gin_v8_snapshot_fingerprint', +# 'type': 'none', +# 'variables': { +# 'snapshot_file': 'snapshot blob file to be fingerprinted', +# 'natives_file': 'natives blob file to be fingerprinted', +# 'output_file': 'output .cc file to generate with fingerprints', +# }, +# 'includes': [ '../gin/fingerprint/fingerprint_v8_snapshot.gypi' ], +# }, +# + +{ + 'conditions': [ + ['v8_use_external_startup_data==1', { + 'actions': [ + { + 'action_name': 'Generate V8 snapshot fingerprint', + 'message': 'Generating V8 snapshot fingerprint', + 'inputs': [ + '<(DEPTH)/gin/fingerprint/fingerprint_v8_snapshot.py', + '<(snapshot_file)', + '<(natives_file)', + ], + 'outputs': [ + '<(output_file)', + ], + 'action': [ + 'python', '<(DEPTH)/gin/fingerprint/fingerprint_v8_snapshot.py', + '--snapshot_file=<(snapshot_file)', + '--natives_file=<(natives_file)', + '--output_file=<(output_file)', + ], + } + ], + }], + ], +}
\ No newline at end of file diff --git a/gin/fingerprint/fingerprint_v8_snapshot.py b/gin/fingerprint/fingerprint_v8_snapshot.py new file mode 100755 index 0000000..d1f7092 --- /dev/null +++ b/gin/fingerprint/fingerprint_v8_snapshot.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Fingerprints the V8 snapshot blob files. + +Constructs a SHA256 fingerprint of the V8 natives and snapshot blob files and +creates a .cc file which includes these fingerprint as variables. +""" + +import hashlib +import optparse +import os +import sys + +_HEADER = """// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file was generated by fingerprint_v8_snapshot.py. + +namespace gin { +""" + +_FOOTER = """ +} // namespace gin +""" + + +def FingerprintFile(file_path): + input_file = open(file_path, 'rb') + sha256 = hashlib.sha256() + while True: + block = input_file.read(sha256.block_size) + if not block: + break + sha256.update(block) + return sha256.digest() + + +def WriteFingerprint(output_file, variable_name, fingerprint): + output_file.write('\nextern const unsigned char %s[] = { ' % variable_name) + for byte in fingerprint: + output_file.write(str(ord(byte)) + ', ') + output_file.write('};\n') + + +def WriteOutputFile(natives_fingerprint, + snapshot_fingerprint, + output_file_path): + output_dir_path = os.path.dirname(output_file_path) + if not os.path.exists(output_dir_path): + os.makedirs(output_dir_path) + output_file = open(output_file_path, 'w') + + output_file.write(_HEADER) + WriteFingerprint(output_file, 'g_natives_fingerprint', natives_fingerprint) + output_file.write('\n') + WriteFingerprint(output_file, 'g_snapshot_fingerprint', snapshot_fingerprint) + output_file.write(_FOOTER) + + +def main(): + parser = optparse.OptionParser() + + parser.add_option('--snapshot_file', + help='The input V8 snapshot blob file path.') + parser.add_option('--natives_file', + help='The input V8 natives blob file path.') + parser.add_option('--output_file', + help='The path for the output cc file which will be write.') + + options, _ = parser.parse_args() + + natives_fingerprint = FingerprintFile(options.natives_file) + snapshot_fingerprint = FingerprintFile(options.snapshot_file) + WriteOutputFile( + natives_fingerprint, snapshot_fingerprint, options.output_file) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/gin/gin.gyp b/gin/gin.gyp index b38dc85..096c120 100644 --- a/gin/gin.gyp +++ b/gin/gin.gyp @@ -5,6 +5,7 @@ { 'variables': { 'chromium_code': 1, + 'gin_gen_path': '<(SHARED_INTERMEDIATE_DIR)/gin/', }, 'targets': [ { @@ -14,7 +15,6 @@ '../base/base.gyp:base', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../v8/tools/gyp/v8.gyp:v8', - ], 'export_dependent_settings': [ '../base/base.gyp:base', @@ -78,6 +78,30 @@ 'wrappable.h', 'wrapper_info.cc', ], + 'conditions': [ + ['v8_use_external_startup_data==1 and OS=="win"', { + 'dependencies': [ + 'gin_v8_snapshot_fingerprint', + '../crypto/crypto.gyp:crypto', + ], + 'sources': [ + '<(gin_gen_path)/v8_snapshot_fingerprint.cc', + ], + 'defines': [ + 'V8_VERIFY_EXTERNAL_STARTUP_DATA', + ] + }], + ], + }, + { + 'target_name': 'gin_v8_snapshot_fingerprint', + 'type': 'none', + 'variables': { + 'snapshot_file': '<(PRODUCT_DIR)/snapshot_blob.bin', + 'natives_file': '<(PRODUCT_DIR)/natives_blob.bin', + 'output_file': '<(gin_gen_path)/v8_snapshot_fingerprint.cc', + }, + 'includes': [ '../gin/fingerprint/fingerprint_v8_snapshot.gypi' ], }, { 'target_name': 'gin_shell', diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc index 2b6d64b..38215b2 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc @@ -12,6 +12,7 @@ #include "base/message_loop/message_loop.h" #include "base/rand_util.h" #include "base/sys_info.h" +#include "crypto/sha2.h" #include "gin/array_buffer.h" #include "gin/debug_impl.h" #include "gin/function_template.h" @@ -19,8 +20,8 @@ #include "gin/public/v8_platform.h" #include "gin/run_microtasks_observer.h" -#ifdef V8_USE_EXTERNAL_STARTUP_DATA -#ifdef OS_MACOSX +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) +#if defined(OS_MACOSX) #include "base/mac/foundation_util.h" #endif // OS_MACOSX #include "base/path_service.h" @@ -40,7 +41,7 @@ bool GenerateEntropy(unsigned char* buffer, size_t amount) { base::MemoryMappedFile* g_mapped_natives = NULL; base::MemoryMappedFile* g_mapped_snapshot = NULL; -#ifdef V8_USE_EXTERNAL_STARTUP_DATA +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) bool MapV8Files(base::FilePath* natives_path, base::FilePath* snapshot_path, int natives_fd = -1, int snapshot_fd = -1) { int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; @@ -72,21 +73,39 @@ bool MapV8Files(base::FilePath* natives_path, base::FilePath* snapshot_path, return true; } +#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) +bool VerifyV8SnapshotFile(base::MemoryMappedFile* snapshot_file, + const unsigned char* fingerprint) { + unsigned char output[crypto::kSHA256Length]; + crypto::SHA256HashString( + base::StringPiece(reinterpret_cast<const char*>(snapshot_file->data()), + snapshot_file->length()), + output, sizeof(output)); + return !memcmp(fingerprint, output, sizeof(output)); +} +#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA + #if !defined(OS_MACOSX) const int v8_snapshot_dir = #if defined(OS_ANDROID) base::DIR_ANDROID_APP_DATA; #elif defined(OS_POSIX) base::DIR_EXE; -#endif // defined(OS_ANDROID) -#endif // !defined(OS_MACOSX) +#endif // OS_ANDROID +#endif // !OS_MACOSX #endif // V8_USE_EXTERNAL_STARTUP_DATA } // namespace +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) + +#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) +// Defined in gen/gin/v8_snapshot_fingerprint.cc +extern const unsigned char g_natives_fingerprint[]; +extern const unsigned char g_snapshot_fingerprint[]; +#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA -#ifdef V8_USE_EXTERNAL_STARTUP_DATA // static bool IsolateHolder::LoadV8Snapshot() { if (g_mapped_natives && g_mapped_snapshot) @@ -108,7 +127,15 @@ bool IsolateHolder::LoadV8Snapshot() { DCHECK(!snapshot_path.empty()); #endif // !defined(OS_MACOSX) - return MapV8Files(&natives_path, &snapshot_path); + if (!MapV8Files(&natives_path, &snapshot_path)) + return false; + +#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) + return VerifyV8SnapshotFile(g_mapped_natives, g_natives_fingerprint) && + VerifyV8SnapshotFile(g_mapped_snapshot, g_snapshot_fingerprint); +#else + return true; +#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA } //static @@ -193,7 +220,7 @@ void IsolateHolder::Initialize(ScriptMode mode, v8::V8::SetFlagsFromString(v8_flags, sizeof(v8_flags) - 1); } v8::V8::SetEntropySource(&GenerateEntropy); -#ifdef V8_USE_EXTERNAL_STARTUP_DATA +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) v8::StartupData natives; natives.data = reinterpret_cast<const char*>(g_mapped_natives->data()); natives.raw_size = static_cast<int>(g_mapped_natives->length()); diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h index b12734c..64fc952 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h @@ -51,7 +51,7 @@ class GIN_EXPORT IsolateHolder { // thread. void RemoveRunMicrotasksObserver(); -#ifdef V8_USE_EXTERNAL_STARTUP_DATA +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) static bool LoadV8SnapshotFD(int natives_fd, int snapshot_fd); static bool LoadV8Snapshot(); #endif // V8_USE_EXTERNAL_STARTUP_DATA |