Index: src/trusted/validator_mips/inst_classes.h |
diff --git a/src/trusted/validator_mips/inst_classes.h b/src/trusted/validator_mips/inst_classes.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..27dd8cc971945b5fea8b688ba1c1c38c77b2ef76 |
--- /dev/null |
+++ b/src/trusted/validator_mips/inst_classes.h |
@@ -0,0 +1,433 @@ |
+/* |
+ * Copyright 2012 The Native Client Authors. All rights reserved. |
+ * Use of this source code is governed by a BSD-style license that can |
+ * be found in the LICENSE file. |
+ * Copyright 2012, Google Inc. |
+ */ |
+ |
+#ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H |
+#define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H |
+ |
+#include <stdint.h> |
+#include "native_client/src/trusted/validator_mips/model.h" |
+#include "native_client/src/include/portability.h" |
+ |
+ |
+/* |
+ * Models the "instruction classes" that the decoder produces. |
+ */ |
+namespace nacl_mips_dec { |
+ |
+/* |
+ * Used to describe whether an instruction is safe, and if not, what the issue |
+ * is. Only instructions that MAY_BE_SAFE should be allowed in untrusted code, |
+ * and even those may be rejected by the validator. |
+ */ |
+enum SafetyLevel { |
+ // The initial value of uninitialized SafetyLevels -- treat as unsafe. |
+ UNKNOWN = 0, |
+ // This instruction is forbidden by our SFI model. |
+ FORBIDDEN = 4, |
+ /* |
+ * This instruction may be safe in untrusted code: in isolation it contains |
+ * nothing scary, but the validator may overrule this during global analysis. |
+ */ |
+ MAY_BE_SAFE = 6 |
+}; |
+ |
+ |
+// Function (op)codes. |
+uint32_t const kBitwiseLogicalAnd = 0x24; // b100100. |
+ |
+ |
+/* |
+ * Decodes a class of instructions. Does spooky undefined things if handed |
+ * instructions that don't belong to its class. Who defines which instructions |
+ * these are? Why, the generated decoder, of course. |
+ * |
+ * This is an abstract base class intended to be overridden with the details of |
+ * particular instruction-classes. |
+ * |
+ * ClassDecoders should be stateless, and should provide a no-arg constructor |
+ * for use by the generated decoder. |
+ */ |
+class ClassDecoder { |
+ public: |
+ /* |
+ * Checks how safe this instruction is, in isolation. |
+ * This will detect any violation in the Mips spec -- undefined encodings, |
+ * use of registers that are unpredictable -- and the most basic constraints |
+ * in our SFI model. Because ClassDecoders are referentially-transparent and |
+ * cannot touch global state, this will not check things that may vary with |
+ * ABI version. |
+ * |
+ * The most positive result this can return is called MAY_BE_SAFE because it |
+ * is necessary, but not sufficient: the validator has the final say. |
+ */ |
+ virtual SafetyLevel safety(Instruction i) const = 0; |
+ |
+ /* |
+ * For instructions that perform 'masking', this function will return whether |
+ * this is true or not for the given instruction. |
+ * |
+ * The result is useful only for Arithm3 'and' instruction. |
+ */ |
+ virtual bool is_mask(Instruction i, nacl_mips_dec::Register dest, |
+ nacl_mips_dec::Register mask) const { |
+ UNREFERENCED_PARAMETER(i); |
+ UNREFERENCED_PARAMETER(dest); |
+ UNREFERENCED_PARAMETER(mask); |
+ return false; |
+ } |
+ |
+ /* |
+ * The gpr register altered by the instruction. |
+ */ |
+ virtual Register dest_gpr_reg(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ |
+ /* |
+ * May be used for instr's with immediate operand; like addiu or jal. |
+ */ |
+ virtual uint32_t get_imm(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return -1; |
+ } |
+ |
+ /* |
+ * For direct jumps (j, jal, branch instructions). |
+ */ |
+ virtual bool is_direct_jump() const { |
+ return false; |
+ } |
+ |
+ /* |
+ * For jump and link (jal, jalr, bal). |
+ */ |
+ virtual bool is_jal() const { |
+ return false; |
+ } |
+ |
+ /* |
+ * For jump register instructions (jr, jalr). |
+ */ |
+ virtual bool is_jmp_reg() const { |
+ return false; |
+ } |
+ |
+ /* |
+ * For the instructions that are followed by a delay slot. |
+ */ |
+ virtual bool has_delay_slot() const { |
+ return is_direct_jump() || is_jmp_reg(); |
+ } |
+ |
+ /* |
+ * For load and store instructions. |
+ */ |
+ virtual bool is_load_store() const { |
+ return false; |
+ } |
+ |
+ /* |
+ * For direct jumps, returning the destination address. |
+ */ |
+ virtual uint32_t dest_addr(Instruction i, uint32_t addr) const { |
+ UNREFERENCED_PARAMETER(i); |
+ UNREFERENCED_PARAMETER(addr); |
+ return 0; |
+ } |
+ |
+ /* |
+ * Used by jump register instructions; returns the register that holds the |
+ * address to jump to. |
+ */ |
+ virtual Register target_reg(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ |
+ /* |
+ * Base address register, for load and store instructions. |
+ */ |
+ virtual Register base_address_register(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return kRegisterNone; |
+ } |
+ |
+ |
+ protected: |
+ ClassDecoder() {} |
+ virtual ~ClassDecoder() {} |
+}; |
+ |
+/* |
+ * Current Mips NaCl halt (jr $zero). |
+ */ |
+class NaClHalt : public ClassDecoder { |
+ public: |
+ virtual ~NaClHalt() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+}; |
+ |
+/* |
+ * Represents an instruction that is forbidden under all circumstances, so we |
+ * didn't bother decoding it further. |
+ */ |
+class Forbidden : public ClassDecoder { |
+ public: |
+ virtual ~Forbidden() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return FORBIDDEN; |
+ } |
+}; |
+ |
+/* |
+ * Instructions with 2 registers and an immediate value, where bits 20-16 |
+ * contain the destination gpr register. |
+ */ |
+class Arithm2 : public ClassDecoder { |
+ public: |
+ virtual ~Arithm2() {} |
+ virtual Register dest_gpr_reg(Instruction i) const { |
+ return i.reg(20, 16); |
+ } |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+}; |
+ |
+/* |
+ * Instruction with 3 registers, with bits 15-11 containing the destination gpr |
+ * register. |
+ */ |
+class Arithm3 : public ClassDecoder { |
+ public: |
+ virtual ~Arithm3() {} |
+ virtual Register dest_gpr_reg(Instruction i) const { |
+ return i.reg(15, 11); |
+ } |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual bool is_mask(const Instruction instr, |
+ const nacl_mips_dec::Register dest, |
+ const nacl_mips_dec::Register mask) const { |
+ return ((instr.bits(5, 0) == kBitwiseLogicalAnd) |
+ && (instr.reg(15, 11) == dest) |
+ && (instr.reg(25, 21) == dest) |
+ && (instr.reg(20, 16) == mask)); |
+ } |
+}; |
+ |
+/* |
+ * Direct jump class, subclassed by Branch and JmpImm. |
+ */ |
+class DirectJump : public ClassDecoder { |
+ public: |
+ virtual ~DirectJump() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual bool is_direct_jump() const { |
+ return true; |
+ } |
+}; |
+ |
+/* |
+ * Branch instructions. |
+ */ |
+class Branch : public DirectJump { |
+ public: |
+ virtual ~Branch() {} |
+ virtual uint32_t get_imm(Instruction instr) const { |
+ return instr.bits(15, 0); |
+ } |
+ virtual uint32_t dest_addr(Instruction instr, uint32_t addr) const { |
+ return ((addr + kInstrSize) + ((int16_t)get_imm(instr) << 2)); |
+ } |
+}; |
+ |
+/* |
+ * Branch and link instructions (bal, bgezal, bltzal, bgezall, bltzall). |
+ */ |
+class BranchAndLink : public Branch { |
+ public: |
+ virtual ~BranchAndLink() {} |
+ virtual bool is_jal() const { |
+ return true; |
+ } |
+}; |
+ |
+/* |
+ * Load and store instructions. |
+ */ |
+class AbstractLoadStore : public ClassDecoder { |
+ public: |
+ virtual bool is_load_store() const { |
+ return true; |
+ } |
+ virtual ~AbstractLoadStore() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual Register base_address_register(Instruction i) const { |
+ return i.reg(25, 21); |
+ } |
+}; |
+ |
+/* |
+ * Store instructions. |
+ */ |
+class Store : public AbstractLoadStore { |
+ public: |
+ virtual ~Store() {} |
+}; |
+ |
+/* |
+ * Load instructions, which alter the destination register. |
+ */ |
+class Load : public AbstractLoadStore { |
+ public: |
+ virtual ~Load() {} |
+ virtual Register dest_gpr_reg(Instruction i) const { |
+ return i.reg(20, 16); |
+ } |
+}; |
+ |
+/* |
+ * Floating point load and store instructions. |
+ */ |
+class FPLoadStore : public AbstractLoadStore { |
+ public: |
+ virtual ~FPLoadStore() {} |
+}; |
+ |
+/* |
+ * Store Conditional class, containing the sc instruction, |
+ * which might alter the contents of the register which is the 1st operand. |
+ */ |
+class StoreConditional : public Store { |
+ public: |
+ virtual ~StoreConditional() {} |
+ virtual Register dest_gpr_reg(Instruction i) const { |
+ return i.reg(20, 16); |
+ } |
+}; |
+ |
+/* |
+ * Direct jumps - j, jal. |
+ */ |
+class JmpImm : public DirectJump { |
+ public: |
+ virtual ~JmpImm() {} |
+ virtual uint32_t get_imm(Instruction instr) const { |
+ return instr.bits(25, 0); |
+ } |
+ virtual uint32_t dest_addr(Instruction instr, uint32_t addr) const { |
+ return ((addr + kInstrSize) & 0xf0000000) + (get_imm(instr) << 2); |
+ } |
+}; |
+ |
+/* |
+ * Direct jump and link (jal). |
+ */ |
+class JalImm : public JmpImm { |
+ public: |
+ virtual ~JalImm() {} |
+ virtual bool is_jal() const { |
+ return true; |
+ } |
+}; |
+ |
+/* |
+ * Jump register instructions - jr, jalr. |
+ */ |
+class JmpReg : public ClassDecoder { |
+ public: |
+ virtual ~JmpReg() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+ virtual bool is_jmp_reg() const { |
+ return true; |
+ } |
+ virtual Register target_reg(Instruction i) const { |
+ return i.reg(25, 21); |
+ } |
+}; |
+ |
+/* |
+ * Jump and link register - jalr. |
+ */ |
+class JalReg : public JmpReg { |
+ public: |
+ virtual ~JalReg() {} |
+ virtual bool is_jal() const { |
+ return true; |
+ } |
+ virtual Register dest_gpr_reg(Instruction i) const { |
+ return i.reg(15, 11); |
+ } |
+}; |
+ |
+/* |
+ * ext and ins instructions. |
+ */ |
+class ExtIns : public ClassDecoder { |
+ public: |
+ virtual ~ExtIns() {} |
+ virtual Register dest_gpr_reg(Instruction i) const { |
+ return i.reg(20, 16); |
+ } |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+}; |
+/* |
+ * The instructions that are safe under all circumstances. |
+ */ |
+class Safe : public ClassDecoder { |
+ public: |
+ virtual ~Safe() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return MAY_BE_SAFE; |
+ } |
+}; |
+ |
+class Other : public ClassDecoder { |
+ public: |
+ virtual ~Other() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return FORBIDDEN; |
+ } |
+}; |
+ |
+/* |
+ * Unknown instructions, treated as forbidden. |
+ */ |
+class Unrecognized : public ClassDecoder { |
+ public: |
+ virtual ~Unrecognized() {} |
+ virtual SafetyLevel safety(Instruction i) const { |
+ UNREFERENCED_PARAMETER(i); |
+ return FORBIDDEN; |
+ } |
+}; |
+} // namespace |
+ |
+#endif // NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_MIPS_INST_CLASSES_H |