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