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