1 // Copyright 2013 The Chromium Authors 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 <stdint.h> 9 10 #include <memory> 11 12 #include "base/containers/circular_deque.h" 13 #include "base/containers/lru_cache.h" 14 #include "base/files/file.h" 15 #include "base/functional/bind.h" 16 #include "base/task/sequenced_task_runner.h" 17 #include "base/task/thread_pool.h" 18 #include "base/time/time.h" 19 #include "build/build_config.h" 20 #include "components/nacl/browser/nacl_browser_delegate.h" 21 #include "components/nacl/browser/nacl_validation_cache.h" 22 23 namespace base { 24 class FileProxy; 25 } 26 27 namespace nacl { 28 29 static const int kGdbDebugStubPortUnknown = -1; 30 static const int kGdbDebugStubPortUnused = 0; 31 32 // Keep the cache bounded to an arbitrary size. If it's too small, useful 33 // entries could be evicted when multiple .nexes are loaded at once. On the 34 // other hand, entries are not always claimed (and hence removed), so the size 35 // of the cache will likely saturate at its maximum size. 36 // Entries may not be claimed for two main reasons. 1) the NaCl process could 37 // be killed while it is loading. 2) the trusted NaCl plugin opens files using 38 // the code path but doesn't resolve them. 39 // TODO(ncbray) don't cache files that the plugin will not resolve. 40 static const int kFilePathCacheSize = 100; 41 42 // Open an immutable executable file that can be mmapped (or a read-only file). 43 // This function should only be called on a thread that can perform file IO. 44 base::File OpenNaClReadExecImpl(const base::FilePath& file_path, 45 bool is_executable); 46 47 // Represents shared state for all NaClProcessHost objects in the browser. 48 class NaClBrowser { 49 public: 50 static NaClBrowser* GetInstance(); 51 52 NaClBrowser(const NaClBrowser&) = delete; 53 NaClBrowser& operator=(const NaClBrowser&) = delete; 54 55 // Will it be possible to launch a NaCl process, eventually? 56 bool IsOk() const; 57 58 // Are we ready to launch a NaCl process now? Implies IsOk(). 59 bool IsReady() const; 60 61 // Attempt to asynchronously acquire all resources needed to start a process. 62 // This method is idempotent - it is safe to call multiple times. 63 void EnsureAllResourcesAvailable(); 64 65 // Enqueues reply() in the message loop when all the resources needed to start 66 // a process have been acquired. 67 void WaitForResources(base::OnceClosure reply); 68 69 // Asynchronously attempt to get the IRT open. 70 // This is entailed by EnsureInitialized. This method is exposed as part of 71 // the public interface, however, so the IRT can be explicitly opened as 72 // early as possible to prevent autoupdate issues. 73 void EnsureIrtAvailable(); 74 75 // Path to IRT. Available even before IRT is loaded. 76 const base::FilePath& GetIrtFilePath(); 77 78 // IRT file handle, only available when IsReady(). 79 const base::File& IrtFile() const; 80 81 // Methods for tracking the GDB debug stub port associated with each NaCl 82 // process. 83 void SetProcessGdbDebugStubPort(int process_id, int port); 84 int GetProcessGdbDebugStubPort(int process_id); 85 86 // While a test has a GDB debug port callback set, Chrome will allocate a 87 // currently-unused TCP port to the debug stub server, instead of a fixed 88 // one. 89 static void SetGdbDebugStubPortListenerForTest( 90 base::RepeatingCallback<void(int)> listener); 91 static void ClearGdbDebugStubPortListenerForTest(); 92 93 enum ValidationCacheStatus { 94 CACHE_MISS = 0, 95 CACHE_HIT, 96 CACHE_MAX 97 }; 98 ValidationCacheIsEnabled()99 bool ValidationCacheIsEnabled() const { 100 return validation_cache_is_enabled_; 101 } 102 GetValidationCacheKey()103 const std::string& GetValidationCacheKey() const { 104 return validation_cache_.GetValidationCacheKey(); 105 } 106 107 // The instance keeps information about NaCl executable files opened via 108 // PPAPI. This allows the NaCl process to get trusted information about the 109 // file directly from the browser process. In theory, a compromised renderer 110 // could provide a writable file handle or lie about the file's path. If we 111 // trusted the handle was read only but it was not, an mmapped file could be 112 // modified after validation, allowing an escape from the NaCl sandbox. 113 // Similarly, if we trusted the file path corresponded to the file handle but 114 // it did not, the validation cache could be tricked into bypassing validation 115 // for bad code. 116 // Instead of allowing these attacks, the NaCl process only trusts information 117 // it gets directly from the browser process. Because the information is 118 // stored in a cache of bounded size, it is not guaranteed the browser process 119 // will be able to provide the requested information. In these cases, the 120 // NaCl process must make conservative assumptions about the origin of the 121 // file. 122 // In theory, a compromised renderer could guess file tokens in an attempt to 123 // read files it normally doesn't have access to. This would not compromise 124 // the NaCl sandbox, however, and only has a 1 in ~2**120 chance of success 125 // per guess. 126 // TODO(ncbray): move the cache onto NaClProcessHost so that we don't need to 127 // rely on tokens being unguessable by another process. 128 void PutFilePath(const base::FilePath& path, 129 uint64_t* file_token_lo, 130 uint64_t* file_token_hi); 131 bool GetFilePath(uint64_t file_token_lo, 132 uint64_t file_token_hi, 133 base::FilePath* path); 134 135 bool QueryKnownToValidate(const std::string& signature, bool off_the_record); 136 void SetKnownToValidate(const std::string& signature, bool off_the_record); 137 void ClearValidationCache(base::OnceClosure callback); 138 139 void EarlyStartup(); 140 141 // Set/get the NaClBrowserDelegate. The |delegate| must be set at startup, 142 // from the Browser's UI thread. It will be leaked at browser teardown. 143 static void SetDelegate(std::unique_ptr<NaClBrowserDelegate> delegate); 144 static NaClBrowserDelegate* GetDelegate(); 145 static void ClearAndDeleteDelegate(); 146 147 // Called whenever a NaCl process exits. 148 void OnProcessEnd(int process_id); 149 150 // Called whenever a NaCl process crashes, before OnProcessEnd(). 151 void OnProcessCrashed(); 152 153 // If "too many" crashes occur within a given time period, NaCl is throttled 154 // until the rate again drops below the threshold. 155 bool IsThrottled(); 156 157 private: 158 enum NaClResourceState { 159 NaClResourceUninitialized, 160 NaClResourceRequested, 161 NaClResourceReady 162 }; 163 164 static NaClBrowser* GetInstanceInternal(); 165 166 NaClBrowser(); 167 ~NaClBrowser(); 168 169 void InitIrtFilePath(); 170 171 void OpenIrtLibraryFile(); 172 173 void OnIrtOpened(std::unique_ptr<base::FileProxy> file_proxy, 174 base::File::Error error_code); 175 176 void InitValidationCacheFilePath(); 177 void EnsureValidationCacheAvailable(); 178 void OnValidationCacheLoaded(const std::string* data); 179 void RunWithoutValidationCache(); 180 181 // Dispatch waiting tasks if we are ready, or if we know we'll never be ready. 182 void CheckWaiting(); 183 184 // Indicate that it is impossible to launch a NaCl process. 185 void MarkAsFailed(); 186 187 void MarkValidationCacheAsModified(); 188 void PersistValidationCache(); 189 190 base::File irt_file_; 191 base::FilePath irt_filepath_; 192 NaClResourceState irt_state_ = NaClResourceUninitialized; 193 NaClValidationCache validation_cache_; 194 NaClValidationCache off_the_record_validation_cache_; 195 base::FilePath validation_cache_file_path_; 196 bool validation_cache_is_enabled_ = false; 197 bool validation_cache_is_modified_ = false; 198 NaClResourceState validation_cache_state_ = NaClResourceUninitialized; 199 base::RepeatingCallback<void(int)> debug_stub_port_listener_; 200 201 // Map from process id to debug stub port if any. 202 typedef std::map<int, int> GdbDebugStubPortMap; 203 GdbDebugStubPortMap gdb_debug_stub_port_map_; 204 205 typedef base::HashingLRUCache<std::string, base::FilePath> PathCacheType; 206 PathCacheType path_cache_{kFilePathCacheSize}; 207 208 // True if it is no longer possible to launch NaCl processes. 209 bool has_failed_ = false; 210 211 // A list of pending tasks to start NaCl processes. 212 std::vector<base::OnceClosure> waiting_; 213 214 base::circular_deque<base::Time> crash_times_; 215 216 scoped_refptr<base::SequencedTaskRunner> file_task_runner_ = 217 base::ThreadPool::CreateSequencedTaskRunner( 218 {base::MayBlock(), base::TaskPriority::USER_VISIBLE}); 219 }; 220 221 } // namespace nacl 222 223 #endif // COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_ 224