| 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_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 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 #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 Loading... |
| 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 Loading... |
| 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__ |
| OLD | NEW |