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

Side by Side Diff: src/trusted/validator_mips/validator_tests.cc

Issue 9979025: [MIPS] Adding validator for MIPS architecture. (Closed) Base URL: http://src.chromium.org/native_client/trunk/src/native_client/
Patch Set: Update per initial code review. Nexes removed. Created 8 years, 8 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
(Empty)
1 /*
2 * Copyright 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can
4 * be found in the LICENSE file.
5 */
6
7 /*
8 * Unit tests for the MIPS validator
9 *
10 * These tests use the google-test framework (gtest for short) to exercise the
11 * MIPS validator. The tests currently fall into two rough categories:
12 * 1. Simple method-level tests that exercise the validator's primitive
13 * capabilities, and
14 * 2. Instruction pattern tests that run the entire validator.
15 *
16 * All instruction pattern tests use hand-assembled machine code fragments,
17 * embedded as byte arrays. This is somewhat ugly, but deliberate: it isolates
18 * these tests from gas, which may be buggy or not installed. It also lets us
19 * hand-craft malicious bit patterns that gas may refuse to produce.
20 *
21 * To write a new instruction pattern, or make sense of an existing one, use the
22 * MIPS. Instructions in this file are written as
23 * 32-bit integers so the hex encoding matches the docs.
24 */
25
26 #include <vector>
27 #include <string>
28 #include <sstream>
29
30 #include "gtest/gtest.h"
31 #include "native_client/src/include/nacl_macros.h"
32
33 #include "native_client/src/trusted/validator_mips/validator.h"
34
35 using std::vector;
36 using std::string;
37 using std::ostringstream;
38
39 using nacl_mips_dec::Register;
40 using nacl_mips_dec::RegisterList;
41 using nacl_mips_dec::Instruction;
42
43 using nacl_mips_val::SfiValidator;
44 using nacl_mips_val::ProblemSink;
45 using nacl_mips_val::CodeSegment;
46
47 namespace {
48
49 /*
50 * This test is written for MIPS
51 */
52
53 typedef uint32_t mips_inst;
54
55 /*
56 * We use these parameters to initialize the validator, below. They are
57 * somewhat different from the parameters used in real NaCl systems, to test
58 * degrees of validator freedom that we don't currently exercise in prod.
59 */
60 // Number of bytes in each bundle.
61 static const uint32_t kBytesPerBundle = 16;
62 // Limit code to 256MiB.
63 static const uint32_t kCodeRegionSize = 0x10000000;
64 // Limit data to 1GiB.
65 static const uint32_t kDataRegionSize = 0x40000000;
66 // Untrusted code must not write to t6,t7,t8.
67 static const RegisterList kAbiReadOnlyRegisters =
68 nacl_mips_dec::kRegisterJumpMask + nacl_mips_dec::kRegisterLoadStoreMask
69 + nacl_mips_dec::kRegisterTls;
70 // The stack pointer can be used for "free" loads and stores.
71 static const RegisterList kAbiDataAddrRegisters = nacl_mips_dec::kRegisterStack;
72
73
74 /*
75 * Support code
76 */
77
78 // Simply records the arguments given to report_problem, below.
79 struct ProblemRecord {
80 uint32_t vaddr;
81 nacl_mips_dec::SafetyLevel safety;
82 nacl::string problem_code;
83 uint32_t ref_vaddr;
84 };
85
86 // A ProblemSink that records all calls (implementation of the Spy pattern)
87 class ProblemSpy : public ProblemSink {
88 public:
89 virtual void report_problem(uint32_t vaddr, nacl_mips_dec::SafetyLevel safety,
90 const nacl::string &problem_code, uint32_t ref_vaddr = 0) {
91 _problems.push_back(
92 (ProblemRecord) { vaddr, safety, problem_code, ref_vaddr });
93 }
94
95 /*
96 * We want *all* the errors that the validator produces. Note that this means
97 * we're not testing the should_continue functionality. This is probably
98 * okay.
99 */
100 virtual bool should_continue() { return true; }
101
102 vector<ProblemRecord> &get_problems() { return _problems; }
103
104 private:
105 vector<ProblemRecord> _problems;
106 };
107
108 /*
109 * Coordinates the fixture objects used by test cases below. This is
110 * forward-declared to the greatest extent possible so we can get on to the
111 * important test stuff below.
112 */
113 class ValidatorTests : public ::testing::Test {
114 protected:
115 ValidatorTests();
116
117 // Utility method for validating a sequence of bytes.
118 bool validate(const mips_inst *pattern,
119 size_t inst_count,
120 uint32_t start_addr,
121 ProblemSink *sink);
122
123 /*
124 * Tests a pattern that's expected to pass, at each possible bundle alignment.
125 * This also tries the pattern across bundle boundaries, and makes sure it
126 * fails.
127 * Note that this only works with 8-byte patterns, but that's all we have
128 * at the moment.
129 */
130 void validation_should_pass(const mips_inst *pattern,
131 size_t inst_count,
132 uint32_t base_addr,
133 const string &msg);
134
135 /*
136 * Tests a pattern that is forbidden in the SFI model.
137 *
138 * Note that the 'msg1' and 'msg2' parameters are merely concatentated in the
139 * output.
140 */
141 vector<ProblemRecord> validation_should_fail(const mips_inst *pattern,
142 size_t inst_count,
143 uint32_t base_addr,
144 const string &msg);
145
146 SfiValidator _validator;
147 };
148
149
150 /*
151 * Primitive tests checking various constructor properties. Any of these
152 * failing would be a very bad sign indeed.
153 */
154
155 TEST_F(ValidatorTests, RecognizesDataAddressRegisters) {
156 /*
157 * Note that the logic below needs to be kept in sync with the definition
158 * of kAbiDataAddrRegisters at the top of this file.
159 *
160 * This test is pretty trivial -- we can exercise the data_address_register
161 * functionality more deeply with pattern tests below.
162 */
163 for (int i = 0; i < 31; i++) {
164 Register r(i);
165 if (r == nacl_mips_dec::kRegisterStack) {
166 EXPECT_TRUE(_validator.is_data_address_register(r))
167 << "Stack pointer must be a data address register.";
168 } else {
169 EXPECT_FALSE(_validator.is_data_address_register(r))
170 << "Only the stack pointer must be a data address register.";
171 }
172 }
173 }
174
175 /*
176 * Code validation tests
177 */
178
179 // This is where untrusted code starts. Most tests use this.
180 static const uint32_t kDefaultBaseAddr = 0x20000;
181
182 /*
183 * Here are examples of every form of safe stores permitted in a Native Client
184 * program.
185 */
186
187 struct AnnotatedInstruction {
188 mips_inst inst;
189 const char *about;
190 };
191
192 static const AnnotatedInstruction examples_of_safe_stores[] = {
193 { 0xa1490200, "sb t1, 1024(t2) : store byte" },
194 { 0xad490200, "sw t1, 1024(t2) : store word" },
195 { 0xa5490200, "sh t1, 1024(t2) : store halfword" },
196 { 0xa9490200, "swl t1, 1024(t2) : store word left" },
197 { 0xb9490200, "swr t1, 1024(t2) : store word right" },
198 };
199
200 static const AnnotatedInstruction examples_of_safe_masks[] = {
201 { (10 << 21 | 15 << 16 | 10 << 11 | 36),
202 "and t2,t2,t7 : simple store masking" },
203 };
204
205 TEST_F(ValidatorTests, SafeMaskedStores) {
206 /*
207 * Produces examples of masked stores using the safe store table (above)
208 * and the list of possible masking instructions (above).
209 */
210
211 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_masks); m++) {
212 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_stores);
213 s++) {
214 ostringstream message;
215 message << examples_of_safe_masks[m].about
216 << ", "
217 << examples_of_safe_stores[s].about;
218 mips_inst program[] = {
219 examples_of_safe_masks[m].inst,
220 examples_of_safe_stores[s].inst,
221 };
222 validation_should_pass(program,
223 2,
224 kDefaultBaseAddr,
225 message.str());
226 }
227 }
228 }
229
230 TEST_F(ValidatorTests, IncorrectStores) {
231 /*
232 * Produces incorrect examples of masked stores using the safe store table
233 * (above) and the list of possible masking instructions (above).
234 */
235
236 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_stores); m++) {
237 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_masks); s++) {
238 ostringstream bad_message;
239 bad_message << examples_of_safe_stores[m].about
240 << ", "
241 << examples_of_safe_masks[s].about;
242 mips_inst bad_program[] = {
243 examples_of_safe_stores[m].inst,
244 examples_of_safe_masks[s].inst,
245 };
246
247 validation_should_fail(bad_program,
248 2,
249 kDefaultBaseAddr,
250 bad_message.str());
251 }
252 }
253 }
254
255 static const AnnotatedInstruction examples_of_safe_jump_masks[] = {
256 { (10 << 21 | 14 << 16 | 10 << 11 | 36),
257 "and t2,t2,t6 : simple jump masking" },
258 };
259
260 static const AnnotatedInstruction examples_of_safe_jumps[] = {
261 { ((10<<21| 31 << 11 |9) ), "simple jump jalr t2" },
262 { (10<<21|8), "simple jump jr t2" },
263 };
264
265 static const AnnotatedInstruction nop_instruction[] = {
266 { 0, "nop"},
267 };
268
269 TEST_F(ValidatorTests, SafeMaskedJumps) {
270 /*
271 * Produces examples of masked jumps using the safe jump table
272 * (above) and the list of possible masking instructions (above).
273 */
274 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_jump_masks); m++) {
275 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_jumps); s++) {
276 ostringstream message;
277 message << examples_of_safe_jump_masks[m].about
278 << ", "
279 << examples_of_safe_jumps[s].about;
280 mips_inst program[] = {
281 nop_instruction[0].inst,
282 examples_of_safe_jump_masks[m].inst,
283 examples_of_safe_jumps[s].inst,
284 };
285 validation_should_pass(program,
286 3,
287 kDefaultBaseAddr,
288 message.str());
289 }
290 }
291 }
292
293 TEST_F(ValidatorTests, IncorrectJumps) {
294 /*
295 * Produces examples of incorrect jumps using the safe jump table
296 * (above) and the list of possible masking instructions (above).
297 */
298 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_jumps); m++) {
299 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_jump_masks);
300 s++) {
301 ostringstream bad_message;
302 bad_message << examples_of_safe_jumps[m].about
303 << ", "
304 << examples_of_safe_jump_masks[s].about;
305
306 mips_inst bad_program[] = {
307 examples_of_safe_jumps[m].inst,
308 examples_of_safe_jump_masks[s].inst,
309 };
310
311 validation_should_fail(bad_program,
312 3,
313 kDefaultBaseAddr,
314 bad_message.str());
315 }
316 }
317 }
318
319 static const AnnotatedInstruction examples_of_safe_stack_masks[] = {
320 { (29 << 21 | 15 << 16 | 29 << 11 | 36),
321 "and sp,sp,t7 : simple stack masking" },
322 };
323
324
325 static const AnnotatedInstruction examples_of_safe_stack_ops[] = {
326 { (29<<21|8<<16|29<<11|32), "add sp,sp,t0 : stack addition" },
327 { (29<<21|8<<16|29<<11|34), "sub sp,sp,t0 : stack substraction" },
328 };
329
330 TEST_F(ValidatorTests, SafeMaskedStack) {
331 /*
332 * Produces examples of safe pseudo-ops on stack using the safe jump table
333 * and the list of possible masking instructions (above).
334 */
335 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_stack_ops); m++) {
336 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_stack_masks);
337 s++) {
338 ostringstream message;
339 message << examples_of_safe_stack_ops[m].about
340 << ", "
341 << examples_of_safe_stack_masks[s].about;
342 mips_inst program[] = {
343 examples_of_safe_stack_ops[m].inst,
344 examples_of_safe_stack_masks[s].inst,
345 };
346 validation_should_pass(program,
347 2,
348 kDefaultBaseAddr,
349 message.str());
350 }
351 }
352 }
353
354 TEST_F(ValidatorTests, IncorrectStackOps) {
355 /*
356 * Produces examples of incorrect pseudo-ops on stack using the safe jump
357 * table and the list of possible masking instructions (above).
358 */
359 for (unsigned m = 0; m < NACL_ARRAY_SIZE(examples_of_safe_stack_masks); m++) {
360 for (unsigned s = 0; s < NACL_ARRAY_SIZE(examples_of_safe_stack_ops); s++) {
361 ostringstream bad_message;
362 bad_message << examples_of_safe_stack_masks[m].about
363 << ", "
364 << examples_of_safe_stack_ops[s].about;
365 mips_inst bad_program[] = {
366 examples_of_safe_stack_masks[m].inst,
367 examples_of_safe_stack_ops[s].inst,
368 nop_instruction[0].inst
369 };
370
371 validation_should_fail(bad_program,
372 3,
373 kDefaultBaseAddr,
374 bad_message.str());
375 }
376 }
377 }
378
379 /*
380 * Implementation of the ValidatorTests utility methods. These are documented
381 * toward the top of this file.
382 */
383 ValidatorTests::ValidatorTests()
384 : _validator(kBytesPerBundle,
385 kCodeRegionSize,
386 kDataRegionSize,
387 kAbiReadOnlyRegisters,
388 kAbiDataAddrRegisters) {}
389
390 bool ValidatorTests::validate(const mips_inst *pattern,
391 size_t inst_count,
392 uint32_t start_addr,
393 ProblemSink *sink) {
394 // We think in instructions; CodeSegment thinks in bytes.
395 const uint8_t *bytes = reinterpret_cast<const uint8_t *>(pattern);
396 CodeSegment segment(bytes, start_addr, inst_count * sizeof(mips_inst));
397
398 vector<CodeSegment> segments;
399 segments.push_back(segment);
400
401 return _validator.validate(segments, sink);
402 }
403
404 void ValidatorTests::validation_should_pass(const mips_inst *pattern,
405 size_t inst_count,
406 uint32_t base_addr,
407 const string &msg) {
408 ASSERT_TRUE(
409 _validator.bundle_for_address(base_addr).begin_addr() == base_addr)
410 << "base_addr parameter must be bundle-aligned";
411
412 ProblemSpy spy;
413
414 bool validation_result = validate(pattern, inst_count, base_addr, &spy);
415 ASSERT_TRUE(validation_result) << msg << " should pass at " << base_addr;
416 vector<ProblemRecord> &problems = spy.get_problems();
417 EXPECT_EQ(0U, problems.size()) << msg
418 << " should have no problems when located at " << base_addr;
419 }
420
421 vector<ProblemRecord> ValidatorTests::validation_should_fail(
422 const mips_inst *pattern,
423 size_t inst_count,
424 uint32_t base_addr,
425 const string &msg) {
426
427 ProblemSpy spy;
428 bool validation_result = validate(pattern, inst_count, base_addr, &spy);
429 EXPECT_FALSE(validation_result) << "Expected to fail: " << msg;
430
431 vector<ProblemRecord> problems = spy.get_problems();
432 // Would use ASSERT here, but cannot ASSERT in non-void functions :-(
433 EXPECT_NE(0U, problems.size())
434 << "Must report validation problems: " << msg;
435
436 // The rest of the checking is done in the caller.
437 return problems;
438 }
439
440 }; // anonymous namespace
441
442 // Test driver function.
443 int main(int argc, char *argv[]) {
444 testing::InitGoogleTest(&argc, argv);
445 return RUN_ALL_TESTS();
446 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698