Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(413)

Side by Side Diff: chrome/browser/policy/cloud/resource_cache.cc

Issue 23868021: Prepare ExternalPolicyDataUpdater and ResourceCache for blocking pool (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Re-uploading due to rietveld flake. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/policy/cloud/resource_cache.h" 5 #include "chrome/browser/policy/cloud/resource_cache.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/files/file_enumerator.h" 9 #include "base/files/file_enumerator.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/sequenced_task_runner.h"
11 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
12 13
13 namespace policy { 14 namespace policy {
14 15
15 namespace { 16 namespace {
16 17
17 // Verifies that |value| is not empty and encodes it into base64url format, 18 // Verifies that |value| is not empty and encodes it into base64url format,
18 // which is safe to use as a file name on all platforms. 19 // which is safe to use as a file name on all platforms.
19 bool Base64Encode(const std::string& value, std::string* encoded) { 20 bool Base64Encode(const std::string& value, std::string* encoded) {
20 DCHECK(!value.empty()); 21 DCHECK(!value.empty());
(...skipping 25 matching lines...) Expand all
46 // emtpy. 47 // emtpy.
47 bool Base64Decode(const std::string& encoded, std::string* value) { 48 bool Base64Decode(const std::string& encoded, std::string* value) {
48 std::string buffer; 49 std::string buffer;
49 ReplaceChars(encoded, "-", "+", &buffer); 50 ReplaceChars(encoded, "-", "+", &buffer);
50 ReplaceChars(buffer, "_", "/", &buffer); 51 ReplaceChars(buffer, "_", "/", &buffer);
51 return base::Base64Decode(buffer, value) && !value->empty(); 52 return base::Base64Decode(buffer, value) && !value->empty();
52 } 53 }
53 54
54 } // namespace 55 } // namespace
55 56
56 ResourceCache::ResourceCache(const base::FilePath& cache_dir) 57 ResourceCache::ResourceCache(
57 : cache_dir_(cache_dir) { 58 const base::FilePath& cache_dir,
58 // Allow the cache to be created in a different thread than the thread that is 59 scoped_refptr<base::SequencedTaskRunner> task_runner)
59 // going to use it. 60 : cache_dir_(cache_dir),
60 DetachFromThread(); 61 task_runner_(task_runner) {
61 } 62 }
62 63
63 ResourceCache::~ResourceCache() { 64 ResourceCache::~ResourceCache() {
64 DCHECK(CalledOnValidThread()); 65 DCHECK(task_runner_->RunsTasksOnCurrentThread());
65 } 66 }
66 67
67 bool ResourceCache::Store(const std::string& key, 68 bool ResourceCache::Store(const std::string& key,
68 const std::string& subkey, 69 const std::string& subkey,
69 const std::string& data) { 70 const std::string& data) {
70 DCHECK(CalledOnValidThread()); 71 DCHECK(task_runner_->RunsTasksOnCurrentThread());
71 base::FilePath subkey_path; 72 base::FilePath subkey_path;
72 // Delete the file before writing to it. This ensures that the write does not 73 // Delete the file before writing to it. This ensures that the write does not
73 // follow a symlink planted at |subkey_path|, clobbering a file outside the 74 // follow a symlink planted at |subkey_path|, clobbering a file outside the
74 // cache directory. The mechanism is meant to foil file-system-level attacks 75 // cache directory. The mechanism is meant to foil file-system-level attacks
75 // where a symlink is planted in the cache directory before Chrome has 76 // where a symlink is planted in the cache directory before Chrome has
76 // started. An attacker controlling a process running concurrently with Chrome 77 // started. An attacker controlling a process running concurrently with Chrome
77 // would be able to race against the protection by re-creating the symlink 78 // would be able to race against the protection by re-creating the symlink
78 // between these two calls. There is nothing in file_util that could be used 79 // between these two calls. There is nothing in file_util that could be used
79 // to protect against such races, especially as the cache is cross-platform 80 // to protect against such races, especially as the cache is cross-platform
80 // and therefore cannot use any POSIX-only tricks. 81 // and therefore cannot use any POSIX-only tricks.
81 return VerifyKeyPathAndGetSubkeyPath(key, true, subkey, &subkey_path) && 82 return VerifyKeyPathAndGetSubkeyPath(key, true, subkey, &subkey_path) &&
82 base::DeleteFile(subkey_path, false) && 83 base::DeleteFile(subkey_path, false) &&
83 file_util::WriteFile(subkey_path, data.data(), data.size()); 84 file_util::WriteFile(subkey_path, data.data(), data.size());
84 } 85 }
85 86
86 bool ResourceCache::Load(const std::string& key, 87 bool ResourceCache::Load(const std::string& key,
87 const std::string& subkey, 88 const std::string& subkey,
88 std::string* data) { 89 std::string* data) {
89 DCHECK(CalledOnValidThread()); 90 DCHECK(task_runner_->RunsTasksOnCurrentThread());
90 base::FilePath subkey_path; 91 base::FilePath subkey_path;
91 // Only read from |subkey_path| if it is not a symlink. 92 // Only read from |subkey_path| if it is not a symlink.
92 if (!VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path) || 93 if (!VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path) ||
93 file_util::IsLink(subkey_path)) { 94 file_util::IsLink(subkey_path)) {
94 return false; 95 return false;
95 } 96 }
96 data->clear(); 97 data->clear();
97 return base::ReadFileToString(subkey_path, data); 98 return base::ReadFileToString(subkey_path, data);
98 } 99 }
99 100
100 void ResourceCache::LoadAllSubkeys( 101 void ResourceCache::LoadAllSubkeys(
101 const std::string& key, 102 const std::string& key,
102 std::map<std::string, std::string>* contents) { 103 std::map<std::string, std::string>* contents) {
103 DCHECK(CalledOnValidThread()); 104 DCHECK(task_runner_->RunsTasksOnCurrentThread());
104 contents->clear(); 105 contents->clear();
105 base::FilePath key_path; 106 base::FilePath key_path;
106 if (!VerifyKeyPath(key, false, &key_path)) 107 if (!VerifyKeyPath(key, false, &key_path))
107 return; 108 return;
108 109
109 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); 110 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES);
110 for (base::FilePath path = enumerator.Next(); !path.empty(); 111 for (base::FilePath path = enumerator.Next(); !path.empty();
111 path = enumerator.Next()) { 112 path = enumerator.Next()) {
112 const std::string encoded_subkey = path.BaseName().MaybeAsASCII(); 113 const std::string encoded_subkey = path.BaseName().MaybeAsASCII();
113 std::string subkey; 114 std::string subkey;
114 std::string data; 115 std::string data;
115 // Only read from |subkey_path| if it is not a symlink and its name is 116 // Only read from |subkey_path| if it is not a symlink and its name is
116 // a base64-encoded string. 117 // a base64-encoded string.
117 if (!file_util::IsLink(path) && 118 if (!file_util::IsLink(path) &&
118 Base64Decode(encoded_subkey, &subkey) && 119 Base64Decode(encoded_subkey, &subkey) &&
119 base::ReadFileToString(path, &data)) { 120 base::ReadFileToString(path, &data)) {
120 (*contents)[subkey].swap(data); 121 (*contents)[subkey].swap(data);
121 } 122 }
122 } 123 }
123 } 124 }
124 125
125 void ResourceCache::Delete(const std::string& key, const std::string& subkey) { 126 void ResourceCache::Delete(const std::string& key, const std::string& subkey) {
126 DCHECK(CalledOnValidThread()); 127 DCHECK(task_runner_->RunsTasksOnCurrentThread());
127 base::FilePath subkey_path; 128 base::FilePath subkey_path;
128 if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path)) 129 if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path))
129 base::DeleteFile(subkey_path, false); 130 base::DeleteFile(subkey_path, false);
130 // Delete() does nothing if the directory given to it is not empty. Hence, the 131 // Delete() does nothing if the directory given to it is not empty. Hence, the
131 // call below deletes the directory representing |key| if its last subkey was 132 // call below deletes the directory representing |key| if its last subkey was
132 // just removed and does nothing otherwise. 133 // just removed and does nothing otherwise.
133 base::DeleteFile(subkey_path.DirName(), false); 134 base::DeleteFile(subkey_path.DirName(), false);
134 } 135 }
135 136
136 void ResourceCache::PurgeOtherKeys(const std::set<std::string>& keys_to_keep) { 137 void ResourceCache::PurgeOtherKeys(const std::set<std::string>& keys_to_keep) {
137 DCHECK(CalledOnValidThread()); 138 DCHECK(task_runner_->RunsTasksOnCurrentThread());
138 std::set<std::string> encoded_keys_to_keep; 139 std::set<std::string> encoded_keys_to_keep;
139 if (!Base64Encode(keys_to_keep, &encoded_keys_to_keep)) 140 if (!Base64Encode(keys_to_keep, &encoded_keys_to_keep))
140 return; 141 return;
141 142
142 base::FileEnumerator enumerator( 143 base::FileEnumerator enumerator(
143 cache_dir_, false, base::FileEnumerator::DIRECTORIES); 144 cache_dir_, false, base::FileEnumerator::DIRECTORIES);
144 for (base::FilePath path = enumerator.Next(); !path.empty(); 145 for (base::FilePath path = enumerator.Next(); !path.empty();
145 path = enumerator.Next()) { 146 path = enumerator.Next()) {
146 const std::string name(path.BaseName().MaybeAsASCII()); 147 const std::string name(path.BaseName().MaybeAsASCII());
147 if (encoded_keys_to_keep.find(name) == encoded_keys_to_keep.end()) 148 if (encoded_keys_to_keep.find(name) == encoded_keys_to_keep.end())
148 base::DeleteFile(path, true); 149 base::DeleteFile(path, true);
149 } 150 }
150 } 151 }
151 152
152 void ResourceCache::PurgeOtherSubkeys( 153 void ResourceCache::PurgeOtherSubkeys(
153 const std::string& key, 154 const std::string& key,
154 const std::set<std::string>& subkeys_to_keep) { 155 const std::set<std::string>& subkeys_to_keep) {
155 DCHECK(CalledOnValidThread()); 156 DCHECK(task_runner_->RunsTasksOnCurrentThread());
156 base::FilePath key_path; 157 base::FilePath key_path;
157 if (!VerifyKeyPath(key, false, &key_path)) 158 if (!VerifyKeyPath(key, false, &key_path))
158 return; 159 return;
159 160
160 std::set<std::string> encoded_subkeys_to_keep; 161 std::set<std::string> encoded_subkeys_to_keep;
161 if (!Base64Encode(subkeys_to_keep, &encoded_subkeys_to_keep)) 162 if (!Base64Encode(subkeys_to_keep, &encoded_subkeys_to_keep))
162 return; 163 return;
163 164
164 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); 165 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES);
165 for (base::FilePath path = enumerator.Next(); !path.empty(); 166 for (base::FilePath path = enumerator.Next(); !path.empty();
(...skipping 28 matching lines...) Expand all
194 if (!VerifyKeyPath(key, allow_create_key, &key_path) || 195 if (!VerifyKeyPath(key, allow_create_key, &key_path) ||
195 !Base64Encode(subkey, &encoded)) { 196 !Base64Encode(subkey, &encoded)) {
196 return false; 197 return false;
197 } 198 }
198 *path = key_path.AppendASCII(encoded); 199 *path = key_path.AppendASCII(encoded);
199 return true; 200 return true;
200 } 201 }
201 202
202 203
203 } // namespace policy 204 } // namespace policy
OLDNEW
« no previous file with comments | « chrome/browser/policy/cloud/resource_cache.h ('k') | chrome/browser/policy/cloud/resource_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698