1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// 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 COMPONENTS_POLICY_CORE_COMMON_CLOUD_RESOURCE_CACHE_H_
#define COMPONENTS_POLICY_CORE_COMMON_CLOUD_RESOURCE_CACHE_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "components/policy/policy_export.h"
namespace base {
class SequencedTaskRunner;
}
namespace policy {
// Manages storage of data at a given path. The data is keyed by a key and
// a subkey, and can be queried by (key, subkey) or (key) lookups.
// The contents of the cache have to be manually cleared using Delete() or
// Purge*().
// The class can be instantiated on any thread but from then on, it must be
// accessed via the |task_runner| only. The |task_runner| must support file I/O.
// The class needs to have exclusive control on cache directory since it should
// know about all files changes for correct recalculating cache directory size.
class POLICY_EXPORT ResourceCache {
public:
ResourceCache(const base::FilePath& cache_path,
scoped_refptr<base::SequencedTaskRunner> task_runner,
const std::optional<int64_t> max_cache_size);
ResourceCache(const ResourceCache&) = delete;
ResourceCache& operator=(const ResourceCache&) = delete;
virtual ~ResourceCache();
// Stores |data| under (key, subkey). Returns file path if the store
// succeeded, and empty FilePath otherwise.
base::FilePath Store(const std::string& key,
const std::string& subkey,
const std::string& data);
// Loads the contents of (key, subkey) into |data| and returns true. Returns
// empty FilePath if (key, subkey) isn't found or if there is a problem
// reading the data, and file path otherwise.
base::FilePath Load(const std::string& key,
const std::string& subkey,
std::string* data);
// Loads all the subkeys of |key| into |contents|.
void LoadAllSubkeys(const std::string& key,
std::map<std::string, std::string>* contents);
// Deletes (key, subkey).
void Delete(const std::string& key, const std::string& subkey);
// Deletes all the subkeys of |key|.
void Clear(const std::string& key);
// Deletes the subkeys of |key| for which the |filter| returns true.
typedef base::RepeatingCallback<bool(const std::string&)> SubkeyFilter;
void FilterSubkeys(const std::string& key, const SubkeyFilter& filter);
// Deletes all keys not in |keys_to_keep|, along with their subkeys.
void PurgeOtherKeys(const std::set<std::string>& keys_to_keep);
// Deletes all the subkeys of |key| not in |subkeys_to_keep|.
void PurgeOtherSubkeys(const std::string& key,
const std::set<std::string>& subkeys_to_keep);
private:
// Points |path| at the cache directory for |key| and returns whether the
// directory exists. If |allow_create| is |true|, the directory is created if
// it did not exist yet.
bool VerifyKeyPath(const std::string& key,
bool allow_create,
base::FilePath* path);
// Points |subkey_path| at the file in which data for (key, subkey) should be
// stored and returns whether the parent directory of this file exists. If
// |allow_create_key| is |true|, the directory is created if it did not exist
// yet. This method does not check whether the file at |subkey_path| exists or
// not.
bool VerifyKeyPathAndGetSubkeyPath(const std::string& key,
bool allow_create_key,
const std::string& subkey,
base::FilePath* subkey_path);
// Initializes |current_cache_size_| with the size of cache directory.
// It's called once from constructor and is executed in provided
// |task_runner_|.
void InitCurrentCacheSize();
// Writes the given data into the file in the cache directory and updates
// |current_cache_size_| accordingly.
// Deletes the file before writing to it. This ensures that the write does not
// follow a symlink planted at |subkey_path|, clobbering a file outside the
// cache directory. The mechanism is meant to foil file-system-level attacks
// where a symlink is planted in the cache directory before Chrome has
// started. An attacker controlling a process running concurrently with Chrome
// would be able to race against the protection by re-creating the symlink
// between these two calls. There is nothing in file_util that could be used
// to protect against such races, especially as the cache is cross-platform
// and therefore cannot use any POSIX-only tricks.
// Note that |path| must belong to |cache_dir_|.
bool WriteCacheFile(const base::FilePath& path, const std::string& data);
// Deletes the given path in the cache directory and updates
// |current_cache_size_| accordingly.
// Note that |path| must belong to |cache_dir_|.
bool DeleteCacheFile(const base::FilePath& path, bool recursive);
// Returns the size of given directory or file in the cache directory skipping
// symlinks or 0 if any error occurred.
// We couldn't use |base::ComputeDirectorySize| here because it doesn't allow
// to skip symlinks.
// Skipping symlinks is important here to prevent exploit which puts symlink
// to e.g. root directory and freezes this thread since traversing the whole
// filesystem takes a while.
// Note that |path| must belong to |cache_dir_|.
int64_t GetCacheDirectoryOrFileSize(const base::FilePath& path) const;
base::FilePath cache_dir_;
// Task runner that |this| runs on.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// Maximum size of the cache directory.
const std::optional<int64_t> max_cache_size_;
// Note that this variable could be created on any thread, but is modified
// only on the |task_runner_| thread.
int64_t current_cache_size_;
};
} // namespace policy
#endif // COMPONENTS_POLICY_CORE_COMMON_CLOUD_RESOURCE_CACHE_H_
|