Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(341)

Side by Side Diff: sandbox/linux/bpf_dsl/verifier.cc

Issue 1001833005: Update from https://crrev.com/320343 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Supress Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sandbox/linux/seccomp-bpf/verifier.h" 5 #include "sandbox/linux/bpf_dsl/verifier.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include <limits> 9 #include <limits>
10 10
11 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 11 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
12 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h" 12 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
13 #include "sandbox/linux/bpf_dsl/policy.h" 13 #include "sandbox/linux/bpf_dsl/policy.h"
14 #include "sandbox/linux/bpf_dsl/policy_compiler.h" 14 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
15 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" 15 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
16 #include "sandbox/linux/bpf_dsl/syscall_set.h" 16 #include "sandbox/linux/bpf_dsl/syscall_set.h"
17 #include "sandbox/linux/seccomp-bpf/errorcode.h" 17 #include "sandbox/linux/seccomp-bpf/errorcode.h"
18 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
19 #include "sandbox/linux/system_headers/linux_seccomp.h" 18 #include "sandbox/linux/system_headers/linux_seccomp.h"
20 19
21 namespace sandbox { 20 namespace sandbox {
21 namespace bpf_dsl {
22 22
23 namespace { 23 namespace {
24 24
25 const uint64_t kLower32Bits = std::numeric_limits<uint32_t>::max(); 25 const uint64_t kLower32Bits = std::numeric_limits<uint32_t>::max();
26 const uint64_t kUpper32Bits = static_cast<uint64_t>(kLower32Bits) << 32; 26 const uint64_t kUpper32Bits = static_cast<uint64_t>(kLower32Bits) << 32;
27 const uint64_t kFull64Bits = std::numeric_limits<uint64_t>::max();
28 27
29 struct State { 28 struct State {
30 State(const std::vector<struct sock_filter>& p, 29 State(const std::vector<struct sock_filter>& p,
31 const struct arch_seccomp_data& d) 30 const struct arch_seccomp_data& d)
32 : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {} 31 : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {}
33 const std::vector<struct sock_filter>& program; 32 const std::vector<struct sock_filter>& program;
34 const struct arch_seccomp_data& data; 33 const struct arch_seccomp_data& data;
35 unsigned int ip; 34 unsigned int ip;
36 uint32_t accumulator; 35 uint32_t accumulator;
37 bool acc_is_valid; 36 bool acc_is_valid;
38 37
39 private: 38 private:
40 DISALLOW_IMPLICIT_CONSTRUCTORS(State); 39 DISALLOW_IMPLICIT_CONSTRUCTORS(State);
41 }; 40 };
42 41
43 uint32_t EvaluateErrorCode(bpf_dsl::PolicyCompiler* compiler, 42 uint32_t EvaluateErrorCode(bpf_dsl::PolicyCompiler* compiler,
44 const ErrorCode& code, 43 const ErrorCode& code,
45 const struct arch_seccomp_data& data) { 44 const struct arch_seccomp_data& data) {
46 if (code.error_type() == ErrorCode::ET_SIMPLE || 45 if (code.error_type() == ErrorCode::ET_SIMPLE ||
47 code.error_type() == ErrorCode::ET_TRAP) { 46 code.error_type() == ErrorCode::ET_TRAP) {
48 return code.err(); 47 return code.err();
49 } else if (code.error_type() == ErrorCode::ET_COND) { 48 } else if (code.error_type() == ErrorCode::ET_COND) {
50 if (code.width() == ErrorCode::TP_32BIT && 49 if (code.width() == ErrorCode::TP_32BIT &&
51 (data.args[code.argno()] >> 32) && 50 (data.args[code.argno()] >> 32) &&
52 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) != 51 (data.args[code.argno()] & 0xFFFFFFFF80000000ull) !=
53 0xFFFFFFFF80000000ull) { 52 0xFFFFFFFF80000000ull) {
54 return compiler->Unexpected64bitArgument().err(); 53 return compiler->Unexpected64bitArgument().err();
55 } 54 }
56 bool equal = (data.args[code.argno()] & code.mask()) == code.value(); 55 bool equal = (data.args[code.argno()] & code.mask()) == code.value();
57 return EvaluateErrorCode( 56 return EvaluateErrorCode(compiler, equal ? *code.passed() : *code.failed(),
58 compiler, equal ? *code.passed() : *code.failed(), data); 57 data);
59 } else { 58 } else {
60 return SECCOMP_RET_INVALID; 59 return SECCOMP_RET_INVALID;
61 } 60 }
62 } 61 }
63 62
64 bool VerifyErrorCode(bpf_dsl::PolicyCompiler* compiler, 63 bool VerifyErrorCode(bpf_dsl::PolicyCompiler* compiler,
65 const std::vector<struct sock_filter>& program, 64 const std::vector<struct sock_filter>& program,
66 struct arch_seccomp_data* data, 65 struct arch_seccomp_data* data,
67 const ErrorCode& root_code, 66 const ErrorCode& root_code,
68 const ErrorCode& code, 67 const ErrorCode& code,
69 const char** err) { 68 const char** err) {
70 if (code.error_type() == ErrorCode::ET_SIMPLE || 69 if (code.error_type() == ErrorCode::ET_SIMPLE ||
71 code.error_type() == ErrorCode::ET_TRAP) { 70 code.error_type() == ErrorCode::ET_TRAP) {
72 uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err); 71 const uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err);
73 if (*err) { 72 if (*err) {
74 return false; 73 return false;
75 } else if (computed_ret != EvaluateErrorCode(compiler, root_code, *data)) { 74 }
75 const uint32_t policy_ret = EvaluateErrorCode(compiler, root_code, *data);
76 if (computed_ret != policy_ret) {
76 // For efficiency's sake, we'd much rather compare "computed_ret" 77 // For efficiency's sake, we'd much rather compare "computed_ret"
77 // against "code.err()". This works most of the time, but it doesn't 78 // against "code.err()". This works most of the time, but it doesn't
78 // always work for nested conditional expressions. The test values 79 // always work for nested conditional expressions. The test values
79 // that we generate on the fly to probe expressions can trigger 80 // that we generate on the fly to probe expressions can trigger
80 // code flow decisions in multiple nodes of the decision tree, and the 81 // code flow decisions in multiple nodes of the decision tree, and the
81 // only way to compute the correct error code in that situation is by 82 // only way to compute the correct error code in that situation is by
82 // calling EvaluateErrorCode(). 83 // calling EvaluateErrorCode().
83 *err = "Exit code from BPF program doesn't match"; 84 *err = "Exit code from BPF program doesn't match";
84 return false; 85 return false;
85 } 86 }
86 } else if (code.error_type() == ErrorCode::ET_COND) { 87 } else if (code.error_type() == ErrorCode::ET_COND) {
87 if (code.argno() < 0 || code.argno() >= 6) { 88 if (code.argno() < 0 || code.argno() >= 6) {
88 *err = "Invalid argument number in error code"; 89 *err = "Invalid argument number in error code";
89 return false; 90 return false;
90 } 91 }
91 92
92 // TODO(mdempsky): The test values generated here try to provide good 93 // TODO(mdempsky): The test values generated here try to provide good
93 // coverage for generated BPF instructions while avoiding combinatorial 94 // coverage for generated BPF instructions while avoiding combinatorial
94 // explosion on large policies. Ideally we would instead take a fuzzing-like 95 // explosion on large policies. Ideally we would instead take a fuzzing-like
95 // approach and generate a bounded number of test cases regardless of policy 96 // approach and generate a bounded number of test cases regardless of policy
96 // size. 97 // size.
97 98
98 // Verify that we can check a value for simple equality. 99 // Verify that we can check a value for simple equality.
99 data->args[code.argno()] = code.value(); 100 data->args[code.argno()] = code.value();
100 if (!VerifyErrorCode( 101 if (!VerifyErrorCode(compiler, program, data, root_code, *code.passed(),
101 compiler, program, data, root_code, *code.passed(), err)) { 102 err)) {
102 return false; 103 return false;
103 } 104 }
104 105
105 // If mask ignores any bits, verify that setting those bits is still 106 // If mask ignores any bits, verify that setting those bits is still
106 // detected as equality. 107 // detected as equality.
107 uint64_t ignored_bits = ~code.mask(); 108 uint64_t ignored_bits = ~code.mask();
108 if (code.width() == ErrorCode::TP_32BIT) { 109 if (code.width() == ErrorCode::TP_32BIT) {
109 ignored_bits = static_cast<uint32_t>(ignored_bits); 110 ignored_bits = static_cast<uint32_t>(ignored_bits);
110 } 111 }
111 if ((ignored_bits & kLower32Bits) != 0) { 112 if ((ignored_bits & kLower32Bits) != 0) {
112 data->args[code.argno()] = code.value() | (ignored_bits & kLower32Bits); 113 data->args[code.argno()] = code.value() | (ignored_bits & kLower32Bits);
113 if (!VerifyErrorCode( 114 if (!VerifyErrorCode(compiler, program, data, root_code, *code.passed(),
114 compiler, program, data, root_code, *code.passed(), err)) { 115 err)) {
115 return false; 116 return false;
116 } 117 }
117 } 118 }
118 if ((ignored_bits & kUpper32Bits) != 0) { 119 if ((ignored_bits & kUpper32Bits) != 0) {
119 data->args[code.argno()] = code.value() | (ignored_bits & kUpper32Bits); 120 data->args[code.argno()] = code.value() | (ignored_bits & kUpper32Bits);
120 if (!VerifyErrorCode( 121 if (!VerifyErrorCode(compiler, program, data, root_code, *code.passed(),
121 compiler, program, data, root_code, *code.passed(), err)) { 122 err)) {
122 return false; 123 return false;
123 } 124 }
124 } 125 }
125 126
126 // Verify that changing bits included in the mask is detected as inequality. 127 // Verify that changing bits included in the mask is detected as inequality.
127 if ((code.mask() & kLower32Bits) != 0) { 128 if ((code.mask() & kLower32Bits) != 0) {
128 data->args[code.argno()] = code.value() ^ (code.mask() & kLower32Bits); 129 data->args[code.argno()] = code.value() ^ (code.mask() & kLower32Bits);
129 if (!VerifyErrorCode( 130 if (!VerifyErrorCode(compiler, program, data, root_code, *code.failed(),
130 compiler, program, data, root_code, *code.failed(), err)) { 131 err)) {
131 return false; 132 return false;
132 } 133 }
133 } 134 }
134 if ((code.mask() & kUpper32Bits) != 0) { 135 if ((code.mask() & kUpper32Bits) != 0) {
135 data->args[code.argno()] = code.value() ^ (code.mask() & kUpper32Bits); 136 data->args[code.argno()] = code.value() ^ (code.mask() & kUpper32Bits);
136 if (!VerifyErrorCode( 137 if (!VerifyErrorCode(compiler, program, data, root_code, *code.failed(),
137 compiler, program, data, root_code, *code.failed(), err)) { 138 err)) {
138 return false; 139 return false;
139 } 140 }
140 } 141 }
141 142
142 if (code.width() == ErrorCode::TP_32BIT) { 143 if (code.width() == ErrorCode::TP_32BIT) {
143 // For 32-bit system call arguments, we emit additional instructions to 144 // For 32-bit system call arguments, we emit additional instructions to
144 // validate the upper 32-bits. Here we test that validation. 145 // validate the upper 32-bits. Here we test that validation.
145 146
146 // Arbitrary 64-bit values should be rejected. 147 // Arbitrary 64-bit values should be rejected.
147 data->args[code.argno()] = 1ULL << 32; 148 data->args[code.argno()] = 1ULL << 32;
148 if (!VerifyErrorCode(compiler, 149 if (!VerifyErrorCode(compiler, program, data, root_code,
149 program, 150 compiler->Unexpected64bitArgument(), err)) {
150 data,
151 root_code,
152 compiler->Unexpected64bitArgument(),
153 err)) {
154 return false; 151 return false;
155 } 152 }
156 153
157 // Upper 32-bits set without the MSB of the lower 32-bits set should be 154 // Upper 32-bits set without the MSB of the lower 32-bits set should be
158 // rejected too. 155 // rejected too.
159 data->args[code.argno()] = kUpper32Bits; 156 data->args[code.argno()] = kUpper32Bits;
160 if (!VerifyErrorCode(compiler, 157 if (!VerifyErrorCode(compiler, program, data, root_code,
161 program, 158 compiler->Unexpected64bitArgument(), err)) {
162 data,
163 root_code,
164 compiler->Unexpected64bitArgument(),
165 err)) {
166 return false; 159 return false;
167 } 160 }
168 } 161 }
169 } else { 162 } else {
170 *err = "Attempting to return invalid error code from BPF program"; 163 *err = "Attempting to return invalid error code from BPF program";
171 return false; 164 return false;
172 } 165 }
173 return true; 166 return true;
174 } 167 }
175 168
176 void Ld(State* state, const struct sock_filter& insn, const char** err) { 169 void Ld(State* state, const struct sock_filter& insn, const char** err) {
177 if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS || 170 if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS ||
178 insn.jt != 0 || insn.jf != 0) { 171 insn.jt != 0 || insn.jf != 0) {
179 *err = "Invalid BPF_LD instruction"; 172 *err = "Invalid BPF_LD instruction";
180 return; 173 return;
181 } 174 }
182 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { 175 if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
183 // We only allow loading of properly aligned 32bit quantities. 176 // We only allow loading of properly aligned 32bit quantities.
184 memcpy(&state->accumulator, 177 memcpy(&state->accumulator,
185 reinterpret_cast<const char*>(&state->data) + insn.k, 178 reinterpret_cast<const char*>(&state->data) + insn.k, 4);
186 4);
187 } else { 179 } else {
188 *err = "Invalid operand in BPF_LD instruction"; 180 *err = "Invalid operand in BPF_LD instruction";
189 return; 181 return;
190 } 182 }
191 state->acc_is_valid = true; 183 state->acc_is_valid = true;
192 return; 184 return;
193 } 185 }
194 186
195 void Jmp(State* state, const struct sock_filter& insn, const char** err) { 187 void Jmp(State* state, const struct sock_filter& insn, const char** err) {
196 if (BPF_OP(insn.code) == BPF_JA) { 188 if (BPF_OP(insn.code) == BPF_JA) {
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 Alu(&state, insn, err); 384 Alu(&state, insn, err);
393 break; 385 break;
394 default: 386 default:
395 *err = "Unexpected instruction in BPF program"; 387 *err = "Unexpected instruction in BPF program";
396 break; 388 break;
397 } 389 }
398 } 390 }
399 return 0; 391 return 0;
400 } 392 }
401 393
394 } // namespace bpf_dsl
402 } // namespace sandbox 395 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/linux/bpf_dsl/verifier.h ('k') | sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698