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
19class URLPattern;
20class GURL;
21
22namespace base {
23class FileProxy;
24}
25
26namespace nacl {
27
28static const int kGdbDebugStubPortUnknown = -1;
29static 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.
33base::File OpenNaClReadExecImpl(const base::FilePath& file_path,
34                                bool is_executable);
35
36// Represents shared state for all NaClProcessHost objects in the browser.
37class 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