1f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be
3f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// found in the LICENSE file.
4f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
5f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
6f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
7f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
8f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include <stdint.h>
9f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
1094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include <memory>
1194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
12f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/files/scoped_file.h"
13f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "base/macros.h"
14f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/linux/bpf_dsl/codegen.h"
15f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#include "sandbox/sandbox_export.h"
16f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
17f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace sandbox {
18f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkostruct arch_seccomp_data;
19f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkonamespace bpf_dsl {
20f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoclass Policy;
21f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}
22f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
23f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// This class can be used to apply a syscall sandboxing policy expressed in a
24f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// bpf_dsl::Policy object to the current process.
25f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// Syscall sandboxing policies get inherited by subprocesses and, once applied,
26f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko// can never be removed for the lifetime of the process.
27f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenkoclass SANDBOX_EXPORT SandboxBPF {
28f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko public:
29f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  enum class SeccompLevel {
30f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko    SINGLE_THREADED,
31f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko    MULTI_THREADED,
32f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  };
33f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
34f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Ownership of |policy| is transfered here to the sandbox object.
35f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // nullptr is allowed for unit tests.
36f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  explicit SandboxBPF(bpf_dsl::Policy* policy);
37f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // NOTE: Setting a policy and starting the sandbox is a one-way operation.
38f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // The kernel does not provide any option for unloading a loaded sandbox. The
39f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // sandbox remains engaged even when the object is destructed.
40f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  ~SandboxBPF();
41f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
42f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Detect if the kernel supports the specified seccomp level.
43f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // See StartSandbox() for a description of these.
44f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  static bool SupportsSeccompSandbox(SeccompLevel level);
45f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
46f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // This is the main public entry point. It sets up the resources needed by
47f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // the sandbox, and enters Seccomp mode.
48f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // The calling process must provide a |level| to tell the sandbox which type
49f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // of kernel support it should engage.
50f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // SINGLE_THREADED will only sandbox the calling thread. Since it would be a
51f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // security risk, the sandbox will also check that the current process is
52f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // single threaded and crash if it isn't the case.
53f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // MULTI_THREADED requires more recent kernel support and allows to sandbox
54f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // all the threads of the current process. Be mindful of potential races,
55f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // with other threads using disallowed system calls either before or after
56f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // the sandbox is engaged.
57f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  //
58f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // It is possible to stack multiple sandboxes by creating separate "Sandbox"
59f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // objects and calling "StartSandbox()" on each of them. Please note, that
60f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // this requires special care, though, as newly stacked sandboxes can never
61f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // relax restrictions imposed by earlier sandboxes. Furthermore, installing
62f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // a new policy requires making system calls, that might already be
63f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // disallowed.
64f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Finally, stacking does add more kernel overhead than having a single
65f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // combined policy. So, it should only be used if there are no alternatives.
66f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  bool StartSandbox(SeccompLevel level) WARN_UNUSED_RESULT;
67f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
68f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // The sandbox needs to be able to access files in "/proc/self/". If
69f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // this directory is not accessible when "StartSandbox()" gets called, the
70f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // caller must provide an already opened file descriptor by calling
71f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // "SetProcFd()".
72f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // The sandbox becomes the new owner of this file descriptor and will
73f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // close it when "StartSandbox()" executes or when the sandbox object
74f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // disappears.
75f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  void SetProcFd(base::ScopedFD proc_fd);
76f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
77f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Checks whether a particular system call number is valid on the current
78f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // architecture.
79f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  static bool IsValidSyscallNumber(int sysnum);
80f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
81f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // UnsafeTraps require some syscalls to always be allowed.
82f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // This helper function returns true for these calls.
83f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  static bool IsRequiredForUnsafeTrap(int sysno);
84f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
85f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // From within an UnsafeTrap() it is often useful to be able to execute
86f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // the system call that triggered the trap. The ForwardSyscall() method
87f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // makes this easy. It is more efficient than calling glibc's syscall()
88f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // function, as it avoid the extra round-trip to the signal handler. And
89f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // it automatically does the correct thing to report kernel-style error
90f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // conditions, rather than setting errno. See the comments for TrapFnc for
91f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // details. In other words, the return value from ForwardSyscall() is
92f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // directly suitable as a return value for a trap handler.
93f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  static intptr_t ForwardSyscall(const struct arch_seccomp_data& args);
94f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
9524854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko private:
9624854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  friend class SandboxBPFTestRunner;
9724854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko
98f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Assembles a BPF filter program from the current policy. After calling this
99f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // function, you must not call any other sandboxing function.
10024854748fba09df2a29f0d08d558c3acea70e7a1Alex Vakulenko  CodeGen::Program AssembleFilter();
101f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
102f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // Assembles and installs a filter based on the policy that has previously
103f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  // been configured with SetSandboxPolicy().
104f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  void InstallFilter(bool must_sync_threads);
105f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
106f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  base::ScopedFD proc_fd_;
107f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  bool sandbox_has_started_;
10894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<bpf_dsl::Policy> policy_;
109f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
110f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko  DISALLOW_COPY_AND_ASSIGN(SandboxBPF);
111f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko};
112f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
113f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko}  // namespace sandbox
114f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko
115f6024733c0d1eed88f68520b5e6a20b96e212ad6Alex Vakulenko#endif  // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
116