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

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

Powered by Google App Engine
This is Rietveld 408576698