summaryrefslogtreecommitdiffstats
path: root/mojo/runner/linux_sandbox.cc
blob: 6990f0acea51f7ce5688b9a428d7b0c5dc0f8c5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "mojo/runner/linux_sandbox.h"

#include <fcntl.h>
#include <sys/syscall.h>

#include "base/bind.h"
#include "base/debug/leak_annotations.h"
#include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"
#include "base/sys_info.h"
#include "sandbox/linux/bpf_dsl/policy.h"
#include "sandbox/linux/bpf_dsl/trap_registry.h"
#include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/namespace_sandbox.h"
#include "sandbox/linux/services/proc_util.h"
#include "sandbox/linux/services/thread_helpers.h"

using sandbox::syscall_broker::BrokerFilePermission;

namespace mandoline {

namespace {

intptr_t SandboxSIGSYSHandler(const struct sandbox::arch_seccomp_data& args,
                              void* aux) {
  RAW_CHECK(aux);
  const sandbox::syscall_broker::BrokerProcess* broker_process =
      static_cast<const sandbox::syscall_broker::BrokerProcess*>(aux);
  switch (args.nr) {
    case __NR_access:
      return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
                                    static_cast<int>(args.args[1]));
    case __NR_open:
      return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
                                  static_cast<int>(args.args[1]));
    case __NR_faccessat:
      if (static_cast<int>(args.args[0]) == AT_FDCWD) {
        return broker_process->Access(
            reinterpret_cast<const char*>(args.args[1]),
            static_cast<int>(args.args[2]));
      } else {
        return -EPERM;
      }
    case __NR_openat:
      // Allow using openat() as open().
      if (static_cast<int>(args.args[0]) == AT_FDCWD) {
        return broker_process->Open(reinterpret_cast<const char*>(args.args[1]),
                                    static_cast<int>(args.args[2]));
      } else {
        return -EPERM;
      }
    default:
      RAW_CHECK(false);
      return -ENOSYS;
  }
}

class SandboxPolicy : public sandbox::BaselinePolicy {
 public:
  explicit SandboxPolicy(sandbox::syscall_broker::BrokerProcess* broker_process)
      : broker_process_(broker_process) {}
  ~SandboxPolicy() override {}

  // Overridden from sandbox::bpf_dsl::Policy:
  sandbox::bpf_dsl::ResultExpr EvaluateSyscall(int sysno) const override {
    // This policy is only advisory/for noticing FS access for the moment.
    switch (sysno) {
      case __NR_access:
      case __NR_open:
      case __NR_faccessat:
      case __NR_openat:
        return sandbox::bpf_dsl::Trap(SandboxSIGSYSHandler, broker_process_);
      case __NR_sched_getaffinity:
        return sandbox::RestrictSchedTarget(policy_pid(), sysno);
      case __NR_ftruncate:
      case __NR_getrlimit:
      case __NR_uname:
        return sandbox::bpf_dsl::Allow();
    }

    return BaselinePolicy::EvaluateSyscall(sysno);
  }

 private:
  // Not owned.
  const sandbox::syscall_broker::BrokerProcess* broker_process_;
  DISALLOW_COPY_AND_ASSIGN(SandboxPolicy);
};

}  // namespace

LinuxSandbox::LinuxSandbox(const std::vector<BrokerFilePermission>& permissions)
    : broker_(new sandbox::syscall_broker::BrokerProcess(EPERM, permissions)) {
  CHECK(broker_->Init(
      base::Bind<bool (*)()>(&sandbox::Credentials::DropAllCapabilities)));
  policy_.reset(new SandboxPolicy(broker_.get()));
}

LinuxSandbox::~LinuxSandbox() {}

void LinuxSandbox::Warmup() {
  proc_fd_ = sandbox::ProcUtil::OpenProc();
  warmed_up_ = true;

  // Verify that we haven't started threads or grabbed directory file
  // descriptors.
  sandbox::ThreadHelpers::AssertSingleThreaded(proc_fd_.get());
  CHECK(!sandbox::ProcUtil::HasOpenDirectory(proc_fd_.get()));
}

void LinuxSandbox::EngageNamespaceSandbox() {
  CHECK(warmed_up_);
  CHECK_EQ(1, getpid());
  CHECK(sandbox::NamespaceSandbox::InNewPidNamespace());
  CHECK(sandbox::Credentials::MoveToNewUserNS());
  CHECK(sandbox::Credentials::DropFileSystemAccess(proc_fd_.get()));
  CHECK(sandbox::Credentials::DropAllCapabilities(proc_fd_.get()));
}

void LinuxSandbox::EngageSeccompSandbox() {
  CHECK(warmed_up_);
  sandbox::SandboxBPF sandbox(policy_.release());
  base::ScopedFD proc_fd(HANDLE_EINTR(
      openat(proc_fd_.get(), ".", O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
  CHECK(proc_fd.is_valid());
  sandbox.SetProcFd(proc_fd.Pass());
  CHECK(
      sandbox.StartSandbox(sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED))
      << "Starting the process with a sandbox failed. Missing kernel support.";

  // The Broker is now bound to this process and should only be destroyed when
  // the process exits or is killed.
  ANNOTATE_LEAKING_OBJECT_PTR(broker_.release());
}

void LinuxSandbox::Seal() {
  proc_fd_.reset();
}

}  // namespace mandoline