Bug Summary

File:root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc
Warning:line 154, column 29
Access to field 'si_code' results in a dereference of a null pointer (loaded from variable 'info')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name trap.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/sandbox/linux -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/sandbox/linux -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D NS_NO_XPCOM -I /root/firefox-clang/security/sandbox/linux -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/security/sandbox/linux -I /root/firefox-clang/security/sandbox/linux -I /root/firefox-clang/security/sandbox/chromium-shim -I /root/firefox-clang/security/sandbox/chromium -I /root/firefox-clang/security/sandbox/chromium-shim/base/allocator/partition_allocator/src -I /root/firefox-clang/security/sandbox/chromium/base/allocator/partition_allocator/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/nsprpub -I /root/firefox-clang/mozglue/baseprofiler/core -I /root/firefox-clang/tools/profiler -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-error=stack-protector -Wno-unreachable-code-return -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc
1// Copyright 2012 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "sandbox/linux/seccomp-bpf/trap.h"
6
7#include <errno(*__errno_location ()).h>
8#include <signal.h>
9#include <stddef.h>
10#include <stdint.h>
11#include <string.h>
12#include <sys/syscall.h>
13
14#include <algorithm>
15#include <atomic>
16#include <limits>
17#include <tuple>
18
19#include "base/compiler_specific.h"
20#include "base/logging.h"
21#include "base/memory/raw_ptr_exclusion.h"
22#include "build/build_config.h"
23#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
24#include "sandbox/linux/seccomp-bpf/die.h"
25#include "sandbox/linux/seccomp-bpf/syscall.h"
26#include "sandbox/linux/services/syscall_wrappers.h"
27#include "sandbox/linux/system_headers/linux_seccomp.h"
28#include "sandbox/linux/system_headers/linux_signal.h"
29
30namespace {
31
32struct arch_sigsys {
33 // RAW_PTR_EXCLUSION: Points to a code address given to us by the kernel.
34 RAW_PTR_EXCLUSION__attribute__((annotate("raw_ptr_exclusion"))) void* ip;
35 int nr;
36 unsigned int arch;
37};
38
39const int kCapacityIncrement = 20;
40
41// Unsafe traps can only be turned on, if the user explicitly allowed them
42// by setting the CHROME_SANDBOX_DEBUGGING environment variable.
43const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
44
45// We need to tell whether we are performing a "normal" callback, or
46// whether we were called recursively from within a UnsafeTrap() callback.
47// This is a little tricky to do, because we need to somehow get access to
48// per-thread data from within a signal context. Normal TLS storage is not
49// safely accessible at this time. We could roll our own, but that involves
50// a lot of complexity. Instead, we co-opt one bit in the signal mask.
51// If BUS is blocked, we assume that we have been called recursively.
52// There is a possibility for collision with other code that needs to do
53// this, but in practice the risks are low.
54// If SIGBUS turns out to be a problem, we could instead co-opt one of the
55// realtime signals. There are plenty of them. Unfortunately, there is no
56// way to mark a signal as allocated. So, the potential for collision is
57// possibly even worse.
58bool GetIsInSigHandler(const ucontext_t* ctx) {
59 // Note: on Android, sigismember does not take a pointer to const.
60 return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), LINUX_SIGBUS7);
61}
62
63void SetIsInSigHandler() {
64 sigset_t mask;
65 if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGBUS7) ||
66 sandbox::sys_sigprocmask(LINUX_SIG_BLOCK0, &mask, nullptr)) {
67 SANDBOX_DIE("Failed to block SIGBUS")sandbox::Die::SandboxDie("Failed to block SIGBUS", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 67)
;
68 }
69}
70
71bool IsDefaultSignalAction(const struct sigaction& sa) {
72 if (sa.sa_flags & SA_SIGINFO4 || sa.sa_handler__sigaction_handler.sa_handler != SIG_DFL((__sighandler_t) 0)) {
73 return false;
74 }
75 return true;
76}
77
78} // namespace
79
80namespace sandbox {
81
82Trap::Trap() {
83 // Set new SIGSYS handler
84 struct sigaction sa = {};
85 // In some toolchain, sa_sigaction is not declared in struct sigaction.
86 // So, here cast the pointer to the sa_handler's type. This works because
87 // |sa_handler| and |sa_sigaction| shares the same memory.
88 sa.sa_handler__sigaction_handler.sa_handler = reinterpret_cast<void (*)(int)>(SigSysAction);
89 sa.sa_flags = LINUX_SA_SIGINFO4 | LINUX_SA_NODEFER0x40000000;
90 struct sigaction old_sa = {};
91 if (sys_sigaction(LINUX_SIGSYS31, &sa, &old_sa) < 0) {
92 SANDBOX_DIE("Failed to configure SIGSYS handler")sandbox::Die::SandboxDie("Failed to configure SIGSYS handler"
, "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 92)
;
93 }
94
95 if (!IsDefaultSignalAction(old_sa)) {
96 static const char kExistingSIGSYSMsg[] =
97 "Existing signal handler when trying to install SIGSYS. SIGSYS needs "
98 "to be reserved for seccomp-bpf.";
99 DLOG(FATAL)!((::logging::ShouldCreateLogMessage(::logging::LOGGING_FATAL
))) ? (void)0 : ::logging::LogMessageVoidify() & (::logging
::LogMessageFatal("/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 99, ::logging::LOGGING_FATAL).stream())
<< kExistingSIGSYSMsg;
100 LOG(ERROR)!((::logging::LOGGING_ERROR == ::logging::LOGGING_FATAL || ::
logging::ShouldCreateLogMessage(::logging::LOGGING_ERROR))) ?
(void)0 : ::logging::LogMessageVoidify() & (::logging::LogMessage
("/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 100, ::logging::LOGGING_ERROR).stream())
<< kExistingSIGSYSMsg;
101 }
102
103 // Unmask SIGSYS
104 sigset_t mask;
105 if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGSYS31) ||
106 sys_sigprocmask(LINUX_SIG_UNBLOCK1, &mask, nullptr)) {
107 SANDBOX_DIE("Failed to configure SIGSYS handler")sandbox::Die::SandboxDie("Failed to configure SIGSYS handler"
, "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 107)
;
108 }
109}
110
111bpf_dsl::TrapRegistry* Trap::Registry() {
112 // Note: This class is not thread safe. It is the caller's responsibility
113 // to avoid race conditions. Normally, this is a non-issue as the sandbox
114 // can only be initialized if there are no other threads present.
115 // Also, this is not a normal singleton. Once created, the global trap
116 // object must never be destroyed again.
117 if (!global_trap_) {
118 global_trap_ = new Trap();
119 if (!global_trap_) {
120 SANDBOX_DIE("Failed to allocate global trap handler")sandbox::Die::SandboxDie("Failed to allocate global trap handler"
, "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 120)
;
121 }
122 }
123 return global_trap_;
124}
125
126void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) {
127 if (info) {
1
Assuming 'info' is null
2
Taking false branch
128 MSAN_UNPOISON(info, sizeof(*info));
129 }
130
131 // Obtain the signal context. This, most notably, gives us access to
132 // all CPU registers at the time of the signal.
133 ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
134 if (ctx) {
3
Assuming 'ctx' is null
4
Taking false branch
135 MSAN_UNPOISON(ctx, sizeof(*ctx));
136 }
137
138 if (!global_trap_) {
5
Assuming 'global_trap_' is non-null
6
Taking false branch
139 RAW_SANDBOX_DIE(sandbox::Die::RawSandboxDie("This can't happen. Found no global singleton instance "
"for Trap() handling.")
140 "This can't happen. Found no global singleton instance "sandbox::Die::RawSandboxDie("This can't happen. Found no global singleton instance "
"for Trap() handling.")
141 "for Trap() handling.")sandbox::Die::RawSandboxDie("This can't happen. Found no global singleton instance "
"for Trap() handling.")
;
142 }
143 global_trap_->SigSys(nr, info, ctx);
7
Passing null pointer value via 2nd parameter 'info'
8
Calling 'Trap::SigSys'
144}
145
146void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) {
147 // Signal handlers should always preserve "errno". Otherwise, we could
148 // trigger really subtle bugs.
149 const int old_errno = errno(*__errno_location ());
150
151 // Various sanity checks to make sure we actually received a signal
152 // triggered by a BPF filter. If something else triggered SIGSYS
153 // (e.g. kill()), there is really nothing we can do with this signal.
154 if (nr != LINUX_SIGSYS31 || info->si_code != SYS_SECCOMPSYS_SECCOMP || !ctx ||
9
Assuming 'nr' is equal to LINUX_SIGSYS
10
Access to field 'si_code' results in a dereference of a null pointer (loaded from variable 'info')
155 info->si_errno <= 0 ||
156 static_cast<size_t>(info->si_errno) > trap_array_size_) {
157 // ATI drivers seem to send SIGSYS, so this cannot be FATAL.
158 // See crbug.com/178166.
159 // TODO(jln): add a DCHECK or move back to FATAL.
160 RAW_LOG(ERROR, "Unexpected SIGSYS received.")::logging::RawLog(::logging::LOGGING_ERROR, "Unexpected SIGSYS received."
)
;
161 errno(*__errno_location ()) = old_errno;
162 return;
163 }
164
165
166 // Obtain the siginfo information that is specific to SIGSYS.
167 struct arch_sigsys sigsys;
168#if defined(si_call_addr_sifields._sigsys._call_addr)
169 sigsys.ip = info->si_call_addr_sifields._sigsys._call_addr;
170 sigsys.nr = info->si_syscall_sifields._sigsys._syscall;
171 sigsys.arch = info->si_arch_sifields._sigsys._arch;
172#else
173 // If the version of glibc doesn't include this information in
174 // siginfo_t (older than 2.17), we need to explicitly copy it
175 // into an arch_sigsys structure.
176 memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
177#endif
178
179#if defined(__mips__)
180 // When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the
181 // number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the
182 // real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx)
183 bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)])) &&
184 sigsys.nr != static_cast<int>(SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)]));
185#else
186 bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)]));
187#endif
188
189 // Some more sanity checks.
190 if (sigsys.ip != reinterpret_cast<void*>(SECCOMP_IP(ctx)((ctx)->uc_mcontext.gregs[(REG_RIP)])) ||
191 sigsys_nr_is_bad || sigsys.arch != SECCOMP_ARCH(62|0x80000000|0x40000000)) {
192 // TODO(markus):
193 // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
194 // safe and can lead to bugs. We should eventually implement a different
195 // logging and reporting mechanism that is safe to be called from
196 // the sigSys() handler.
197 RAW_SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.")sandbox::Die::RawSandboxDie("Sanity checks are failing after receiving SIGSYS."
)
;
198 }
199
200 intptr_t rc;
201 if (has_unsafe_traps_ && GetIsInSigHandler(ctx)) {
202 errno(*__errno_location ()) = old_errno;
203 if (sigsys.nr == __NR_clone56) {
204 RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.")sandbox::Die::RawSandboxDie("Cannot call clone() from an UnsafeTrap() handler."
)
;
205 }
206#if defined(__mips__)
207 // Mips supports up to eight arguments for syscall.
208 // However, seccomp bpf can filter only up to six arguments, so using eight
209 // arguments has sense only when using UnsafeTrap() handler.
210 rc = Syscall::Call(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)]),
211 SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)]),
212 SECCOMP_PARM2(ctx)((ctx)->uc_mcontext.gregs[(REG_RSI)]),
213 SECCOMP_PARM3(ctx)((ctx)->uc_mcontext.gregs[(REG_RDX)]),
214 SECCOMP_PARM4(ctx)((ctx)->uc_mcontext.gregs[(REG_R10)]),
215 SECCOMP_PARM5(ctx)((ctx)->uc_mcontext.gregs[(REG_R8)]),
216 SECCOMP_PARM6(ctx)((ctx)->uc_mcontext.gregs[(REG_R9)]),
217 SECCOMP_PARM7(ctx),
218 SECCOMP_PARM8(ctx));
219#else
220 rc = Syscall::Call(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)]),
221 SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)]),
222 SECCOMP_PARM2(ctx)((ctx)->uc_mcontext.gregs[(REG_RSI)]),
223 SECCOMP_PARM3(ctx)((ctx)->uc_mcontext.gregs[(REG_RDX)]),
224 SECCOMP_PARM4(ctx)((ctx)->uc_mcontext.gregs[(REG_R10)]),
225 SECCOMP_PARM5(ctx)((ctx)->uc_mcontext.gregs[(REG_R8)]),
226 SECCOMP_PARM6(ctx)((ctx)->uc_mcontext.gregs[(REG_R9)]));
227#endif // defined(__mips__)
228 } else {
229 const auto& trap = UNSAFE_TODO(trap_array_[info->si_errno - 1])clang unsafe_buffer_usage begin trap_array_[info->si_errno
- 1] clang unsafe_buffer_usage end
;
230 if (!trap.safe) {
231 SetIsInSigHandler();
232 }
233
234 // Copy the seccomp-specific data into a arch_seccomp_data structure. This
235 // is what we are showing to TrapFnc callbacks that the system call
236 // evaluator registered with the sandbox.
237 struct arch_seccomp_data data = {
238 static_cast<int>(SECCOMP_SYSCALL(ctx)((ctx)->uc_mcontext.gregs[(REG_RAX)])),
239 SECCOMP_ARCH(62|0x80000000|0x40000000),
240 reinterpret_cast<uint64_t>(sigsys.ip),
241 {static_cast<uint64_t>(SECCOMP_PARM1(ctx)((ctx)->uc_mcontext.gregs[(REG_RDI)])),
242 static_cast<uint64_t>(SECCOMP_PARM2(ctx)((ctx)->uc_mcontext.gregs[(REG_RSI)])),
243 static_cast<uint64_t>(SECCOMP_PARM3(ctx)((ctx)->uc_mcontext.gregs[(REG_RDX)])),
244 static_cast<uint64_t>(SECCOMP_PARM4(ctx)((ctx)->uc_mcontext.gregs[(REG_R10)])),
245 static_cast<uint64_t>(SECCOMP_PARM5(ctx)((ctx)->uc_mcontext.gregs[(REG_R8)])),
246 static_cast<uint64_t>(SECCOMP_PARM6(ctx)((ctx)->uc_mcontext.gregs[(REG_R9)]))}};
247
248 // Now call the TrapFnc callback associated with this particular instance
249 // of SECCOMP_RET_TRAP.
250 rc = trap.fnc(data, reinterpret_cast<void*>(trap.aux));
251 }
252
253 // Update the CPU register that stores the return code of the system call
254 // that we just handled, and restore "errno" to the value that it had
255 // before entering the signal handler.
256 Syscall::PutValueInUcontext(rc, ctx);
257 errno(*__errno_location ()) = old_errno;
258
259 return;
260}
261
262uint16_t Trap::Add(const Handler& handler) {
263 if (!handler.safe && !SandboxDebuggingAllowedByUser()) {
264 // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable,
265 // we never return an ErrorCode that is marked as "unsafe". This also
266 // means, the BPF compiler will never emit code that allow unsafe system
267 // calls to by-pass the filter (because they use the magic return address
268 // from Syscall::Call(-1)).
269
270 // This SANDBOX_DIE() can optionally be removed. It won't break security,
271 // but it might make error messages from the BPF compiler a little harder
272 // to understand. Removing the SANDBOX_DIE() allows callers to easily check
273 // whether unsafe traps are supported (by checking whether the returned
274 // ErrorCode is ET_INVALID).
275 SANDBOX_DIE(sandbox::Die::SandboxDie("Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
"is enabled", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 277)
276 "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "sandbox::Die::SandboxDie("Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
"is enabled", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 277)
277 "is enabled")sandbox::Die::SandboxDie("Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
"is enabled", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 277)
;
278 }
279
280 // We return unique identifiers together with SECCOMP_RET_TRAP. This allows
281 // us to associate trap with the appropriate handler. The kernel allows us
282 // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to
283 // avoid 0, as it could be confused for a trap without any specific id.
284 // The nice thing about sequentially numbered identifiers is that we can also
285 // trivially look them up from our signal handler without making any system
286 // calls that might be async-signal-unsafe.
287 // In order to do so, we store all of our traps in a C-style trap_array_.
288
289 auto iter = trap_ids_.find(handler);
290 if (iter != trap_ids_.end()) {
291 // We have seen this pair before. Return the same id that we assigned
292 // earlier.
293 return iter->second;
294 }
295
296 // This is a new pair. Remember it and assign a new id.
297 if (trap_array_size_ >= SECCOMP_RET_DATA0x0000ffffU /* 0xFFFF */ ||
298 trap_array_size_ >= std::numeric_limits<uint16_t>::max()) {
299 // In practice, this is pretty much impossible to trigger, as there
300 // are other kernel limitations that restrict overall BPF program sizes.
301 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances")sandbox::Die::SandboxDie("Too many SECCOMP_RET_TRAP callback instances"
, "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 301)
;
302 }
303
304 // Our callers ensure that there are no other threads accessing trap_array_
305 // concurrently (typically this is done by ensuring that we are single-
306 // threaded while the sandbox is being set up). But we nonetheless are
307 // modifying a live data structure that could be accessed any time a
308 // system call is made; as system calls could be triggering SIGSYS.
309 // So, we have to be extra careful that we update trap_array_ atomically.
310 // In particular, this means we shouldn't be using realloc() to resize it.
311 // Instead, we allocate a new array, copy the values, and then switch the
312 // pointer. We only really care about the pointer being updated atomically
313 // and the data that is pointed to being valid, as these are the only
314 // values accessed from the signal handler. It is OK if trap_array_size_
315 // is inconsistent with the pointer, as it is monotonously increasing.
316 // Also, we only care about compiler barriers, as the signal handler is
317 // triggered synchronously from a system call. We don't have to protect
318 // against issues with the memory model or with completely asynchronous
319 // events.
320 if (trap_array_size_ >= trap_array_capacity_) {
321 trap_array_capacity_ += kCapacityIncrement;
322 auto* old_trap_array = trap_array_;
323 auto* new_trap_array = new TrapRegistry::Handler[trap_array_capacity_];
324 std::copy_n(old_trap_array, trap_array_size_, new_trap_array);
325
326 trap_array_ = new_trap_array;
327 // Prevent the compiler from moving delete[] before the store of the
328 // |new_trap_array|, otherwise a concurrent SIGSYS may see a |trap_array_|
329 // that still points to |old_trap_array| after it has been deleted.
330 std::atomic_signal_fence(std::memory_order_release);
331 delete[] old_trap_array;
332 }
333
334 uint16_t id = trap_array_size_ + 1;
335 trap_ids_[handler] = id;
336 UNSAFE_TODO(trap_array_[trap_array_size_])clang unsafe_buffer_usage begin trap_array_[trap_array_size_
] clang unsafe_buffer_usage end
= handler;
337 trap_array_size_++;
338 return id;
339}
340
341bool Trap::SandboxDebuggingAllowedByUser() {
342 const char* debug_flag = getenv(kSandboxDebuggingEnv);
343 return debug_flag && *debug_flag;
344}
345
346bool Trap::EnableUnsafeTraps() {
347 if (!has_unsafe_traps_) {
348 // Unsafe traps are a one-way fuse. Once enabled, they can never be turned
349 // off again.
350 // We only allow enabling unsafe traps, if the user explicitly set an
351 // appropriate environment variable. This prevents bugs that accidentally
352 // disable all sandboxing for all users.
353 if (SandboxDebuggingAllowedByUser()) {
354 // We only ever print this message once, when we enable unsafe traps the
355 // first time.
356 SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes")sandbox::Die::SandboxInfo("WARNING! Disabling sandbox for debugging purposes"
, "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 356)
;
357 has_unsafe_traps_ = true;
358 } else {
359 SANDBOX_INFO(sandbox::Die::SandboxInfo("Cannot disable sandbox and use unsafe traps unless "
"CHROME_SANDBOX_DEBUGGING is turned on first", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 361)
360 "Cannot disable sandbox and use unsafe traps unless "sandbox::Die::SandboxInfo("Cannot disable sandbox and use unsafe traps unless "
"CHROME_SANDBOX_DEBUGGING is turned on first", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 361)
361 "CHROME_SANDBOX_DEBUGGING is turned on first")sandbox::Die::SandboxInfo("Cannot disable sandbox and use unsafe traps unless "
"CHROME_SANDBOX_DEBUGGING is turned on first", "/root/firefox-clang/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc"
, 361)
;
362 }
363 }
364 // Returns the, possibly updated, value of has_unsafe_traps_.
365 return has_unsafe_traps_;
366}
367
368Trap* Trap::global_trap_;
369
370} // namespace sandbox