Home | History | Annotate | Download | only in bpf_dsl
      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