1 // Copyright 2013 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 #ifndef COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_ 6 #define COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_ 7 8 #include <deque> 9 10 #include "base/bind.h" 11 #include "base/containers/mru_cache.h" 12 #include "base/files/file.h" 13 #include "base/memory/singleton.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/time/time.h" 16 #include "components/nacl/browser/nacl_browser_delegate.h" 17 #include "components/nacl/browser/nacl_validation_cache.h" 18 19 class URLPattern; 20 class GURL; 21 22 namespace base { 23 class FileProxy; 24 } 25 26 namespace nacl { 27 28 static const int kGdbDebugStubPortUnknown = -1; 29 static const int kGdbDebugStubPortUnused = 0; 30 31 // Open an immutable executable file that can be mmapped (or a read-only file). 32 // This function should only be called on a thread that can perform file IO. 33 base::File OpenNaClReadExecImpl(const base::FilePath& file_path, 34 bool is_executable); 35 36 // Represents shared state for all NaClProcessHost objects in the browser. 37 class NaClBrowser { 38 public: 39 static NaClBrowser* GetInstance(); 40 41 // Will it be possible to launch a NaCl process, eventually? 42 bool IsOk() const; 43 44 // Are we ready to launch a NaCl process now? Implies IsOk(). 45 bool IsReady() const; 46 47 // Attempt to asynchronously acquire all resources needed to start a process. 48 // This method is idempotent - it is safe to call multiple times. 49 void EnsureAllResourcesAvailable(); 50 51 // Enqueues reply() in the message loop when all the resources needed to start 52 // a process have been acquired. 53 void WaitForResources(const base::Closure& reply); 54 55 // Asynchronously attempt to get the IRT open. 56 // This is entailed by EnsureInitialized. This method is exposed as part of 57 // the public interface, however, so the IRT can be explicitly opened as 58 // early as possible to prevent autoupdate issues. 59 void EnsureIrtAvailable(); 60 61 // Path to IRT. Available even before IRT is loaded. 62 const base::FilePath& GetIrtFilePath(); 63 64 // IRT file handle, only available when IsReady(). 65 const base::File& IrtFile() const; 66 67 // Methods for testing GDB debug stub in browser. If test adds debug stub 68 // port listener, Chrome will allocate a currently-unused TCP port number for 69 // debug stub server instead of a fixed one. 70 71 // Notify listener that new debug stub TCP port is allocated. 72 void SetProcessGdbDebugStubPort(int process_id, int port); 73 void SetGdbDebugStubPortListener(base::Callback<void(int)> listener); 74 void ClearGdbDebugStubPortListener(); 75 76 int GetProcessGdbDebugStubPort(int process_id); 77 78 enum ValidationCacheStatus { 79 CACHE_MISS = 0, 80 CACHE_HIT, 81 CACHE_MAX 82 }; 83 84 bool ValidationCacheIsEnabled() const { 85 return validation_cache_is_enabled_; 86 } 87 88 const std::string& GetValidationCacheKey() const { 89 return validation_cache_.GetValidationCacheKey(); 90 } 91 92 // The NaCl singleton keeps information about NaCl executable files opened via 93 // PPAPI. This allows the NaCl process to get trusted information about the 94 // file directly from the browser process. In theory, a compromised renderer 95 // could provide a writable file handle or lie about the file's path. If we 96 // trusted the handle was read only but it was not, an mmapped file could be 97 // modified after validation, allowing an escape from the NaCl sandbox. 98 // Similarly, if we trusted the file path corresponded to the file handle but 99 // it did not, the validation cache could be tricked into bypassing validation 100 // for bad code. 101 // Instead of allowing these attacks, the NaCl process only trusts information 102 // it gets directly from the browser process. Because the information is 103 // stored in a cache of bounded size, it is not guaranteed the browser process 104 // will be able to provide the requested information. In these cases, the 105 // NaCl process must make conservative assumptions about the origin of the 106 // file. 107 // In theory, a compromised renderer could guess file tokens in an attempt to 108 // read files it normally doesn't have access to. This would not compromise 109 // the NaCl sandbox, however, and only has a 1 in ~2**120 chance of success 110 // per guess. 111 // TODO(ncbray): move the cache onto NaClProcessHost so that we don't need to 112 // rely on tokens being unguessable by another process. 113 void PutFilePath(const base::FilePath& path, uint64* file_token_lo, 114 uint64* file_token_hi); 115 bool GetFilePath(uint64 file_token_lo, uint64 file_token_hi, 116 base::FilePath* path); 117 118 bool QueryKnownToValidate(const std::string& signature, bool off_the_record); 119 void SetKnownToValidate(const std::string& signature, bool off_the_record); 120 void ClearValidationCache(const base::Closure& callback); 121 #if defined(OS_WIN) 122 // Get path to NaCl loader on the filesystem if possible. 123 // |exe_path| does not change if the method fails. 124 bool GetNaCl64ExePath(base::FilePath* exe_path); 125 #endif 126 127 void EarlyStartup(); 128 static void SetDelegate(NaClBrowserDelegate* delegate); 129 static NaClBrowserDelegate* GetDelegate(); 130 131 // Each time a NaCl process ends, the browser is notified. 132 void OnProcessEnd(int process_id); 133 // Support for NaCl crash throttling. 134 // Each time a NaCl module crashes, the browser is notified. 135 void OnProcessCrashed(); 136 // If "too many" crashes occur within a given time period, NaCl is throttled 137 // until the rate again drops below the threshold. 138 bool IsThrottled(); 139 140 private: 141 friend struct DefaultSingletonTraits<NaClBrowser>; 142 143 enum NaClResourceState { 144 NaClResourceUninitialized, 145 NaClResourceRequested, 146 NaClResourceReady 147 }; 148 149 NaClBrowser(); 150 ~NaClBrowser(); 151 152 void InitIrtFilePath(); 153 154 void OpenIrtLibraryFile(); 155 156 void OnIrtOpened(scoped_ptr<base::FileProxy> file_proxy, 157 base::File::Error error_code); 158 159 void InitValidationCacheFilePath(); 160 void EnsureValidationCacheAvailable(); 161 void OnValidationCacheLoaded(const std::string* data); 162 void RunWithoutValidationCache(); 163 164 // Dispatch waiting tasks if we are ready, or if we know we'll never be ready. 165 void CheckWaiting(); 166 167 // Indicate that it is impossible to launch a NaCl process. 168 void MarkAsFailed(); 169 170 void MarkValidationCacheAsModified(); 171 void PersistValidationCache(); 172 173 174 base::File irt_file_; 175 base::FilePath irt_filepath_; 176 NaClResourceState irt_state_; 177 NaClValidationCache validation_cache_; 178 NaClValidationCache off_the_record_validation_cache_; 179 base::FilePath validation_cache_file_path_; 180 bool validation_cache_is_enabled_; 181 bool validation_cache_is_modified_; 182 NaClResourceState validation_cache_state_; 183 base::Callback<void(int)> debug_stub_port_listener_; 184 185 // Map from process id to debug stub port if any. 186 typedef std::map<int, int> GdbDebugStubPortMap; 187 GdbDebugStubPortMap gdb_debug_stub_port_map_; 188 189 typedef base::HashingMRUCache<std::string, base::FilePath> PathCacheType; 190 PathCacheType path_cache_; 191 192 bool ok_; 193 194 // A list of pending tasks to start NaCl processes. 195 std::vector<base::Closure> waiting_; 196 197 scoped_ptr<NaClBrowserDelegate> browser_delegate_; 198 199 std::deque<base::Time> crash_times_; 200 201 // Singletons get destroyed at shutdown. 202 base::WeakPtrFactory<NaClBrowser> weak_factory_; 203 204 DISALLOW_COPY_AND_ASSIGN(NaClBrowser); 205 }; 206 207 } // namespace nacl 208 209 #endif // COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_ 210