security/sandbox/chromium/base/path_service.cc

changeset 0
6474c204b198
     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 +}

mercurial