1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/net/chrome_network_delegate.h"
6 
7 #include "base/base_paths.h"
8 #include "base/logging.h"
9 #include "base/path_service.h"
10 #include "build/build_config.h"
11 
12 #if defined(OS_ANDROID)
13 #include "base/android/path_utils.h"
14 #endif
15 
16 namespace {
17 
18 bool g_access_to_all_files_enabled = false;
19 
IsAccessAllowedInternal(const base::FilePath & path,const base::FilePath & profile_path)20 bool IsAccessAllowedInternal(const base::FilePath& path,
21                              const base::FilePath& profile_path) {
22   if (g_access_to_all_files_enabled)
23     return true;
24 
25 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
26   return true;
27 #else
28 
29   std::vector<base::FilePath> whitelist;
30 #if defined(OS_CHROMEOS)
31   // Use a whitelist to only allow access to files residing in the list of
32   // directories below.
33   static const base::FilePath::CharType* const kLocalAccessWhiteList[] = {
34       "/home/chronos/user/Downloads",
35       "/home/chronos/user/MyFiles",
36       "/home/chronos/user/log",
37       "/home/chronos/user/WebRTC Logs",
38       "/media",
39       "/opt/oem",
40       "/run/arc/sdcard/write/emulated/0",
41       "/usr/share/chromeos-assets",
42       "/var/log",
43   };
44 
45   base::FilePath temp_dir;
46   if (base::PathService::Get(base::DIR_TEMP, &temp_dir))
47     whitelist.push_back(temp_dir);
48 
49   // The actual location of "/home/chronos/user/Xyz" is the Xyz directory under
50   // the profile path ("/home/chronos/user' is a hard link to current primary
51   // logged in profile.) For the support of multi-profile sessions, we are
52   // switching to use explicit "$PROFILE_PATH/Xyz" path and here whitelist such
53   // access.
54   if (!profile_path.empty()) {
55     const base::FilePath downloads = profile_path.AppendASCII("Downloads");
56     whitelist.push_back(downloads);
57     whitelist.push_back(profile_path.AppendASCII("MyFiles"));
58     const base::FilePath webrtc_logs = profile_path.AppendASCII("WebRTC Logs");
59     whitelist.push_back(webrtc_logs);
60   }
61 #elif defined(OS_ANDROID)
62   // Access to files in external storage is allowed.
63   base::FilePath external_storage_path;
64   base::PathService::Get(base::DIR_ANDROID_EXTERNAL_STORAGE,
65                          &external_storage_path);
66   if (external_storage_path.IsParent(path))
67     return true;
68 
69   auto all_download_dirs = base::android::GetAllPrivateDownloadsDirectories();
70   for (const auto& dir : all_download_dirs)
71     whitelist.push_back(dir);
72 
73   // Whitelist of other allowed directories.
74   static const base::FilePath::CharType* const kLocalAccessWhiteList[] = {
75       "/sdcard", "/mnt/sdcard",
76   };
77 #endif
78 
79   for (const auto* whitelisted_path : kLocalAccessWhiteList)
80     whitelist.push_back(base::FilePath(whitelisted_path));
81 
82   for (const auto& whitelisted_path : whitelist) {
83     // base::FilePath::operator== should probably handle trailing separators.
84     if (whitelisted_path == path.StripTrailingSeparators() ||
85         whitelisted_path.IsParent(path)) {
86       return true;
87     }
88   }
89 
90 #if defined(OS_CHROMEOS)
91   // Allow access to DriveFS logs. These reside in
92   // $PROFILE_PATH/GCache/v2/<opaque id>/Logs.
93   base::FilePath path_within_gcache_v2;
94   if (profile_path.Append("GCache/v2")
95           .AppendRelativePath(path, &path_within_gcache_v2)) {
96     std::vector<std::string> components;
97     path_within_gcache_v2.GetComponents(&components);
98     if (components.size() > 1 && components[1] == "Logs") {
99       return true;
100     }
101   }
102 #endif  // defined(OS_CHROMEOS)
103 
104   DVLOG(1) << "File access denied - " << path.value().c_str();
105   return false;
106 #endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
107 }
108 
109 }  // namespace
110 
111 // static
IsAccessAllowed(const base::FilePath & path,const base::FilePath & profile_path)112 bool ChromeNetworkDelegate::IsAccessAllowed(
113     const base::FilePath& path,
114     const base::FilePath& profile_path) {
115   return IsAccessAllowedInternal(path, profile_path);
116 }
117 
118 // static
IsAccessAllowed(const base::FilePath & path,const base::FilePath & absolute_path,const base::FilePath & profile_path)119 bool ChromeNetworkDelegate::IsAccessAllowed(
120     const base::FilePath& path,
121     const base::FilePath& absolute_path,
122     const base::FilePath& profile_path) {
123 #if defined(OS_ANDROID)
124   // Android's whitelist relies on symbolic links (ex. /sdcard is whitelisted
125   // and commonly a symbolic link), thus do not check absolute paths.
126   return IsAccessAllowedInternal(path, profile_path);
127 #else
128   return (IsAccessAllowedInternal(path, profile_path) &&
129           IsAccessAllowedInternal(absolute_path, profile_path));
130 #endif
131 }
132 
133 // static
EnableAccessToAllFilesForTesting(bool enabled)134 void ChromeNetworkDelegate::EnableAccessToAllFilesForTesting(bool enabled) {
135   g_access_to_all_files_enabled = enabled;
136 }
137