Chromium Code Reviews| Index: src/trusted/validator_arm/validator.h |
| diff --git a/src/trusted/validator_arm/validator.h b/src/trusted/validator_arm/validator.h |
| index e3af968786851d5d8bbcd32b65ea8d6a82f75e0c..796f6404e238bc5b6397489c68f5b5d997a2cbcd 100644 |
| --- a/src/trusted/validator_arm/validator.h |
| +++ b/src/trusted/validator_arm/validator.h |
| @@ -1,14 +1,19 @@ |
| /* |
| - * Copyright 2009 The Native Client Authors. All rights reserved. |
| + * Copyright 2011 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 2009, Google Inc. |
| + * Copyright 2011, Google Inc. |
| */ |
| #ifndef NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_V2_VALIDATOR_H |
| #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_V2_VALIDATOR_H |
| /* |
| + * MRM DEBUG Header, clean this out |
| + */ |
| +#include <stdio.h> |
| + |
| +/* |
| * The SFI validator, and some utility classes it uses. |
| */ |
| @@ -51,12 +56,38 @@ class Bundle { |
| // Note that all Bundles are currently assumed to be the same size. |
| return virtual_base_ != other.virtual_base_; |
| } |
| + bool operator==(const Bundle &other) const { |
| + return virtual_base_ == other.virtual_base_; |
| + } |
| private: |
| uint32_t virtual_base_; |
| uint32_t size_; |
| }; |
| +class SfiValidator; |
| + |
| +// A possible result from a validator pattern. |
| +enum PatternMatchMode { |
| + // The pattern does not apply to the instructions it was given. |
| + NO_MATCH_MODE, |
| + // The pattern matches, and is safe; do not allow jumps to split it. |
| + PATTERN_SAFE_MODE, |
| + // The pattern matches, and has detected a problem. |
| + PATTERN_UNSAFE_MODE |
| +}; |
| + |
| +// Full result from a pattern. Describes whether it matched, and if it did, |
| +// specifies how long the matching pattern was. |
| +typedef struct { |
| + PatternMatchMode pm_mode; |
| + int8_t size; |
| +} PatternMatch; |
| + |
| +/* Pattern matching type */ |
| +typedef PatternMatch (*Pattern)(const SfiValidator &, |
| + DecodedInstruction insns[], |
| + ProblemSink *out); |
| /* |
| * The SFI validator itself. The validator is controlled by the following |
| @@ -83,7 +114,8 @@ class SfiValidator { |
| uint32_t code_region_bytes, |
| uint32_t data_region_bytes, |
| nacl_arm_dec::RegisterList read_only_registers, |
| - nacl_arm_dec::RegisterList data_address_registers); |
| + nacl_arm_dec::RegisterList data_address_registers, |
| + uint8_t thumb); |
| /* |
| * The main validator entry point. Validates the provided CodeSegments, |
| @@ -100,8 +132,9 @@ class SfiValidator { |
| */ |
| bool is_data_address_register(nacl_arm_dec::Register) const; |
| - uint32_t data_address_mask() const { return data_address_mask_; } |
| - uint32_t code_address_mask() const { return code_address_mask_; } |
| + uint32_t data_address_mask() const { return data_address_mask_; } |
| + uint32_t code_address_mask() const { return code_address_mask_; } |
| + uint32_t code_address_ormask() const { return code_address_ormask_; } |
| nacl_arm_dec::RegisterList read_only_registers() const { |
| return read_only_registers_; |
| @@ -117,9 +150,12 @@ class SfiValidator { |
| * Change masks: this is useful for debugging and cannot be completely |
| * controlled with constructor arguments |
| */ |
| - void change_masks(uint32_t code_address_mask, uint32_t data_address_mask) { |
| - code_address_mask_ = code_address_mask; |
| - data_address_mask_ = data_address_mask; |
| + void change_masks(uint32_t code_address_mask, |
| + uint32_t code_address_ormask, |
| + uint32_t data_address_mask) { |
| + code_address_mask_ = code_address_mask; |
| + code_address_ormask_ = code_address_ormask; |
| + data_address_mask_ = data_address_mask; |
| } |
| private: |
| @@ -139,15 +175,6 @@ class SfiValidator { |
| AddressSet *branches, AddressSet *critical); |
| /* |
| - * Factor of validate_fallthrough, above. Checks a single instruction using |
| - * the instruction patterns defined in the .cc file, with two possible |
| - * results: |
| - * 1. No patterns matched, or all were safe: nothing happens. |
| - * 2. Patterns matched and were unsafe: problems get sent to 'out'. |
| - */ |
| - bool apply_patterns(const DecodedInstruction &, ProblemSink *out); |
| - |
| - /* |
| * Factor of validate_fallthrough, above. Checks a pair of instructions using |
| * the instruction patterns defined in the .cc file, with three possible |
| * results: |
| @@ -156,8 +183,9 @@ class SfiValidator { |
| * 'critical' for use by the second pass. |
| * 3. Patterns matched and were unsafe: problems get sent to 'out'. |
| */ |
| - bool apply_patterns(const DecodedInstruction &first, |
| - const DecodedInstruction &second, AddressSet *critical, ProblemSink *out); |
| + bool apply_patterns(DecodedInstruction insns[], |
| + const Pattern patterns[], unsigned int nPatterns, |
| + AddressSet *critical, ProblemSink *out); |
| /* |
| * Validates all branches found by a previous pass, checking destinations. |
| @@ -171,14 +199,24 @@ class SfiValidator { |
| uint32_t bytes_per_bundle_; |
| uint32_t data_address_mask_; |
| uint32_t code_address_mask_; |
| + uint32_t code_address_ormask_; |
| uint32_t code_region_bytes_; |
| // Registers which cannot be modified by untrusted code. |
| nacl_arm_dec::RegisterList read_only_registers_; |
| // Registers which must always contain a valid data region address. |
| nacl_arm_dec::RegisterList data_address_registers_; |
| + bool thumb_; |
| const nacl_arm_dec::DecoderState *decode_state_; |
| }; |
| +/* |
| + * Defines the maximal pattern size to be made available to the pattern |
| + * matcher. |
| + * I know 5 seems a little big, but it is required for the IT matcher. |
| + * 16 is a hack, it is a magic number to make sure that the second pattern |
|
Karl
2011/08/30 19:53:52
What 16?
|
| + * matching phase interacts properly with breakpoint. |
| + */ |
| +const uint8_t kMaxPattern = 5; |
| /* |
| * A facade that combines an Instruction with its address and a ClassDecoder. |
| @@ -208,9 +246,9 @@ class DecodedInstruction { |
| * take it into account. The SfiValidator reasons on this separately. |
| */ |
| bool always_precedes(const DecodedInstruction &other) const { |
| - return inst_.condition() == other.inst_.condition(); |
| + return condition() == other.condition(); |
| } |
| - |
| + // TODO(mrm) These predicates will all be able to lie without an IT predicator |
| /* |
| * Checks that 'this' always follows 'other' -- meaning that if 'other' |
| * executes, 'this' is guaranteed to follow. This is important if 'other' |
| @@ -220,7 +258,7 @@ class DecodedInstruction { |
| * take it into account. The SfiValidator reasons on this separately. |
| */ |
| bool always_follows(const DecodedInstruction &other) const { |
| - return inst_.condition() == other.inst_.condition() |
| + return condition() == condition() |
|
Karl
2011/08/30 19:53:52
Why compare condition to itself?
|
| && !other.defines(nacl_arm_dec::kRegisterFlags); |
| } |
| @@ -230,8 +268,8 @@ class DecodedInstruction { |
| * adjacent for this simple check to be meaningful. |
| */ |
| bool is_conditional_on(const DecodedInstruction &other) const { |
| - return inst_.condition() == nacl_arm_dec::Instruction::EQ |
| - && other.inst_.condition() == nacl_arm_dec::Instruction::AL |
| + return condition() == nacl_arm_dec::Instruction::EQ |
| + && other.condition() == nacl_arm_dec::Instruction::AL |
| && other.defines(nacl_arm_dec::kRegisterFlags); |
| } |
| @@ -239,6 +277,40 @@ class DecodedInstruction { |
| nacl_arm_dec::SafetyLevel safety() const { return safety_; } |
| nacl_arm_dec::RegisterList defs() const { return defs_; } |
| + /* Passes through queries about the it status */ |
| + nacl_arm_dec::ITCond it() const { |
| + return decoder_->it_sequence(inst_); |
| + } |
| + |
| + /* Passes through queries about it safety */ |
| + nacl_arm_dec::ITSafety it_safe() const { |
| + return decoder_->it_safe(inst_); |
| + } |
| + |
| + // Calculates the size of the current instruction. It is here instead of |
| + // ClassDecoder because it needs the vaddr. |
| + nacl_arm_dec::Instruction::Condition condition() const { |
| + if (vaddr_ & 1) { |
| + if (condition_ != nacl_arm_dec::Instruction::UNCONDITIONAL) |
| + return condition_; |
| + return decoder_->condition(inst_); |
| + } else { |
| + return inst_.condition(); |
| + } |
| + } |
| + uint8_t size() const { |
| + if (vaddr_ & 1) { |
| + switch (inst_.bits(15, 11)) { |
| + case 0x1D: // 0b11101 |
| + case 0x1E: // 0b11110 |
| + case 0x1F: return 4; // 0b11111 |
| + default: return 2; |
| + } |
| + } else { |
| + return 4; |
| + } |
| + } |
| + |
| // The methods below pull values from ClassDecoder on demand. |
| bool is_relative_branch() const { |
| return decoder_->is_relative_branch(inst_); |
| @@ -260,6 +332,10 @@ class DecodedInstruction { |
| return decoder_->base_address_register(inst_); |
| } |
| + bool sets_bits(uint32_t mask) const { |
| + return decoder_->sets_bits(inst_, mask); |
| + } |
| + |
| bool clears_bits(uint32_t mask) const { |
| return decoder_->clears_bits(inst_, mask); |
| } |
| @@ -285,6 +361,15 @@ class DecodedInstruction { |
| return defs().contains_all(rl); |
| } |
| + /* |
| + * Overrides the conditional for this insn, if thumb mode is active. |
| + * It should be used only once on any given insn, as it should originate |
| + * only from within an IT block, and IT blocks must not overlap. |
| + */ |
| + void set_condition(nacl_arm_dec::Instruction::Condition condition) { |
| + condition_ = condition; |
| + } |
| + |
| private: |
| uint32_t vaddr_; |
| nacl_arm_dec::Instruction inst_; |
| @@ -292,6 +377,7 @@ class DecodedInstruction { |
| nacl_arm_dec::SafetyLevel safety_; |
| nacl_arm_dec::RegisterList defs_; |
| + nacl_arm_dec::Instruction::Condition condition_; |
| }; |
| @@ -314,14 +400,22 @@ class CodeSegment { |
| const nacl_arm_dec::Instruction operator[](uint32_t address) const { |
| const uint8_t *element = &base_[address - start_addr_]; |
| - return nacl_arm_dec::Instruction( |
| - *reinterpret_cast<const uint32_t *>(element)); |
| + // Special case to allow addresses two from the end to be read |
| + if ((address - start_addr_) + 2 < size_) { |
| + return nacl_arm_dec::Instruction( |
| + *reinterpret_cast<const uint32_t *>(element)); |
| + } else if ((address - start_addr_) + 2 == size_) { |
| + return nacl_arm_dec::Instruction(((uint32_t) |
| + (*reinterpret_cast<const uint16_t *>(element)))); |
| + } else { |
| + fprintf(stderr, "Out of bounds access to code segment: %x\n", address); |
| + exit(1); |
| + } |
| } |
| bool operator<(const CodeSegment &other) const { |
| return start_addr_ < other.start_addr_; |
| } |
| - |
|
Karl
2011/08/30 19:53:52
Nit. Why blank line removed?
|
| private: |
| const uint8_t *base_; |
| uint32_t start_addr_; |
| @@ -380,6 +474,10 @@ class ProblemSink { |
| // An instruction is unsafe -- more information in the SafetyLevel. |
| const char * const kProblemUnsafe = "kProblemUnsafe"; |
| +// An instruction runs off the end of a segment |
| +const char * const kProblemStraddlesSegment = "kProblemStraddlesSegment"; |
| +// An IT instruction is unconditional, meaning the condition is uninvertable. |
| +const char * const kProblemUnconditionalIT = "kProblemUnconditionalIT"; |
| // A branch would break a pseudo-operation pattern. |
| const char * const kProblemBranchSplitsPattern = "kProblemBranchSplitsPattern"; |
| // A branch targets an invalid code address (out of segment). |