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.
5 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
12 #include "sandbox/linux/bpf_dsl/errorcode.h"
13 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
14 #include "sandbox/linux/system_headers/linux_seccomp.h"
20 class ReturnResultExprImpl
: public internal::ResultExprImpl
{
22 explicit ReturnResultExprImpl(uint32_t ret
) : ret_(ret
) {}
24 CodeGen::Node
Compile(PolicyCompiler
* pc
) const override
{
25 return pc
->Return(ret_
);
28 bool IsAllow() const override
{ return IsAction(SECCOMP_RET_ALLOW
); }
30 bool IsDeny() const override
{
31 return IsAction(SECCOMP_RET_ERRNO
) || IsAction(SECCOMP_RET_KILL
);
35 ~ReturnResultExprImpl() override
{}
37 bool IsAction(uint32_t action
) const {
38 return (ret_
& SECCOMP_RET_ACTION
) == action
;
43 DISALLOW_COPY_AND_ASSIGN(ReturnResultExprImpl
);
46 class TrapResultExprImpl
: public internal::ResultExprImpl
{
48 TrapResultExprImpl(TrapRegistry::TrapFnc func
, const void* arg
, bool safe
)
49 : func_(func
), arg_(arg
), safe_(safe
) {
53 CodeGen::Node
Compile(PolicyCompiler
* pc
) const override
{
54 return pc
->Trap(func_
, arg_
, safe_
);
57 bool HasUnsafeTraps() const override
{ return safe_
== false; }
59 bool IsDeny() const override
{ return true; }
62 ~TrapResultExprImpl() override
{}
64 TrapRegistry::TrapFnc func_
;
68 DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl
);
71 class IfThenResultExprImpl
: public internal::ResultExprImpl
{
73 IfThenResultExprImpl(const BoolExpr
& cond
,
74 const ResultExpr
& then_result
,
75 const ResultExpr
& else_result
)
76 : cond_(cond
), then_result_(then_result
), else_result_(else_result
) {}
78 CodeGen::Node
Compile(PolicyCompiler
* pc
) const override
{
79 // We compile the "then" and "else" expressions in separate statements so
80 // they have a defined sequencing. See https://crbug.com/529480.
81 CodeGen::Node then_node
= then_result_
->Compile(pc
);
82 CodeGen::Node else_node
= else_result_
->Compile(pc
);
83 return cond_
->Compile(pc
, then_node
, else_node
);
86 bool HasUnsafeTraps() const override
{
87 return then_result_
->HasUnsafeTraps() || else_result_
->HasUnsafeTraps();
91 ~IfThenResultExprImpl() override
{}
94 ResultExpr then_result_
;
95 ResultExpr else_result_
;
97 DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl
);
100 class ConstBoolExprImpl
: public internal::BoolExprImpl
{
102 ConstBoolExprImpl(bool value
) : value_(value
) {}
104 CodeGen::Node
Compile(PolicyCompiler
* pc
,
105 CodeGen::Node then_node
,
106 CodeGen::Node else_node
) const override
{
107 return value_
? then_node
: else_node
;
111 ~ConstBoolExprImpl() override
{}
115 DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl
);
118 class MaskedEqualBoolExprImpl
: public internal::BoolExprImpl
{
120 MaskedEqualBoolExprImpl(int argno
,
124 : argno_(argno
), width_(width
), mask_(mask
), value_(value
) {}
126 CodeGen::Node
Compile(PolicyCompiler
* pc
,
127 CodeGen::Node then_node
,
128 CodeGen::Node else_node
) const override
{
129 return pc
->MaskedEqual(argno_
, width_
, mask_
, value_
, then_node
, else_node
);
133 ~MaskedEqualBoolExprImpl() override
{}
140 DISALLOW_COPY_AND_ASSIGN(MaskedEqualBoolExprImpl
);
143 class NegateBoolExprImpl
: public internal::BoolExprImpl
{
145 explicit NegateBoolExprImpl(const BoolExpr
& cond
) : cond_(cond
) {}
147 CodeGen::Node
Compile(PolicyCompiler
* pc
,
148 CodeGen::Node then_node
,
149 CodeGen::Node else_node
) const override
{
150 return cond_
->Compile(pc
, else_node
, then_node
);
154 ~NegateBoolExprImpl() override
{}
158 DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl
);
161 class AndBoolExprImpl
: public internal::BoolExprImpl
{
163 AndBoolExprImpl(const BoolExpr
& lhs
, const BoolExpr
& rhs
)
164 : lhs_(lhs
), rhs_(rhs
) {}
166 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
),
174 ~AndBoolExprImpl() override
{}
179 DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl
);
182 class OrBoolExprImpl
: public internal::BoolExprImpl
{
184 OrBoolExprImpl(const BoolExpr
& lhs
, const BoolExpr
& rhs
)
185 : lhs_(lhs
), rhs_(rhs
) {}
187 CodeGen::Node
Compile(PolicyCompiler
* pc
,
188 CodeGen::Node then_node
,
189 CodeGen::Node else_node
) const override
{
190 return lhs_
->Compile(pc
, then_node
,
191 rhs_
->Compile(pc
, then_node
, else_node
));
195 ~OrBoolExprImpl() override
{}
200 DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl
);
207 bool ResultExprImpl::HasUnsafeTraps() const {
211 bool ResultExprImpl::IsAllow() const {
215 bool ResultExprImpl::IsDeny() const {
219 uint64_t DefaultMask(size_t size
) {
222 return std::numeric_limits
<uint32_t>::max();
224 return std::numeric_limits
<uint64_t>::max();
226 CHECK(false) << "Unimplemented DefaultMask case";
231 BoolExpr
ArgEq(int num
, size_t size
, uint64_t mask
, uint64_t val
) {
232 // If this is changed, update Arg<T>::EqualTo's static_cast rules
234 CHECK(size
== 4 || size
== 8);
236 return BoolExpr(new const MaskedEqualBoolExprImpl(num
, size
, mask
, val
));
239 } // namespace internal
242 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ALLOW
));
245 ResultExpr
Error(int err
) {
246 CHECK(err
>= ErrorCode::ERR_MIN_ERRNO
&& err
<= ErrorCode::ERR_MAX_ERRNO
);
247 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_ERRNO
+ err
));
251 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_KILL
));
254 ResultExpr
Trace(uint16_t aux
) {
255 return ResultExpr(new const ReturnResultExprImpl(SECCOMP_RET_TRACE
+ aux
));
258 ResultExpr
Trap(TrapRegistry::TrapFnc trap_func
, const void* aux
) {
260 new const TrapResultExprImpl(trap_func
, aux
, true /* safe */));
263 ResultExpr
UnsafeTrap(TrapRegistry::TrapFnc trap_func
, const void* aux
) {
265 new const TrapResultExprImpl(trap_func
, aux
, false /* unsafe */));
268 BoolExpr
BoolConst(bool value
) {
269 return BoolExpr(new const ConstBoolExprImpl(value
));
272 BoolExpr
operator!(const BoolExpr
& cond
) {
273 return BoolExpr(new const NegateBoolExprImpl(cond
));
276 BoolExpr
operator&&(const BoolExpr
& lhs
, const BoolExpr
& rhs
) {
277 return BoolExpr(new const AndBoolExprImpl(lhs
, rhs
));
280 BoolExpr
operator||(const BoolExpr
& lhs
, const BoolExpr
& rhs
) {
281 return BoolExpr(new const OrBoolExprImpl(lhs
, rhs
));
284 Elser
If(const BoolExpr
& cond
, const ResultExpr
& then_result
) {
285 return Elser(nullptr).ElseIf(cond
, then_result
);
288 Elser::Elser(cons::List
<Clause
> clause_list
) : clause_list_(clause_list
) {
291 Elser::Elser(const Elser
& elser
) : clause_list_(elser
.clause_list_
) {
297 Elser
Elser::ElseIf(const BoolExpr
& cond
, const ResultExpr
& then_result
) const {
298 return Elser(Cons(std::make_pair(cond
, then_result
), clause_list_
));
301 ResultExpr
Elser::Else(const ResultExpr
& else_result
) const {
302 // We finally have the default result expression for this
303 // if/then/else sequence. Also, we've already accumulated all
304 // if/then pairs into a list of reverse order (i.e., lower priority
305 // conditions are listed before higher priority ones). E.g., an
308 // If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4)
310 // will have built up a list like
312 // [(b3, e3), (b2, e2), (b1, e1)].
314 // Now that we have e4, we can walk the list and create a ResultExpr
318 // expr = (b3 ? e3 : expr) = (b3 ? e3 : e4)
319 // expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4))
320 // expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4)))
322 // and end up with an appropriately chained tree.
324 ResultExpr expr
= else_result
;
325 for (const Clause
& clause
: clause_list_
) {
327 new const IfThenResultExprImpl(clause
.first
, clause
.second
, expr
));
332 } // namespace bpf_dsl
333 } // namespace sandbox
335 template class scoped_refptr
<const sandbox::bpf_dsl::internal::BoolExprImpl
>;
336 template class scoped_refptr
<const sandbox::bpf_dsl::internal::ResultExprImpl
>;