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_MIPS_INST_CLASSES_H
8 : #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H
9 :
10 : #include <stdint.h>
11 : #include "native_client/src/trusted/validator_mips/model.h"
12 : #include "native_client/src/include/portability.h"
13 :
14 :
15 : /*
16 : * Models the "instruction classes" that the decoder produces.
17 : */
18 : namespace nacl_mips_dec {
19 :
20 : /*
21 : * Used to describe whether an instruction is safe, and if not, what the issue
22 : * is. Only instructions that MAY_BE_SAFE should be allowed in untrusted code,
23 : * and even those may be rejected by the validator.
24 : */
25 : enum SafetyLevel {
26 : /*
27 : * The initial value of uninitialized SafetyLevels -- treat as unsafe.
28 : */
29 : UNKNOWN = 0,
30 : /*
31 : * This instruction is forbidden by our SFI model.
32 : */
33 : FORBIDDEN,
34 : /*
35 : * This instruction may be safe in untrusted code: in isolation it contains
36 : * nothing scary, but the validator may overrule this during global analysis.
37 : */
38 : MAY_BE_SAFE
39 : };
40 :
41 :
42 : // Function (op)codes.
43 : uint32_t const kBitwiseLogicalAnd = 0x24; // b100100.
44 :
45 :
46 : /*
47 : * Decodes a class of instructions. Does spooky undefined things if handed
48 : * instructions that don't belong to its class. Who defines which instructions
49 : * these are? Why, the generated decoder, of course.
50 : *
51 : * This is an abstract base class intended to be overridden with the details of
52 : * particular instruction-classes.
53 : *
54 : * ClassDecoders should be stateless, and should provide a no-arg constructor
55 : * for use by the generated decoder.
56 : */
57 : class ClassDecoder {
58 : public:
59 : /*
60 : * Checks how safe this instruction is, in isolation.
61 : * This will detect any violation in the MIPS spec -- undefined encodings,
62 : * use of registers that are unpredictable -- and the most basic constraints
63 : * in our SFI model. Because ClassDecoders are referentially-transparent and
64 : * cannot touch global state, this will not check things that may vary with
65 : * ABI version.
66 : *
67 : * The most positive result this can return is called MAY_BE_SAFE because it
68 : * is necessary, but not sufficient: the validator has the final say.
69 : */
70 : virtual SafetyLevel safety(const Instruction instr) const = 0;
71 :
72 : /*
73 : * For instructions that perform 'masking', this function will return whether
74 : * this is true or not for the given instruction.
75 : *
76 : * The result is useful only for Arithm3 'and' instruction.
77 : */
78 15 : virtual bool IsMask(const Instruction instr,
79 : const nacl_mips_dec::Register dest,
80 : const nacl_mips_dec::Register mask) const {
81 : UNREFERENCED_PARAMETER(instr);
82 : UNREFERENCED_PARAMETER(dest);
83 : UNREFERENCED_PARAMETER(mask);
84 15 : return false;
85 : }
86 :
87 : /*
88 : * The gpr register altered by the instruction.
89 : */
90 72 : virtual Register DestGprReg(const Instruction instr) const {
91 : UNREFERENCED_PARAMETER(instr);
92 72 : return Register::None();
93 : }
94 :
95 : /*
96 : * May be used for instr's with immediate operand; like addiu or jal.
97 : */
98 0 : virtual uint32_t GetImm(const Instruction instr) const {
99 : UNREFERENCED_PARAMETER(instr);
100 0 : return -1;
101 : }
102 :
103 : /*
104 : * For direct jumps (j, jal, branch instructions).
105 : */
106 403 : virtual bool IsDirectJump() const {
107 403 : return false;
108 : }
109 :
110 : /*
111 : * For jump and link (jal, jalr, bal).
112 : */
113 116 : virtual bool IsJal() const {
114 116 : return false;
115 : }
116 :
117 : /*
118 : * For jump register instructions (jr, jalr).
119 : */
120 307 : virtual bool IsJmpReg() const {
121 307 : return false;
122 : }
123 :
124 : /*
125 : * For the instructions that are followed by a delay slot.
126 : */
127 167 : virtual bool HasDelaySlot() const {
128 167 : return IsDirectJump() || IsJmpReg();
129 : }
130 :
131 : /*
132 : * For load and store instructions.
133 : */
134 132 : virtual bool IsLoadStore() const {
135 132 : return false;
136 : }
137 :
138 : /*
139 : * For direct jumps, returning the destination address.
140 : */
141 0 : virtual uint32_t DestAddr(const Instruction instr, uint32_t addr) const {
142 : UNREFERENCED_PARAMETER(instr);
143 : UNREFERENCED_PARAMETER(addr);
144 0 : return 0;
145 : }
146 :
147 : /*
148 : * Used by jump register instructions; returns the register that holds the
149 : * address to jump to.
150 : */
151 0 : virtual Register TargetReg(const Instruction instr) const {
152 : UNREFERENCED_PARAMETER(instr);
153 0 : return Register::None();
154 : }
155 :
156 : /*
157 : * Base address register, for load and store instructions.
158 : */
159 0 : virtual Register BaseAddressRegister(const Instruction instr) const {
160 : UNREFERENCED_PARAMETER(instr);
161 0 : return Register::None();
162 : }
163 :
164 :
165 : protected:
166 190 : ClassDecoder() {}
167 30 : virtual ~ClassDecoder() {}
168 : };
169 :
170 : /*
171 : * Current MIPS NaCl halt (break).
172 : */
173 10 : class NaClHalt : public ClassDecoder {
174 : public:
175 0 : virtual ~NaClHalt() {}
176 0 : virtual SafetyLevel safety(const Instruction instr) const {
177 : UNREFERENCED_PARAMETER(instr);
178 0 : return MAY_BE_SAFE;
179 : }
180 : };
181 :
182 : /*
183 : * Represents an instruction that is forbidden under all circumstances, so we
184 : * didn't bother decoding it further.
185 : */
186 40 : class Forbidden : public ClassDecoder {
187 : public:
188 30 : virtual ~Forbidden() {}
189 30 : virtual SafetyLevel safety(const Instruction instr) const {
190 : UNREFERENCED_PARAMETER(instr);
191 30 : return FORBIDDEN;
192 : }
193 : };
194 :
195 : /*
196 : * Instructions with 2 registers and an immediate value, where bits 20-16
197 : * contain the destination gpr register.
198 : */
199 10 : class Arithm2 : public ClassDecoder {
200 : public:
201 0 : virtual ~Arithm2() {}
202 0 : virtual Register DestGprReg(const Instruction instr) const {
203 0 : return instr.Reg(20, 16);
204 : }
205 0 : virtual SafetyLevel safety(const Instruction instr) const {
206 : UNREFERENCED_PARAMETER(instr);
207 0 : return MAY_BE_SAFE;
208 : }
209 : };
210 :
211 : /*
212 : * Instruction with 3 registers, with bits 15-11 containing the destination gpr
213 : * register.
214 : */
215 10 : class Arithm3 : public ClassDecoder {
216 : public:
217 0 : virtual ~Arithm3() {}
218 380 : virtual Register DestGprReg(const Instruction instr) const {
219 380 : return instr.Reg(15, 11);
220 : }
221 134 : virtual SafetyLevel safety(const Instruction instr) const {
222 : UNREFERENCED_PARAMETER(instr);
223 134 : return MAY_BE_SAFE;
224 : }
225 67 : virtual bool IsMask(const Instruction instr,
226 : const nacl_mips_dec::Register dest,
227 : const nacl_mips_dec::Register mask) const {
228 67 : return ((instr.Bits(5, 0) == kBitwiseLogicalAnd)
229 39 : && instr.Reg(15, 11).Equals(dest)
230 39 : && instr.Reg(25, 21).Equals(dest)
231 145 : && instr.Reg(20, 16).Equals(mask));
232 : }
233 : };
234 :
235 : /*
236 : * Direct jump class, subclassed by Branch and JmpImm.
237 : */
238 40 : class DirectJump : public ClassDecoder {
239 : public:
240 0 : virtual ~DirectJump() {}
241 0 : virtual SafetyLevel safety(const Instruction instr) const {
242 : UNREFERENCED_PARAMETER(instr);
243 0 : return MAY_BE_SAFE;
244 : }
245 0 : virtual bool IsDirectJump() const {
246 0 : return true;
247 : }
248 : };
249 :
250 : /*
251 : * Branch instructions.
252 : */
253 20 : class Branch : public DirectJump {
254 : public:
255 0 : virtual ~Branch() {}
256 0 : virtual uint32_t GetImm(const Instruction instr) const {
257 0 : return instr.Bits(15, 0);
258 : }
259 0 : virtual uint32_t DestAddr(const Instruction instr, uint32_t addr) const {
260 0 : return ((addr + kInstrSize) + ((int16_t)GetImm(instr) << 2));
261 : }
262 : };
263 :
264 : /*
265 : * Branch and link instructions (bal, bgezal, bltzal, bgezall, bltzall).
266 : */
267 10 : class BranchAndLink : public Branch {
268 : public:
269 0 : virtual ~BranchAndLink() {}
270 0 : virtual bool IsJal() const {
271 0 : return true;
272 : }
273 : };
274 :
275 : /*
276 : * Load and store instructions.
277 : */
278 40 : class AbstractLoadStore : public ClassDecoder {
279 : public:
280 16 : virtual bool IsLoadStore() const {
281 16 : return true;
282 : }
283 0 : virtual ~AbstractLoadStore() {}
284 16 : virtual SafetyLevel safety(const Instruction instr) const {
285 : UNREFERENCED_PARAMETER(instr);
286 16 : return MAY_BE_SAFE;
287 : }
288 16 : virtual Register BaseAddressRegister(const Instruction instr) const {
289 16 : return instr.Reg(25, 21);
290 : }
291 : };
292 :
293 : /*
294 : * Store instructions.
295 : */
296 20 : class Store : public AbstractLoadStore {
297 : public:
298 0 : virtual ~Store() {}
299 : };
300 :
301 : /*
302 : * Load instructions, which alter the destination register.
303 : */
304 10 : class Load : public AbstractLoadStore {
305 : public:
306 0 : virtual ~Load() {}
307 24 : virtual Register DestGprReg(const Instruction instr) const {
308 24 : return instr.Reg(20, 16);
309 : }
310 : };
311 :
312 : /*
313 : * Floating point load and store instructions.
314 : */
315 10 : class FPLoadStore : public AbstractLoadStore {
316 : public:
317 0 : virtual ~FPLoadStore() {}
318 : };
319 :
320 : /*
321 : * Store Conditional class, containing the sc instruction,
322 : * which might alter the contents of the register which is the 1st operand.
323 : */
324 10 : class StoreConditional : public Store {
325 : public:
326 0 : virtual ~StoreConditional() {}
327 0 : virtual Register DestGprReg(const Instruction instr) const {
328 0 : return instr.Reg(20, 16);
329 : }
330 : };
331 :
332 : /*
333 : * Direct jumps - j, jal.
334 : */
335 20 : class JmpImm : public DirectJump {
336 : public:
337 0 : virtual ~JmpImm() {}
338 0 : virtual uint32_t GetImm(const Instruction instr) const {
339 0 : return instr.Bits(25, 0);
340 : }
341 0 : virtual uint32_t DestAddr(const Instruction instr, uint32_t addr) const {
342 0 : return ((addr + kInstrSize) & 0xf0000000) + (GetImm(instr) << 2);
343 : }
344 : };
345 :
346 : /*
347 : * Direct jump and link (jal).
348 : */
349 10 : class JalImm : public JmpImm {
350 : public:
351 0 : virtual ~JalImm() {}
352 0 : virtual bool IsJal() const {
353 0 : return true;
354 : }
355 : };
356 :
357 : /*
358 : * Jump register instructions - jr, jalr.
359 : */
360 20 : class JmpReg : public ClassDecoder {
361 : public:
362 0 : virtual ~JmpReg() {}
363 4 : virtual SafetyLevel safety(const Instruction instr) const {
364 : UNREFERENCED_PARAMETER(instr);
365 4 : return MAY_BE_SAFE;
366 : }
367 8 : virtual bool IsJmpReg() const {
368 8 : return true;
369 : }
370 4 : virtual Register TargetReg(const Instruction instr) const {
371 4 : return instr.Reg(25, 21);
372 : }
373 : };
374 :
375 : /*
376 : * Jump and link register - jalr.
377 : */
378 10 : class JalReg : public JmpReg {
379 : public:
380 0 : virtual ~JalReg() {}
381 2 : virtual bool IsJal() const {
382 2 : return true;
383 : }
384 6 : virtual Register DestGprReg(const Instruction instr) const {
385 6 : return instr.Reg(15, 11);
386 : }
387 : };
388 :
389 : /*
390 : * ext and ins instructions.
391 : */
392 10 : class ExtIns : public ClassDecoder {
393 : public:
394 0 : virtual ~ExtIns() {}
395 0 : virtual Register DestGprReg(const Instruction instr) const {
396 0 : return instr.Reg(20, 16);
397 : }
398 0 : virtual SafetyLevel safety(const Instruction instr) const {
399 : UNREFERENCED_PARAMETER(instr);
400 0 : return MAY_BE_SAFE;
401 : }
402 : };
403 : /*
404 : * The instructions that are safe under all circumstances.
405 : */
406 10 : class Safe : public ClassDecoder {
407 : public:
408 0 : virtual ~Safe() {}
409 0 : virtual SafetyLevel safety(const Instruction instr) const {
410 : UNREFERENCED_PARAMETER(instr);
411 0 : return MAY_BE_SAFE;
412 : }
413 : };
414 :
415 : class Other : public ClassDecoder {
416 : public:
417 0 : virtual ~Other() {}
418 0 : virtual SafetyLevel safety(const Instruction instr) const {
419 : UNREFERENCED_PARAMETER(instr);
420 0 : return FORBIDDEN;
421 : }
422 : };
423 :
424 : /*
425 : * Unknown instructions, treated as forbidden.
426 : */
427 : class Unrecognized : public ClassDecoder {
428 : public:
429 0 : virtual ~Unrecognized() {}
430 0 : virtual SafetyLevel safety(const Instruction instr) const {
431 : UNREFERENCED_PARAMETER(instr);
432 0 : return FORBIDDEN;
433 : }
434 : };
435 : } // namespace
436 :
437 : #endif // NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H
|