• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if BUILDFLAG(IS_WIN)
139   // Get path to NaCl loader on the filesystem if possible.
140   // |exe_path| does not change if the method fails.
141   bool GetNaCl64ExePath(base::FilePath* exe_path);
142 #endif
143 
144   void EarlyStartup();
145 
146   // Set/get the NaClBrowserDelegate. The |delegate| must be set at startup,
147   // from the Browser's UI thread. It will be leaked at browser teardown.
148   static void SetDelegate(std::unique_ptr<NaClBrowserDelegate> delegate);
149   static NaClBrowserDelegate* GetDelegate();
150   static void ClearAndDeleteDelegateForTest();
151 
152   // Called whenever a NaCl process exits.
153   void OnProcessEnd(int process_id);
154 
155   // Called whenever a NaCl process crashes, before OnProcessEnd().
156   void OnProcessCrashed();
157 
158   // If "too many" crashes occur within a given time period, NaCl is throttled
159   // until the rate again drops below the threshold.
160   bool IsThrottled();
161 
162  private:
163   enum NaClResourceState {
164     NaClResourceUninitialized,
165     NaClResourceRequested,
166     NaClResourceReady
167   };
168 
169   static NaClBrowser* GetInstanceInternal();
170 
171   NaClBrowser();
172   ~NaClBrowser();
173 
174   void InitIrtFilePath();
175 
176   void OpenIrtLibraryFile();
177 
178   void OnIrtOpened(std::unique_ptr<base::FileProxy> file_proxy,
179                    base::File::Error error_code);
180 
181   void InitValidationCacheFilePath();
182   void EnsureValidationCacheAvailable();
183   void OnValidationCacheLoaded(const std::string* data);
184   void RunWithoutValidationCache();
185 
186   // Dispatch waiting tasks if we are ready, or if we know we'll never be ready.
187   void CheckWaiting();
188 
189   // Indicate that it is impossible to launch a NaCl process.
190   void MarkAsFailed();
191 
192   void MarkValidationCacheAsModified();
193   void PersistValidationCache();
194 
195   base::File irt_file_;
196   base::FilePath irt_filepath_;
197   NaClResourceState irt_state_ = NaClResourceUninitialized;
198   NaClValidationCache validation_cache_;
199   NaClValidationCache off_the_record_validation_cache_;
200   base::FilePath validation_cache_file_path_;
201   bool validation_cache_is_enabled_ = false;
202   bool validation_cache_is_modified_ = false;
203   NaClResourceState validation_cache_state_ = NaClResourceUninitialized;
204   base::RepeatingCallback<void(int)> debug_stub_port_listener_;
205 
206   // Map from process id to debug stub port if any.
207   typedef std::map<int, int> GdbDebugStubPortMap;
208   GdbDebugStubPortMap gdb_debug_stub_port_map_;
209 
210   typedef base::HashingLRUCache<std::string, base::FilePath> PathCacheType;
211   PathCacheType path_cache_{kFilePathCacheSize};
212 
213   // True if it is no longer possible to launch NaCl processes.
214   bool has_failed_ = false;
215 
216   // A list of pending tasks to start NaCl processes.
217   std::vector<base::OnceClosure> waiting_;
218 
219   base::circular_deque<base::Time> crash_times_;
220 
221   scoped_refptr<base::SequencedTaskRunner> file_task_runner_ =
222       base::ThreadPool::CreateSequencedTaskRunner(
223           {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
224 };
225 
226 } // namespace nacl
227 
228 #endif  // COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_
229