tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SandboxBroker.h (7111B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_SandboxBroker_h
      8 #define mozilla_SandboxBroker_h
      9 
     10 #include "mozilla/SandboxBrokerCommon.h"
     11 
     12 #include "base/platform_thread.h"
     13 #include "mozilla/UniquePtr.h"
     14 #include "nsTHashMap.h"
     15 #include "nsHashKeys.h"
     16 #include "nsString.h"
     17 
     18 namespace mozilla {
     19 
     20 namespace ipc {
     21 class FileDescriptor;
     22 }
     23 
     24 // This class implements a broker for filesystem operations requested
     25 // by a sandboxed child process -- opening files and accessing their
     26 // metadata.  (This is necessary in order to restrict access by path;
     27 // seccomp-bpf can filter only on argument register values, not
     28 // parameters passed in memory like pathnames.)
     29 //
     30 // The broker currently runs on a thread in the parent process (with
     31 // effective uid changed on B2G), which is for memory efficiency
     32 // (compared to forking a process) and simplicity (compared to having
     33 // a separate executable and serializing/deserializing the policy).
     34 //
     35 // See also ../SandboxBrokerClient.h for the corresponding client.
     36 
     37 class SandboxBroker final : private SandboxBrokerCommon,
     38                            public PlatformThread::Delegate {
     39 public:
     40  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SandboxBroker)
     41 
     42  enum Perms {
     43    MAY_ACCESS = 1 << 0,
     44    MAY_READ = 1 << 1,
     45    MAY_WRITE = 1 << 2,
     46    MAY_CREATE = 1 << 3,
     47    // This flag is for testing policy changes -- when the client is
     48    // used with the seccomp-bpf integration, an access to this file
     49    // will invoke a crash dump with the context of the syscall.
     50    // (This overrides all other flags.)
     51    CRASH_INSTEAD = 1 << 4,
     52    // Applies to everything below this path, including subdirs created
     53    // at runtime
     54    RECURSIVE = 1 << 5,
     55    // Allow Unix-domain socket connections to a path
     56    MAY_CONNECT = 1 << 6,
     57    // This flag is for adding a deny rule, so that we can e.g., allow read
     58    // access to ~/.config/ but still deny access to ~/.config/mozilla/.
     59    // It will bypass other checks.
     60    FORCE_DENY = 1 << 7,
     61  };
     62  // Bitwise operations on enum values return ints, so just use int in
     63  // the hash table type (and below) to avoid cluttering code with casts.
     64  typedef nsTHashMap<nsCStringHashKey, int> PathPermissionMap;
     65 
     66  class Policy {
     67    PathPermissionMap mMap;
     68 
     69   public:
     70    Policy();
     71    Policy(const Policy& aOther);
     72    ~Policy();
     73 
     74    // Add permissions from AddTree/AddDynamic rules to any rules that
     75    // exist for their descendents, and remove any descendent rules
     76    // made redundant by this process.
     77    //
     78    // Call this after adding rules and before using the policy to
     79    // prevent the descendent rules from shadowing the ancestor rules
     80    // and removing permissions that we expect the file to have.
     81    void FixRecursivePermissions();
     82 
     83    enum AddCondition {
     84      AddIfExistsNow,
     85      AddAlways,
     86    };
     87    // Typically, files that don't exist at policy creation time don't
     88    // need to be whitelisted, but this allows adding entries for
     89    // them if they'll exist later.  See also the overload below.
     90    void AddPath(int aPerms, const char* aPath, AddCondition aCond);
     91    // A directory, and all files and directories under it, even those
     92    // added after creation (the dir itself must exist).
     93    void AddTree(int aPerms, const char* aPath);
     94    // A directory, and all files and directories under it, even those
     95    // added after creation (the dir itself may not exist).
     96    void AddFutureDir(int aPerms, const char* aPath);
     97    // All files in a directory with a given prefix; useful for devices.
     98    void AddFilePrefix(int aPerms, const char* aDir, const char* aPrefix);
     99    // Everything starting with the given path, even those files/dirs
    100    // added after creation. The file or directory may or may not exist.
    101    void AddPrefix(int aPerms, const char* aPath);
    102    // Adds a file or dir (end with /) if it exists, and a prefix otherwhise.
    103    void AddDynamic(int aPerms, const char* aPath);
    104    // Adds permissions on all ancestors of a path.  (This doesn't
    105    // include the root directory, but if the path is given with a
    106    // trailing slash it includes the path without the slash.)
    107    void AddAncestors(const char* aPath, int aPerms = MAY_ACCESS);
    108    // Default: add file if it exists when creating policy or if we're
    109    // conferring permission to create it (log files, etc.).
    110    void AddPath(int aPerms, const char* aPath) {
    111      AddPath(aPerms, aPath,
    112              (aPerms & MAY_CREATE) ? AddAlways : AddIfExistsNow);
    113    }
    114    int Lookup(const nsACString& aPath) const;
    115    int Lookup(const char* aPath) const {
    116      return Lookup(nsDependentCString(aPath));
    117    }
    118 
    119    bool IsEmpty() const { return mMap.Count() == 0; }
    120 
    121   private:
    122    // ValidatePath checks |path| and returns true if these conditions are met
    123    // * Greater than 0 length
    124    // * Is an absolute path
    125    // * No trailing slash
    126    // * No /../ path traversal
    127    bool ValidatePath(const char* path) const;
    128    void AddPrefixInternal(int aPerms, const nsACString& aPath);
    129    void AddTreeInternal(int aPerms, const char* aPath);
    130  };
    131 
    132  // Constructing a broker involves creating a socketpair and a
    133  // background thread to handle requests, so it can fail.  If this
    134  // returns nullptr, do not use the value of aClientFdOut.
    135  static already_AddRefed<SandboxBroker> Create(
    136      UniquePtr<const Policy> aPolicy, int aChildPid,
    137      ipc::FileDescriptor& aClientFdOut);
    138 
    139  // Allow for explicit termination in the gtests
    140  void Terminate();
    141 
    142 private:
    143  PlatformThreadHandle mThread;
    144  int mFileDesc;
    145  const int mChildPid;
    146  const UniquePtr<const Policy> mPolicy;
    147 
    148  typedef nsTHashMap<nsCStringHashKey, nsCString> PathMap;
    149  PathMap mSymlinkMap;
    150 
    151  SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid, int& aClientFd);
    152  ~SandboxBroker() override;
    153 
    154  void ThreadMain(void) override;
    155  void AuditPermissive(int aOp, int aFlags, uint64_t aId, int aPerms,
    156                       const char* aPath);
    157  void AuditDenial(int aOp, int aFlags, uint64_t aId, int aPerms,
    158                   const char* aPath);
    159  // Remap relative paths to absolute paths.
    160  size_t ConvertRelativePath(char* aPath, size_t aBufSize, size_t aPathLen);
    161  size_t RealPath(char* aPath, size_t aBufSize, size_t aPathLen);
    162  nsCString ReverseSymlinks(const nsACString& aPath);
    163  // Retrieves permissions for the path the original symlink sits in.
    164  int SymlinkPermissions(const char* aPath, const size_t aPathLen);
    165  // In SandboxBrokerRealPath.cpp
    166  char* SymlinkPath(const Policy* aPolicy, const char* __restrict aPath,
    167                    char* __restrict aResolved, int* aPermission);
    168 
    169  // Holding a UniquePtr should disallow copying, but to make that explicit:
    170  SandboxBroker(const SandboxBroker&) = delete;
    171  void operator=(const SandboxBroker&) = delete;
    172 };
    173 
    174 }  // namespace mozilla
    175 
    176 #endif  // mozilla_SandboxBroker_h