1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef SANDBOX_POLICY_LINUX_SANDBOX_LINUX_H_
6 #define SANDBOX_POLICY_LINUX_SANDBOX_LINUX_H_
7 
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include "base/check_op.h"
13 #include "base/macros.h"
14 #include "base/posix/global_descriptors.h"
15 #include "sandbox/linux/syscall_broker/broker_command.h"
16 #include "sandbox/linux/syscall_broker/broker_file_permission.h"
17 #include "sandbox/policy/export.h"
18 #include "sandbox/policy/linux/sandbox_seccomp_bpf_linux.h"
19 #include "sandbox/policy/sandbox_type.h"
20 #include "sandbox/policy/sanitizer_buildflags.h"
21 
22 #if BUILDFLAG(USING_SANITIZER)
23 #include <sanitizer/common_interface_defs.h>
24 #endif
25 
26 namespace base {
27 template <typename T>
28 struct DefaultSingletonTraits;
29 class Thread;
30 }  // namespace base
31 
32 namespace sandbox {
33 namespace syscall_broker {
34 class BrokerProcess;
35 }  // namespace syscall_broker
36 class SetuidSandboxClient;
37 }  // namespace sandbox
38 
39 namespace sandbox {
40 namespace policy {
41 
42 // A singleton class to represent and change our sandboxing state for the
43 // three main Linux sandboxes.
44 // The sandboxing model allows using two layers of sandboxing. The first layer
45 // can be implemented either with unprivileged namespaces or with the setuid
46 // sandbox. This class provides a way to engage the namespace sandbox, but does
47 // not deal with the legacy setuid sandbox directly.
48 // The second layer is mainly based on seccomp-bpf and is engaged with
49 // InitializeSandbox(). InitializeSandbox() is also responsible for "sealing"
50 // the first layer of sandboxing. That is, InitializeSandbox must always be
51 // called to have any meaningful sandboxing at all.
52 class SANDBOX_POLICY_EXPORT SandboxLinux {
53  public:
54   // This is a list of sandbox IPC methods which the renderer may send to the
55   // sandbox host. See
56   // https://chromium.googlesource.com/chromium/src/+/master/docs/linux/sandbox_ipc.md
57   // This isn't the full list, values < 32 are reserved for methods called from
58   // Skia, and values < 64 are reserved for libc_interceptor.cc.
59   enum LinuxSandboxIPCMethods {
60     DEPRECATED_METHOD_GET_FALLBACK_FONT_FOR_CHAR = 64,
61     DEPRECATED_METHOD_GET_CHILD_WITH_INODE,
62     DEPRECATED_METHOD_GET_STYLE_FOR_STRIKE,
63     METHOD_MAKE_SHARED_MEMORY_SEGMENT,
64     DEPRECATED_METHOD_MATCH_WITH_FALLBACK,
65   };
66 
67   // These form a bitmask which describes the conditions of the Linux sandbox.
68   // Note: this doesn't strictly give you the current status, it states
69   // what will be enabled when the relevant processes are initialized.
70   enum Status {
71     // SUID sandbox active.
72     kSUID = 1 << 0,
73 
74     // Sandbox is using a new PID namespace.
75     kPIDNS = 1 << 1,
76 
77     // Sandbox is using a new network namespace.
78     kNetNS = 1 << 2,
79 
80     // seccomp-bpf sandbox active.
81     kSeccompBPF = 1 << 3,
82 
83     // The Yama LSM module is present and enforcing.
84     kYama = 1 << 4,
85 
86     // seccomp-bpf sandbox is active and the kernel supports TSYNC.
87     kSeccompTSYNC = 1 << 5,
88 
89     // User namespace sandbox active.
90     kUserNS = 1 << 6,
91 
92     // A flag that denotes an invalid sandbox status.
93     kInvalid = 1 << 31,
94   };
95 
96   // SandboxLinux Options are a superset of SandboxSecompBPF Options.
97   struct Options : public SandboxSeccompBPF::Options {
98     // When running with a zygote, the namespace sandbox will have already
99     // been engaged prior to initializing SandboxLinux itself, and need not
100     // be done so again. Set to true to indicate that there isn't a zygote
101     // for this process and the step is to be performed here explicitly.
102     bool engage_namespace_sandbox = false;
103 
104     // Allow starting the sandbox with multiple threads already running. This
105     // will enable TSYNC for seccomp-BPF, which syncs the seccomp-BPF policy
106     // across all running threads.
107     bool allow_threads_during_sandbox_init = false;
108 
109     // Enables the CHECK for open directories. The open directory check is only
110     // useful for the chroot jail (from the semantic layer of the sandbox), and
111     // can safely be disabled if we are only enabling the seccomp-BPF layer.
112     bool check_for_open_directories = true;
113   };
114 
115   // Callers can provide this hook to run code right before the policy
116   // is passed to the BPF compiler and the sandbox is engaged. If
117   // pre_sandbox_hook() returns true, the sandbox will be engaged
118   // afterwards, otherwise the process is terminated.
119   using PreSandboxHook = base::OnceCallback<bool(Options)>;
120 
121   // Get our singleton instance.
122   static SandboxLinux* GetInstance();
123 
124   // Do some initialization that can only be done before any of the sandboxes
125   // are enabled. If using the setuid sandbox, this should be called manually
126   // before the setuid sandbox is engaged.
127   // Security: When this runs, it is imperative that either InitializeSandbox()
128   // runs as well or that all file descriptors returned in
129   // GetFileDescriptorsToClose() get closed.
130   // Otherwise file descriptors that bypass the security of the setuid sandbox
131   // would be kept open. One must be particularly careful if a process performs
132   // a fork().
133   void PreinitializeSandbox();
134 
135   // Check that the current process is the init process of a new PID
136   // namespace and then proceed to drop access to the file system by using
137   // a new unprivileged namespace. This is a layer-1 sandbox.
138   // In order for this sandbox to be effective, it must be "sealed" by calling
139   // InitializeSandbox().
140   // Terminates the process in case the sandboxing operations cannot complete
141   // successfully.
142   void EngageNamespaceSandbox(bool from_zygote);
143 
144   // Performs the same actions as EngageNamespaceSandbox, but is allowed to
145   // to fail. This is useful when sandboxed non-renderer processes could
146   // benefit from extra sandboxing but is not strictly required on systems that
147   // don't support unprivileged user namespaces.
148   // Zygote should use EngageNamespaceSandbox instead.
149   bool EngageNamespaceSandboxIfPossible();
150 
151   // Return a list of file descriptors to close if PreinitializeSandbox() ran
152   // but InitializeSandbox() won't. Avoid using.
153   // TODO(jln): get rid of this hack.
154   std::vector<int> GetFileDescriptorsToClose();
155 
156   // Seal an eventual layer-1 sandbox and initialize the layer-2 sandbox with
157   // an adequate policy depending on the process type and command line
158   // arguments.
159   // Currently the layer-2 sandbox is composed of seccomp-bpf and address space
160   // limitations.
161   // This function should only be called without any thread running.
162   bool InitializeSandbox(SandboxType sandbox_type,
163                          PreSandboxHook hook,
164                          const Options& options);
165 
166   // Stop |thread| in a way that can be trusted by the sandbox.
167   void StopThread(base::Thread* thread);
168 
169   // Returns the status of the renderer, worker and ppapi sandbox. Can only
170   // be queried after going through PreinitializeSandbox(). This is a bitmask
171   // and uses the constants defined in "enum Status" above. Since the
172   // status needs to be provided before the sandboxes are actually started,
173   // this returns what will actually happen once InitializeSandbox()
174   // is called from inside these processes.
175   int GetStatus();
176 
177   // Returns true if the current process is single-threaded or if the number
178   // of threads cannot be determined.
179   bool IsSingleThreaded() const;
180 
181   // Returns true if we started Seccomp BPF.
182   bool seccomp_bpf_started() const;
183 
184   // Simple accessor for our instance of the setuid sandbox. Will never return
185   // NULL.
186   // There is no StartSetuidSandbox(), the SetuidSandboxClient instance should
187   // be used directly.
188   SetuidSandboxClient* setuid_sandbox_client() const;
189 
190   // Check the policy and eventually start the seccomp-bpf sandbox. Fine to be
191   // called with threads, as long as
192   // |options.allow_threads_during_sandbox_init| is true and the kernel
193   // supports seccomp's TSYNC feature. If TSYNC is not available we treat
194   // multiple threads as a fatal error.
195   bool StartSeccompBPF(SandboxType sandbox_type,
196                        PreSandboxHook hook,
197                        const Options& options);
198 
199   // Limit the address space of the current process (and its children) to make
200   // some vulnerabilities harder to exploit. Writes the errno due to setrlimit
201   // (including 0 if no error) into |error|.
202   bool LimitAddressSpace(int* error);
203 
204   // Returns a file descriptor to proc. The file descriptor is no longer valid
205   // after the sandbox has been sealed.
proc_fd()206   int proc_fd() const {
207     DCHECK_NE(-1, proc_fd_);
208     return proc_fd_;
209   }
210 
211 #if BUILDFLAG(USING_SANITIZER)
sanitizer_args()212   __sanitizer_sandbox_arguments* sanitizer_args() const {
213     return sanitizer_args_.get();
214   }
215 #endif
216 
217   // A BrokerProcess is a helper that is started before the sandbox is engaged,
218   // typically from a pre-sandbox hook, that will serve requests to access
219   // files over an IPC channel. The client  of this runs from a SIGSYS handler
220   // triggered by the seccomp-bpf sandbox.
221   // |client_sandbox_policy| is the policy being run by the client, and is
222   // used to derive the equivalent broker-side policy.
223   // |broker_side_hook| is an alternate pre-sandbox hook to be run before the
224   // broker itself gets sandboxed, to which the broker side policy and
225   // |options| are passed.
226   // Crashes the process if the broker can not be started since continuation
227   // is impossible (and presumably unsafe).
228   // This should never be destroyed, as after the sandbox is started it is
229   // vital to the process.
230   void StartBrokerProcess(
231       const syscall_broker::BrokerCommandSet& allowed_command_set,
232       std::vector<syscall_broker::BrokerFilePermission> permissions,
233       PreSandboxHook broker_side_hook,
234       const Options& options);
235 
236   // Returns true if the broker should handle a particular syscall indicated by
237   // |sysno|. This will typically return true for system calls that take
238   // filepaths as arguments.
239   bool ShouldBrokerHandleSyscall(int sysno) const;
240 
241   // Returns an expression that indicates the syscall in question should be
242   // handled transparently by the broker process. This is useful for file
243   // syscalls that take pathnames, so we can enforce pathname whitelisting.
244   // Only usable if StartBrokerProcess() was already called.
245   bpf_dsl::ResultExpr HandleViaBroker() const;
246 
247  private:
248   friend struct base::DefaultSingletonTraits<SandboxLinux>;
249 
250   SandboxLinux();
251   ~SandboxLinux();
252 
253   // We must have been pre_initialized_ before using these.
254   bool seccomp_bpf_supported() const;
255   bool seccomp_bpf_with_tsync_supported() const;
256 
257   // Returns true if it can be determined that the current process has open
258   // directories that are not managed by the SandboxLinux class. This would
259   // be a vulnerability as it would allow to bypass the setuid sandbox.
260   bool HasOpenDirectories() const;
261 
262   // The last part of the initialization is to make sure any temporary "hole"
263   // in the sandbox is closed. For now, this consists of closing proc_fd_.
264   void SealSandbox();
265 
266   // GetStatus() makes promises as to how the sandbox will behave. This
267   // checks that no promises have been broken.
268   void CheckForBrokenPromises(SandboxType sandbox_type);
269 
270   // Stop |thread| and make sure it does not appear in /proc/self/tasks/
271   // anymore.
272   void StopThreadAndEnsureNotCounted(base::Thread* thread) const;
273 
274   // Engages the namespace sandbox as described for EngageNamespaceSandbox.
275   // Returns false if it fails to transition to a new user namespace, but
276   // after transitioning to a new user namespace we don't allow this function
277   // to fail.
278   bool EngageNamespaceSandboxInternal(bool from_zygote);
279 
280   // A file descriptor to /proc. It's dangerous to have it around as it could
281   // allow for sandbox bypasses. It needs to be closed before we consider
282   // ourselves sandboxed.
283   int proc_fd_;
284 
285   bool seccomp_bpf_started_;
286   // The value returned by GetStatus(). Gets computed once and then cached.
287   int sandbox_status_flags_;
288   // Did PreinitializeSandbox() run?
289   bool pre_initialized_;
290   bool seccomp_bpf_supported_;             // Accurate if pre_initialized_.
291   bool seccomp_bpf_with_tsync_supported_;  // Accurate if pre_initialized_.
292   bool yama_is_enforcing_;                 // Accurate if pre_initialized_.
293   bool initialize_sandbox_ran_;            // InitializeSandbox() was called.
294   std::unique_ptr<SetuidSandboxClient> setuid_sandbox_client_;
295 #if BUILDFLAG(USING_SANITIZER)
296   std::unique_ptr<__sanitizer_sandbox_arguments> sanitizer_args_;
297 #endif
298   syscall_broker::BrokerProcess* broker_process_;  // Leaked as global.
299 
300   DISALLOW_COPY_AND_ASSIGN(SandboxLinux);
301 };
302 
303 }  // namespace policy
304 }  // namespace sandbox
305 
306 #endif  // SANDBOX_POLICY_LINUX_SANDBOX_LINUX_H_
307