Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(727)

Side by Side Diff: sandbox/linux/seccomp-bpf/sandbox_bpf.h

Issue 10833044: Refactored ErrorCode into it's own class (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added unittest (and new framework to make this possible) Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef SANDBOX_BPF_H__ 5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
6 #define SANDBOX_BPF_H__ 6 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
7 7
8 #include <endian.h> 8 #include <endian.h>
9 #include <errno.h> 9 #include <errno.h>
10 #include <fcntl.h> 10 #include <fcntl.h>
11 #include <linux/audit.h> 11 #include <linux/audit.h>
12 #include <linux/filter.h> 12 #include <linux/filter.h>
13 // #include <linux/seccomp.h> 13 // #include <linux/seccomp.h>
14 #include <linux/unistd.h> 14 #include <linux/unistd.h>
15 #include <netinet/in.h> 15 #include <netinet/in.h>
16 #include <netinet/tcp.h> 16 #include <netinet/tcp.h>
(...skipping 21 matching lines...) Expand all
38 #include <map> 38 #include <map>
39 #include <utility> 39 #include <utility>
40 #include <vector> 40 #include <vector>
41 41
42 #ifndef SECCOMP_BPF_STANDALONE 42 #ifndef SECCOMP_BPF_STANDALONE
43 #include "base/basictypes.h" 43 #include "base/basictypes.h"
44 #include "base/eintr_wrapper.h" 44 #include "base/eintr_wrapper.h"
45 #include "base/logging.h" 45 #include "base/logging.h"
46 #endif 46 #endif
47 47
48 #if defined(SECCOMP_BPF_VALGRIND_HACKS)
49 #ifndef SECCOMP_BPF_STANDALONE
50 #include "base/third_party/valgrind/valgrind.h"
51 #endif
52 #endif
53
54
48 // The Seccomp2 kernel ABI is not part of older versions of glibc. 55 // The Seccomp2 kernel ABI is not part of older versions of glibc.
49 // As we can't break compilation with these versions of the library, 56 // As we can't break compilation with these versions of the library,
50 // we explicitly define all missing symbols. 57 // we explicitly define all missing symbols.
51 58
52 #ifndef PR_SET_NO_NEW_PRIVS 59 #ifndef PR_SET_NO_NEW_PRIVS
53 #define PR_SET_NO_NEW_PRIVS 38 60 #define PR_SET_NO_NEW_PRIVS 38
54 #define PR_GET_NO_NEW_PRIVS 39 61 #define PR_GET_NO_NEW_PRIVS 39
55 #endif 62 #endif
56 #ifndef IPC_64 63 #ifndef IPC_64
57 #define IPC_64 0x0100 64 #define IPC_64 0x0100
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 #define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, r2) 144 #define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, r2)
138 #define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, r3) 145 #define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, r3)
139 #define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, r4) 146 #define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, r4)
140 #define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, r5) 147 #define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, r5)
141 148
142 #else 149 #else
143 #error Unsupported target platform 150 #error Unsupported target platform
144 151
145 #endif 152 #endif
146 153
154 #include "sandbox/linux/seccomp-bpf/die.h"
155 #include "sandbox/linux/seccomp-bpf/errorcode.h"
156
157
158 namespace playground2 {
159
147 struct arch_seccomp_data { 160 struct arch_seccomp_data {
148 int nr; 161 int nr;
149 uint32_t arch; 162 uint32_t arch;
150 uint64_t instruction_pointer; 163 uint64_t instruction_pointer;
151 uint64_t args[6]; 164 uint64_t args[6];
152 }; 165 };
153 166
154 struct arch_sigsys { 167 struct arch_sigsys {
155 void *ip; 168 void *ip;
156 int nr; 169 int nr;
157 unsigned int arch; 170 unsigned int arch;
158 }; 171 };
159 172
160 #ifdef SECCOMP_BPF_STANDALONE 173 #if defined(SECCOMP_BPF_STANDALONE)
161 #define arraysize(x) sizeof(x)/sizeof(*(x))) 174 #define arraysize(x) sizeof(x)/sizeof(*(x)))
162 #define HANDLE_EINTR TEMP_FAILURE_RETRY 175 #define HANDLE_EINTR TEMP_FAILURE_RETRY
163 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ 176 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
164 TypeName(); \ 177 TypeName(); \
165 TypeName(const TypeName&); \ 178 TypeName(const TypeName&); \
166 void operator=(const TypeName&) 179 void operator=(const TypeName&)
167 #endif 180 #endif
168 181
169
170 namespace playground2 {
171
172 class Sandbox { 182 class Sandbox {
173 public: 183 public:
174 enum SandboxStatus { 184 enum SandboxStatus {
175 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() 185 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox()
176 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing 186 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing
177 STATUS_UNAVAILABLE, // Currently unavailable but might work again later 187 STATUS_UNAVAILABLE, // Currently unavailable but might work again later
178 STATUS_AVAILABLE, // Sandboxing is available but not currently active 188 STATUS_AVAILABLE, // Sandboxing is available but not currently active
179 STATUS_ENABLED // The sandbox is now active 189 STATUS_ENABLED // The sandbox is now active
180 }; 190 };
181 191
182 enum {
183 SB_INVALID = -1,
184 SB_ALLOWED = 0x0000,
185 SB_INSPECT_ARG_1 = 0x8001,
186 SB_INSPECT_ARG_2 = 0x8002,
187 SB_INSPECT_ARG_3 = 0x8004,
188 SB_INSPECT_ARG_4 = 0x8008,
189 SB_INSPECT_ARG_5 = 0x8010,
190 SB_INSPECT_ARG_6 = 0x8020
191 };
192
193 // TrapFnc is a pointer to a function that handles Seccomp traps in 192 // TrapFnc is a pointer to a function that handles Seccomp traps in
194 // user-space. The seccomp policy can request that a trap handler gets 193 // user-space. The seccomp policy can request that a trap handler gets
195 // installed; it does so by returning a suitable ErrorCode() from the 194 // installed; it does so by returning a suitable ErrorCode() from the
196 // syscallEvaluator. See the ErrorCode() constructor for how to pass in 195 // syscallEvaluator. See the ErrorCode() constructor for how to pass in
197 // the function pointer. 196 // the function pointer.
198 // Please note that TrapFnc is executed from signal context and must be 197 // Please note that TrapFnc is executed from signal context and must be
199 // async-signal safe: 198 // async-signal safe:
200 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html 199 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
201 typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void *aux); 200 typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void *aux);
202 201
203 class ErrorCode {
204 friend class Sandbox;
205 public:
206 // We can either wrap a symbolic ErrorCode (i.e. enum values), an errno
207 // value (in the range 1..4095), or a pointer to a TrapFnc callback
208 // handling a SECCOMP_RET_TRAP trap.
209 // All of these different values are stored in the "err_" field. So, code
210 // that is using the ErrorCode class typically operates on a single 32bit
211 // field.
212 // This is not only quiet efficient, it also makes the API really easy to
213 // use.
214 ErrorCode(int err = SB_INVALID)
215 : id_(0),
216 fnc_(NULL),
217 aux_(NULL) {
218 switch (err) {
219 case SB_INVALID:
220 err_ = SECCOMP_RET_INVALID;
221 break;
222 case SB_ALLOWED:
223 err_ = SECCOMP_RET_ALLOW;
224 break;
225 case SB_INSPECT_ARG_1...SB_INSPECT_ARG_6:
226 die("Not implemented");
227 break;
228 case 1 ... 4095:
229 err_ = SECCOMP_RET_ERRNO + err;
230 break;
231 default:
232 die("Invalid use of ErrorCode object");
233 }
234 }
235
236 // If we are wrapping a callback, we must assign a unique id. This id is
237 // how the kernel tells us which one of our different SECCOMP_RET_TRAP
238 // cases has been triggered.
239 // The getTrapId() function assigns one unique id (starting at 1) for
240 // each distinct pair of TrapFnc and auxiliary data.
241 ErrorCode(TrapFnc fnc, const void *aux, int id = 0) :
242 id_(id ? id : getTrapId(fnc, aux)),
243 fnc_(fnc),
244 aux_(const_cast<void *>(aux)),
245 err_(SECCOMP_RET_TRAP + id_) {
246 }
247
248 // Destructor doesn't need to do anything.
249 ~ErrorCode() { }
250
251 // Always return the value that goes into the BPF filter program.
252 operator uint32_t() const { return err_; }
253
254 protected:
255 // Fields needed for SECCOMP_RET_TRAP callbacks
256 int id_;
257 TrapFnc fnc_;
258 void *aux_;
259
260 // 32bit field used for all possible types of ErrorCode values
261 uint32_t err_;
262 };
263
264 enum Operation { 202 enum Operation {
265 OP_NOP, OP_EQUAL, OP_NOTEQUAL, OP_LESS, 203 OP_NOP, OP_EQUAL, OP_NOTEQUAL, OP_LESS,
266 OP_LESS_EQUAL, OP_GREATER, OP_GREATER_EQUAL, 204 OP_LESS_EQUAL, OP_GREATER, OP_GREATER_EQUAL,
267 OP_HAS_BITS, OP_DOES_NOT_HAVE_BITS 205 OP_HAS_BITS, OP_DOES_NOT_HAVE_BITS
268 }; 206 };
269 207
270 struct Constraint { 208 struct Constraint {
271 bool is32bit; 209 bool is32bit;
272 Operation op; 210 Operation op;
273 uint32_t value; 211 uint32_t value;
(...skipping 27 matching lines...) Expand all
301 // of system call argument(s) by returning a suitable combination of 239 // of system call argument(s) by returning a suitable combination of
302 // SB_INSPECT_ARG_x bits. 240 // SB_INSPECT_ARG_x bits.
303 // The system argument evaluator is called (if needed) to query additional 241 // The system argument evaluator is called (if needed) to query additional
304 // constraints for the system call arguments. In the vast majority of 242 // constraints for the system call arguments. In the vast majority of
305 // cases, it will set a "Constraint" that forces a new "errno" value. 243 // cases, it will set a "Constraint" that forces a new "errno" value.
306 // But for more complex filters, it is possible to return another mask 244 // But for more complex filters, it is possible to return another mask
307 // of SB_INSPECT_ARG_x bits. 245 // of SB_INSPECT_ARG_x bits.
308 static void setSandboxPolicy(EvaluateSyscall syscallEvaluator, 246 static void setSandboxPolicy(EvaluateSyscall syscallEvaluator,
309 EvaluateArguments argumentEvaluator); 247 EvaluateArguments argumentEvaluator);
310 248
249 // We can use ErrorCode to request calling of a trap handler. This method
250 // performs the required wrapping of the callback function into an
251 // ErrorCode object.
252 static ErrorCode Trap(ErrorCode::TrapFnc fnc, const void *aux);
253
254 // Kill the program and print an error message.
255 static ErrorCode Kill(const char *msg);
256
311 // This is the main public entry point. It finds all system calls that 257 // This is the main public entry point. It finds all system calls that
312 // need rewriting, sets up the resources needed by the sandbox, and 258 // need rewriting, sets up the resources needed by the sandbox, and
313 // enters Seccomp mode. 259 // enters Seccomp mode.
314 static void startSandbox(); 260 static void startSandbox();
315 261
316 protected:
317 // Print an error message and terminate the program. Used for fatal errors.
318 static void die(const char *msg) __attribute__((noreturn)) {
319 if (msg) {
320 #ifndef SECCOMP_BPF_STANDALONE
321 if (!dryRun_) {
322 // LOG(FATAL) is not neccessarily async-signal safe. It would be
323 // better to always use the code for the SECCOMP_BPF_STANDALONE case.
324 // But that prevents the logging and reporting infrastructure from
325 // picking up sandbox related crashes.
326 // For now, in picking between two evils, we decided in favor of
327 // LOG(FATAL). In the long run, we probably want to rewrite this code
328 // to be async-signal safe.
329 LOG(FATAL) << msg;
330 } else
331 #endif
332 {
333 // If there is no logging infrastructure in place, we just write error
334 // messages to stderr.
335 // We also write to stderr, if we are called in a child process from
336 // supportsSeccompSandbox(). This makes sure we can actually do the
337 // correct logging from the parent process, which is more likely to
338 // have access to logging infrastructure.
339 if (HANDLE_EINTR(write(2, msg, strlen(msg)))) { }
340 if (HANDLE_EINTR(write(2, "\n", 1))) { }
341 }
342 }
343 for (;;) {
344 // exit_group() should exit our program. After all, it is defined as a
345 // function that doesn't return. But things can theoretically go wrong.
346 // Especially, since we are dealing with system call filters. Continuing
347 // execution would be very bad in most cases where die() gets called.
348 // So, if there is no way for us to ask for the program to exit, the next
349 // best thing we can do is to loop indefinitely. Maybe, somebody will
350 // notice and file a bug...
351 syscall(__NR_exit_group, 1);
352 _exit(1);
353 }
354 }
355
356 // Get a file descriptor pointing to "/proc", if currently available.
357 static int getProcFd() { return proc_fd_; }
358
359 private: 262 private:
263 friend class ErrorCode;
360 friend class Util; 264 friend class Util;
361 friend class Verifier; 265 friend class Verifier;
266
267
362 struct Range { 268 struct Range {
363 Range(uint32_t f, uint32_t t, const ErrorCode& e) : 269 Range(uint32_t f, uint32_t t, const ErrorCode& e) :
364 from(f), 270 from(f),
365 to(t), 271 to(t),
366 err(e) { 272 err(e) {
367 } 273 }
368 uint32_t from, to; 274 uint32_t from, to;
369 ErrorCode err; 275 ErrorCode err;
370 }; 276 };
371 struct FixUp { 277 struct FixUp {
372 FixUp(unsigned int a, bool j) : 278 FixUp(unsigned int a, bool j) :
373 jt(j), addr(a) { } 279 jt(j), addr(a) { }
374 bool jt:1; 280 bool jt:1;
375 unsigned addr:31; 281 unsigned addr:31;
376 }; 282 };
377 typedef std::vector<Range> Ranges; 283 typedef std::vector<Range> Ranges;
378 typedef std::map<uint32_t, std::vector<FixUp> > RetInsns; 284 typedef std::map<uint32_t, std::vector<FixUp> > RetInsns;
379 typedef std::vector<struct sock_filter> Program; 285 typedef std::vector<struct sock_filter> Program;
286 typedef std::map<uint32_t, ErrorCode> ErrMap;
380 typedef std::vector<ErrorCode> Traps; 287 typedef std::vector<ErrorCode> Traps;
381 typedef std::map<std::pair<TrapFnc, const void *>, int> TrapIds; 288 typedef std::map<std::pair<TrapFnc, const void *>, int> TrapIds;
382 289
383 static ErrorCode probeEvaluator(int signo) __attribute__((const)); 290 static ErrorCode probeEvaluator(int signo) __attribute__((const));
384 static void probeProcess(void); 291 static void probeProcess(void);
385 static ErrorCode allowAllEvaluator(int signo); 292 static ErrorCode allowAllEvaluator(int signo);
386 static void tryVsyscallProcess(void); 293 static void tryVsyscallProcess(void);
387 static bool kernelSupportSeccompBPF(int proc_fd); 294 static bool kernelSupportSeccompBPF(int proc_fd);
388 static bool RunFunctionInPolicy(void (*function)(), 295 static bool RunFunctionInPolicy(void (*function)(),
389 EvaluateSyscall syscallEvaluator, 296 EvaluateSyscall syscallEvaluator,
390 int proc_fd); 297 int proc_fd);
391 static bool isSingleThreaded(int proc_fd); 298 static bool isSingleThreaded(int proc_fd);
299 static bool isDenied(const ErrorCode& code);
392 static bool disableFilesystem(); 300 static bool disableFilesystem();
393 static void policySanityChecks(EvaluateSyscall syscallEvaluator, 301 static void policySanityChecks(EvaluateSyscall syscallEvaluator,
394 EvaluateArguments argumentEvaluator); 302 EvaluateArguments argumentEvaluator);
395 static void installFilter(); 303 static void installFilter();
396 static void findRanges(Ranges *ranges); 304 static void findRanges(Ranges *ranges);
397 static void emitJumpStatements(Program *program, RetInsns *rets, 305 static void emitJumpStatements(Program *program, RetInsns *rets,
398 Ranges::const_iterator start, 306 Ranges::const_iterator start,
399 Ranges::const_iterator stop); 307 Ranges::const_iterator stop);
400 static void emitReturnStatements(Program *prog, const RetInsns& rets); 308 static void emitReturnStatements(Program *prog, const RetInsns& rets);
401 static void sigSys(int nr, siginfo_t *info, void *void_context); 309 static void sigSys(int nr, siginfo_t *info, void *void_context);
402 static intptr_t bpfFailure(const struct arch_seccomp_data& data, void *aux); 310 static intptr_t bpfFailure(const struct arch_seccomp_data& data, void *aux);
403 static int getTrapId(TrapFnc fnc, const void *aux); 311 static int getTrapId(TrapFnc fnc, const void *aux);
404 312
405 static bool dryRun_; 313 // Get a file descriptor pointing to "/proc", if currently available.
314 static int proc_fd() { return proc_fd_; }
315
316
406 static SandboxStatus status_; 317 static SandboxStatus status_;
407 static int proc_fd_; 318 static int proc_fd_;
408 static Evaluators evaluators_; 319 static Evaluators evaluators_;
320 static ErrMap errMap_;
409 static Traps *traps_; 321 static Traps *traps_;
410 static TrapIds trapIds_; 322 static TrapIds trapIds_;
411 static ErrorCode *trapArray_; 323 static ErrorCode *trapArray_;
412 static size_t trapArraySize_; 324 static size_t trapArraySize_;
413 DISALLOW_IMPLICIT_CONSTRUCTORS(Sandbox); 325 DISALLOW_IMPLICIT_CONSTRUCTORS(Sandbox);
414 }; 326 };
415 327
416 } // namespace 328 } // namespace
417 329
418 #endif // SANDBOX_BPF_H__ 330 #endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698