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 #include "sandbox/linux/seccomp-bpf/trap.h"
6
7 #include <errno.h>
8 #include <signal.h>
9 #include <string.h>
10 #include <sys/prctl.h>
11 #include <sys/syscall.h>
12
13 #include <limits>
14
15 #include "base/logging.h"
16 #include "sandbox/linux/seccomp-bpf/codegen.h"
17 #include "sandbox/linux/seccomp-bpf/die.h"
18 #include "sandbox/linux/seccomp-bpf/syscall.h"
19
20 // Android's signal.h doesn't define ucontext etc.
21 #if defined(OS_ANDROID)
22 #include "sandbox/linux/services/android_ucontext.h"
23 #endif
24
25 namespace {
26
27 const int kCapacityIncrement = 20;
28
29 // Unsafe traps can only be turned on, if the user explicitly allowed them
30 // by setting the CHROME_SANDBOX_DEBUGGING environment variable.
31 const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
32
33 // We need to tell whether we are performing a "normal" callback, or
34 // whether we were called recursively from within a UnsafeTrap() callback.
35 // This is a little tricky to do, because we need to somehow get access to
36 // per-thread data from within a signal context. Normal TLS storage is not
37 // safely accessible at this time. We could roll our own, but that involves
38 // a lot of complexity. Instead, we co-opt one bit in the signal mask.
39 // If BUS is blocked, we assume that we have been called recursively.
40 // There is a possibility for collision with other code that needs to do
41 // this, but in practice the risks are low.
42 // If SIGBUS turns out to be a problem, we could instead co-opt one of the
43 // realtime signals. There are plenty of them. Unfortunately, there is no
44 // way to mark a signal as allocated. So, the potential for collision is
45 // possibly even worse.
GetIsInSigHandler(const ucontext_t * ctx)46 bool GetIsInSigHandler(const ucontext_t* ctx) {
47 // Note: on Android, sigismember does not take a pointer to const.
48 return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), SIGBUS);
49 }
50
SetIsInSigHandler()51 void SetIsInSigHandler() {
52 sigset_t mask;
53 if (sigemptyset(&mask) || sigaddset(&mask, SIGBUS) ||
54 sigprocmask(SIG_BLOCK, &mask, NULL)) {
55 SANDBOX_DIE("Failed to block SIGBUS");
56 }
57 }
58
IsDefaultSignalAction(const struct sigaction & sa)59 bool IsDefaultSignalAction(const struct sigaction& sa) {
60 if (sa.sa_flags & SA_SIGINFO || sa.sa_handler != SIG_DFL) {
61 return false;
62 }
63 return true;
64 }
65
66 } // namespace
67
68 namespace sandbox {
69
Trap()70 Trap::Trap()
71 : trap_array_(NULL),
72 trap_array_size_(0),
73 trap_array_capacity_(0),
74 has_unsafe_traps_(false) {
75 // Set new SIGSYS handler
76 struct sigaction sa = {};
77 sa.sa_sigaction = SigSysAction;
78 sa.sa_flags = SA_SIGINFO | SA_NODEFER;
79 struct sigaction old_sa;
80 if (sigaction(SIGSYS, &sa, &old_sa) < 0) {
81 SANDBOX_DIE("Failed to configure SIGSYS handler");
82 }
83
84 if (!IsDefaultSignalAction(old_sa)) {
85 // TODO(jln): make this FATAL, at least in DEBUG mode.
86 LOG(ERROR) << "Existing signal handler when trying to install SIGSYS";
87 }
88
89 // Unmask SIGSYS
90 sigset_t mask;
91 if (sigemptyset(&mask) || sigaddset(&mask, SIGSYS) ||
92 sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
93 SANDBOX_DIE("Failed to configure SIGSYS handler");
94 }
95 }
96
GetInstance()97 Trap* Trap::GetInstance() {
98 // Note: This class is not thread safe. It is the caller's responsibility
99 // to avoid race conditions. Normally, this is a non-issue as the sandbox
100 // can only be initialized if there are no other threads present.
101 // Also, this is not a normal singleton. Once created, the global trap
102 // object must never be destroyed again.
103 if (!global_trap_) {
104 global_trap_ = new Trap();
105 if (!global_trap_) {
106 SANDBOX_DIE("Failed to allocate global trap handler");
107 }
108 }
109 return global_trap_;
110 }
111
SigSysAction(int nr,siginfo_t * info,void * void_context)112 void Trap::SigSysAction(int nr, siginfo_t* info, void* void_context) {
113 if (!global_trap_) {
114 RAW_SANDBOX_DIE(
115 "This can't happen. Found no global singleton instance "
116 "for Trap() handling.");
117 }
118 global_trap_->SigSys(nr, info, void_context);
119 }
120
SigSys(int nr,siginfo_t * info,void * void_context)121 void Trap::SigSys(int nr, siginfo_t* info, void* void_context) {
122 // Signal handlers should always preserve "errno". Otherwise, we could
123 // trigger really subtle bugs.
124 const int old_errno = errno;
125
126 // Various sanity checks to make sure we actually received a signal
127 // triggered by a BPF filter. If something else triggered SIGSYS
128 // (e.g. kill()), there is really nothing we can do with this signal.
129 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context ||
130 info->si_errno <= 0 ||
131 static_cast<size_t>(info->si_errno) > trap_array_size_) {
132 // ATI drivers seem to send SIGSYS, so this cannot be FATAL.
133 // See crbug.com/178166.
134 // TODO(jln): add a DCHECK or move back to FATAL.
135 RAW_LOG(ERROR, "Unexpected SIGSYS received.");
136 errno = old_errno;
137 return;
138 }
139
140 // Obtain the signal context. This, most notably, gives us access to
141 // all CPU registers at the time of the signal.
142 ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
143
144 // Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
145 // most versions of glibc don't include this information in siginfo_t. So,
146 // we need to explicitly copy it into a arch_sigsys structure.
147 struct arch_sigsys sigsys;
148 memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
149
150 // Some more sanity checks.
151 if (sigsys.ip != reinterpret_cast<void*>(SECCOMP_IP(ctx)) ||
152 sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) ||
153 sigsys.arch != SECCOMP_ARCH) {
154 // TODO(markus):
155 // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
156 // safe and can lead to bugs. We should eventually implement a different
157 // logging and reporting mechanism that is safe to be called from
158 // the sigSys() handler.
159 RAW_SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.");
160 }
161
162 intptr_t rc;
163 if (has_unsafe_traps_ && GetIsInSigHandler(ctx)) {
164 errno = old_errno;
165 if (sigsys.nr == __NR_clone) {
166 RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
167 }
168 rc = SandboxSyscall(sigsys.nr,
169 SECCOMP_PARM1(ctx),
170 SECCOMP_PARM2(ctx),
171 SECCOMP_PARM3(ctx),
172 SECCOMP_PARM4(ctx),
173 SECCOMP_PARM5(ctx),
174 SECCOMP_PARM6(ctx));
175 } else {
176 const ErrorCode& err = trap_array_[info->si_errno - 1];
177 if (!err.safe_) {
178 SetIsInSigHandler();
179 }
180
181 // Copy the seccomp-specific data into a arch_seccomp_data structure. This
182 // is what we are showing to TrapFnc callbacks that the system call
183 // evaluator registered with the sandbox.
184 struct arch_seccomp_data data = {
185 sigsys.nr, SECCOMP_ARCH, reinterpret_cast<uint64_t>(sigsys.ip),
186 {static_cast<uint64_t>(SECCOMP_PARM1(ctx)),
187 static_cast<uint64_t>(SECCOMP_PARM2(ctx)),
188 static_cast<uint64_t>(SECCOMP_PARM3(ctx)),
189 static_cast<uint64_t>(SECCOMP_PARM4(ctx)),
190 static_cast<uint64_t>(SECCOMP_PARM5(ctx)),
191 static_cast<uint64_t>(SECCOMP_PARM6(ctx))}};
192
193 // Now call the TrapFnc callback associated with this particular instance
194 // of SECCOMP_RET_TRAP.
195 rc = err.fnc_(data, err.aux_);
196 }
197
198 // Update the CPU register that stores the return code of the system call
199 // that we just handled, and restore "errno" to the value that it had
200 // before entering the signal handler.
201 SECCOMP_RESULT(ctx) = static_cast<greg_t>(rc);
202 errno = old_errno;
203
204 return;
205 }
206
operator <(const TrapKey & o) const207 bool Trap::TrapKey::operator<(const TrapKey& o) const {
208 if (fnc != o.fnc) {
209 return fnc < o.fnc;
210 } else if (aux != o.aux) {
211 return aux < o.aux;
212 } else {
213 return safe < o.safe;
214 }
215 }
216
MakeTrap(TrapFnc fnc,const void * aux,bool safe)217 ErrorCode Trap::MakeTrap(TrapFnc fnc, const void* aux, bool safe) {
218 return GetInstance()->MakeTrapImpl(fnc, aux, safe);
219 }
220
MakeTrapImpl(TrapFnc fnc,const void * aux,bool safe)221 ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe) {
222 if (!safe && !SandboxDebuggingAllowedByUser()) {
223 // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable,
224 // we never return an ErrorCode that is marked as "unsafe". This also
225 // means, the BPF compiler will never emit code that allow unsafe system
226 // calls to by-pass the filter (because they use the magic return address
227 // from SandboxSyscall(-1)).
228
229 // This SANDBOX_DIE() can optionally be removed. It won't break security,
230 // but it might make error messages from the BPF compiler a little harder
231 // to understand. Removing the SANDBOX_DIE() allows callers to easyly check
232 // whether unsafe traps are supported (by checking whether the returned
233 // ErrorCode is ET_INVALID).
234 SANDBOX_DIE(
235 "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
236 "is enabled");
237
238 return ErrorCode();
239 }
240
241 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance
242 // of a SECCOMP_RET_TRAP.
243 TrapKey key(fnc, aux, safe);
244 TrapIds::const_iterator iter = trap_ids_.find(key);
245
246 // We return unique identifiers together with SECCOMP_RET_TRAP. This allows
247 // us to associate trap with the appropriate handler. The kernel allows us
248 // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to
249 // avoid 0, as it could be confused for a trap without any specific id.
250 // The nice thing about sequentially numbered identifiers is that we can also
251 // trivially look them up from our signal handler without making any system
252 // calls that might be async-signal-unsafe.
253 // In order to do so, we store all of our traps in a C-style trap_array_.
254 uint16_t id;
255 if (iter != trap_ids_.end()) {
256 // We have seen this pair before. Return the same id that we assigned
257 // earlier.
258 id = iter->second;
259 } else {
260 // This is a new pair. Remember it and assign a new id.
261 if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ ||
262 trap_array_size_ >= std::numeric_limits<typeof(id)>::max()) {
263 // In practice, this is pretty much impossible to trigger, as there
264 // are other kernel limitations that restrict overall BPF program sizes.
265 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances");
266 }
267 id = trap_array_size_ + 1;
268
269 // Our callers ensure that there are no other threads accessing trap_array_
270 // concurrently (typically this is done by ensuring that we are single-
271 // threaded while the sandbox is being set up). But we nonetheless are
272 // modifying a life data structure that could be accessed any time a
273 // system call is made; as system calls could be triggering SIGSYS.
274 // So, we have to be extra careful that we update trap_array_ atomically.
275 // In particular, this means we shouldn't be using realloc() to resize it.
276 // Instead, we allocate a new array, copy the values, and then switch the
277 // pointer. We only really care about the pointer being updated atomically
278 // and the data that is pointed to being valid, as these are the only
279 // values accessed from the signal handler. It is OK if trap_array_size_
280 // is inconsistent with the pointer, as it is monotonously increasing.
281 // Also, we only care about compiler barriers, as the signal handler is
282 // triggered synchronously from a system call. We don't have to protect
283 // against issues with the memory model or with completely asynchronous
284 // events.
285 if (trap_array_size_ >= trap_array_capacity_) {
286 trap_array_capacity_ += kCapacityIncrement;
287 ErrorCode* old_trap_array = trap_array_;
288 ErrorCode* new_trap_array = new ErrorCode[trap_array_capacity_];
289
290 // Language specs are unclear on whether the compiler is allowed to move
291 // the "delete[]" above our preceding assignments and/or memory moves,
292 // iff the compiler believes that "delete[]" doesn't have any other
293 // global side-effects.
294 // We insert optimization barriers to prevent this from happening.
295 // The first barrier is probably not needed, but better be explicit in
296 // what we want to tell the compiler.
297 // The clang developer mailing list couldn't answer whether this is a
298 // legitimate worry; but they at least thought that the barrier is
299 // sufficient to prevent the (so far hypothetical) problem of re-ordering
300 // of instructions by the compiler.
301 memcpy(new_trap_array, trap_array_, trap_array_size_ * sizeof(ErrorCode));
302 asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory");
303 trap_array_ = new_trap_array;
304 asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory");
305
306 delete[] old_trap_array;
307 }
308 trap_ids_[key] = id;
309 trap_array_[trap_array_size_] = ErrorCode(fnc, aux, safe, id);
310 return trap_array_[trap_array_size_++];
311 }
312
313 return ErrorCode(fnc, aux, safe, id);
314 }
315
SandboxDebuggingAllowedByUser() const316 bool Trap::SandboxDebuggingAllowedByUser() const {
317 const char* debug_flag = getenv(kSandboxDebuggingEnv);
318 return debug_flag && *debug_flag;
319 }
320
EnableUnsafeTrapsInSigSysHandler()321 bool Trap::EnableUnsafeTrapsInSigSysHandler() {
322 Trap* trap = GetInstance();
323 if (!trap->has_unsafe_traps_) {
324 // Unsafe traps are a one-way fuse. Once enabled, they can never be turned
325 // off again.
326 // We only allow enabling unsafe traps, if the user explicitly set an
327 // appropriate environment variable. This prevents bugs that accidentally
328 // disable all sandboxing for all users.
329 if (trap->SandboxDebuggingAllowedByUser()) {
330 // We only ever print this message once, when we enable unsafe traps the
331 // first time.
332 SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes");
333 trap->has_unsafe_traps_ = true;
334 } else {
335 SANDBOX_INFO(
336 "Cannot disable sandbox and use unsafe traps unless "
337 "CHROME_SANDBOX_DEBUGGING is turned on first");
338 }
339 }
340 // Returns the, possibly updated, value of has_unsafe_traps_.
341 return trap->has_unsafe_traps_;
342 }
343
ErrorCodeFromTrapId(uint16_t id)344 ErrorCode Trap::ErrorCodeFromTrapId(uint16_t id) {
345 if (global_trap_ && id > 0 && id <= global_trap_->trap_array_size_) {
346 return global_trap_->trap_array_[id - 1];
347 } else {
348 return ErrorCode();
349 }
350 }
351
352 Trap* Trap::global_trap_;
353
354 } // namespace sandbox
355