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