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