OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/nacl_host/nacl_browser.h" | 5 #include "chrome/browser/nacl_host/nacl_browser.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/path_service.h" | 11 #include "base/path_service.h" |
12 #include "base/pickle.h" | 12 #include "base/pickle.h" |
| 13 #include "base/rand_util.h" |
13 #include "base/strings/string_split.h" | 14 #include "base/strings/string_split.h" |
14 #include "base/win/windows_version.h" | 15 #include "base/win/windows_version.h" |
15 #include "build/build_config.h" | 16 #include "build/build_config.h" |
16 #include "chrome/common/chrome_paths.h" | 17 #include "chrome/common/chrome_paths.h" |
17 #include "chrome/common/chrome_paths_internal.h" | 18 #include "chrome/common/chrome_paths_internal.h" |
18 #include "chrome/common/chrome_switches.h" | 19 #include "chrome/common/chrome_switches.h" |
19 #include "content/public/browser/browser_thread.h" | 20 #include "content/public/browser/browser_thread.h" |
20 #include "extensions/common/url_pattern.h" | 21 #include "extensions/common/url_pattern.h" |
21 #include "googleurl/src/gurl.h" | 22 #include "googleurl/src/gurl.h" |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
25 // An arbitrary delay to coalesce multiple writes to the cache. | 26 // An arbitrary delay to coalesce multiple writes to the cache. |
26 const int kValidationCacheCoalescingTimeMS = 6000; | 27 const int kValidationCacheCoalescingTimeMS = 6000; |
27 const char kValidationCacheSequenceName[] = "NaClValidationCache"; | 28 const char kValidationCacheSequenceName[] = "NaClValidationCache"; |
28 const base::FilePath::CharType kValidationCacheFileName[] = | 29 const base::FilePath::CharType kValidationCacheFileName[] = |
29 FILE_PATH_LITERAL("nacl_validation_cache.bin"); | 30 FILE_PATH_LITERAL("nacl_validation_cache.bin"); |
30 | 31 |
31 const bool kValidationCacheEnabledByDefault = true; | 32 const bool kValidationCacheEnabledByDefault = true; |
32 | 33 |
33 enum ValidationCacheStatus { | 34 enum ValidationCacheStatus { |
34 CACHE_MISS = 0, | 35 CACHE_MISS = 0, |
35 CACHE_HIT, | 36 CACHE_HIT, |
36 CACHE_MAX | 37 CACHE_MAX |
37 }; | 38 }; |
38 | 39 |
| 40 // Keep the cache bounded to an arbitrary size. If it's too small, useful |
| 41 // entries could be evicted when multiple .nexes are loaded at once. On the |
| 42 // other hand, entries are not always claimed (and hence removed), so the size |
| 43 // of the cache will likely saturate at its maximum size. |
| 44 // Entries may not be claimed for two main reasons. 1) the NaCl process could |
| 45 // be killed while it is loading. 2) the trusted NaCl plugin opens files using |
| 46 // the code path but doesn't resolve them. |
| 47 // TODO(ncbray) don't cache files that the plugin will not resolve. |
| 48 const int kFilePathCacheSize = 100; |
| 49 |
39 const base::FilePath::StringType NaClIrtName() { | 50 const base::FilePath::StringType NaClIrtName() { |
40 base::FilePath::StringType irt_name(FILE_PATH_LITERAL("nacl_irt_")); | 51 base::FilePath::StringType irt_name(FILE_PATH_LITERAL("nacl_irt_")); |
41 | 52 |
42 #if defined(ARCH_CPU_X86_FAMILY) | 53 #if defined(ARCH_CPU_X86_FAMILY) |
43 #if defined(ARCH_CPU_X86_64) | 54 #if defined(ARCH_CPU_X86_64) |
44 bool is64 = true; | 55 bool is64 = true; |
45 #elif defined(OS_WIN) | 56 #elif defined(OS_WIN) |
46 bool is64 = (base::win::OSInfo::GetInstance()->wow64_status() == | 57 bool is64 = (base::win::OSInfo::GetInstance()->wow64_status() == |
47 base::win::OSInfo::WOW64_ENABLED); | 58 base::win::OSInfo::WOW64_ENABLED); |
48 #else | 59 #else |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX); | 110 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX); |
100 } | 111 } |
101 | 112 |
102 void LogCacheSet(ValidationCacheStatus status) { | 113 void LogCacheSet(ValidationCacheStatus status) { |
103 // Bucket zero is reserved for future use. | 114 // Bucket zero is reserved for future use. |
104 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX); | 115 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX); |
105 } | 116 } |
106 | 117 |
107 } // namespace | 118 } // namespace |
108 | 119 |
| 120 namespace nacl { |
| 121 |
| 122 void OpenNaClExecutableImpl(const base::FilePath& file_path, |
| 123 base::PlatformFile* file) { |
| 124 // Get a file descriptor. On Windows, we need 'GENERIC_EXECUTE' in order to |
| 125 // memory map the executable. |
| 126 // IMPORTANT: This file descriptor must not have write access - that could |
| 127 // allow a NaCl inner sandbox escape. |
| 128 base::PlatformFileError error_code; |
| 129 *file = base::CreatePlatformFile( |
| 130 file_path, |
| 131 (base::PLATFORM_FILE_OPEN | |
| 132 base::PLATFORM_FILE_READ | |
| 133 base::PLATFORM_FILE_EXECUTE), // Windows only flag. |
| 134 NULL, |
| 135 &error_code); |
| 136 if (error_code != base::PLATFORM_FILE_OK) { |
| 137 *file = base::kInvalidPlatformFileValue; |
| 138 return; |
| 139 } |
| 140 // Check that the file does not reference a directory. Returning a descriptor |
| 141 // to an extension directory could allow an outer sandbox escape. openat(...) |
| 142 // could be used to traverse into the file system. |
| 143 base::PlatformFileInfo file_info; |
| 144 if (!base::GetPlatformFileInfo(*file, &file_info) || |
| 145 file_info.is_directory) { |
| 146 base::ClosePlatformFile(*file); |
| 147 *file = base::kInvalidPlatformFileValue; |
| 148 return; |
| 149 } |
| 150 } |
| 151 |
| 152 } |
| 153 |
109 NaClBrowser::NaClBrowser() | 154 NaClBrowser::NaClBrowser() |
110 : weak_factory_(this), | 155 : weak_factory_(this), |
111 irt_platform_file_(base::kInvalidPlatformFileValue), | 156 irt_platform_file_(base::kInvalidPlatformFileValue), |
112 irt_filepath_(), | 157 irt_filepath_(), |
113 irt_state_(NaClResourceUninitialized), | 158 irt_state_(NaClResourceUninitialized), |
114 debug_patterns_(), | 159 debug_patterns_(), |
115 inverse_debug_patterns_(false), | 160 inverse_debug_patterns_(false), |
116 validation_cache_file_path_(), | 161 validation_cache_file_path_(), |
117 validation_cache_is_enabled_( | 162 validation_cache_is_enabled_( |
118 CheckEnvVar("NACL_VALIDATION_CACHE", | 163 CheckEnvVar("NACL_VALIDATION_CACHE", |
119 kValidationCacheEnabledByDefault)), | 164 kValidationCacheEnabledByDefault)), |
120 validation_cache_is_modified_(false), | 165 validation_cache_is_modified_(false), |
121 validation_cache_state_(NaClResourceUninitialized), | 166 validation_cache_state_(NaClResourceUninitialized), |
| 167 path_cache_(kFilePathCacheSize), |
122 ok_(true) { | 168 ok_(true) { |
123 InitIrtFilePath(); | 169 InitIrtFilePath(); |
124 InitValidationCacheFilePath(); | 170 InitValidationCacheFilePath(); |
125 } | 171 } |
126 | 172 |
127 NaClBrowser::~NaClBrowser() { | 173 NaClBrowser::~NaClBrowser() { |
128 if (irt_platform_file_ != base::kInvalidPlatformFileValue) | 174 if (irt_platform_file_ != base::kInvalidPlatformFileValue) |
129 base::ClosePlatformFile(irt_platform_file_); | 175 base::ClosePlatformFile(irt_platform_file_); |
130 } | 176 } |
131 | 177 |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 void NaClBrowser::WaitForResources(const base::Closure& reply) { | 411 void NaClBrowser::WaitForResources(const base::Closure& reply) { |
366 waiting_.push_back(reply); | 412 waiting_.push_back(reply); |
367 EnsureAllResourcesAvailable(); | 413 EnsureAllResourcesAvailable(); |
368 CheckWaiting(); | 414 CheckWaiting(); |
369 } | 415 } |
370 | 416 |
371 const base::FilePath& NaClBrowser::GetIrtFilePath() { | 417 const base::FilePath& NaClBrowser::GetIrtFilePath() { |
372 return irt_filepath_; | 418 return irt_filepath_; |
373 } | 419 } |
374 | 420 |
| 421 void NaClBrowser::PutFilePath(const base::FilePath& path, uint64* file_token_lo, |
| 422 uint64* file_token_hi) { |
| 423 while (true) { |
| 424 uint64 file_token[2] = {base::RandUint64(), base::RandUint64()}; |
| 425 // A zero file_token indicates there is no file_token, if we get zero, ask |
| 426 // for another number. |
| 427 if (file_token[0] != 0 || file_token[1] != 0) { |
| 428 // If the file_token is in use, ask for another number. |
| 429 std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token)); |
| 430 PathCacheType::iterator iter = path_cache_.Peek(key); |
| 431 if (iter == path_cache_.end()) { |
| 432 path_cache_.Put(key, path); |
| 433 *file_token_lo = file_token[0]; |
| 434 *file_token_hi = file_token[1]; |
| 435 break; |
| 436 } |
| 437 } |
| 438 } |
| 439 } |
| 440 |
| 441 bool NaClBrowser::GetFilePath(uint64 file_token_lo, uint64 file_token_hi, |
| 442 base::FilePath* path) { |
| 443 uint64 file_token[2] = {file_token_lo, file_token_hi}; |
| 444 std::string key(reinterpret_cast<char*>(file_token), sizeof(file_token)); |
| 445 PathCacheType::iterator iter = path_cache_.Peek(key); |
| 446 if (iter == path_cache_.end()) { |
| 447 *path = base::FilePath(FILE_PATH_LITERAL("")); |
| 448 return false; |
| 449 } |
| 450 *path = iter->second; |
| 451 path_cache_.Erase(iter); |
| 452 return true; |
| 453 } |
| 454 |
| 455 |
375 bool NaClBrowser::QueryKnownToValidate(const std::string& signature, | 456 bool NaClBrowser::QueryKnownToValidate(const std::string& signature, |
376 bool off_the_record) { | 457 bool off_the_record) { |
377 if (off_the_record) { | 458 if (off_the_record) { |
378 // If we're off the record, don't reorder the main cache. | 459 // If we're off the record, don't reorder the main cache. |
379 return validation_cache_.QueryKnownToValidate(signature, false) || | 460 return validation_cache_.QueryKnownToValidate(signature, false) || |
380 off_the_record_validation_cache_.QueryKnownToValidate(signature, true); | 461 off_the_record_validation_cache_.QueryKnownToValidate(signature, true); |
381 } else { | 462 } else { |
382 bool result = validation_cache_.QueryKnownToValidate(signature, true); | 463 bool result = validation_cache_.QueryKnownToValidate(signature, true); |
383 LogCacheQuery(result ? CACHE_HIT : CACHE_MISS); | 464 LogCacheQuery(result ? CACHE_HIT : CACHE_MISS); |
384 // Queries can modify the MRU order of the cache. | 465 // Queries can modify the MRU order of the cache. |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 // because it can degrade the responsiveness of the browser. | 546 // because it can degrade the responsiveness of the browser. |
466 // The task is sequenced so that multiple writes happen in order. | 547 // The task is sequenced so that multiple writes happen in order. |
467 content::BrowserThread::PostBlockingPoolSequencedTask( | 548 content::BrowserThread::PostBlockingPoolSequencedTask( |
468 kValidationCacheSequenceName, | 549 kValidationCacheSequenceName, |
469 FROM_HERE, | 550 FROM_HERE, |
470 base::Bind(WriteCache, validation_cache_file_path_, | 551 base::Bind(WriteCache, validation_cache_file_path_, |
471 base::Owned(pickle))); | 552 base::Owned(pickle))); |
472 } | 553 } |
473 validation_cache_is_modified_ = false; | 554 validation_cache_is_modified_ = false; |
474 } | 555 } |
OLD | NEW |