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 #include <ostream>
12 
13 #include "base/check.h"
14 #include "base/macros.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) {}
~ReturnResultExprImpl()27   ~ReturnResultExprImpl() override {}
28 
Compile(PolicyCompiler * pc) const29   CodeGen::Node Compile(PolicyCompiler* pc) const override {
30     return pc->Return(ret_);
31   }
32 
IsAllow() const33   bool IsAllow() const override { return IsAction(SECCOMP_RET_ALLOW); }
34 
IsDeny() const35   bool IsDeny() const override {
36     return IsAction(SECCOMP_RET_ERRNO) || IsAction(SECCOMP_RET_KILL) ||
37            IsAction(SECCOMP_RET_USER_NOTIF);
38   }
39 
40  private:
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   }
~TrapResultExprImpl()56   ~TrapResultExprImpl() override {}
57 
Compile(PolicyCompiler * pc) const58   CodeGen::Node Compile(PolicyCompiler* pc) const override {
59     return pc->Trap(func_, arg_, safe_);
60   }
61 
HasUnsafeTraps() const62   bool HasUnsafeTraps() const override { return safe_ == false; }
63 
IsDeny() const64   bool IsDeny() const override { return true; }
65 
66  private:
67   TrapRegistry::TrapFnc func_;
68   const void* arg_;
69   bool safe_;
70 
71   DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl);
72 };
73 
74 class IfThenResultExprImpl : public internal::ResultExprImpl {
75  public:
IfThenResultExprImpl(BoolExpr cond,ResultExpr then_result,ResultExpr else_result)76   IfThenResultExprImpl(BoolExpr cond,
77                        ResultExpr then_result,
78                        ResultExpr else_result)
79       : cond_(std::move(cond)),
80         then_result_(std::move(then_result)),
81         else_result_(std::move(else_result)) {}
~IfThenResultExprImpl()82   ~IfThenResultExprImpl() override {}
83 
Compile(PolicyCompiler * pc) const84   CodeGen::Node Compile(PolicyCompiler* pc) const override {
85     // We compile the "then" and "else" expressions in separate statements so
86     // they have a defined sequencing.  See https://crbug.com/529480.
87     CodeGen::Node then_node = then_result_->Compile(pc);
88     CodeGen::Node else_node = else_result_->Compile(pc);
89     return cond_->Compile(pc, then_node, else_node);
90   }
91 
HasUnsafeTraps() const92   bool HasUnsafeTraps() const override {
93     return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps();
94   }
95 
96  private:
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) {}
~ConstBoolExprImpl()107   ~ConstBoolExprImpl() override {}
108 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const109   CodeGen::Node Compile(PolicyCompiler* pc,
110                         CodeGen::Node then_node,
111                         CodeGen::Node else_node) const override {
112     return value_ ? then_node : else_node;
113   }
114 
115  private:
116   bool value_;
117 
118   DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
119 };
120 
121 class MaskedEqualBoolExprImpl : public internal::BoolExprImpl {
122  public:
MaskedEqualBoolExprImpl(int argno,size_t width,uint64_t mask,uint64_t value)123   MaskedEqualBoolExprImpl(int argno,
124                           size_t width,
125                           uint64_t mask,
126                           uint64_t value)
127       : argno_(argno), width_(width), mask_(mask), value_(value) {}
~MaskedEqualBoolExprImpl()128   ~MaskedEqualBoolExprImpl() override {}
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:
137   int argno_;
138   size_t width_;
139   uint64_t mask_;
140   uint64_t value_;
141 
142   DISALLOW_COPY_AND_ASSIGN(MaskedEqualBoolExprImpl);
143 };
144 
145 class NegateBoolExprImpl : public internal::BoolExprImpl {
146  public:
NegateBoolExprImpl(BoolExpr cond)147   explicit NegateBoolExprImpl(BoolExpr cond) : cond_(std::move(cond)) {}
~NegateBoolExprImpl()148   ~NegateBoolExprImpl() override {}
149 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const150   CodeGen::Node Compile(PolicyCompiler* pc,
151                         CodeGen::Node then_node,
152                         CodeGen::Node else_node) const override {
153     return cond_->Compile(pc, else_node, then_node);
154   }
155 
156  private:
157   BoolExpr cond_;
158 
159   DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl);
160 };
161 
162 class AndBoolExprImpl : public internal::BoolExprImpl {
163  public:
AndBoolExprImpl(BoolExpr lhs,BoolExpr rhs)164   AndBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
165       : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
~AndBoolExprImpl()166   ~AndBoolExprImpl() override {}
167 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const168   CodeGen::Node Compile(PolicyCompiler* pc,
169                         CodeGen::Node then_node,
170                         CodeGen::Node else_node) const override {
171     return lhs_->Compile(pc, rhs_->Compile(pc, then_node, else_node),
172                          else_node);
173   }
174 
175  private:
176   BoolExpr lhs_;
177   BoolExpr rhs_;
178 
179   DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl);
180 };
181 
182 class OrBoolExprImpl : public internal::BoolExprImpl {
183  public:
OrBoolExprImpl(BoolExpr lhs,BoolExpr rhs)184   OrBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
185       : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
~OrBoolExprImpl()186   ~OrBoolExprImpl() override {}
187 
Compile(PolicyCompiler * pc,CodeGen::Node then_node,CodeGen::Node else_node) const188   CodeGen::Node Compile(PolicyCompiler* pc,
189                         CodeGen::Node then_node,
190                         CodeGen::Node else_node) const override {
191     return lhs_->Compile(pc, then_node,
192                          rhs_->Compile(pc, then_node, else_node));
193   }
194 
195  private:
196   BoolExpr lhs_;
197   BoolExpr rhs_;
198 
199   DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl);
200 };
201 
202 }  // namespace
203 
204 namespace internal {
205 
HasUnsafeTraps() const206 bool ResultExprImpl::HasUnsafeTraps() const {
207   return false;
208 }
209 
IsAllow() const210 bool ResultExprImpl::IsAllow() const {
211   return false;
212 }
213 
IsDeny() const214 bool ResultExprImpl::IsDeny() const {
215   return false;
216 }
217 
DefaultMask(size_t size)218 uint64_t DefaultMask(size_t size) {
219   switch (size) {
220     case 4:
221       return std::numeric_limits<uint32_t>::max();
222     case 8:
223       return std::numeric_limits<uint64_t>::max();
224     default:
225       CHECK(false) << "Unimplemented DefaultMask case";
226       return 0;
227   }
228 }
229 
ArgEq(int num,size_t size,uint64_t mask,uint64_t val)230 BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) {
231   // If this is changed, update Arg<T>::EqualTo's static_cast rules
232   // accordingly.
233   CHECK(size == 4 || size == 8);
234 
235   return std::make_shared<MaskedEqualBoolExprImpl>(num, size, mask, val);
236 }
237 
238 }  // namespace internal
239 
Allow()240 ResultExpr Allow() {
241   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ALLOW);
242 }
243 
Error(int err)244 ResultExpr Error(int err) {
245   CHECK(err >= ErrorCode::ERR_MIN_ERRNO && err <= ErrorCode::ERR_MAX_ERRNO);
246   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ERRNO + err);
247 }
248 
Kill()249 ResultExpr Kill() {
250   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_KILL);
251 }
252 
Trace(uint16_t aux)253 ResultExpr Trace(uint16_t aux) {
254   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_TRACE + aux);
255 }
256 
Trap(TrapRegistry::TrapFnc trap_func,const void * aux)257 ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
258   return std::make_shared<TrapResultExprImpl>(trap_func, aux, true /* safe */);
259 }
260 
UnsafeTrap(TrapRegistry::TrapFnc trap_func,const void * aux)261 ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
262   return std::make_shared<TrapResultExprImpl>(trap_func, aux,
263                                               false /* unsafe */);
264 }
265 
UserNotify()266 ResultExpr UserNotify() {
267   return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_USER_NOTIF);
268 }
269 
BoolConst(bool value)270 BoolExpr BoolConst(bool value) {
271   return std::make_shared<ConstBoolExprImpl>(value);
272 }
273 
Not(BoolExpr cond)274 BoolExpr Not(BoolExpr cond) {
275   return std::make_shared<NegateBoolExprImpl>(std::move(cond));
276 }
277 
AllOf()278 BoolExpr AllOf() {
279   return BoolConst(true);
280 }
281 
AllOf(BoolExpr lhs,BoolExpr rhs)282 BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs) {
283   return std::make_shared<AndBoolExprImpl>(std::move(lhs), std::move(rhs));
284 }
285 
AnyOf()286 BoolExpr AnyOf() {
287   return BoolConst(false);
288 }
289 
AnyOf(BoolExpr lhs,BoolExpr rhs)290 BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs) {
291   return std::make_shared<OrBoolExprImpl>(std::move(lhs), std::move(rhs));
292 }
293 
If(BoolExpr cond,ResultExpr then_result)294 Elser If(BoolExpr cond, ResultExpr then_result) {
295   return Elser(nullptr).ElseIf(std::move(cond), std::move(then_result));
296 }
297 
Elser(cons::List<Clause> clause_list)298 Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
299 }
300 
Elser(const Elser & elser)301 Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
302 }
303 
~Elser()304 Elser::~Elser() {
305 }
306 
ElseIf(BoolExpr cond,ResultExpr then_result) const307 Elser Elser::ElseIf(BoolExpr cond, ResultExpr then_result) const {
308   return Elser(Cons(std::make_pair(std::move(cond), std::move(then_result)),
309                     clause_list_));
310 }
311 
Else(ResultExpr else_result) const312 ResultExpr Elser::Else(ResultExpr else_result) const {
313   // We finally have the default result expression for this
314   // if/then/else sequence.  Also, we've already accumulated all
315   // if/then pairs into a list of reverse order (i.e., lower priority
316   // conditions are listed before higher priority ones).  E.g., an
317   // expression like
318   //
319   //    If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4)
320   //
321   // will have built up a list like
322   //
323   //    [(b3, e3), (b2, e2), (b1, e1)].
324   //
325   // Now that we have e4, we can walk the list and create a ResultExpr
326   // tree like:
327   //
328   //    expr = e4
329   //    expr = (b3 ? e3 : expr) = (b3 ? e3 : e4)
330   //    expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4))
331   //    expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4)))
332   //
333   // and end up with an appropriately chained tree.
334 
335   ResultExpr expr = std::move(else_result);
336   for (const Clause& clause : clause_list_) {
337     expr = std::make_shared<IfThenResultExprImpl>(clause.first, clause.second,
338                                                   std::move(expr));
339   }
340   return expr;
341 }
342 
343 }  // namespace bpf_dsl
344 }  // namespace sandbox
345 
346 namespace std {
347 template class shared_ptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
348 template class shared_ptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
349 }  // namespace std
350