LCOV - code coverage report
Current view: directory - src/trusted/validator_arm - validator_tests.h (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 37 31 83.8 %
Date: 2014-07-02 Functions: 0 0 -

       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_ARM_VALIDATOR_TESTS_H_
       8                 : #define NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_VALIDATOR_TESTS_H_
       9                 : 
      10                 : #ifndef NACL_TRUSTED_BUT_NOT_TCB
      11                 : #error This file is not meant for use in the TCB
      12                 : #endif
      13                 : 
      14                 : /*
      15                 :  * Unit tests for the ARM validator
      16                 :  *
      17                 :  * These tests use the google-test framework (gtest for short) to exercise the
      18                 :  * ARM validator.  The tests currently fall into two rough categories:
      19                 :  *  1. Simple method-level tests that exercise the validator's primitive
      20                 :  *     capabilities, and
      21                 :  *  2. Instruction pattern tests that run the entire validator.
      22                 :  *
      23                 :  * All instruction pattern tests use hand-assembled machine code fragments,
      24                 :  * embedded as byte arrays.  This is somewhat ugly, but deliberate: it isolates
      25                 :  * these tests from gas, which may be buggy or not installed.  It also lets us
      26                 :  * hand-craft malicious bit patterns that gas may refuse to produce.
      27                 :  *
      28                 :  * To write a new instruction pattern, or make sense of an existing one, use the
      29                 :  * ARMv7-A ARM (available online).  Instructions in this file are written as
      30                 :  * 32-bit integers so the hex encoding matches the docs.
      31                 :  *
      32                 :  * Also see validator_tests.cc and validator_large_tests.cc
      33                 :  */
      34                 : 
      35                 : #include <algorithm>
      36                 : #include <climits>
      37                 : #include <limits>
      38                 : #include <string>
      39                 : #include <sstream>
      40                 : #include <vector>
      41                 : 
      42                 : #include "gtest/gtest.h"
      43                 : #include "native_client/src/include/nacl_macros.h"
      44                 : #include "native_client/src/include/portability_bits.h"
      45                 : 
      46                 : #include "native_client/src/trusted/validator_arm/problem_reporter.h"
      47                 : #include "native_client/src/trusted/validator_arm/validator.h"
      48                 : 
      49                 : using std::vector;
      50                 : using std::string;
      51                 : using std::ostringstream;
      52                 : 
      53                 : using nacl_arm_dec::kNoViolations;
      54                 : using nacl_arm_dec::Instruction;
      55                 : using nacl_arm_dec::Register;
      56                 : using nacl_arm_dec::RegisterList;
      57                 : using nacl_arm_dec::Violation;
      58                 : using nacl_arm_dec::ViolationSet;
      59                 : 
      60                 : using nacl_arm_val::SfiValidator;
      61                 : using nacl_arm_val::CodeSegment;
      62                 : using nacl_arm_val::ProblemReporter;
      63                 : using nacl_arm_val::ProblemSink;
      64                 : 
      65                 : namespace nacl_val_arm_test {
      66                 : 
      67                 : #ifdef __BIG_ENDIAN__
      68                 : #error This test will only succeed on a little-endian machine.  Sorry.
      69                 : #endif
      70                 : 
      71                 : // Since ARM instructions are always little-endian, on a little-endian machine
      72                 : // we can represent them as ints.  This makes things somewhat easier to read
      73                 : // below.
      74                 : typedef uint32_t arm_inst;
      75                 : 
      76                 : // This is where untrusted code starts.  Most tests use this.
      77                 : static const uint32_t kDefaultBaseAddr = 0x20000;
      78                 : 
      79                 : /*
      80                 :  * We use these parameters to initialize the validator, below.  They are
      81                 :  * somewhat different from the parameters used in real NaCl systems, to test
      82                 :  * degrees of validator freedom that we don't currently exercise in prod.
      83                 :  */
      84                 : // Number of bytes in each bundle.  Theoretically can also be 32 - not tested.
      85                 : static const uint32_t kBytesPerBundle = 16;
      86                 : // Limit code to 512MiB.
      87                 : static const uint32_t kCodeRegionSize = 0x20000000;
      88                 : // Limit data to 1GiB.
      89                 : static const uint32_t kDataRegionSize = 0x40000000;
      90                 : // Untrusted code must not write to the thread pointer.
      91               2 : static const RegisterList kAbiReadOnlyRegisters(Register::Tp());
      92                 : // The stack pointer can be used for "free" loads and stores.
      93               2 : static const RegisterList kAbiDataAddrRegisters(nacl_arm_dec::Register::Sp());
      94                 : // By default don't support TST+LDR/TST+STR, only allow it in tests that
      95                 : // explicitly have them.
      96                 : static const bool kAllowCondMemSfi = false;
      97                 : 
      98                 : // Simply records the arguments given to ReportProblem, below.
      99                 : class ProblemRecord {
     100                 :  public:
     101            3480 :   ProblemRecord(Violation violation,
     102                 :                 uint32_t vaddr,
     103                 :                 const std::string& message)
     104            3480 :       : violation_(violation), vaddr_(vaddr), message_(message) {}
     105                 : 
     106            8853 :   ProblemRecord(const ProblemRecord& r)
     107            8853 :       : violation_(r.violation_), vaddr_(r.vaddr_), message_(r.message_) {}
     108                 : 
     109           12333 :   ~ProblemRecord() {}
     110                 : 
     111               0 :   ProblemRecord& operator=(const ProblemRecord& r) {
     112               0 :     violation_ = r.violation_;
     113               0 :     vaddr_ = r.vaddr_;
     114               0 :     message_ = r.message_;
     115               0 :     return *this;
     116                 :   }
     117                 : 
     118            3480 :   uint32_t vaddr() const { return vaddr_; }
     119           10200 :   Violation violation() const { return violation_; }
     120               0 :   std::string message() const { return message_; }
     121                 : 
     122                 :  private:
     123                 :   Violation violation_;
     124                 :   uint32_t vaddr_;
     125                 :   std::string message_;
     126                 : };
     127                 : 
     128                 : // A ProblemSink that records all calls (implementation of the Spy pattern)
     129          246898 : class ProblemSpy : public ProblemReporter {
     130                 :  public:
     131                 :   // Returns the list of found problems.
     132          125342 :   vector<ProblemRecord> &get_problems() { return problems_; }
     133                 : 
     134                 :  protected:
     135                 :   virtual void ReportProblemMessage(Violation violation,
     136                 :                                     uint32_t vaddr,
     137                 :                                     const char* message);
     138                 : 
     139                 :  private:
     140                 :   static const vector<ProblemRecord>::size_type max_problems = 5000;
     141                 :   vector<ProblemRecord> problems_;
     142                 : };
     143                 : 
     144                 : // Coordinates the fixture objects used by test cases below.
     145                 : class ValidatorTests : public ::testing::Test {
     146                 :  public:
     147                 :   // Utility method to decode an instruction.
     148                 :   const nacl_arm_dec::ClassDecoder& decode(
     149                 :       nacl_arm_dec::Instruction inst) const;
     150                 : 
     151                 :   // Returns the given instruction, after modifying the instruction condition
     152                 :   // to the given value.
     153          444005 :   static arm_inst ChangeCond(arm_inst inst, Instruction::Condition c) {
     154          444005 :     return (inst & 0x0fffffff) | (static_cast<arm_inst>(c) << 28);
     155                 :   }
     156                 : 
     157                 :  protected:
     158                 :   ValidatorTests();
     159                 : 
     160             102 :   virtual ~ValidatorTests() {
     161              51 :     EXPECT_EQ(_validator, (SfiValidator *) NULL);
     162              51 :   }
     163                 : 
     164              51 :   virtual void SetUp() {
     165              51 :     EXPECT_EQ(_validator, (SfiValidator *) NULL);
     166                 : 
     167                 :     NaClCPUFeaturesArm cpu_features;
     168              51 :     NaClClearCPUFeaturesArm(&cpu_features);
     169                 :     NaClSetCPUFeatureArm(&cpu_features, NaClCPUFeatureArm_CanUseTstMem,
     170              51 :                          kAllowCondMemSfi);
     171                 : 
     172                 :     _validator = new SfiValidator(kBytesPerBundle,
     173                 :                                   kCodeRegionSize,
     174                 :                                   kDataRegionSize,
     175                 :                                   kAbiReadOnlyRegisters,
     176                 :                                   kAbiDataAddrRegisters,
     177              51 :                                   &cpu_features);
     178              51 :   }
     179                 : 
     180              51 :   virtual void  TearDown() {
     181              51 :     EXPECT_NE(_validator, (SfiValidator *) NULL);
     182              51 :     delete _validator;
     183              51 :     _validator = NULL;
     184              51 :   }
     185                 : 
     186                 :   // Utility method for validating a sequence of bytes.
     187                 :   bool validate(const arm_inst *pattern,
     188                 :                 size_t inst_count,
     189                 :                 uint32_t start_addr,
     190                 :                 ProblemSink *sink = NULL);
     191                 : 
     192                 :   // Utility method for validating a sequence of bytes.
     193                 :   ViolationSet find_violations(const arm_inst *pattern,
     194                 :                                size_t inst_count,
     195                 :                                uint32_t start_addr,
     196                 :                                ProblemSink *sink = NULL);
     197                 : 
     198                 :   // Tests an arbitrary-size instruction fragment that is expected to pass.
     199                 :   // Does not modulate or rewrite the pattern in any way.
     200                 :   void validation_should_pass(const arm_inst *pattern,
     201                 :                               size_t inst_count,
     202                 :                               uint32_t base_addr,
     203                 :                               const string &msg);
     204                 : 
     205                 :   // Tests a two-instruction pattern that's expected to pass, at each possible
     206                 :   // bundle alignment. This also tries the pattern across bundle boundaries,
     207                 :   // and makes sure it fails.
     208                 :   void validation_should_pass2(const arm_inst *pattern,
     209                 :                                size_t inst_count,
     210                 :                                uint32_t base_addr,
     211                 :                                const string &msg);
     212                 : 
     213                 :   // Tests a pattern that is forbidden in the SFI model.
     214                 :   //
     215                 :   // Note that the 'msg1' and 'msg2' parameters are merely concatentated in the
     216                 :   // output.
     217                 :   ViolationSet validation_should_fail(const arm_inst *pattern,
     218                 :                                       size_t inst_count,
     219                 :                                       uint32_t base_addr,
     220                 :                                       const string &msg,
     221                 :                                       ProblemSpy* spy = NULL);
     222                 : 
     223                 :   // Tests an instruction with all possible conditions (i.e. all except 1111),
     224                 :   // verifying all cases are safe.
     225                 :   void all_cond_values_pass(const arm_inst prototype,
     226                 :                             uint32_t base_addr,
     227                 :                             const string &msg);
     228                 : 
     229                 :   // Tests an instruction with all possible conditions (i.e. all except 1111),
     230                 :   // verifying all cases are unsafe.
     231                 :   void all_cond_values_fail(const arm_inst prototype,
     232                 :                             uint32_t base_addr,
     233                 :                             const string &msg);
     234                 : 
     235                 :   // Returns the given instruction, after modifying its S bit (bit 20) to
     236                 :   // the given value.
     237               2 :   static arm_inst SetSBit(arm_inst inst, bool s) {
     238               2 :     return (inst & 0xffefffff) | (static_cast<arm_inst>(s) << 20);
     239                 :   }
     240                 : 
     241                 :   // Returns true if the given register is not in {Tp, Sp, Pc}. That is,
     242                 :   // not one of the registers requiring either: a 2-instruction sequence
     243                 :   // to update (Sp and Pc); or should not be updated at all (Tp).
     244             480 :   bool IsValidSingleInstructionDestinationRegister(Register r) const {
     245             480 :     return !_is_valid_single_instruction_destination_register.Contains(r);
     246                 :   }
     247                 : 
     248                 :   SfiValidator *_validator;
     249                 : 
     250                 :  private:
     251                 :   RegisterList _is_valid_single_instruction_destination_register;
     252                 : };
     253                 : 
     254                 : }  // namespace nacl_val_arm_test
     255                 : 
     256                 : #endif  // NATIVE_CLIENT_SRC_TRUSTED_VALIDATOR_ARM_VALIDATOR_TESTS_H_

Generated by: LCOV version 1.7