1 // Copyright 2014 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 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 6 7 #include <stddef.h> 8 #include <stdint.h> 9 10 #include <limits> 11 12 #include "base/logging.h" 13 #include "base/macros.h" 14 #include "base/memory/ref_counted.h" 15 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h" 16 #include "sandbox/linux/bpf_dsl/errorcode.h" 17 #include "sandbox/linux/bpf_dsl/policy_compiler.h" 18 #include "sandbox/linux/system_headers/linux_seccomp.h" 19 20 namespace sandbox { 21 namespace bpf_dsl { 22 namespace { 23 24 class ReturnResultExprImpl : public internal::ResultExprImpl { 25 public: 26 explicit ReturnResultExprImpl(uint32_t ret) : ret_(ret) {} 27 28 CodeGen::Node Compile(PolicyCompiler* pc) const override { 29 return pc->Return(ret_); 30 } 31 32 bool IsAllow() const override { return IsAction(SECCOMP_RET_ALLOW); } 33 34 bool IsDeny() const override { 35 return IsAction(SECCOMP_RET_ERRNO) || IsAction(SECCOMP_RET_KILL); 36 } 37 38 private: 39 ~ReturnResultExprImpl() override {} 40 41 bool IsAction(uint32_t action) const { 42 return (ret_ & SECCOMP_RET_ACTION) == action; 43 } 44 45 uint32_t ret_; 46 47 DISALLOW_COPY_AND_ASSIGN(ReturnResultExprImpl); 48 }; 49 50 class TrapResultExprImpl : public internal::ResultExprImpl { 51 public: 52 TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg, bool safe) 53 : func_(func), arg_(arg), safe_(safe) { 54 DCHECK(func_); 55 } 56 57 CodeGen::Node Compile(PolicyCompiler* pc) const override { 58 return pc->Trap(func_, arg_, safe_); 59 } 60 61 bool HasUnsafeTraps() const override { return safe_ == false; } 62 63 bool IsDeny() const override { return true; } 64 65 private: 66 ~TrapResultExprImpl() override {} 67 68 TrapRegistry::TrapFnc func_; 69 const void* arg_; 70 bool safe_; 71 72 DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl); 73 }; 74 75 class IfThenResultExprImpl : public internal::ResultExprImpl { 76 public: 77 IfThenResultExprImpl(const BoolExpr& cond, 78 const ResultExpr& then_result, 79 const ResultExpr& else_result) 80 : cond_(cond), then_result_(then_result), else_result_(else_result) {} 81 82 CodeGen::Node Compile(PolicyCompiler* pc) const override { 83 // We compile the "then" and "else" expressions in separate statements so 84 // they have a defined sequencing. See https://crbug.com/529480. 85 CodeGen::Node then_node = then_result_->Compile(pc); 86 CodeGen::Node else_node = else_result_->Compile(pc); 87 return cond_->Compile(pc, then_node, else_node); 88 } 89 90 bool HasUnsafeTraps() const override { 91 return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps(); 92 } 93 94 private: 95 ~IfThenResultExprImpl() override {} 96 97 BoolExpr cond_; 98 ResultExpr then_result_; 99 ResultExpr else_result_; 100 101 DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl); 102 }; 103 104 class ConstBoolExprImpl : public internal::BoolExprImpl { 105 public: 106 ConstBoolExprImpl(bool value) : value_(value) {} 107 108 CodeGen::Node Compile(PolicyCompiler* pc, 109 CodeGen::Node then_node, 110 CodeGen::Node else_node) const override { 111 return value_ ? then_node : else_node; 112 } 113 114 private: 115 ~ConstBoolExprImpl() override {} 116 117 bool value_; 118 119 DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl); 120 }; 121 122 class MaskedEqualBoolExprImpl : public internal::BoolExprImpl { 123 public: 124 MaskedEqualBoolExprImpl(int argno, 125 size_t width, 126 uint64_t mask, 127 uint64_t value) 128 : argno_(argno), width_(width), mask_(mask), value_(value) {} 129 130 CodeGen::Node Compile(PolicyCompiler* pc, 131 CodeGen::Node then_node, 132 CodeGen::Node else_node) const override { 133 return pc->MaskedEqual(argno_, width_, mask_, value_, then_node, else_node); 134 } 135 136 private: 137 ~MaskedEqualBoolExprImpl() override {} 138 139 int argno_; 140 size_t width_; 141 uint64_t mask_; 142 uint64_t value_; 143 144 DISALLOW_COPY_AND_ASSIGN(MaskedEqualBoolExprImpl); 145 }; 146 147 class NegateBoolExprImpl : public internal::BoolExprImpl { 148 public: 149 explicit NegateBoolExprImpl(const BoolExpr& cond) : cond_(cond) {} 150 151 CodeGen::Node Compile(PolicyCompiler* pc, 152 CodeGen::Node then_node, 153 CodeGen::Node else_node) const override { 154 return cond_->Compile(pc, else_node, then_node); 155 } 156 157 private: 158 ~NegateBoolExprImpl() override {} 159 160 BoolExpr cond_; 161 162 DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl); 163 }; 164 165 class AndBoolExprImpl : public internal::BoolExprImpl { 166 public: 167 AndBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs) 168 : lhs_(lhs), rhs_(rhs) {} 169 170 CodeGen::Node Compile(PolicyCompiler* pc, 171 CodeGen::Node then_node, 172 CodeGen::Node else_node) const override { 173 return lhs_->Compile(pc, rhs_->Compile(pc, then_node, else_node), 174 else_node); 175 } 176 177 private: 178 ~AndBoolExprImpl() override {} 179 180 BoolExpr lhs_; 181 BoolExpr rhs_; 182 183 DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl); 184 }; 185 186 class OrBoolExprImpl : public internal::BoolExprImpl { 187 public: 188 OrBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs) 189 : lhs_(lhs), rhs_(rhs) {} 190 191 CodeGen::Node Compile(PolicyCompiler* pc, 192 CodeGen::Node then_node, 193 CodeGen::Node else_node) const override { 194 return lhs_->Compile(pc, then_node, 195 rhs_->Compile(pc, then_node, else_node)); 196 } 197 198 private: 199 ~OrBoolExprImpl() override {} 200 201 BoolExpr lhs_; 202 BoolExpr rhs_; 203 204 DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl); 205 }; 206 207 } // namespace 208 209 namespace internal { 210 211 bool ResultExprImpl::HasUnsafeTraps() const { 212 return false; 213 } 214 215 bool ResultExprImpl::IsAllow() const { 216 return false; 217 } 218 219 bool ResultExprImpl::IsDeny() const { 220 return false; 221 } 222 223 uint64_t DefaultMask(size_t size) { 224 switch (size) { 225 case 4: 226 return std::numeric_limits<uint32_t>::max(); 227 case 8: 228 return std::numeric_limits<uint64_t>::max(); 229 default: 230 CHECK(false) << "Unimplemented DefaultMask case"; 231 return 0; 232 } 233 } 234 235 BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) { 236 // If this is changed, update Arg<T>::EqualTo's static_cast rules 237 // accordingly. 238 CHECK(size == 4 || size == 8); 239 240 return BoolExpr(new const MaskedEqualBoolExprImpl(num, size, mask, val)); 241 } 242 243 } // namespace internal 244 245 ResultExpr Allow() { 246 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ALLOW)); 247 } 248 249 ResultExpr Error(int err) { 250 CHECK(err >= ErrorCode::ERR_MIN_ERRNO && err <= ErrorCode::ERR_MAX_ERRNO); 251 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ERRNO + err)); 252 } 253 254 ResultExpr Kill() { 255 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_KILL)); 256 } 257 258 ResultExpr Trace(uint16_t aux) { 259 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_TRACE + aux)); 260 } 261 262 ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) { 263 return ResultExpr( 264 new const TrapResultExprImpl(trap_func, aux, true /* safe */)); 265 } 266 267 ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) { 268 return ResultExpr( 269 new const TrapResultExprImpl(trap_func, aux, false /* unsafe */)); 270 } 271 272 BoolExpr BoolConst(bool value) { 273 return BoolExpr(new const ConstBoolExprImpl(value)); 274 } 275 276 BoolExpr Not(const BoolExpr& cond) { 277 return BoolExpr(new const NegateBoolExprImpl(cond)); 278 } 279 280 BoolExpr AllOf() { 281 return BoolConst(true); 282 } 283 284 BoolExpr AllOf(const BoolExpr& lhs, const BoolExpr& rhs) { 285 return BoolExpr(new const AndBoolExprImpl(lhs, rhs)); 286 } 287 288 BoolExpr AnyOf() { 289 return BoolConst(false); 290 } 291 292 BoolExpr AnyOf(const BoolExpr& lhs, const BoolExpr& rhs) { 293 return BoolExpr(new const OrBoolExprImpl(lhs, rhs)); 294 } 295 296 Elser If(const BoolExpr& cond, const ResultExpr& then_result) { 297 return Elser(nullptr).ElseIf(cond, then_result); 298 } 299 300 Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) { 301 } 302 303 Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) { 304 } 305 306 Elser::~Elser() { 307 } 308 309 Elser Elser::ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const { 310 return Elser(Cons(std::make_pair(cond, then_result), clause_list_)); 311 } 312 313 ResultExpr Elser::Else(const ResultExpr& else_result) const { 314 // We finally have the default result expression for this 315 // if/then/else sequence. Also, we've already accumulated all 316 // if/then pairs into a list of reverse order (i.e., lower priority 317 // conditions are listed before higher priority ones). E.g., an 318 // expression like 319 // 320 // If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4) 321 // 322 // will have built up a list like 323 // 324 // [(b3, e3), (b2, e2), (b1, e1)]. 325 // 326 // Now that we have e4, we can walk the list and create a ResultExpr 327 // tree like: 328 // 329 // expr = e4 330 // expr = (b3 ? e3 : expr) = (b3 ? e3 : e4) 331 // expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4)) 332 // expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4))) 333 // 334 // and end up with an appropriately chained tree. 335 336 ResultExpr expr = else_result; 337 for (const Clause& clause : clause_list_) { 338 expr = ResultExpr( 339 new const IfThenResultExprImpl(clause.first, clause.second, expr)); 340 } 341 return expr; 342 } 343 344 } // namespace bpf_dsl 345 } // namespace sandbox 346 347 template class scoped_refptr<const sandbox::bpf_dsl::internal::BoolExprImpl>; 348 template class scoped_refptr<const sandbox::bpf_dsl::internal::ResultExprImpl>; 349