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:
ReturnResultExprImpl(uint32_t ret)25   explicit ReturnResultExprImpl(uint32_t ret) : ret_(ret) {}
~ReturnResultExprImpl()26   ~ReturnResultExprImpl() override {}
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:
IsAction(uint32_t action) const39   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:
TrapResultExprImpl(TrapRegistry::TrapFnc func,const void * arg,bool safe)50   TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg, bool safe)
51       : func_(func), arg_(arg), safe_(safe) {
52     DCHECK(func_);
53   }
~TrapResultExprImpl()54   ~TrapResultExprImpl() override {}
55 
Compile(PolicyCompiler * pc) const56   CodeGen::Node Compile(PolicyCompiler* pc) const override {
57     return pc->Trap(func_, arg_, safe_);
58   }
59 
HasUnsafeTraps() const60   bool HasUnsafeTraps() const override { return safe_ == false; }
61 
IsDeny() const62   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:
IfThenResultExprImpl(BoolExpr cond,ResultExpr then_result,ResultExpr else_result)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)) {}
~IfThenResultExprImpl()80   ~IfThenResultExprImpl() override {}
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:
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:
ConstBoolExprImpl(bool value)104   ConstBoolExprImpl(bool value) : value_(value) {}
~ConstBoolExprImpl()105   ~ConstBoolExprImpl() override {}
106 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const107   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:
MaskedEqualBoolExprImpl(int argno,size_t width,uint64_t mask,uint64_t value)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) {}
~MaskedEqualBoolExprImpl()126   ~MaskedEqualBoolExprImpl() override {}
127 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const128   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:
NegateBoolExprImpl(BoolExpr cond)145   explicit NegateBoolExprImpl(BoolExpr cond) : cond_(std::move(cond)) {}
~NegateBoolExprImpl()146   ~NegateBoolExprImpl() override {}
147 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const148   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:
AndBoolExprImpl(BoolExpr lhs,BoolExpr rhs)162   AndBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
163       : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
~AndBoolExprImpl()164   ~AndBoolExprImpl() override {}
165 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const166   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:
OrBoolExprImpl(BoolExpr lhs,BoolExpr rhs)182   OrBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
183       : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
~OrBoolExprImpl()184   ~OrBoolExprImpl() override {}
185 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const186   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 
HasUnsafeTraps() const204 bool ResultExprImpl::HasUnsafeTraps() const {
205   return false;
206 }
207 
IsAllow() const208 bool ResultExprImpl::IsAllow() const {
209   return false;
210 }
211 
IsDeny() const212 bool ResultExprImpl::IsDeny() const {
213   return false;
214 }
215 
DefaultMask(size_t size)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 
ArgEq(int num,size_t size,uint64_t mask,uint64_t val)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 
Allow()238 ResultExpr Allow() {
239   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ALLOW);
240 }
241 
Error(int err)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 
Kill()247 ResultExpr Kill() {
248   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_KILL);
249 }
250 
Trace(uint16_t aux)251 ResultExpr Trace(uint16_t aux) {
252   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_TRACE + aux);
253 }
254 
Trap(TrapRegistry::TrapFnc trap_func,const void * aux)255 ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
256   return std::make_shared<TrapResultExprImpl>(trap_func, aux, true /* safe */);
257 }
258 
UnsafeTrap(TrapRegistry::TrapFnc trap_func,const void * aux)259 ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
260   return std::make_shared<TrapResultExprImpl>(trap_func, aux,
261                                               false /* unsafe */);
262 }
263 
BoolConst(bool value)264 BoolExpr BoolConst(bool value) {
265   return std::make_shared<ConstBoolExprImpl>(value);
266 }
267 
Not(BoolExpr cond)268 BoolExpr Not(BoolExpr cond) {
269   return std::make_shared<NegateBoolExprImpl>(std::move(cond));
270 }
271 
AllOf()272 BoolExpr AllOf() {
273   return BoolConst(true);
274 }
275 
AllOf(BoolExpr lhs,BoolExpr rhs)276 BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs) {
277   return std::make_shared<AndBoolExprImpl>(std::move(lhs), std::move(rhs));
278 }
279 
AnyOf()280 BoolExpr AnyOf() {
281   return BoolConst(false);
282 }
283 
AnyOf(BoolExpr lhs,BoolExpr rhs)284 BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs) {
285   return std::make_shared<OrBoolExprImpl>(std::move(lhs), std::move(rhs));
286 }
287 
If(BoolExpr cond,ResultExpr then_result)288 Elser If(BoolExpr cond, ResultExpr then_result) {
289   return Elser(nullptr).ElseIf(std::move(cond), std::move(then_result));
290 }
291 
Elser(cons::List<Clause> clause_list)292 Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
293 }
294 
Elser(const Elser & elser)295 Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
296 }
297 
~Elser()298 Elser::~Elser() {
299 }
300 
ElseIf(BoolExpr cond,ResultExpr then_result) const301 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 
Else(ResultExpr else_result) const306 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