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