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 | |
| 49 #ifndef SECCOMP_BPF_STANDALONE | |
| 50 #include "base/third_party/valgrind/valgrind.h" | |
| 51 #else | |
| 52 #include "valgrind/valgrind.h" | |
| 53 #endif | |
| 54 #endif | |
| 55 | |
| 48 // The Seccomp2 kernel ABI is not part of older versions of glibc. | 56 // 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, | 57 // As we can't break compilation with these versions of the library, |
| 50 // we explicitly define all missing symbols. | 58 // we explicitly define all missing symbols. |
| 51 | 59 |
| 52 #ifndef PR_SET_NO_NEW_PRIVS | 60 #ifndef PR_SET_NO_NEW_PRIVS |
| 53 #define PR_SET_NO_NEW_PRIVS 38 | 61 #define PR_SET_NO_NEW_PRIVS 38 |
| 54 #define PR_GET_NO_NEW_PRIVS 39 | 62 #define PR_GET_NO_NEW_PRIVS 39 |
| 55 #endif | 63 #endif |
| 56 #ifndef IPC_64 | 64 #ifndef IPC_64 |
| 57 #define IPC_64 0x0100 | 65 #define IPC_64 0x0100 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 | 132 |
| 125 #ifdef SECCOMP_BPF_STANDALONE | 133 #ifdef SECCOMP_BPF_STANDALONE |
| 126 #define arraysize(x) sizeof(x)/sizeof(*(x))) | 134 #define arraysize(x) sizeof(x)/sizeof(*(x))) |
| 127 #define HANDLE_EINTR TEMP_FAILURE_RETRY | 135 #define HANDLE_EINTR TEMP_FAILURE_RETRY |
| 128 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ | 136 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ |
| 129 TypeName(); \ | 137 TypeName(); \ |
| 130 TypeName(const TypeName&); \ | 138 TypeName(const TypeName&); \ |
| 131 void operator=(const TypeName&) | 139 void operator=(const TypeName&) |
| 132 #endif | 140 #endif |
| 133 | 141 |
| 142 #include "sandbox/linux/seccomp-bpf/errorcode.h" | |
|
jln (very slow on Chromium)
2012/07/27 19:46:30
Can this be moved up towards the other includes?
| |
| 143 | |
| 134 | 144 |
| 135 namespace playground2 { | 145 namespace playground2 { |
| 136 | 146 |
| 137 class Sandbox { | 147 class Sandbox { |
| 138 public: | 148 public: |
| 139 enum SandboxStatus { | 149 enum SandboxStatus { |
| 140 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() | 150 STATUS_UNKNOWN, // Status prior to calling supportsSeccompSandbox() |
| 141 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing | 151 STATUS_UNSUPPORTED, // The kernel does not appear to support sandboxing |
| 142 STATUS_UNAVAILABLE, // Currently unavailable but might work again later | 152 STATUS_UNAVAILABLE, // Currently unavailable but might work again later |
| 143 STATUS_AVAILABLE, // Sandboxing is available but not currently active | 153 STATUS_AVAILABLE, // Sandboxing is available but not currently active |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 158 // TrapFnc is a pointer to a function that handles Seccomp traps in | 168 // 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 | 169 // user-space. The seccomp policy can request that a trap handler gets |
| 160 // installed; it does so by returning a suitable ErrorCode() from the | 170 // installed; it does so by returning a suitable ErrorCode() from the |
| 161 // syscallEvaluator. See the ErrorCode() constructor for how to pass in | 171 // syscallEvaluator. See the ErrorCode() constructor for how to pass in |
| 162 // the function pointer. | 172 // the function pointer. |
| 163 // Please note that TrapFnc is executed from signal context and must be | 173 // Please note that TrapFnc is executed from signal context and must be |
| 164 // async-signal safe: | 174 // async-signal safe: |
| 165 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html | 175 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html |
| 166 typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void *aux); | 176 typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void *aux); |
| 167 | 177 |
| 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 { | 178 enum Operation { |
| 230 OP_NOP, OP_EQUAL, OP_NOTEQUAL, OP_LESS, | 179 OP_NOP, OP_EQUAL, OP_NOTEQUAL, OP_LESS, |
| 231 OP_LESS_EQUAL, OP_GREATER, OP_GREATER_EQUAL, | 180 OP_LESS_EQUAL, OP_GREATER, OP_GREATER_EQUAL, |
| 232 OP_HAS_BITS, OP_DOES_NOT_HAVE_BITS | 181 OP_HAS_BITS, OP_DOES_NOT_HAVE_BITS |
| 233 }; | 182 }; |
| 234 | 183 |
| 235 struct Constraint { | 184 struct Constraint { |
| 236 bool is32bit; | 185 bool is32bit; |
| 237 Operation op; | 186 Operation op; |
| 238 uint32_t value; | 187 uint32_t value; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 266 // of system call argument(s) by returning a suitable combination of | 215 // of system call argument(s) by returning a suitable combination of |
| 267 // SB_INSPECT_ARG_x bits. | 216 // SB_INSPECT_ARG_x bits. |
| 268 // The system argument evaluator is called (if needed) to query additional | 217 // The system argument evaluator is called (if needed) to query additional |
| 269 // constraints for the system call arguments. In the vast majority of | 218 // constraints for the system call arguments. In the vast majority of |
| 270 // cases, it will set a "Constraint" that forces a new "errno" value. | 219 // 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 | 220 // But for more complex filters, it is possible to return another mask |
| 272 // of SB_INSPECT_ARG_x bits. | 221 // of SB_INSPECT_ARG_x bits. |
| 273 static void setSandboxPolicy(EvaluateSyscall syscallEvaluator, | 222 static void setSandboxPolicy(EvaluateSyscall syscallEvaluator, |
| 274 EvaluateArguments argumentEvaluator); | 223 EvaluateArguments argumentEvaluator); |
| 275 | 224 |
| 225 // We can use ErrorCode to request calling of a trap handler. This method | |
| 226 // performs the required wrapping of the callback function into an | |
| 227 // ErrorCode object. | |
| 228 static ErrorCode Trap(ErrorCode::TrapFnc fnc, const void *aux); | |
| 229 | |
| 230 // Kill the program and print an error message. | |
| 231 static ErrorCode Kill(const char *msg); | |
| 232 | |
| 276 // This is the main public entry point. It finds all system calls that | 233 // 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 | 234 // need rewriting, sets up the resources needed by the sandbox, and |
| 278 // enters Seccomp mode. | 235 // enters Seccomp mode. |
| 279 static void startSandbox(); | 236 static void startSandbox(); |
| 280 | 237 |
| 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: | 238 private: |
| 239 friend class ErrorCode; | |
| 325 friend class Util; | 240 friend class Util; |
| 326 friend class Verifier; | 241 friend class Verifier; |
| 242 | |
| 243 | |
| 327 struct Range { | 244 struct Range { |
| 328 Range(uint32_t f, uint32_t t, const ErrorCode& e) : | 245 Range(uint32_t f, uint32_t t, const ErrorCode& e) : |
| 329 from(f), | 246 from(f), |
| 330 to(t), | 247 to(t), |
| 331 err(e) { | 248 err(e) { |
| 332 } | 249 } |
| 333 uint32_t from, to; | 250 uint32_t from, to; |
| 334 ErrorCode err; | 251 ErrorCode err; |
| 335 }; | 252 }; |
| 336 struct FixUp { | 253 struct FixUp { |
| 337 FixUp(unsigned int a, bool j) : | 254 FixUp(unsigned int a, bool j) : |
| 338 jt(j), addr(a) { } | 255 jt(j), addr(a) { } |
| 339 bool jt:1; | 256 bool jt:1; |
| 340 unsigned addr:31; | 257 unsigned addr:31; |
| 341 }; | 258 }; |
| 342 typedef std::vector<Range> Ranges; | 259 typedef std::vector<Range> Ranges; |
| 343 typedef std::map<uint32_t, std::vector<FixUp> > RetInsns; | 260 typedef std::map<uint32_t, std::vector<FixUp> > RetInsns; |
| 344 typedef std::vector<struct sock_filter> Program; | 261 typedef std::vector<struct sock_filter> Program; |
| 262 typedef std::map<uint32_t, ErrorCode> ErrMap; | |
| 345 typedef std::vector<ErrorCode> Traps; | 263 typedef std::vector<ErrorCode> Traps; |
| 346 typedef std::map<std::pair<TrapFnc, const void *>, int> TrapIds; | 264 typedef std::map<std::pair<TrapFnc, const void *>, int> TrapIds; |
| 347 | 265 |
| 348 static ErrorCode probeEvaluator(int signo) __attribute__((const)); | 266 static ErrorCode probeEvaluator(int signo) __attribute__((const)); |
| 349 static void probeProcess(void); | 267 static void probeProcess(void); |
| 350 static ErrorCode allowAllEvaluator(int signo); | 268 static ErrorCode allowAllEvaluator(int signo); |
| 351 static void tryVsyscallProcess(void); | 269 static void tryVsyscallProcess(void); |
| 352 static bool kernelSupportSeccompBPF(int proc_fd); | 270 static bool kernelSupportSeccompBPF(int proc_fd); |
| 353 static bool RunFunctionInPolicy(void (*function)(), | 271 static bool RunFunctionInPolicy(void (*function)(), |
| 354 EvaluateSyscall syscallEvaluator, | 272 EvaluateSyscall syscallEvaluator, |
| 355 int proc_fd); | 273 int proc_fd); |
| 356 static bool isSingleThreaded(int proc_fd); | 274 static bool isSingleThreaded(int proc_fd); |
| 275 static bool isDenied(ErrorCode code); | |
| 357 static bool disableFilesystem(); | 276 static bool disableFilesystem(); |
| 358 static void policySanityChecks(EvaluateSyscall syscallEvaluator, | 277 static void policySanityChecks(EvaluateSyscall syscallEvaluator, |
| 359 EvaluateArguments argumentEvaluator); | 278 EvaluateArguments argumentEvaluator); |
| 360 static void installFilter(); | 279 static void installFilter(); |
| 361 static void findRanges(Ranges *ranges); | 280 static void findRanges(Ranges *ranges); |
| 362 static void emitJumpStatements(Program *program, RetInsns *rets, | 281 static void emitJumpStatements(Program *program, RetInsns *rets, |
| 363 Ranges::const_iterator start, | 282 Ranges::const_iterator start, |
| 364 Ranges::const_iterator stop); | 283 Ranges::const_iterator stop); |
| 365 static void emitReturnStatements(Program *prog, const RetInsns& rets); | 284 static void emitReturnStatements(Program *prog, const RetInsns& rets); |
| 366 static void sigSys(int nr, siginfo_t *info, void *void_context); | 285 static void sigSys(int nr, siginfo_t *info, void *void_context); |
| 367 static intptr_t bpfFailure(const struct arch_seccomp_data& data, void *aux); | 286 static intptr_t bpfFailure(const struct arch_seccomp_data& data, void *aux); |
| 368 static int getTrapId(TrapFnc fnc, const void *aux); | 287 static int getTrapId(TrapFnc fnc, const void *aux); |
| 369 | 288 |
| 289 // Get a file descriptor pointing to "/proc", if currently available. | |
| 290 static int getProcFd() { return proc_fd_; } | |
|
jln (very slow on Chromium)
2012/07/27 19:46:30
Style: accessor should be named proc_fd()
| |
| 291 | |
| 292 // Print an error message and terminate the program. Used for fatal errors. | |
| 293 static void die(const char *msg) __attribute__((noreturn)) { | |
| 294 if (msg) { | |
| 295 #ifndef SECCOMP_BPF_STANDALONE | |
| 296 if (!dryRun_) { | |
| 297 // LOG(FATAL) is not neccessarily async-signal safe. It would be | |
| 298 // better to always use the code for the SECCOMP_BPF_STANDALONE case. | |
| 299 // But that prevents the logging and reporting infrastructure from | |
| 300 // picking up sandbox related crashes. | |
| 301 // For now, in picking between two evils, we decided in favor of | |
| 302 // LOG(FATAL). In the long run, we probably want to rewrite this code | |
| 303 // to be async-signal safe. | |
| 304 LOG(FATAL) << msg; | |
| 305 } else | |
| 306 #endif | |
| 307 { | |
| 308 // If there is no logging infrastructure in place, we just write error | |
| 309 // messages to stderr. | |
| 310 // We also write to stderr, if we are called in a child process from | |
| 311 // supportsSeccompSandbox(). This makes sure we can actually do the | |
| 312 // correct logging from the parent process, which is more likely to | |
| 313 // have access to logging infrastructure. | |
| 314 if (HANDLE_EINTR(write(2, msg, strlen(msg)))) { } | |
| 315 if (HANDLE_EINTR(write(2, "\n", 1))) { } | |
| 316 } | |
| 317 } | |
| 318 for (;;) { | |
| 319 // exit_group() should exit our program. After all, it is defined as a | |
| 320 // function that doesn't return. But things can theoretically go wrong. | |
| 321 // Especially, since we are dealing with system call filters. Continuing | |
| 322 // execution would be very bad in most cases where die() gets called. | |
| 323 // So, if there is no way for us to ask for the program to exit, the next | |
| 324 // best thing we can do is to loop indefinitely. Maybe, somebody will | |
| 325 // notice and file a bug... | |
| 326 syscall(__NR_exit_group, 1); | |
| 327 _exit(1); | |
| 328 } | |
| 329 } | |
| 330 | |
| 370 static bool dryRun_; | 331 static bool dryRun_; |
| 371 static SandboxStatus status_; | 332 static SandboxStatus status_; |
| 372 static int proc_fd_; | 333 static int proc_fd_; |
| 373 static Evaluators evaluators_; | 334 static Evaluators evaluators_; |
| 335 static ErrMap errMap_; | |
| 374 static Traps *traps_; | 336 static Traps *traps_; |
| 375 static TrapIds trapIds_; | 337 static TrapIds trapIds_; |
|
jln (very slow on Chromium)
2012/07/27 19:46:30
This probably should not be part of this CL, but w
| |
| 376 static ErrorCode *trapArray_; | 338 static ErrorCode *trapArray_; |
| 377 static size_t trapArraySize_; | 339 static size_t trapArraySize_; |
| 378 DISALLOW_IMPLICIT_CONSTRUCTORS(Sandbox); | 340 DISALLOW_IMPLICIT_CONSTRUCTORS(Sandbox); |
| 379 }; | 341 }; |
| 380 | 342 |
| 381 } // namespace | 343 } // namespace |
| 382 | 344 |
| 383 #endif // SANDBOX_BPF_H__ | 345 #endif // SANDBOX_BPF_H__ |
| OLD | NEW |