1 // Copyright (c) 2012 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/verifier.h"
9 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
10 #include "sandbox/linux/bpf_dsl/trap_registry.h"
11 #include "sandbox/linux/system_headers/linux_filter.h"
12 #include "sandbox/linux/system_headers/linux_seccomp.h"
20 State(const std::vector
<struct sock_filter
>& p
,
21 const struct arch_seccomp_data
& d
)
22 : program(p
), data(d
), ip(0), accumulator(0), acc_is_valid(false) {}
23 const std::vector
<struct sock_filter
>& program
;
24 const struct arch_seccomp_data
& data
;
30 DISALLOW_IMPLICIT_CONSTRUCTORS(State
);
33 void Ld(State
* state
, const struct sock_filter
& insn
, const char** err
) {
34 if (BPF_SIZE(insn
.code
) != BPF_W
|| BPF_MODE(insn
.code
) != BPF_ABS
||
35 insn
.jt
!= 0 || insn
.jf
!= 0) {
36 *err
= "Invalid BPF_LD instruction";
39 if (insn
.k
< sizeof(struct arch_seccomp_data
) && (insn
.k
& 3) == 0) {
40 // We only allow loading of properly aligned 32bit quantities.
41 memcpy(&state
->accumulator
,
42 reinterpret_cast<const char*>(&state
->data
) + insn
.k
, 4);
44 *err
= "Invalid operand in BPF_LD instruction";
47 state
->acc_is_valid
= true;
51 void Jmp(State
* state
, const struct sock_filter
& insn
, const char** err
) {
52 if (BPF_OP(insn
.code
) == BPF_JA
) {
53 if (state
->ip
+ insn
.k
+ 1 >= state
->program
.size() ||
54 state
->ip
+ insn
.k
+ 1 <= state
->ip
) {
56 *err
= "Invalid BPF_JMP instruction";
61 if (BPF_SRC(insn
.code
) != BPF_K
|| !state
->acc_is_valid
||
62 state
->ip
+ insn
.jt
+ 1 >= state
->program
.size() ||
63 state
->ip
+ insn
.jf
+ 1 >= state
->program
.size()) {
64 goto compilation_failure
;
66 switch (BPF_OP(insn
.code
)) {
68 if (state
->accumulator
== insn
.k
) {
75 if (state
->accumulator
> insn
.k
) {
82 if (state
->accumulator
>= insn
.k
) {
89 if (state
->accumulator
& insn
.k
) {
96 goto compilation_failure
;
101 uint32_t Ret(State
*, const struct sock_filter
& insn
, const char** err
) {
102 if (BPF_SRC(insn
.code
) != BPF_K
) {
103 *err
= "Invalid BPF_RET instruction";
109 void Alu(State
* state
, const struct sock_filter
& insn
, const char** err
) {
110 if (BPF_OP(insn
.code
) == BPF_NEG
) {
111 state
->accumulator
= -state
->accumulator
;
114 if (BPF_SRC(insn
.code
) != BPF_K
) {
115 *err
= "Unexpected source operand in arithmetic operation";
118 switch (BPF_OP(insn
.code
)) {
120 state
->accumulator
+= insn
.k
;
123 state
->accumulator
-= insn
.k
;
126 state
->accumulator
*= insn
.k
;
130 *err
= "Illegal division by zero";
133 state
->accumulator
/= insn
.k
;
137 *err
= "Illegal division by zero";
140 state
->accumulator
%= insn
.k
;
143 state
->accumulator
|= insn
.k
;
146 state
->accumulator
^= insn
.k
;
149 state
->accumulator
&= insn
.k
;
153 *err
= "Illegal shift operation";
156 state
->accumulator
<<= insn
.k
;
160 *err
= "Illegal shift operation";
163 state
->accumulator
>>= insn
.k
;
166 *err
= "Invalid operator in arithmetic operation";
174 uint32_t Verifier::EvaluateBPF(const std::vector
<struct sock_filter
>& program
,
175 const struct arch_seccomp_data
& data
,
178 if (program
.size() < 1 || program
.size() >= SECCOMP_MAX_PROGRAM_SIZE
) {
179 *err
= "Invalid program length";
182 for (State
state(program
, data
); !*err
; ++state
.ip
) {
183 if (state
.ip
>= program
.size()) {
184 *err
= "Invalid instruction pointer in BPF program";
187 const struct sock_filter
& insn
= program
[state
.ip
];
188 switch (BPF_CLASS(insn
.code
)) {
190 Ld(&state
, insn
, err
);
193 Jmp(&state
, insn
, err
);
196 uint32_t r
= Ret(&state
, insn
, err
);
197 switch (r
& SECCOMP_RET_ACTION
) {
198 case SECCOMP_RET_ALLOW
:
199 case SECCOMP_RET_ERRNO
:
200 case SECCOMP_RET_KILL
:
201 case SECCOMP_RET_TRACE
:
202 case SECCOMP_RET_TRAP
:
204 case SECCOMP_RET_INVALID
: // Should never show up in BPF program
206 *err
= "Unexpected return code found in BPF program";
212 Alu(&state
, insn
, err
);
215 *err
= "Unexpected instruction in BPF program";
222 } // namespace bpf_dsl
223 } // namespace sandbox