File: broker_process.cc

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (206 lines) | stat: -rw-r--r-- 6,573 bytes parent folder | download | duplicates (3)
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/linux/syscall_broker/broker_process.h"

#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/process_metrics.h"
#include "build/build_config.h"
#include "sandbox/linux/syscall_broker/broker_channel.h"
#include "sandbox/linux/syscall_broker/broker_client.h"
#include "sandbox/linux/syscall_broker/broker_command.h"
#include "sandbox/linux/syscall_broker/broker_host.h"
#include "sandbox/linux/syscall_broker/broker_permission_list.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"

namespace sandbox {

namespace syscall_broker {

BrokerProcess::BrokerProcess(std::optional<BrokerSandboxConfig> policy,
                             BrokerType broker_type,
                             bool fast_check_in_client,
                             bool quiet_failures_for_tests)
    : policy_(std::move(policy)),
      broker_type_(broker_type),
      fast_check_in_client_(fast_check_in_client),
      quiet_failures_for_tests_(quiet_failures_for_tests) {}

BrokerProcess::~BrokerProcess() {
  if (initialized_) {
    if (broker_client_.get()) {
      // Closing the socket should be enough to notify the child to die,
      // unless it has been duplicated.
      CloseChannel();
    }
    PCHECK(0 == kill(broker_pid_, SIGKILL));
    siginfo_t process_info;
    // Reap the child.
    int ret = HANDLE_EINTR(waitid(P_PID, broker_pid_, &process_info, WEXITED));
    PCHECK(0 == ret);
  }
}

bool BrokerProcess::ForkSignalBasedBroker(
    BrokerSideCallback broker_process_init_callback) {
  BrokerChannel::EndPoint ipc_reader, ipc_writer;
  BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);

  pid_t parent_pid = getpid();

  pid_t child_pid = fork();
  if (child_pid == -1)
    return false;

  if (child_pid) {
    // We are the parent and we have just forked our broker process.
    ipc_reader.reset();

    // If we already know our policy we can go ahead and create the
    // BrokerClient.
    CHECK(policy_);
    broker_client_ = std::make_unique<BrokerClient>(
        *policy_, std::move(ipc_writer), fast_check_in_client_);

    broker_pid_ = child_pid;
    initialized_ = true;
    return true;
  }

  // We are the broker process. Make sure to close the writer's end so that
  // we get notified if the client disappears.
  ipc_writer.reset();

  CHECK(std::move(broker_process_init_callback).Run(*policy_));

  BrokerHost broker_host_signal_based(*policy_, std::move(ipc_reader),
                                      parent_pid);
  broker_host_signal_based.LoopAndHandleRequests();
  _exit(1);
}

bool BrokerProcess::Fork(BrokerSideCallback broker_process_init_callback) {
  CHECK(!initialized_);

#if !defined(THREAD_SANITIZER)
  DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
#endif

  return ForkSignalBasedBroker(std::move(broker_process_init_callback));
}

bool BrokerProcess::IsSyscallAllowed(int sysno) const {
  return IsSyscallBrokerable(sysno, fast_check_in_client_);
}

bool BrokerProcess::IsSyscallBrokerable(int sysno, bool fast_check) const {
  CHECK(policy_);

  // The syscalls unavailable on aarch64 are all blocked by Android's default
  // seccomp policy, even on non-aarch64 architectures. I.e., the syscalls XX()
  // with a corresponding XXat() versions are typically unavailable in aarch64
  // and are default disabled in Android. So, we should refuse to broker them
  // to be consistent with the platform's restrictions.
  switch (sysno) {
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_access:
#endif
    case __NR_faccessat:
    case __NR_faccessat2:
      return !fast_check || policy_->allowed_command_set.test(COMMAND_ACCESS);

#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_mkdir:
#endif
    case __NR_mkdirat:
      return !fast_check || policy_->allowed_command_set.test(COMMAND_MKDIR);

#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_open:
#endif
    case __NR_openat:
      return !fast_check || policy_->allowed_command_set.test(COMMAND_OPEN);

#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_readlink:
#endif
    case __NR_readlinkat:
      return !fast_check || policy_->allowed_command_set.test(COMMAND_READLINK);

#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_rename:
#endif
    case __NR_renameat:
    case __NR_renameat2:
      return !fast_check || policy_->allowed_command_set.test(COMMAND_RENAME);

#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_rmdir:
      return !fast_check || policy_->allowed_command_set.test(COMMAND_RMDIR);
#endif

#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_stat:
    case __NR_lstat:
#endif
#if defined(__NR_fstatat)
    case __NR_fstatat:
#endif
#if defined(__NR_fstatat64)
    case __NR_fstatat64:
#endif
#if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__)
    case __NR_newfstatat:
#endif
      return !fast_check || policy_->allowed_command_set.test(COMMAND_STAT);

#if defined(__i386__) || defined(__arm__) || \
    (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
    case __NR_stat64:
    case __NR_lstat64:
      // For security purposes, map stat64 to COMMAND_STAT permission. The
      // separate COMMAND_STAT64 only exists to broker different-sized
      // argument structs.
      return !fast_check || policy_->allowed_command_set.test(COMMAND_STAT);
#endif

#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
    case __NR_unlink:
      return !fast_check || policy_->allowed_command_set.test(COMMAND_UNLINK);
#endif
    case __NR_unlinkat:
      // If rmdir() doesn't exist, unlinkat is used with AT_REMOVEDIR.
      return !fast_check || policy_->allowed_command_set.test(COMMAND_RMDIR) ||
             policy_->allowed_command_set.test(COMMAND_UNLINK);
    case __NR_inotify_add_watch:
      return !fast_check ||
             policy_->allowed_command_set.test(COMMAND_INOTIFY_ADD_WATCH);
    default:
      return false;
  }
}

void BrokerProcess::CloseChannel() {
  broker_client_.reset();
}

}  // namespace syscall_broker
}  // namespace sandbox