pref_hash_store_impl.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright 2013 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. #include "services/preferences/tracked/pref_hash_store_impl.h"
  5. #include <stddef.h>
  6. #include <utility>
  7. #include "base/check.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/metrics/histogram_macros.h"
  10. #include "base/no_destructor.h"
  11. #include "base/notreached.h"
  12. #include "services/preferences/tracked/device_id.h"
  13. #include "services/preferences/tracked/hash_store_contents.h"
  14. namespace {
  15. using ValueState =
  16. prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
  17. // Returns a deterministic ID for this machine.
  18. std::string GenerateDeviceId() {
  19. static base::NoDestructor<std::string> cached_device_id;
  20. if (!cached_device_id->empty())
  21. return *cached_device_id;
  22. std::string device_id;
  23. MachineIdStatus status = GetDeterministicMachineSpecificId(&device_id);
  24. DCHECK(status == MachineIdStatus::NOT_IMPLEMENTED ||
  25. status == MachineIdStatus::SUCCESS);
  26. if (status == MachineIdStatus::SUCCESS) {
  27. *cached_device_id = device_id;
  28. return device_id;
  29. }
  30. return std::string();
  31. }
  32. } // namespace
  33. class PrefHashStoreImpl::PrefHashStoreTransactionImpl
  34. : public PrefHashStoreTransaction {
  35. public:
  36. // Constructs a PrefHashStoreTransactionImpl which can use the private
  37. // members of its |outer| PrefHashStoreImpl.
  38. PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer,
  39. HashStoreContents* storage);
  40. PrefHashStoreTransactionImpl(const PrefHashStoreTransactionImpl&) = delete;
  41. PrefHashStoreTransactionImpl& operator=(const PrefHashStoreTransactionImpl&) =
  42. delete;
  43. ~PrefHashStoreTransactionImpl() override;
  44. // PrefHashStoreTransaction implementation.
  45. base::StringPiece GetStoreUMASuffix() const override;
  46. ValueState CheckValue(const std::string& path,
  47. const base::Value* value) const override;
  48. void StoreHash(const std::string& path, const base::Value* value) override;
  49. ValueState CheckSplitValue(
  50. const std::string& path,
  51. const base::DictionaryValue* initial_split_value,
  52. std::vector<std::string>* invalid_keys) const override;
  53. void StoreSplitHash(const std::string& path,
  54. const base::DictionaryValue* split_value) override;
  55. bool HasHash(const std::string& path) const override;
  56. void ImportHash(const std::string& path, const base::Value* hash) override;
  57. void ClearHash(const std::string& path) override;
  58. bool IsSuperMACValid() const override;
  59. bool StampSuperMac() override;
  60. private:
  61. raw_ptr<PrefHashStoreImpl> outer_;
  62. raw_ptr<HashStoreContents> contents_;
  63. bool super_mac_valid_;
  64. bool super_mac_dirty_;
  65. };
  66. PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
  67. const std::string& legacy_device_id,
  68. bool use_super_mac)
  69. : pref_hash_calculator_(seed, GenerateDeviceId(), legacy_device_id),
  70. use_super_mac_(use_super_mac) {}
  71. PrefHashStoreImpl::~PrefHashStoreImpl() {}
  72. std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
  73. HashStoreContents* storage) {
  74. return std::unique_ptr<PrefHashStoreTransaction>(
  75. new PrefHashStoreTransactionImpl(this, storage));
  76. }
  77. std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
  78. const base::Value* value) {
  79. return pref_hash_calculator_.Calculate(path, value);
  80. }
  81. std::unique_ptr<base::DictionaryValue> PrefHashStoreImpl::ComputeSplitMacs(
  82. const std::string& path,
  83. const base::DictionaryValue* split_values) {
  84. if (!split_values)
  85. return std::make_unique<base::DictionaryValue>();
  86. std::string keyed_path(path);
  87. keyed_path.push_back('.');
  88. const size_t common_part_length = keyed_path.length();
  89. std::unique_ptr<base::DictionaryValue> split_macs(new base::DictionaryValue);
  90. for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
  91. it.Advance()) {
  92. // Keep the common part from the old |keyed_path| and replace the key to
  93. // get the new |keyed_path|.
  94. keyed_path.replace(common_part_length, std::string::npos, it.key());
  95. split_macs->SetKey(it.key(),
  96. base::Value(ComputeMac(keyed_path, &it.value())));
  97. }
  98. return split_macs;
  99. }
  100. PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
  101. PrefHashStoreImpl* outer,
  102. HashStoreContents* storage)
  103. : outer_(outer),
  104. contents_(storage),
  105. super_mac_valid_(false),
  106. super_mac_dirty_(false) {
  107. if (!outer_->use_super_mac_)
  108. return;
  109. // The store must have a valid super MAC to be trusted.
  110. std::string super_mac = contents_->GetSuperMac();
  111. if (super_mac.empty())
  112. return;
  113. super_mac_valid_ =
  114. outer_->pref_hash_calculator_.Validate(
  115. "", contents_->GetContents(), super_mac) == PrefHashCalculator::VALID;
  116. }
  117. PrefHashStoreImpl::PrefHashStoreTransactionImpl::
  118. ~PrefHashStoreTransactionImpl() {
  119. if (super_mac_dirty_ && outer_->use_super_mac_) {
  120. // Get the dictionary of hashes (or NULL if it doesn't exist).
  121. const base::DictionaryValue* hashes_dict = contents_->GetContents();
  122. contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict));
  123. }
  124. }
  125. base::StringPiece
  126. PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const {
  127. return contents_->GetUMASuffix();
  128. }
  129. ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
  130. const std::string& path,
  131. const base::Value* initial_value) const {
  132. std::string last_hash;
  133. contents_->GetMac(path, &last_hash);
  134. if (last_hash.empty()) {
  135. // In the absence of a hash for this pref, always trust a NULL value, but
  136. // only trust an existing value if the initial hashes dictionary is trusted.
  137. if (!initial_value)
  138. return ValueState::TRUSTED_NULL_VALUE;
  139. else if (super_mac_valid_)
  140. return ValueState::TRUSTED_UNKNOWN_VALUE;
  141. else
  142. return ValueState::UNTRUSTED_UNKNOWN_VALUE;
  143. }
  144. PrefHashCalculator::ValidationResult validation_result =
  145. outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash);
  146. switch (validation_result) {
  147. case PrefHashCalculator::VALID:
  148. return ValueState::UNCHANGED;
  149. case PrefHashCalculator::VALID_SECURE_LEGACY:
  150. return ValueState::SECURE_LEGACY;
  151. case PrefHashCalculator::INVALID:
  152. return initial_value ? ValueState::CHANGED : ValueState::CLEARED;
  153. }
  154. NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
  155. << validation_result;
  156. return ValueState::UNTRUSTED_UNKNOWN_VALUE;
  157. }
  158. void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
  159. const std::string& path,
  160. const base::Value* new_value) {
  161. const std::string mac = outer_->ComputeMac(path, new_value);
  162. contents_->SetMac(path, mac);
  163. super_mac_dirty_ = true;
  164. }
  165. ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
  166. const std::string& path,
  167. const base::DictionaryValue* initial_split_value,
  168. std::vector<std::string>* invalid_keys) const {
  169. DCHECK(invalid_keys && invalid_keys->empty());
  170. std::map<std::string, std::string> split_macs;
  171. const bool has_hashes = contents_->GetSplitMacs(path, &split_macs);
  172. // Treat NULL and empty the same; otherwise we would need to store a hash for
  173. // the entire dictionary (or some other special beacon) to differentiate these
  174. // two cases which are really the same for dictionaries.
  175. if (!initial_split_value || initial_split_value->DictEmpty())
  176. return has_hashes ? ValueState::CLEARED : ValueState::UNCHANGED;
  177. if (!has_hashes)
  178. return super_mac_valid_ ? ValueState::TRUSTED_UNKNOWN_VALUE
  179. : ValueState::UNTRUSTED_UNKNOWN_VALUE;
  180. bool has_secure_legacy_id_hashes = false;
  181. std::string keyed_path(path);
  182. keyed_path.push_back('.');
  183. const size_t common_part_length = keyed_path.length();
  184. for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd();
  185. it.Advance()) {
  186. std::map<std::string, std::string>::iterator entry =
  187. split_macs.find(it.key());
  188. if (entry == split_macs.end()) {
  189. invalid_keys->push_back(it.key());
  190. } else {
  191. // Keep the common part from the old |keyed_path| and replace the key to
  192. // get the new |keyed_path|.
  193. keyed_path.replace(common_part_length, std::string::npos, it.key());
  194. switch (outer_->pref_hash_calculator_.Validate(keyed_path, &it.value(),
  195. entry->second)) {
  196. case PrefHashCalculator::VALID:
  197. break;
  198. case PrefHashCalculator::VALID_SECURE_LEGACY:
  199. // Secure legacy device IDs based hashes are still accepted, but we
  200. // should make sure to notify the caller for them to update the legacy
  201. // hashes.
  202. has_secure_legacy_id_hashes = true;
  203. break;
  204. case PrefHashCalculator::INVALID:
  205. invalid_keys->push_back(it.key());
  206. break;
  207. }
  208. // Remove processed MACs, remaining MACs at the end will also be
  209. // considered invalid.
  210. split_macs.erase(entry);
  211. }
  212. }
  213. // Anything left in the map is missing from the data.
  214. for (std::map<std::string, std::string>::const_iterator it =
  215. split_macs.begin();
  216. it != split_macs.end(); ++it) {
  217. invalid_keys->push_back(it->first);
  218. }
  219. return invalid_keys->empty()
  220. ? (has_secure_legacy_id_hashes ? ValueState::SECURE_LEGACY
  221. : ValueState::UNCHANGED)
  222. : ValueState::CHANGED;
  223. }
  224. void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
  225. const std::string& path,
  226. const base::DictionaryValue* split_value) {
  227. contents_->RemoveEntry(path);
  228. if (split_value) {
  229. std::unique_ptr<base::DictionaryValue> split_macs =
  230. outer_->ComputeSplitMacs(path, split_value);
  231. for (base::DictionaryValue::Iterator it(*split_macs); !it.IsAtEnd();
  232. it.Advance()) {
  233. DCHECK(it.value().is_string());
  234. contents_->SetSplitMac(path, it.key(), it.value().GetString());
  235. }
  236. }
  237. super_mac_dirty_ = true;
  238. }
  239. bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash(
  240. const std::string& path) const {
  241. std::string out_value;
  242. std::map<std::string, std::string> out_values;
  243. return contents_->GetMac(path, &out_value) ||
  244. contents_->GetSplitMacs(path, &out_values);
  245. }
  246. void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
  247. const std::string& path,
  248. const base::Value* hash) {
  249. DCHECK(hash);
  250. contents_->ImportEntry(path, hash);
  251. if (super_mac_valid_)
  252. super_mac_dirty_ = true;
  253. }
  254. void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash(
  255. const std::string& path) {
  256. if (contents_->RemoveEntry(path) && super_mac_valid_) {
  257. super_mac_dirty_ = true;
  258. }
  259. }
  260. bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const {
  261. return super_mac_valid_;
  262. }
  263. bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() {
  264. if (!outer_->use_super_mac_ || super_mac_valid_)
  265. return false;
  266. super_mac_dirty_ = true;
  267. return true;
  268. }