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