errorcode.h revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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#ifndef SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__ 6#define SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__ 7 8#include "sandbox/linux/seccomp-bpf/linux_seccomp.h" 9#include "sandbox/linux/seccomp-bpf/trap.h" 10#include "sandbox/sandbox_export.h" 11 12namespace sandbox { 13 14struct arch_seccomp_data; 15 16// This class holds all the possible values that can be returned by a sandbox 17// policy. 18// We can either wrap a symbolic ErrorCode (i.e. ERR_XXX enum values), an 19// errno value (in the range 0..4095), a pointer to a TrapFnc callback 20// handling a SECCOMP_RET_TRAP trap, or a complex constraint. 21// All of the commonly used values are stored in the "err_" field. So, code 22// that is using the ErrorCode class typically operates on a single 32bit 23// field. 24class SANDBOX_EXPORT ErrorCode { 25 public: 26 enum { 27 // Allow this system call. The value of ERR_ALLOWED is pretty much 28 // completely arbitrary. But we want to pick it so that is is unlikely 29 // to be passed in accidentally, when the user intended to return an 30 // "errno" (see below) value instead. 31 ERR_ALLOWED = 0x04000000, 32 33 // If the progress is being ptraced with PTRACE_O_TRACESECCOMP, then the 34 // tracer will be notified of a PTRACE_EVENT_SECCOMP and allowed to change 35 // or skip the system call. The lower 16 bits of err will be available to 36 // the tracer via PTRACE_GETEVENTMSG. 37 ERR_TRACE = 0x08000000, 38 39 // Deny the system call with a particular "errno" value. 40 // N.B.: It is also possible to return "0" here. That would normally 41 // indicate success, but it won't actually run the system call. 42 // This is very different from return ERR_ALLOWED. 43 ERR_MIN_ERRNO = 0, 44 // TODO(markus): Android only supports errno up to 255 45 // (crbug.com/181647). 46 ERR_MAX_ERRNO = 4095, 47 }; 48 49 // While BPF filter programs always operate on 32bit quantities, the kernel 50 // always sees system call arguments as 64bit values. This statement is true 51 // no matter whether the host system is natively operating in 32bit or 64bit. 52 // The BPF compiler hides the fact that BPF instructions cannot directly 53 // access 64bit quantities. But policies are still advised to specify whether 54 // a system call expects a 32bit or a 64bit quantity. 55 enum ArgType { 56 // When passed as an argument to SandboxBPF::Cond(), TP_32BIT requests that 57 // the conditional test should operate on the 32bit part of the system call 58 // argument. 59 // On 64bit architectures, this verifies that user space did not pass 60 // a 64bit value as an argument to the system call. If it did, that will be 61 // interpreted as an attempt at breaking the sandbox and results in the 62 // program getting terminated. 63 // In other words, only perform a 32bit test, if you are sure this 64 // particular system call would never legitimately take a 64bit 65 // argument. 66 // Implementation detail: TP_32BIT does two things. 1) it restricts the 67 // conditional test to operating on the LSB only, and 2) it adds code to 68 // the BPF filter program verifying that the MSB the kernel received from 69 // user space is either 0, or 0xFFFFFFFF; the latter is acceptable, iff bit 70 // 31 was set in the system call argument. It deals with 32bit arguments 71 // having been sign extended. 72 TP_32BIT, 73 74 // When passed as an argument to SandboxBPF::Cond(), TP_64BIT requests that 75 // the conditional test should operate on the full 64bit argument. It is 76 // generally harmless to perform a 64bit test on 32bit systems, as the 77 // kernel will always see the top 32 bits of all arguments as zero'd out. 78 // This approach has the desirable property that for tests of pointer 79 // values, we can always use TP_64BIT no matter the host architecture. 80 // But of course, that also means, it is possible to write conditional 81 // policies that turn into no-ops on 32bit systems; this is by design. 82 TP_64BIT, 83 }; 84 85 enum Operation { 86 // Test whether the system call argument is equal to the operand. 87 OP_EQUAL, 88 89 // Test whether the system call argument is greater (or equal) to the 90 // operand. Please note that all tests always operate on unsigned 91 // values. You can generally emulate signed tests, if that's what you 92 // need. 93 // TODO(markus): Check whether we should automatically emulate signed 94 // operations. 95 OP_GREATER_UNSIGNED, 96 OP_GREATER_EQUAL_UNSIGNED, 97 98 // Tests a system call argument against a bit mask. 99 // The "ALL_BITS" variant performs this test: "arg & mask == mask" 100 // This implies that a mask of zero always results in a passing test. 101 // The "ANY_BITS" variant performs this test: "arg & mask != 0" 102 // This implies that a mask of zero always results in a failing test. 103 OP_HAS_ALL_BITS, 104 OP_HAS_ANY_BITS, 105 106 // Total number of operations. 107 OP_NUM_OPS, 108 }; 109 110 enum ErrorType { 111 ET_INVALID, 112 ET_SIMPLE, 113 ET_TRAP, 114 ET_COND, 115 }; 116 117 // We allow the default constructor, as it makes the ErrorCode class 118 // much easier to use. But if we ever encounter an invalid ErrorCode 119 // when compiling a BPF filter, we deliberately generate an invalid 120 // program that will get flagged both by our Verifier class and by 121 // the Linux kernel. 122 ErrorCode() : error_type_(ET_INVALID), err_(SECCOMP_RET_INVALID) {} 123 explicit ErrorCode(int err); 124 125 // For all practical purposes, ErrorCodes are treated as if they were 126 // structs. The copy constructor and assignment operator are trivial and 127 // we do not need to explicitly specify them. 128 // Most notably, it is in fact perfectly OK to directly copy the passed_ and 129 // failed_ field. They only ever get set by our private constructor, and the 130 // callers handle life-cycle management for these objects. 131 132 // Destructor 133 ~ErrorCode() {} 134 135 bool Equals(const ErrorCode& err) const; 136 bool LessThan(const ErrorCode& err) const; 137 138 uint32_t err() const { return err_; } 139 ErrorType error_type() const { return error_type_; } 140 141 bool safe() const { return safe_; } 142 143 uint64_t value() const { return value_; } 144 int argno() const { return argno_; } 145 ArgType width() const { return width_; } 146 Operation op() const { return op_; } 147 const ErrorCode* passed() const { return passed_; } 148 const ErrorCode* failed() const { return failed_; } 149 150 struct LessThan { 151 bool operator()(const ErrorCode& a, const ErrorCode& b) const { 152 return a.LessThan(b); 153 } 154 }; 155 156 private: 157 friend class CodeGen; 158 friend class SandboxBPF; 159 friend class Trap; 160 161 // If we are wrapping a callback, we must assign a unique id. This id is 162 // how the kernel tells us which one of our different SECCOMP_RET_TRAP 163 // cases has been triggered. 164 ErrorCode(Trap::TrapFnc fnc, const void* aux, bool safe, uint16_t id); 165 166 // Some system calls require inspection of arguments. This constructor 167 // allows us to specify additional constraints. 168 ErrorCode(int argno, 169 ArgType width, 170 Operation op, 171 uint64_t value, 172 const ErrorCode* passed, 173 const ErrorCode* failed); 174 175 ErrorType error_type_; 176 177 union { 178 // Fields needed for SECCOMP_RET_TRAP callbacks 179 struct { 180 Trap::TrapFnc fnc_; // Callback function and arg, if trap was 181 void* aux_; // triggered by the kernel's BPF filter. 182 bool safe_; // Keep sandbox active while calling fnc_() 183 }; 184 185 // Fields needed when inspecting additional arguments. 186 struct { 187 uint64_t value_; // Value that we are comparing with. 188 int argno_; // Syscall arg number that we are inspecting. 189 ArgType width_; // Whether we are looking at a 32/64bit value. 190 Operation op_; // Comparison operation. 191 const ErrorCode* passed_; // Value to be returned if comparison passed, 192 const ErrorCode* failed_; // or if it failed. 193 }; 194 }; 195 196 // 32bit field used for all possible types of ErrorCode values. This is 197 // the value that uniquely identifies any ErrorCode and it (typically) can 198 // be emitted directly into a BPF filter program. 199 uint32_t err_; 200}; 201 202} // namespace sandbox 203 204#endif // SANDBOX_LINUX_SECCOMP_BPF_ERRORCODE_H__ 205