blob: 38aa98f3c74f869d47524e3d6727f03bd9430256 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_PREFERENCES_TRACKED_PREF_HASH_FILTER_H_
#define SERVICES_PREFERENCES_TRACKED_PREF_HASH_FILTER_H_
#include <stddef.h>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "base/compiler_specific.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/deferred_sequenced_task_runner.h"
#include "base/values.h"
#include "components/prefs/transparent_unordered_string_map.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/preferences/tracked/hash_store_contents.h"
#include "services/preferences/tracked/interceptable_pref_filter.h"
#include "services/preferences/tracked/pref_hash_store.h"
#include "services/preferences/tracked/tracked_preference.h"
class PrefService;
namespace base {
class Time;
} // namespace base
namespace prefs::mojom {
class TrackedPreferenceValidationDelegate;
}
namespace user_prefs {
class PrefRegistrySyncable;
} // namespace user_prefs
// Intercepts preference values as they are loaded from disk and verifies them
// using a PrefHashStore. Keeps the PrefHashStore contents up to date as values
// are changed.
class PrefHashFilter final : public InterceptablePrefFilter {
public:
using StoreContentsPair = std::pair<std::unique_ptr<PrefHashStore>,
std::unique_ptr<HashStoreContents>>;
// A map from changed paths to their corresponding TrackedPreferences (which
// aren't owned by this map).
using ChangedPathsMap =
std::map<std::string, raw_ptr<const TrackedPreference, CtnExperimental>>;
// Constructs a PrefHashFilter tracking the specified |tracked_preferences|
// using |pref_hash_store| to check/store hashes. An optional |delegate| is
// notified of the status of each preference as it is checked.
// If |reset_on_load_observer| is provided, it will be notified if a reset
// occurs in FilterOnLoad.
// |reporting_ids_count| is the count of all possible IDs (possibly greater
// than |tracked_preferences.size()|).
// |external_validation_hash_store_pair_| will be used (if non-null) to
// perform extra validations without triggering resets.
// |os_crypt| provides an asynchronous interface to OS-level encryption for
// storing an additional encrypted hash if kEncryptedPrefHashing is enabled.
// The encryptor could be null on start-up but it will be retrieved
// asynchronously.
PrefHashFilter(
std::unique_ptr<PrefHashStore> pref_hash_store,
StoreContentsPair external_validation_hash_store_pair_,
const std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>&
tracked_preferences,
mojo::PendingRemote<prefs::mojom::ResetOnLoadObserver>
reset_on_load_observer,
scoped_refptr<base::RefCountedData<
mojo::Remote<prefs::mojom::TrackedPreferenceValidationDelegate>>>
delegate,
size_t reporting_ids_count,
os_crypt_async::OSCryptAsync* os_crypt);
PrefHashFilter(const PrefHashFilter&) = delete;
PrefHashFilter& operator=(const PrefHashFilter&) = delete;
~PrefHashFilter() override;
// Registers required user preferences.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// Retrieves the time of the last reset event, if any, for the provided user
// preferences. If no reset has occurred, Returns a null |Time|.
static base::Time GetResetTime(PrefService* user_prefs);
// Clears the time of the last reset event, if any, for the provided user
// preferences.
static void ClearResetTime(PrefService* user_prefs);
// Sets the time of the last reset event to now.
static void SetResetTime(PrefService* user_prefs);
// Initializes the PrefHashStore with hashes of the tracked preferences in
// |pref_store_contents|. |pref_store_contents| will be the |storage| passed
// to PrefHashStore::BeginTransaction().
void Initialize(base::Value::Dict& pref_store_contents);
// PrefFilter remaining implementation.
void FilterUpdate(std::string_view path) override;
OnWriteCallbackPair FilterSerializeData(
base::Value::Dict& pref_store_contents) override;
void OnStoreDeletionFromDisk() override;
static void SetDeprecatedPrefsForTesting(
const std::vector<const char*>& deprecated_prefs);
// Sets a callback to be run for testing purposes when deferred revalidation
// is complete.
void SetOnDeferredRevalidationCompleteForTesting(base::OnceClosure callback);
// Sets the PrefService that owns this filter. This must be called after
// construction and before any deferred tasks can run that might need it.
void SetPrefService(PrefService* pref_service) override;
private:
// InterceptablePrefFilter implementation.
void FinalizeFilterOnLoad(
PostFilterOnLoadCallback post_filter_on_load_callback,
base::Value::Dict pref_store_contents,
bool prefs_altered) override;
base::WeakPtr<InterceptablePrefFilter> AsWeakPtr() override;
// Helper function to generate FilterSerializeData()'s pre-write and
// post-write callbacks. The returned callbacks are thread-safe.
OnWriteCallbackPair GetOnWriteSynchronousCallbacks(
base::Value::Dict& pref_store_contents);
// Clears the MACs contained in |external_validation_hash_store_contents|
// which are present in |paths_to_clear|.
static void ClearFromExternalStore(
HashStoreContents* external_validation_hash_store_contents,
const base::Value::Dict* changed_paths_and_macs);
// Flushes the MACs contained in |changed_paths_and_mac| to
// external_hash_store_contents if |write_success|, otherwise discards the
// changes.
static void FlushToExternalStore(
std::unique_ptr<HashStoreContents> external_hash_store_contents,
std::unique_ptr<base::Value::Dict> changed_paths_and_macs,
bool write_success);
void OnEncryptorReceived(os_crypt_async::Encryptor encryptor) override;
// Performs the deferred work of re-validating preferences after the
// encryptor has been fetched. This is posted from FinalizeFilterOnLoad.
void DeferredEncryptorRevalidation(
base::Value::Dict pref_store_contents_at_load);
// Callback to be invoked only once (and subsequently reset) on the next
// FilterOnLoad event. It will be allowed to modify the |prefs| handed to
// FilterOnLoad before handing them back to this PrefHashFilter.
FilterOnLoadInterceptor filter_on_load_interceptor_;
// A map of paths to TrackedPreferences; this map owns this individual
// TrackedPreference objects.
using TrackedPreferencesMap =
TransparentUnorderedStringMap<std::unique_ptr<TrackedPreference>>;
std::unique_ptr<PrefHashStore> pref_hash_store_;
// A store and contents on which to perform extra validations without
// triggering resets.
// Will be null if the platform does not support external validation.
std::optional<StoreContentsPair> external_validation_hash_store_pair_;
// Notified if a reset occurs in a call to FilterOnLoad.
mojo::Remote<prefs::mojom::ResetOnLoadObserver> reset_on_load_observer_;
scoped_refptr<base::RefCountedData<
mojo::Remote<prefs::mojom::TrackedPreferenceValidationDelegate>>>
delegate_;
TrackedPreferencesMap tracked_paths_;
// The set of all paths whose value has changed since the last call to
// FilterSerializeData.
ChangedPathsMap changed_paths_;
// A deferred task runner to defer and start the async encryptor related
// validation task.
scoped_refptr<base::DeferredSequencedTaskRunner> deferred_task_runner_;
SEQUENCE_CHECKER(sequence_checker_);
// A raw pointer to the PrefService that owns this filter. This is safe
// because the PrefService is guaranteed to outlive this filter.
raw_ptr<PrefService> pref_service_ = nullptr;
const bool encrypted_hashing_enabled_;
std::optional<os_crypt_async::Encryptor> encryptor_
GUARDED_BY_CONTEXT(sequence_checker_);
// A callback to be run for testing purposes when deferred revalidation is
// complete.
base::OnceClosure on_deferred_revalidation_complete_for_testing_;
base::WeakPtrFactory<PrefHashFilter> weak_ptr_factory_{this};
};
#endif // SERVICES_PREFERENCES_TRACKED_PREF_HASH_FILTER_H_