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