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 5 #include "chrome/browser/nacl_host/nacl_validation_cache.h" 6 7 #include "base/pickle.h" 8 #include "base/rand_util.h" 9 10 namespace { 11 12 // For the moment, choose an arbitrary cache size. 13 const size_t kValidationCacheCacheSize = 200; 14 // Key size is equal to the block size (not the digest size) of SHA256. 15 const size_t kValidationCacheKeySize = 64; 16 // Entry size is equal to the digest size of SHA256. 17 const size_t kValidationCacheEntrySize = 32; 18 19 const char kValidationCacheBeginMagic[] = "NaCl"; 20 const char kValidationCacheEndMagic[] = "Done"; 21 22 } // namespace 23 24 NaClValidationCache::NaClValidationCache() 25 : validation_cache_(kValidationCacheCacheSize) { 26 // Make sure the cache key is unpredictable, even if the cache has not 27 // been loaded. 28 Reset(); 29 } 30 31 NaClValidationCache::~NaClValidationCache() { 32 // Make clang's style checking happy by adding a destructor. 33 } 34 35 bool NaClValidationCache::QueryKnownToValidate(const std::string& signature, 36 bool reorder) { 37 if (signature.length() == kValidationCacheEntrySize) { 38 ValidationCacheType::iterator iter; 39 if (reorder) { 40 iter = validation_cache_.Get(signature); 41 } else { 42 iter = validation_cache_.Peek(signature); 43 } 44 if (iter != validation_cache_.end()) { 45 return iter->second; 46 } 47 } 48 return false; 49 } 50 51 void NaClValidationCache::SetKnownToValidate(const std::string& signature) { 52 if (signature.length() == kValidationCacheEntrySize) { 53 validation_cache_.Put(signature, true); 54 } 55 } 56 57 void NaClValidationCache::Serialize(Pickle* pickle) const { 58 // Mark the beginning of the data stream. 59 pickle->WriteString(kValidationCacheBeginMagic); 60 pickle->WriteString(validation_cache_key_); 61 pickle->WriteInt(validation_cache_.size()); 62 63 // Serialize the cache in reverse order so that deserializing it can easily 64 // preserve the MRU order. (Last item deserialized => most recently used.) 65 ValidationCacheType::const_reverse_iterator iter; 66 for (iter = validation_cache_.rbegin(); 67 iter != validation_cache_.rend(); 68 ++iter) { 69 pickle->WriteString(iter->first); 70 } 71 72 // Mark the end of the data stream. 73 pickle->WriteString(kValidationCacheEndMagic); 74 } 75 76 void NaClValidationCache::Reset() { 77 validation_cache_key_ = base::RandBytesAsString(kValidationCacheKeySize); 78 validation_cache_.Clear(); 79 } 80 81 bool NaClValidationCache::Deserialize(const Pickle* pickle) { 82 bool success = DeserializeImpl(pickle); 83 if (!success) { 84 Reset(); 85 } 86 return success; 87 } 88 89 bool NaClValidationCache::DeserializeImpl(const Pickle* pickle) { 90 PickleIterator iter(*pickle); 91 std::string buffer; 92 int count; 93 94 // Magic 95 if (!iter.ReadString(&buffer)) 96 return false; 97 if (0 != buffer.compare(kValidationCacheBeginMagic)) 98 return false; 99 100 // Key 101 if (!iter.ReadString(&buffer)) 102 return false; 103 if (buffer.size() != kValidationCacheKeySize) 104 return false; 105 106 validation_cache_key_ = buffer; 107 validation_cache_.Clear(); 108 109 // Cache entries 110 if (!iter.ReadInt(&count)) 111 return false; 112 for (int i = 0; i < count; ++i) { 113 if (!iter.ReadString(&buffer)) 114 return false; 115 if (buffer.size() != kValidationCacheEntrySize) 116 return false; 117 validation_cache_.Put(buffer, true); 118 } 119 120 // Magic 121 if (!iter.ReadString(&buffer)) 122 return false; 123 if (0 != buffer.compare(kValidationCacheEndMagic)) 124 return false; 125 126 // Success! 127 return true; 128 } 129 130