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