| OLD | NEW |
| 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" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 // Delete the file before writing to it. This ensures that the write does not | 55 // Delete the file before writing to it. This ensures that the write does not |
| 56 // follow a symlink planted at |subkey_path|, clobbering a file outside the | 56 // follow a symlink planted at |subkey_path|, clobbering a file outside the |
| 57 // cache directory. The mechanism is meant to foil file-system-level attacks | 57 // cache directory. The mechanism is meant to foil file-system-level attacks |
| 58 // where a symlink is planted in the cache directory before Chrome has | 58 // where a symlink is planted in the cache directory before Chrome has |
| 59 // started. An attacker controlling a process running concurrently with Chrome | 59 // started. An attacker controlling a process running concurrently with Chrome |
| 60 // would be able to race against the protection by re-creating the symlink | 60 // would be able to race against the protection by re-creating the symlink |
| 61 // between these two calls. There is nothing in file_util that could be used | 61 // between these two calls. There is nothing in file_util that could be used |
| 62 // to protect against such races, especially as the cache is cross-platform | 62 // to protect against such races, especially as the cache is cross-platform |
| 63 // and therefore cannot use any POSIX-only tricks. | 63 // and therefore cannot use any POSIX-only tricks. |
| 64 return VerifyKeyPathAndGetSubkeyPath(key, true, subkey, &subkey_path) && | 64 return VerifyKeyPathAndGetSubkeyPath(key, true, subkey, &subkey_path) && |
| 65 base::Delete(subkey_path, false) && | 65 base::DeleteFile(subkey_path, false) && |
| 66 file_util::WriteFile(subkey_path, data.data(), data.size()); | 66 file_util::WriteFile(subkey_path, data.data(), data.size()); |
| 67 } | 67 } |
| 68 | 68 |
| 69 bool ResourceCache::Load(const std::string& key, | 69 bool ResourceCache::Load(const std::string& key, |
| 70 const std::string& subkey, | 70 const std::string& subkey, |
| 71 std::string* data) { | 71 std::string* data) { |
| 72 DCHECK(CalledOnValidThread()); | 72 DCHECK(CalledOnValidThread()); |
| 73 base::FilePath subkey_path; | 73 base::FilePath subkey_path; |
| 74 // Only read from |subkey_path| if it is not a symlink. | 74 // Only read from |subkey_path| if it is not a symlink. |
| 75 if (!VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path) || | 75 if (!VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path) || |
| (...skipping 26 matching lines...) Expand all Loading... |
| 102 file_util::ReadFileToString(path, &data)) { | 102 file_util::ReadFileToString(path, &data)) { |
| 103 (*contents)[subkey].swap(data); | 103 (*contents)[subkey].swap(data); |
| 104 } | 104 } |
| 105 } | 105 } |
| 106 } | 106 } |
| 107 | 107 |
| 108 void ResourceCache::Delete(const std::string& key, const std::string& subkey) { | 108 void ResourceCache::Delete(const std::string& key, const std::string& subkey) { |
| 109 DCHECK(CalledOnValidThread()); | 109 DCHECK(CalledOnValidThread()); |
| 110 base::FilePath subkey_path; | 110 base::FilePath subkey_path; |
| 111 if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path)) | 111 if (VerifyKeyPathAndGetSubkeyPath(key, false, subkey, &subkey_path)) |
| 112 base::Delete(subkey_path, false); | 112 base::DeleteFile(subkey_path, false); |
| 113 // Delete() does nothing if the directory given to it is not empty. Hence, the | 113 // Delete() does nothing if the directory given to it is not empty. Hence, the |
| 114 // call below deletes the directory representing |key| if its last subkey was | 114 // call below deletes the directory representing |key| if its last subkey was |
| 115 // just removed and does nothing otherwise. | 115 // just removed and does nothing otherwise. |
| 116 base::Delete(subkey_path.DirName(), false); | 116 base::DeleteFile(subkey_path.DirName(), false); |
| 117 } | 117 } |
| 118 | 118 |
| 119 void ResourceCache::PurgeOtherSubkeys( | 119 void ResourceCache::PurgeOtherSubkeys( |
| 120 const std::string& key, | 120 const std::string& key, |
| 121 const std::set<std::string>& subkeys_to_keep) { | 121 const std::set<std::string>& subkeys_to_keep) { |
| 122 DCHECK(CalledOnValidThread()); | 122 DCHECK(CalledOnValidThread()); |
| 123 base::FilePath key_path; | 123 base::FilePath key_path; |
| 124 if (!VerifyKeyPath(key, false, &key_path)) | 124 if (!VerifyKeyPath(key, false, &key_path)) |
| 125 return; | 125 return; |
| 126 | 126 |
| 127 std::set<std::string> encoded_subkeys_to_keep; | 127 std::set<std::string> encoded_subkeys_to_keep; |
| 128 for (std::set<std::string>::const_iterator it = subkeys_to_keep.begin(); | 128 for (std::set<std::string>::const_iterator it = subkeys_to_keep.begin(); |
| 129 it != subkeys_to_keep.end(); ++it) { | 129 it != subkeys_to_keep.end(); ++it) { |
| 130 std::string encoded; | 130 std::string encoded; |
| 131 if (!Base64Encode(*it, &encoded)) | 131 if (!Base64Encode(*it, &encoded)) |
| 132 return; | 132 return; |
| 133 encoded_subkeys_to_keep.insert(encoded); | 133 encoded_subkeys_to_keep.insert(encoded); |
| 134 } | 134 } |
| 135 | 135 |
| 136 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); | 136 base::FileEnumerator enumerator(key_path, false, base::FileEnumerator::FILES); |
| 137 for (base::FilePath path = enumerator.Next(); !path.empty(); | 137 for (base::FilePath path = enumerator.Next(); !path.empty(); |
| 138 path = enumerator.Next()) { | 138 path = enumerator.Next()) { |
| 139 const std::string name(path.BaseName().MaybeAsASCII()); | 139 const std::string name(path.BaseName().MaybeAsASCII()); |
| 140 if (encoded_subkeys_to_keep.find(name) == encoded_subkeys_to_keep.end()) | 140 if (encoded_subkeys_to_keep.find(name) == encoded_subkeys_to_keep.end()) |
| 141 base::Delete(path, false); | 141 base::DeleteFile(path, false); |
| 142 } | 142 } |
| 143 // Delete() does nothing if the directory given to it is not empty. Hence, the | 143 // Delete() does nothing if the directory given to it is not empty. Hence, the |
| 144 // call below deletes the directory representing |key| if all of its subkeys | 144 // call below deletes the directory representing |key| if all of its subkeys |
| 145 // were just removed and does nothing otherwise. | 145 // were just removed and does nothing otherwise. |
| 146 base::Delete(key_path, false); | 146 base::DeleteFile(key_path, false); |
| 147 } | 147 } |
| 148 | 148 |
| 149 bool ResourceCache::VerifyKeyPath(const std::string& key, | 149 bool ResourceCache::VerifyKeyPath(const std::string& key, |
| 150 bool allow_create, | 150 bool allow_create, |
| 151 base::FilePath* path) { | 151 base::FilePath* path) { |
| 152 std::string encoded; | 152 std::string encoded; |
| 153 if (!Base64Encode(key, &encoded)) | 153 if (!Base64Encode(key, &encoded)) |
| 154 return false; | 154 return false; |
| 155 *path = cache_dir_.AppendASCII(encoded); | 155 *path = cache_dir_.AppendASCII(encoded); |
| 156 return allow_create ? file_util::CreateDirectory(*path) : | 156 return allow_create ? file_util::CreateDirectory(*path) : |
| 157 base::DirectoryExists(*path); | 157 base::DirectoryExists(*path); |
| 158 } | 158 } |
| 159 | 159 |
| 160 bool ResourceCache::VerifyKeyPathAndGetSubkeyPath(const std::string& key, | 160 bool ResourceCache::VerifyKeyPathAndGetSubkeyPath(const std::string& key, |
| 161 bool allow_create_key, | 161 bool allow_create_key, |
| 162 const std::string& subkey, | 162 const std::string& subkey, |
| 163 base::FilePath* path) { | 163 base::FilePath* path) { |
| 164 base::FilePath key_path; | 164 base::FilePath key_path; |
| 165 std::string encoded; | 165 std::string encoded; |
| 166 if (!VerifyKeyPath(key, allow_create_key, &key_path) || | 166 if (!VerifyKeyPath(key, allow_create_key, &key_path) || |
| 167 !Base64Encode(subkey, &encoded)) { | 167 !Base64Encode(subkey, &encoded)) { |
| 168 return false; | 168 return false; |
| 169 } | 169 } |
| 170 *path = key_path.AppendASCII(encoded); | 170 *path = key_path.AppendASCII(encoded); |
| 171 return true; | 171 return true; |
| 172 } | 172 } |
| 173 | 173 |
| 174 | 174 |
| 175 } // namespace policy | 175 } // namespace policy |
| OLD | NEW |