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
20namespace sandbox {
21namespace bpf_dsl {
22namespace {
23
24class 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
50class 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
75class 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
104class 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
122class 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
147class 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
165class 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
186class 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
209namespace internal {
210
211bool ResultExprImpl::HasUnsafeTraps() const {
212  return false;
213}
214
215bool ResultExprImpl::IsAllow() const {
216  return false;
217}
218
219bool ResultExprImpl::IsDeny() const {
220  return false;
221}
222
223uint64_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
235BoolExpr 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
245ResultExpr Allow() {
246  return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ALLOW));
247}
248
249ResultExpr 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
254ResultExpr Kill() {
255  return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_KILL));
256}
257
258ResultExpr Trace(uint16_t aux) {
259  return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_TRACE + aux));
260}
261
262ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
263  return ResultExpr(
264      new const TrapResultExprImpl(trap_func, aux, true /* safe */));
265}
266
267ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
268  return ResultExpr(
269      new const TrapResultExprImpl(trap_func, aux, false /* unsafe */));
270}
271
272BoolExpr BoolConst(bool value) {
273  return BoolExpr(new const ConstBoolExprImpl(value));
274}
275
276BoolExpr Not(const BoolExpr& cond) {
277  return BoolExpr(new const NegateBoolExprImpl(cond));
278}
279
280BoolExpr AllOf() {
281  return BoolConst(true);
282}
283
284BoolExpr AllOf(const BoolExpr& lhs, const BoolExpr& rhs) {
285  return BoolExpr(new const AndBoolExprImpl(lhs, rhs));
286}
287
288BoolExpr AnyOf() {
289  return BoolConst(false);
290}
291
292BoolExpr AnyOf(const BoolExpr& lhs, const BoolExpr& rhs) {
293  return BoolExpr(new const OrBoolExprImpl(lhs, rhs));
294}
295
296Elser If(const BoolExpr& cond, const ResultExpr& then_result) {
297  return Elser(nullptr).ElseIf(cond, then_result);
298}
299
300Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
301}
302
303Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
304}
305
306Elser::~Elser() {
307}
308
309Elser Elser::ElseIf(const BoolExpr& cond, const ResultExpr& then_result) const {
310  return Elser(Cons(std::make_pair(cond, then_result), clause_list_));
311}
312
313ResultExpr 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
347template class scoped_refptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
348template class scoped_refptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
349