1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_VALIDATOR_TESTS_H_
8 : #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_VALIDATOR_TESTS_H_
9 :
10 : #ifndef NACL_TRUSTED_BUT_NOT_TCB
11 : #error This file is not meant for use in the TCB
12 : #endif
13 :
14 : /*
15 : * Unit tests for the ARM validator
16 : *
17 : * These tests use the google-test framework (gtest for short) to exercise the
18 : * ARM validator. The tests currently fall into two rough categories:
19 : * 1. Simple method-level tests that exercise the validator's primitive
20 : * capabilities, and
21 : * 2. Instruction pattern tests that run the entire validator.
22 : *
23 : * All instruction pattern tests use hand-assembled machine code fragments,
24 : * embedded as byte arrays. This is somewhat ugly, but deliberate: it isolates
25 : * these tests from gas, which may be buggy or not installed. It also lets us
26 : * hand-craft malicious bit patterns that gas may refuse to produce.
27 : *
28 : * To write a new instruction pattern, or make sense of an existing one, use the
29 : * ARMv7-A ARM (available online). Instructions in this file are written as
30 : * 32-bit integers so the hex encoding matches the docs.
31 : *
32 : * Also see validator_tests.cc and validator_large_tests.cc
33 : */
34 :
35 : #include <algorithm>
36 : #include <climits>
37 : #include <limits>
38 : #include <string>
39 : #include <sstream>
40 : #include <vector>
41 :
42 : #include "gtest/gtest.h"
43 : #include "native_client/src/include/nacl_macros.h"
44 : #include "native_client/src/include/portability_bits.h"
45 :
46 : #include "native_client/src/trusted/validator_arm/problem_reporter.h"
47 : #include "native_client/src/trusted/validator_arm/validator.h"
48 :
49 : using std::vector;
50 : using std::string;
51 : using std::ostringstream;
52 :
53 : using nacl_arm_dec::kNoViolations;
54 : using nacl_arm_dec::Instruction;
55 : using nacl_arm_dec::Register;
56 : using nacl_arm_dec::RegisterList;
57 : using nacl_arm_dec::Violation;
58 : using nacl_arm_dec::ViolationSet;
59 :
60 : using nacl_arm_val::SfiValidator;
61 : using nacl_arm_val::CodeSegment;
62 : using nacl_arm_val::ProblemReporter;
63 : using nacl_arm_val::ProblemSink;
64 :
65 : namespace nacl_val_arm_test {
66 :
67 : #ifdef __BIG_ENDIAN__
68 : #error This test will only succeed on a little-endian machine. Sorry.
69 : #endif
70 :
71 : // Since ARM instructions are always little-endian, on a little-endian machine
72 : // we can represent them as ints. This makes things somewhat easier to read
73 : // below.
74 : typedef uint32_t arm_inst;
75 :
76 : // This is where untrusted code starts. Most tests use this.
77 : static const uint32_t kDefaultBaseAddr = 0x20000;
78 :
79 : /*
80 : * We use these parameters to initialize the validator, below. They are
81 : * somewhat different from the parameters used in real NaCl systems, to test
82 : * degrees of validator freedom that we don't currently exercise in prod.
83 : */
84 : // Number of bytes in each bundle. Theoretically can also be 32 - not tested.
85 : static const uint32_t kBytesPerBundle = 16;
86 : // Limit code to 512MiB.
87 : static const uint32_t kCodeRegionSize = 0x20000000;
88 : // Limit data to 1GiB.
89 : static const uint32_t kDataRegionSize = 0x40000000;
90 : // Untrusted code must not write to the thread pointer.
91 2 : static const RegisterList kAbiReadOnlyRegisters(Register::Tp());
92 : // The stack pointer can be used for "free" loads and stores.
93 2 : static const RegisterList kAbiDataAddrRegisters(nacl_arm_dec::Register::Sp());
94 : // By default don't support TST+LDR/TST+STR, only allow it in tests that
95 : // explicitly have them.
96 : static const bool kAllowCondMemSfi = false;
97 :
98 : // Simply records the arguments given to ReportProblem, below.
99 : class ProblemRecord {
100 : public:
101 3480 : ProblemRecord(Violation violation,
102 : uint32_t vaddr,
103 : const std::string& message)
104 3480 : : violation_(violation), vaddr_(vaddr), message_(message) {}
105 :
106 8853 : ProblemRecord(const ProblemRecord& r)
107 8853 : : violation_(r.violation_), vaddr_(r.vaddr_), message_(r.message_) {}
108 :
109 12333 : ~ProblemRecord() {}
110 :
111 0 : ProblemRecord& operator=(const ProblemRecord& r) {
112 0 : violation_ = r.violation_;
113 0 : vaddr_ = r.vaddr_;
114 0 : message_ = r.message_;
115 0 : return *this;
116 : }
117 :
118 3480 : uint32_t vaddr() const { return vaddr_; }
119 10200 : Violation violation() const { return violation_; }
120 0 : std::string message() const { return message_; }
121 :
122 : private:
123 : Violation violation_;
124 : uint32_t vaddr_;
125 : std::string message_;
126 : };
127 :
128 : // A ProblemSink that records all calls (implementation of the Spy pattern)
129 246898 : class ProblemSpy : public ProblemReporter {
130 : public:
131 : // Returns the list of found problems.
132 125342 : vector<ProblemRecord> &get_problems() { return problems_; }
133 :
134 : protected:
135 : virtual void ReportProblemMessage(Violation violation,
136 : uint32_t vaddr,
137 : const char* message);
138 :
139 : private:
140 : static const vector<ProblemRecord>::size_type max_problems = 5000;
141 : vector<ProblemRecord> problems_;
142 : };
143 :
144 : // Coordinates the fixture objects used by test cases below.
145 : class ValidatorTests : public ::testing::Test {
146 : public:
147 : // Utility method to decode an instruction.
148 : const nacl_arm_dec::ClassDecoder& decode(
149 : nacl_arm_dec::Instruction inst) const;
150 :
151 : // Returns the given instruction, after modifying the instruction condition
152 : // to the given value.
153 444005 : static arm_inst ChangeCond(arm_inst inst, Instruction::Condition c) {
154 444005 : return (inst & 0x0fffffff) | (static_cast<arm_inst>(c) << 28);
155 : }
156 :
157 : protected:
158 : ValidatorTests();
159 :
160 102 : virtual ~ValidatorTests() {
161 51 : EXPECT_EQ(_validator, (SfiValidator *) NULL);
162 51 : }
163 :
164 51 : virtual void SetUp() {
165 51 : EXPECT_EQ(_validator, (SfiValidator *) NULL);
166 :
167 : NaClCPUFeaturesArm cpu_features;
168 51 : NaClClearCPUFeaturesArm(&cpu_features);
169 : NaClSetCPUFeatureArm(&cpu_features, NaClCPUFeatureArm_CanUseTstMem,
170 51 : kAllowCondMemSfi);
171 :
172 : _validator = new SfiValidator(kBytesPerBundle,
173 : kCodeRegionSize,
174 : kDataRegionSize,
175 : kAbiReadOnlyRegisters,
176 : kAbiDataAddrRegisters,
177 51 : &cpu_features);
178 51 : }
179 :
180 51 : virtual void TearDown() {
181 51 : EXPECT_NE(_validator, (SfiValidator *) NULL);
182 51 : delete _validator;
183 51 : _validator = NULL;
184 51 : }
185 :
186 : // Utility method for validating a sequence of bytes.
187 : bool validate(const arm_inst *pattern,
188 : size_t inst_count,
189 : uint32_t start_addr,
190 : ProblemSink *sink = NULL);
191 :
192 : // Utility method for validating a sequence of bytes.
193 : ViolationSet find_violations(const arm_inst *pattern,
194 : size_t inst_count,
195 : uint32_t start_addr,
196 : ProblemSink *sink = NULL);
197 :
198 : // Tests an arbitrary-size instruction fragment that is expected to pass.
199 : // Does not modulate or rewrite the pattern in any way.
200 : void validation_should_pass(const arm_inst *pattern,
201 : size_t inst_count,
202 : uint32_t base_addr,
203 : const string &msg);
204 :
205 : // Tests a two-instruction pattern that's expected to pass, at each possible
206 : // bundle alignment. This also tries the pattern across bundle boundaries,
207 : // and makes sure it fails.
208 : void validation_should_pass2(const arm_inst *pattern,
209 : size_t inst_count,
210 : uint32_t base_addr,
211 : const string &msg);
212 :
213 : // Tests a pattern that is forbidden in the SFI model.
214 : //
215 : // Note that the 'msg1' and 'msg2' parameters are merely concatentated in the
216 : // output.
217 : ViolationSet validation_should_fail(const arm_inst *pattern,
218 : size_t inst_count,
219 : uint32_t base_addr,
220 : const string &msg,
221 : ProblemSpy* spy = NULL);
222 :
223 : // Tests an instruction with all possible conditions (i.e. all except 1111),
224 : // verifying all cases are safe.
225 : void all_cond_values_pass(const arm_inst prototype,
226 : uint32_t base_addr,
227 : const string &msg);
228 :
229 : // Tests an instruction with all possible conditions (i.e. all except 1111),
230 : // verifying all cases are unsafe.
231 : void all_cond_values_fail(const arm_inst prototype,
232 : uint32_t base_addr,
233 : const string &msg);
234 :
235 : // Returns the given instruction, after modifying its S bit (bit 20) to
236 : // the given value.
237 2 : static arm_inst SetSBit(arm_inst inst, bool s) {
238 2 : return (inst & 0xffefffff) | (static_cast<arm_inst>(s) << 20);
239 : }
240 :
241 : // Returns true if the given register is not in {Tp, Sp, Pc}. That is,
242 : // not one of the registers requiring either: a 2-instruction sequence
243 : // to update (Sp and Pc); or should not be updated at all (Tp).
244 480 : bool IsValidSingleInstructionDestinationRegister(Register r) const {
245 480 : return !_is_valid_single_instruction_destination_register.Contains(r);
246 : }
247 :
248 : SfiValidator *_validator;
249 :
250 : private:
251 : RegisterList _is_valid_single_instruction_destination_register;
252 : };
253 :
254 : } // namespace nacl_val_arm_test
255 :
256 : #endif // NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_VALIDATOR_TESTS_H_
|