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:
ReturnResultExprImpl(uint32_t ret)26   explicit ReturnResultExprImpl(uint32_t ret) : ret_(ret) {}
27 
Compile(PolicyCompiler * pc) const28   CodeGen::Node Compile(PolicyCompiler* pc) const override {
29     return pc->Return(ret_);
30   }
31 
IsAllow() const32   bool IsAllow() const override { return IsAction(SECCOMP_RET_ALLOW); }
33 
IsDeny() const34   bool IsDeny() const override {
35     return IsAction(SECCOMP_RET_ERRNO) || IsAction(SECCOMP_RET_KILL);
36   }
37 
38  private:
~ReturnResultExprImpl()39   ~ReturnResultExprImpl() override {}
40 
IsAction(uint32_t action) const41   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:
TrapResultExprImpl(TrapRegistry::TrapFnc func,const void * arg,bool safe)52   TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg, bool safe)
53       : func_(func), arg_(arg), safe_(safe) {
54     DCHECK(func_);
55   }
56 
Compile(PolicyCompiler * pc) const57   CodeGen::Node Compile(PolicyCompiler* pc) const override {
58     return pc->Trap(func_, arg_, safe_);
59   }
60 
HasUnsafeTraps() const61   bool HasUnsafeTraps() const override { return safe_ == false; }
62 
IsDeny() const63   bool IsDeny() const override { return true; }
64 
65  private:
~TrapResultExprImpl()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:
IfThenResultExprImpl(const BoolExpr & cond,const ResultExpr & then_result,const ResultExpr & else_result)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 
Compile(PolicyCompiler * pc) const82   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 
HasUnsafeTraps() const90   bool HasUnsafeTraps() const override {
91     return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps();
92   }
93 
94  private:
~IfThenResultExprImpl()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:
ConstBoolExprImpl(bool value)106   ConstBoolExprImpl(bool value) : value_(value) {}
107 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const108   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:
~ConstBoolExprImpl()115   ~ConstBoolExprImpl() override {}
116 
117   bool value_;
118 
119   DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
120 };
121 
122 class MaskedEqualBoolExprImpl : public internal::BoolExprImpl {
123  public:
MaskedEqualBoolExprImpl(int argno,size_t width,uint64_t mask,uint64_t value)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 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const130   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:
~MaskedEqualBoolExprImpl()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:
NegateBoolExprImpl(const BoolExpr & cond)149   explicit NegateBoolExprImpl(const BoolExpr& cond) : cond_(cond) {}
150 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const151   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:
~NegateBoolExprImpl()158   ~NegateBoolExprImpl() override {}
159 
160   BoolExpr cond_;
161 
162   DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl);
163 };
164 
165 class AndBoolExprImpl : public internal::BoolExprImpl {
166  public:
AndBoolExprImpl(const BoolExpr & lhs,const BoolExpr & rhs)167   AndBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs)
168       : lhs_(lhs), rhs_(rhs) {}
169 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const170   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:
~AndBoolExprImpl()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:
OrBoolExprImpl(const BoolExpr & lhs,const BoolExpr & rhs)188   OrBoolExprImpl(const BoolExpr& lhs, const BoolExpr& rhs)
189       : lhs_(lhs), rhs_(rhs) {}
190 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const191   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:
~OrBoolExprImpl()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 
HasUnsafeTraps() const211 bool ResultExprImpl::HasUnsafeTraps() const {
212   return false;
213 }
214 
IsAllow() const215 bool ResultExprImpl::IsAllow() const {
216   return false;
217 }
218 
IsDeny() const219 bool ResultExprImpl::IsDeny() const {
220   return false;
221 }
222 
DefaultMask(size_t size)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 
ArgEq(int num,size_t size,uint64_t mask,uint64_t val)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 
Allow()245 ResultExpr Allow() {
246   return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ALLOW));
247 }
248 
Error(int err)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 
Kill()254 ResultExpr Kill() {
255   return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_KILL));
256 }
257 
Trace(uint16_t aux)258 ResultExpr Trace(uint16_t aux) {
259   return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_TRACE + aux));
260 }
261 
Trap(TrapRegistry::TrapFnc trap_func,const void * aux)262 ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
263   return ResultExpr(
264       new const TrapResultExprImpl(trap_func, aux, true /* safe */));
265 }
266 
UnsafeTrap(TrapRegistry::TrapFnc trap_func,const void * aux)267 ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
268   return ResultExpr(
269       new const TrapResultExprImpl(trap_func, aux, false /* unsafe */));
270 }
271 
BoolConst(bool value)272 BoolExpr BoolConst(bool value) {
273   return BoolExpr(new const ConstBoolExprImpl(value));
274 }
275 
Not(const BoolExpr & cond)276 BoolExpr Not(const BoolExpr& cond) {
277   return BoolExpr(new const NegateBoolExprImpl(cond));
278 }
279 
AllOf()280 BoolExpr AllOf() {
281   return BoolConst(true);
282 }
283 
AllOf(const BoolExpr & lhs,const BoolExpr & rhs)284 BoolExpr AllOf(const BoolExpr& lhs, const BoolExpr& rhs) {
285   return BoolExpr(new const AndBoolExprImpl(lhs, rhs));
286 }
287 
AnyOf()288 BoolExpr AnyOf() {
289   return BoolConst(false);
290 }
291 
AnyOf(const BoolExpr & lhs,const BoolExpr & rhs)292 BoolExpr AnyOf(const BoolExpr& lhs, const BoolExpr& rhs) {
293   return BoolExpr(new const OrBoolExprImpl(lhs, rhs));
294 }
295 
If(const BoolExpr & cond,const ResultExpr & then_result)296 Elser If(const BoolExpr& cond, const ResultExpr& then_result) {
297   return Elser(nullptr).ElseIf(cond, then_result);
298 }
299 
Elser(cons::List<Clause> clause_list)300 Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
301 }
302 
Elser(const Elser & elser)303 Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
304 }
305 
~Elser()306 Elser::~Elser() {
307 }
308 
ElseIf(const BoolExpr & cond,const ResultExpr & then_result) const309 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 
Else(const ResultExpr & else_result) const313 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