1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/path_service.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,336 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/path_service.h" 1.9 + 1.10 +#if defined(OS_WIN) 1.11 +#include <windows.h> 1.12 +#include <shellapi.h> 1.13 +#include <shlobj.h> 1.14 +#endif 1.15 + 1.16 +#include "base/containers/hash_tables.h" 1.17 +#include "base/file_util.h" 1.18 +#include "base/files/file_path.h" 1.19 +#include "base/lazy_instance.h" 1.20 +#include "base/logging.h" 1.21 +#include "base/synchronization/lock.h" 1.22 + 1.23 +using base::FilePath; 1.24 +using base::MakeAbsoluteFilePath; 1.25 + 1.26 +namespace base { 1.27 + bool PathProvider(int key, FilePath* result); 1.28 +#if defined(OS_WIN) 1.29 + bool PathProviderWin(int key, FilePath* result); 1.30 +#elif defined(OS_MACOSX) 1.31 + bool PathProviderMac(int key, FilePath* result); 1.32 +#elif defined(OS_ANDROID) 1.33 + bool PathProviderAndroid(int key, FilePath* result); 1.34 +#elif defined(OS_POSIX) 1.35 + // PathProviderPosix is the default path provider on POSIX OSes other than 1.36 + // Mac and Android. 1.37 + bool PathProviderPosix(int key, FilePath* result); 1.38 +#endif 1.39 +} 1.40 + 1.41 +namespace { 1.42 + 1.43 +typedef base::hash_map<int, FilePath> PathMap; 1.44 + 1.45 +// We keep a linked list of providers. In a debug build we ensure that no two 1.46 +// providers claim overlapping keys. 1.47 +struct Provider { 1.48 + PathService::ProviderFunc func; 1.49 + struct Provider* next; 1.50 +#ifndef NDEBUG 1.51 + int key_start; 1.52 + int key_end; 1.53 +#endif 1.54 + bool is_static; 1.55 +}; 1.56 + 1.57 +Provider base_provider = { 1.58 + base::PathProvider, 1.59 + NULL, 1.60 +#ifndef NDEBUG 1.61 + base::PATH_START, 1.62 + base::PATH_END, 1.63 +#endif 1.64 + true 1.65 +}; 1.66 + 1.67 +#if defined(OS_WIN) 1.68 +Provider base_provider_win = { 1.69 + base::PathProviderWin, 1.70 + &base_provider, 1.71 +#ifndef NDEBUG 1.72 + base::PATH_WIN_START, 1.73 + base::PATH_WIN_END, 1.74 +#endif 1.75 + true 1.76 +}; 1.77 +#endif 1.78 + 1.79 +#if defined(OS_MACOSX) 1.80 +Provider base_provider_mac = { 1.81 + base::PathProviderMac, 1.82 + &base_provider, 1.83 +#ifndef NDEBUG 1.84 + base::PATH_MAC_START, 1.85 + base::PATH_MAC_END, 1.86 +#endif 1.87 + true 1.88 +}; 1.89 +#endif 1.90 + 1.91 +#if defined(OS_ANDROID) 1.92 +Provider base_provider_android = { 1.93 + base::PathProviderAndroid, 1.94 + &base_provider, 1.95 +#ifndef NDEBUG 1.96 + base::PATH_ANDROID_START, 1.97 + base::PATH_ANDROID_END, 1.98 +#endif 1.99 + true 1.100 +}; 1.101 +#endif 1.102 + 1.103 +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 1.104 +Provider base_provider_posix = { 1.105 + base::PathProviderPosix, 1.106 + &base_provider, 1.107 +#ifndef NDEBUG 1.108 + base::PATH_POSIX_START, 1.109 + base::PATH_POSIX_END, 1.110 +#endif 1.111 + true 1.112 +}; 1.113 +#endif 1.114 + 1.115 + 1.116 +struct PathData { 1.117 + base::Lock lock; 1.118 + PathMap cache; // Cache mappings from path key to path value. 1.119 + PathMap overrides; // Track path overrides. 1.120 + Provider* providers; // Linked list of path service providers. 1.121 + bool cache_disabled; // Don't use cache if true; 1.122 + 1.123 + PathData() : cache_disabled(false) { 1.124 +#if defined(OS_WIN) 1.125 + providers = &base_provider_win; 1.126 +#elif defined(OS_MACOSX) 1.127 + providers = &base_provider_mac; 1.128 +#elif defined(OS_ANDROID) 1.129 + providers = &base_provider_android; 1.130 +#elif defined(OS_POSIX) 1.131 + providers = &base_provider_posix; 1.132 +#endif 1.133 + } 1.134 + 1.135 + ~PathData() { 1.136 + Provider* p = providers; 1.137 + while (p) { 1.138 + Provider* next = p->next; 1.139 + if (!p->is_static) 1.140 + delete p; 1.141 + p = next; 1.142 + } 1.143 + } 1.144 +}; 1.145 + 1.146 +static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER; 1.147 + 1.148 +static PathData* GetPathData() { 1.149 + return g_path_data.Pointer(); 1.150 +} 1.151 + 1.152 +// Tries to find |key| in the cache. |path_data| should be locked by the caller! 1.153 +bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) { 1.154 + if (path_data->cache_disabled) 1.155 + return false; 1.156 + // check for a cached version 1.157 + PathMap::const_iterator it = path_data->cache.find(key); 1.158 + if (it != path_data->cache.end()) { 1.159 + *result = it->second; 1.160 + return true; 1.161 + } 1.162 + return false; 1.163 +} 1.164 + 1.165 +// Tries to find |key| in the overrides map. |path_data| should be locked by the 1.166 +// caller! 1.167 +bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) { 1.168 + // check for an overridden version. 1.169 + PathMap::const_iterator it = path_data->overrides.find(key); 1.170 + if (it != path_data->overrides.end()) { 1.171 + if (!path_data->cache_disabled) 1.172 + path_data->cache[key] = it->second; 1.173 + *result = it->second; 1.174 + return true; 1.175 + } 1.176 + return false; 1.177 +} 1.178 + 1.179 +} // namespace 1.180 + 1.181 +// TODO(brettw): this function does not handle long paths (filename > MAX_PATH) 1.182 +// characters). This isn't supported very well by Windows right now, so it is 1.183 +// moot, but we should keep this in mind for the future. 1.184 +// static 1.185 +bool PathService::Get(int key, FilePath* result) { 1.186 + PathData* path_data = GetPathData(); 1.187 + DCHECK(path_data); 1.188 + DCHECK(result); 1.189 + DCHECK_GE(key, base::DIR_CURRENT); 1.190 + 1.191 + // special case the current directory because it can never be cached 1.192 + if (key == base::DIR_CURRENT) 1.193 + return file_util::GetCurrentDirectory(result); 1.194 + 1.195 + Provider* provider = NULL; 1.196 + { 1.197 + base::AutoLock scoped_lock(path_data->lock); 1.198 + if (LockedGetFromCache(key, path_data, result)) 1.199 + return true; 1.200 + 1.201 + if (LockedGetFromOverrides(key, path_data, result)) 1.202 + return true; 1.203 + 1.204 + // Get the beginning of the list while it is still locked. 1.205 + provider = path_data->providers; 1.206 + } 1.207 + 1.208 + FilePath path; 1.209 + 1.210 + // Iterating does not need the lock because only the list head might be 1.211 + // modified on another thread. 1.212 + while (provider) { 1.213 + if (provider->func(key, &path)) 1.214 + break; 1.215 + DCHECK(path.empty()) << "provider should not have modified path"; 1.216 + provider = provider->next; 1.217 + } 1.218 + 1.219 + if (path.empty()) 1.220 + return false; 1.221 + 1.222 + if (path.ReferencesParent()) { 1.223 + // Make sure path service never returns a path with ".." in it. 1.224 + path = MakeAbsoluteFilePath(path); 1.225 + if (path.empty()) 1.226 + return false; 1.227 + } 1.228 + *result = path; 1.229 + 1.230 + base::AutoLock scoped_lock(path_data->lock); 1.231 + if (!path_data->cache_disabled) 1.232 + path_data->cache[key] = path; 1.233 + 1.234 + return true; 1.235 +} 1.236 + 1.237 +// static 1.238 +bool PathService::Override(int key, const FilePath& path) { 1.239 + // Just call the full function with true for the value of |create|. 1.240 + return OverrideAndCreateIfNeeded(key, path, true); 1.241 +} 1.242 + 1.243 +// static 1.244 +bool PathService::OverrideAndCreateIfNeeded(int key, 1.245 + const FilePath& path, 1.246 + bool create) { 1.247 + PathData* path_data = GetPathData(); 1.248 + DCHECK(path_data); 1.249 + DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key"; 1.250 + 1.251 + FilePath file_path = path; 1.252 + 1.253 + // For some locations this will fail if called from inside the sandbox there- 1.254 + // fore we protect this call with a flag. 1.255 + if (create) { 1.256 + // Make sure the directory exists. We need to do this before we translate 1.257 + // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails 1.258 + // if called on a non-existent path. 1.259 + if (!base::PathExists(file_path) && 1.260 + !file_util::CreateDirectory(file_path)) 1.261 + return false; 1.262 + } 1.263 + 1.264 + // We need to have an absolute path. 1.265 + file_path = MakeAbsoluteFilePath(file_path); 1.266 + if (file_path.empty()) 1.267 + return false; 1.268 + 1.269 + base::AutoLock scoped_lock(path_data->lock); 1.270 + 1.271 + // Clear the cache now. Some of its entries could have depended 1.272 + // on the value we are overriding, and are now out of sync with reality. 1.273 + path_data->cache.clear(); 1.274 + 1.275 + path_data->overrides[key] = file_path; 1.276 + 1.277 + return true; 1.278 +} 1.279 + 1.280 +// static 1.281 +bool PathService::RemoveOverride(int key) { 1.282 + PathData* path_data = GetPathData(); 1.283 + DCHECK(path_data); 1.284 + 1.285 + base::AutoLock scoped_lock(path_data->lock); 1.286 + 1.287 + if (path_data->overrides.find(key) == path_data->overrides.end()) 1.288 + return false; 1.289 + 1.290 + // Clear the cache now. Some of its entries could have depended on the value 1.291 + // we are going to remove, and are now out of sync. 1.292 + path_data->cache.clear(); 1.293 + 1.294 + path_data->overrides.erase(key); 1.295 + 1.296 + return true; 1.297 +} 1.298 + 1.299 +// static 1.300 +void PathService::RegisterProvider(ProviderFunc func, int key_start, 1.301 + int key_end) { 1.302 + PathData* path_data = GetPathData(); 1.303 + DCHECK(path_data); 1.304 + DCHECK_GT(key_end, key_start); 1.305 + 1.306 + Provider* p; 1.307 + 1.308 + p = new Provider; 1.309 + p->is_static = false; 1.310 + p->func = func; 1.311 +#ifndef NDEBUG 1.312 + p->key_start = key_start; 1.313 + p->key_end = key_end; 1.314 +#endif 1.315 + 1.316 + base::AutoLock scoped_lock(path_data->lock); 1.317 + 1.318 +#ifndef NDEBUG 1.319 + Provider *iter = path_data->providers; 1.320 + while (iter) { 1.321 + DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) << 1.322 + "path provider collision"; 1.323 + iter = iter->next; 1.324 + } 1.325 +#endif 1.326 + 1.327 + p->next = path_data->providers; 1.328 + path_data->providers = p; 1.329 +} 1.330 + 1.331 +// static 1.332 +void PathService::DisableCache() { 1.333 + PathData* path_data = GetPathData(); 1.334 + DCHECK(path_data); 1.335 + 1.336 + base::AutoLock scoped_lock(path_data->lock); 1.337 + path_data->cache.clear(); 1.338 + path_data->cache_disabled = true; 1.339 +}