Index: ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
index bcf636254aa907ded1866aa8ca97aca6ee42fc4a..d26a97568009ed1d6e0b82e72019550d2547592e 100644 |
--- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc |
@@ -365,6 +365,11 @@ PnaclCoordinator::PnaclCoordinator( |
static_cast<void*>(this), static_cast<void*>(plugin))); |
callback_factory_.Initialize(this); |
ld_manifest_.reset(new PnaclLDManifest(plugin_->manifest(), manifest_.get())); |
+ pp::Module *module = pp::Module::Get(); |
+ DCHECK(module); |
+ nacl_hash_private_interface_ = static_cast<const PPB_NaCl_Hash_Private*>( |
+ module->GetBrowserInterface(PPB_NACL_HASH_PRIVATE_INTERFACE)); |
+ bitcode_hash_verifier_ = nacl_hash_private_interface_->CreateSHA256Hasher(); |
} |
PnaclCoordinator::~PnaclCoordinator() { |
@@ -379,6 +384,7 @@ PnaclCoordinator::~PnaclCoordinator() { |
if (translate_thread_.get() != NULL) { |
translate_thread_->AbortSubprocesses(); |
} |
+ nacl_hash_private_interface_->Delete(bitcode_hash_verifier_); |
} |
void PnaclCoordinator::ReportNonPpapiError(enum PluginErrorCode err_code, |
@@ -470,13 +476,20 @@ void PnaclCoordinator::TranslateFinished(int32_t pp_error) { |
if (pnacl_options_.HasCacheKey() && cached_nexe_file_ != NULL) { |
// We are using a cache, but had a cache miss, which is why we did the |
- // translation. Reset cached_nexe_file_ to have a random name, |
- // for scratch purposes, before renaming to the final cache_identity. |
- cached_nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), |
- nacl::string(kPnaclTempDir))); |
- pp::CompletionCallback cb = callback_factory_.NewCallback( |
- &PnaclCoordinator::CachedNexeOpenedForWrite); |
- cached_nexe_file_->OpenWrite(cb); |
+ // translation. |
+ if (BitcodeHashMatchesContents()) { |
+ // Reset cached_nexe_file_ to have a random name, for scratch purposes, |
+ // before renaming to the final cache_identity. |
+ cached_nexe_file_.reset(new LocalTempFile(plugin_, file_system_.get(), |
+ nacl::string(kPnaclTempDir))); |
+ pp::CompletionCallback cb = callback_factory_.NewCallback( |
+ &PnaclCoordinator::CachedNexeOpenedForWrite); |
+ cached_nexe_file_->OpenWrite(cb); |
+ } else { |
+ ReportNonPpapiError( |
+ ERROR_PNACL_CACHE_HASH_MISMATCH, |
+ "Bitcode hash does not match bitcode contents."); |
+ } |
} else { |
// For now, tolerate bitcode that is missing a cache identity, and |
// tolerate the lack of caching in incognito mode. |
@@ -485,6 +498,31 @@ void PnaclCoordinator::TranslateFinished(int32_t pp_error) { |
} |
} |
+bool PnaclCoordinator::BitcodeHashMatchesContents() { |
+ const nacl::string& expected_hash = pnacl_options_.GetBitcodeHash(); |
+ nacl::string actual_hash; |
+ uint8_t hash_digest[32]; |
+ nacl_hash_private_interface_->Finish(bitcode_hash_verifier_, |
+ &hash_digest, |
+ sizeof hash_digest); |
+ // Convert 32-byte binary digest to 64-byte hex digest for comparison. |
+ for (size_t i = 0; i < sizeof hash_digest; i+=8) { |
+ char buf[17]; // do 16 chars + a null byte at a time. |
+ SNPRINTF(buf, sizeof buf, "%02x%02x%02x%02x%02x%02x%02x%02x", |
+ hash_digest[i ], hash_digest[i+1], |
+ hash_digest[i+2], hash_digest[i+3], |
+ hash_digest[i+4], hash_digest[i+5], |
+ hash_digest[i+6], hash_digest[i+7]); |
+ actual_hash.append(buf); |
+ } |
+ if (expected_hash.size() != actual_hash.size()) { |
+ return false; |
+ } |
+ return nacl_hash_private_interface_->SecureMemEqual(expected_hash.c_str(), |
+ actual_hash.c_str(), |
+ expected_hash.size()); |
+} |
+ |
void PnaclCoordinator::CachedNexeOpenedForWrite(int32_t pp_error) { |
if (pp_error != PP_OK) { |
if (pp_error == PP_ERROR_NOACCESS) { |
@@ -910,11 +948,17 @@ void PnaclCoordinator::BitcodeStreamGotData(int32_t pp_error, |
PLUGIN_PRINTF(("PnaclCoordinator::BitcodeStreamGotData (pp_error=%" |
NACL_PRId32", data=%p)\n", pp_error, data ? &(*data)[0] : 0)); |
DCHECK(translate_thread_.get()); |
- translate_thread_->PutBytes(data, pp_error); |
// If pp_error > 0, then it represents the number of bytes received. |
- if (data && pp_error > 0) { |
+ if (pp_error > 0) { |
pexe_size_ += pp_error; |
+ // Update hash for verification before data is taken by PutBytes. |
+ if (pnacl_options_.HasCacheKey()) { |
+ nacl_hash_private_interface_->Update(bitcode_hash_verifier_, |
+ &(*data)[0], |
+ pp_error); |
+ } |
} |
+ translate_thread_->PutBytes(data, pp_error); |
} |
StreamCallback PnaclCoordinator::GetCallback() { |