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 "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