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