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

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