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

Side by Side Diff: sandbox/linux/seccomp-bpf/verifier.cc

Issue 11411254: SECCOMP-BPF: Added supported for inspection system call arguments from BPF filters. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments and fixed death tests Created 8 years 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 | Annotate | Revision Log
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/sandbox_bpf.h" 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
6 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 6 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
7 #include "sandbox/linux/seccomp-bpf/verifier.h" 7 #include "sandbox/linux/seccomp-bpf/verifier.h"
8 8
9 9
10 namespace playground2 { 10 namespace playground2 {
(...skipping 24 matching lines...) Expand all
35 if (!(sysnum & 0x40000000u)) { 35 if (!(sysnum & 0x40000000u)) {
36 continue; 36 continue;
37 } 37 }
38 #else 38 #else
39 if (sysnum & 0x40000000u) { 39 if (sysnum & 0x40000000u) {
40 continue; 40 continue;
41 } 41 }
42 #endif 42 #endif
43 #endif 43 #endif
44 ErrorCode code = evaluate_syscall(sysnum, aux); 44 ErrorCode code = evaluate_syscall(sysnum, aux);
45 uint32_t computed_ret = EvaluateBPF(program, data, err); 45 if (!VerifyErrorCode(program, &data, code, err)) {
46 return false;
47 }
48 }
49 return true;
50 }
51
52 bool Verifier::VerifyErrorCode(const std::vector<struct sock_filter>& program,
53 struct arch_seccomp_data *data,
54 const ErrorCode& code, const char **err) {
55 if (code.error_type_ == ErrorCode::ET_SIMPLE ||
56 code.error_type_ == ErrorCode::ET_TRAP) {
57 uint32_t computed_ret = EvaluateBPF(program, *data, err);
46 if (*err) { 58 if (*err) {
47 return false; 59 return false;
48 } else if (computed_ret != code.err()) { 60 } else if (computed_ret != code.err()) {
49 *err = "Exit code from BPF program doesn't match"; 61 *err = "Exit code from BPF program doesn't match";
50 return false; 62 return false;
51 } 63 }
64 } else if (code.error_type_ == ErrorCode::ET_COND) {
65 if (code.argno_ < 0 || code.argno_ >= 6) {
66 *err = "Invalid argument number in error code";
67 return false;
68 }
69 switch (code.op_) {
70 case ErrorCode::OP_EQUAL:
71 // Verify that we can check a 32bit value (or the LSB of a 64bit value)
72 // for equality.
73 data->args[code.argno_] = code.value_;
74 if (!VerifyErrorCode(program, data, *code.passed_, err)) {
75 return false;
76 }
77
78 // Change the value to no longer match and verify that this is detected
79 // as an inequality.
80 data->args[code.argno_] = code.value_ ^ 0x55AA55AA;
81 if (!VerifyErrorCode(program, data, *code.failed_, err)) {
82 return false;
83 }
84
85 // BPF programs can only ever operate on 32bit values. So, we have
86 // generated additional BPF instructions that inspect the MSB. Verify
87 // that they behave as intended.
88 if (code.width_ == ErrorCode::TP_32BIT) {
89 if (code.value_ >> 32) {
90 SANDBOX_DIE("Invalid comparison of a 32bit system call argument "
91 "against a 64bit constant; this test is always false.");
92 }
93
94 // If the system call argument was intended to be a 32bit parameter,
95 // verify that it is a fatal error if a 64bit value is ever passed
96 // here.
97 data->args[code.argno_] = 0x100000000ull;
98 if (!VerifyErrorCode(program, data, Sandbox::Unexpected64bitArgument(),
99 err)) {
100 return false;
101 }
102 } else {
103 // If the system call argument was intended to be a 64bit parameter,
104 // verify that we can handle (in-)equality for the MSB. This is
105 // essentially the same test that we did earlier for the LSB.
106 // We only need to verify the behavior of the inequality test. We
107 // know that the equality test already passed, as unlike the kernel
108 // the Verifier does operate on 64bit quantities.
109 data->args[code.argno_] = code.value_ ^ 0x55AA55AA00000000ull;
110 if (!VerifyErrorCode(program, data, *code.failed_, err)) {
111 return false;
112 }
113 }
114 break;
115 default: // TODO(markus): We can only check for equality so far.
116 *err = "Unsupported operation in conditional error code";
117 return false;
118 }
119 } else {
120 *err = "Attempting to return invalid error code from BPF program";
121 return false;
52 } 122 }
53 return true; 123 return true;
54 } 124 }
55 125
56 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, 126 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program,
57 const struct arch_seccomp_data& data, 127 const struct arch_seccomp_data& data,
58 const char **err) { 128 const char **err) {
59 *err = NULL; 129 *err = NULL;
60 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { 130 if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) {
61 *err = "Invalid program length"; 131 *err = "Invalid program length";
62 return 0; 132 return 0;
63 } 133 }
64 for (State state(program, data); !*err; ++state.ip) { 134 for (State state(program, data); !*err; ++state.ip) {
65 if (state.ip >= program.size()) { 135 if (state.ip >= program.size()) {
66 *err = "Invalid instruction pointer in BPF program"; 136 *err = "Invalid instruction pointer in BPF program";
67 break; 137 break;
68 } 138 }
69 const struct sock_filter& insn = program[state.ip]; 139 const struct sock_filter& insn = program[state.ip];
70 switch (BPF_CLASS(insn.code)) { 140 switch (BPF_CLASS(insn.code)) {
71 case BPF_LD: 141 case BPF_LD:
72 Ld(&state, insn, err); 142 Ld(&state, insn, err);
73 break; 143 break;
74 case BPF_JMP: 144 case BPF_JMP:
75 Jmp(&state, insn, err); 145 Jmp(&state, insn, err);
76 break; 146 break;
77 case BPF_RET: 147 case BPF_RET: {
78 return Ret(&state, insn, err); 148 uint32_t r = Ret(&state, insn, err);
149 switch (r & SECCOMP_RET_ACTION) {
150 case SECCOMP_RET_TRAP:
jln (very slow on Chromium) 2012/12/14 02:28:02 nit: indent the case:
151 case SECCOMP_RET_ERRNO:
152 case SECCOMP_RET_ALLOW:
153 break;
154 case SECCOMP_RET_KILL: // We don't ever generate this
155 case SECCOMP_RET_TRACE: // We don't ever generate this
156 case SECCOMP_RET_INVALID: // Should never show up in BPF program
157 default:
158 *err = "Unexpected return code found in BPF program";
159 return 0;
160 }
161 return r; }
79 default: 162 default:
80 *err = "Unexpected instruction in BPF program"; 163 *err = "Unexpected instruction in BPF program";
81 break; 164 break;
82 } 165 }
83 } 166 }
84 return 0; 167 return 0;
85 } 168 }
86 169
87 void Verifier::Ld(State *state, const struct sock_filter& insn, 170 void Verifier::Ld(State *state, const struct sock_filter& insn,
88 const char **err) { 171 const char **err) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 uint32_t Verifier::Ret(State *, const struct sock_filter& insn, 242 uint32_t Verifier::Ret(State *, const struct sock_filter& insn,
160 const char **err) { 243 const char **err) {
161 if (BPF_SRC(insn.code) != BPF_K) { 244 if (BPF_SRC(insn.code) != BPF_K) {
162 *err = "Invalid BPF_RET instruction"; 245 *err = "Invalid BPF_RET instruction";
163 return 0; 246 return 0;
164 } 247 }
165 return insn.k; 248 return insn.k;
166 } 249 }
167 250
168 } // namespace 251 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698