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