C++程序  |  208行  |  7.21 KB

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_
#define COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_

#include <deque>

#include "base/bind.h"
#include "base/containers/mru_cache.h"
#include "base/files/file.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "components/nacl/browser/nacl_browser_delegate.h"
#include "components/nacl/browser/nacl_validation_cache.h"

class URLPattern;
class GURL;

namespace base {
class FileProxy;
}

namespace nacl {

static const int kGdbDebugStubPortUnknown = -1;
static const int kGdbDebugStubPortUnused = 0;

// Open an immutable executable file that can be mmapped.
// This function should only be called on a thread that can perform file IO.
base::File OpenNaClExecutableImpl(const base::FilePath& file_path);

// Represents shared state for all NaClProcessHost objects in the browser.
class NaClBrowser {
 public:
  static NaClBrowser* GetInstance();

  // Will it be possible to launch a NaCl process, eventually?
  bool IsOk() const;

  // Are we ready to launch a NaCl process now?  Implies IsOk().
  bool IsReady() const;

  // Attempt to asynchronously acquire all resources needed to start a process.
  // This method is idempotent - it is safe to call multiple times.
  void EnsureAllResourcesAvailable();

  // Enqueues reply() in the message loop when all the resources needed to start
  // a process have been acquired.
  void WaitForResources(const base::Closure& reply);

  // Asynchronously attempt to get the IRT open.
  // This is entailed by EnsureInitialized.  This method is exposed as part of
  // the public interface, however, so the IRT can be explicitly opened as
  // early as possible to prevent autoupdate issues.
  void EnsureIrtAvailable();

  // Path to IRT. Available even before IRT is loaded.
  const base::FilePath& GetIrtFilePath();

  // IRT file handle, only available when IsReady().
  const base::File& IrtFile() const;

  // Methods for testing GDB debug stub in browser. If test adds debug stub
  // port listener, Chrome will allocate a currently-unused TCP port number for
  // debug stub server instead of a fixed one.

  // Notify listener that new debug stub TCP port is allocated.
  void SetProcessGdbDebugStubPort(int process_id, int port);
  void SetGdbDebugStubPortListener(base::Callback<void(int)> listener);
  void ClearGdbDebugStubPortListener();

  int GetProcessGdbDebugStubPort(int process_id);

  enum ValidationCacheStatus {
    CACHE_MISS = 0,
    CACHE_HIT,
    CACHE_MAX
  };

  bool ValidationCacheIsEnabled() const {
    return validation_cache_is_enabled_;
  }

  const std::string& GetValidationCacheKey() const {
    return validation_cache_.GetValidationCacheKey();
  }

  // The NaCl singleton keeps information about NaCl executable files opened via
  // PPAPI.  This allows the NaCl process to get trusted information about the
  // file directly from the browser process.  In theory, a compromised renderer
  // could provide a writable file handle or lie about the file's path.  If we
  // trusted the handle was read only but it was not, an mmapped file could be
  // modified after validation, allowing an escape from the NaCl sandbox.
  // Similarly, if we trusted the file path corresponded to the file handle but
  // it did not, the validation cache could be tricked into bypassing validation
  // for bad code.
  // Instead of allowing these attacks, the NaCl process only trusts information
  // it gets directly from the browser process.  Because the information is
  // stored in a cache of bounded size, it is not guaranteed the browser process
  // will be able to provide the requested information.  In these cases, the
  // NaCl process must make conservative assumptions about the origin of the
  // file.
  // In theory, a compromised renderer could guess file tokens in an attempt to
  // read files it normally doesn't have access to.  This would not compromise
  // the NaCl sandbox, however, and only has a 1 in ~2**120 chance of success
  // per guess.
  // TODO(ncbray): move the cache onto NaClProcessHost so that we don't need to
  // rely on tokens being unguessable by another process.
  void PutFilePath(const base::FilePath& path, uint64* file_token_lo,
                   uint64* file_token_hi);
  bool GetFilePath(uint64 file_token_lo, uint64 file_token_hi,
                   base::FilePath* path);

  bool QueryKnownToValidate(const std::string& signature, bool off_the_record);
  void SetKnownToValidate(const std::string& signature, bool off_the_record);
  void ClearValidationCache(const base::Closure& callback);
#if defined(OS_WIN)
  // Get path to NaCl loader on the filesystem if possible.
  // |exe_path| does not change if the method fails.
  bool GetNaCl64ExePath(base::FilePath* exe_path);
#endif

  void EarlyStartup();
  static void SetDelegate(NaClBrowserDelegate* delegate);
  static NaClBrowserDelegate* GetDelegate();

  // Each time a NaCl process ends, the browser is notified.
  void OnProcessEnd(int process_id);
  // Support for NaCl crash throttling.
  // Each time a NaCl module crashes, the browser is notified.
  void OnProcessCrashed();
  // If "too many" crashes occur within a given time period, NaCl is throttled
  // until the rate again drops below the threshold.
  bool IsThrottled();

 private:
  friend struct DefaultSingletonTraits<NaClBrowser>;

  enum NaClResourceState {
    NaClResourceUninitialized,
    NaClResourceRequested,
    NaClResourceReady
  };

  NaClBrowser();
  ~NaClBrowser();

  void InitIrtFilePath();

  void OpenIrtLibraryFile();

  void OnIrtOpened(scoped_ptr<base::FileProxy> file_proxy,
                   base::File::Error error_code);

  void InitValidationCacheFilePath();
  void EnsureValidationCacheAvailable();
  void OnValidationCacheLoaded(const std::string* data);
  void RunWithoutValidationCache();

  // Dispatch waiting tasks if we are ready, or if we know we'll never be ready.
  void CheckWaiting();

  // Indicate that it is impossible to launch a NaCl process.
  void MarkAsFailed();

  void MarkValidationCacheAsModified();
  void PersistValidationCache();

  // Singletons get destroyed at shutdown.
  base::WeakPtrFactory<NaClBrowser> weak_factory_;

  base::File irt_file_;
  base::FilePath irt_filepath_;
  NaClResourceState irt_state_;
  NaClValidationCache validation_cache_;
  NaClValidationCache off_the_record_validation_cache_;
  base::FilePath validation_cache_file_path_;
  bool validation_cache_is_enabled_;
  bool validation_cache_is_modified_;
  NaClResourceState validation_cache_state_;
  base::Callback<void(int)> debug_stub_port_listener_;

  // Map from process id to debug stub port if any.
  typedef std::map<int, int> GdbDebugStubPortMap;
  GdbDebugStubPortMap gdb_debug_stub_port_map_;

  typedef base::HashingMRUCache<std::string, base::FilePath> PathCacheType;
  PathCacheType path_cache_;

  bool ok_;

  // A list of pending tasks to start NaCl processes.
  std::vector<base::Closure> waiting_;

  scoped_ptr<NaClBrowserDelegate> browser_delegate_;

  std::deque<base::Time> crash_times_;

  DISALLOW_COPY_AND_ASSIGN(NaClBrowser);
};

} // namespace nacl

#endif  // COMPONENTS_NACL_BROWSER_NACL_BROWSER_H_