LCOV - code coverage report
Current view: directory - src/trusted/validator_arm - validator.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 148 0 0.0 %
Date: 2014-09-25 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                 : #include <climits>
       8                 : #include <cstdarg>
       9                 : 
      10                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      11                 : #include "native_client/src/trusted/validator_arm/model.h"
      12                 : #include "native_client/src/trusted/validator_arm/validator.h"
      13                 : #include "native_client/src/include/nacl_macros.h"
      14                 : #include "native_client/src/include/portability_bits.h"
      15                 : #include "native_client/src/shared/platform/nacl_log.h"
      16                 : 
      17                 : using nacl_arm_dec::Instruction;
      18                 : using nacl_arm_dec::ClassDecoder;
      19                 : using nacl_arm_dec::Register;
      20                 : using nacl_arm_dec::RegisterList;
      21                 : 
      22                 : using std::vector;
      23                 : 
      24                 : namespace nacl_arm_val {
      25                 : 
      26                 : /*********************************************************
      27                 :  *
      28                 :  * Implementation of SfiValidator itself.
      29                 :  *
      30                 :  *********************************************************/
      31                 : 
      32                 : // See ARM ARM A8.3 Conditional execution.
      33                 : //
      34                 : // Flags are:
      35                 : //    N - Negative condition code flag.
      36                 : //    Z - Zero condition code flag.
      37                 : //    C - Carry condition code flag.
      38                 : //    V - Overflow condition code flag.
      39                 : const bool SfiValidator::
      40                 : condition_implies[nacl_arm_dec::Instruction::kConditionSize + 1]
      41                 :                  [nacl_arm_dec::Instruction::kConditionSize + 1] = {
      42                 : # if defined(T) || defined(_)
      43                 : #   error Macros already defined.
      44                 : # endif
      45                 : # define T true
      46                 : # define _ false
      47                 :   //                       EQ NE CS CC MI PL VS VC HI LS GE LT GT LE AL UN
      48                 :   /* EQ => Z==1        */ { T, _, _, _, _, _, _, _, _, T, _, _, _, _, T, T },
      49                 :   /* NE => Z==0        */ { _, T, _, _, _, _, _, _, _, _, _, _, _, _, T, T },
      50                 :   /* CS => C==1        */ { _, _, T, _, _, _, _, _, _, _, _, _, _, _, T, T },
      51                 :   /* CC => C==0        */ { _, _, _, T, _, _, _, _, _, T, _, _, _, _, T, T },
      52                 :   /* MI => N==1        */ { _, _, _, _, T, _, _, _, _, _, _, _, _, _, T, T },
      53                 :   /* PL => N==0        */ { _, _, _, _, _, T, _, _, _, _, _, _, _, _, T, T },
      54                 :   /* VS => V==1        */ { _, _, _, _, _, _, T, _, _, _, _, _, _, _, T, T },
      55                 :   /* VC => V==0        */ { _, _, _, _, _, _, _, T, _, _, _, _, _, _, T, T },
      56                 :   /* HI => C==1 & Z==0 */ { _, T, T, _, _, _, _, _, T, _, _, _, _, _, T, T },
      57                 :   /* LS => C==0 | Z==1 */ { _, _, _, _, _, _, _, _, _, T, _, _, _, _, T, T },
      58                 :   /* GE => N==V        */ { _, _, _, _, _, _, _, _, _, _, T, _, _, _, T, T },
      59                 :   /* LT => N!=V        */ { _, _, _, _, _, _, _, _, _, _, _, T, _, _, T, T },
      60                 :   /* GT => Z==0 & N==V */ { _, T, _, _, _, _, _, _, _, _, T, _, T, _, T, T },
      61                 :   /* LE => Z==1 & N!=V */ { T, _, _, _, _, _, _, _, _, T, _, T, _, T, T, T },
      62                 :   /* AL => Any         */ { _, _, _, _, _, _, _, _, _, _, _, _, _, _, T, T },
      63                 :   /* UN => Any         */ { _, _, _, _, _, _, _, _, _, _, _, _, _, _, T, T },
      64                 : # undef _
      65                 : # undef T
      66                 : };
      67                 : 
      68                 : SfiValidator::SfiValidator(uint32_t bytes_per_bundle,
      69                 :                            uint32_t code_region_bytes,
      70                 :                            uint32_t data_region_bytes,
      71                 :                            RegisterList read_only_registers,
      72                 :                            RegisterList data_address_registers,
      73                 :                            const NaClCPUFeaturesArm *cpu_features)
      74                 :     : cpu_features_(),
      75                 :       bytes_per_bundle_(bytes_per_bundle),
      76                 :       code_region_bytes_(code_region_bytes),
      77                 :       data_region_bytes_(data_region_bytes),
      78                 :       read_only_registers_(read_only_registers),
      79                 :       data_address_registers_(data_address_registers),
      80                 :       decode_state_(),
      81                 :       construction_failed_(false),
      82               0 :       is_position_independent_(true) {
      83               0 :   NaClCopyCPUFeaturesArm(&cpu_features_, cpu_features);
      84                 :   // Make sure we can construct sane masks with the values.
      85                 :   if ((nacl::PopCount(bytes_per_bundle_) != 1) ||
      86                 :       (nacl::PopCount(code_region_bytes_) != 1) ||
      87                 :       (nacl::PopCount(data_region_bytes_) != 1) ||
      88                 :       (bytes_per_bundle_ < 4) ||
      89                 :       (code_region_bytes_ < 4) ||
      90                 :       (data_region_bytes_ < 4) ||
      91               0 :       (code_region_bytes_ < bytes_per_bundle_)) {
      92               0 :     construction_failed_ = true;
      93                 :   }
      94               0 : }
      95                 : 
      96                 : SfiValidator::SfiValidator(const SfiValidator& v)
      97                 :     : cpu_features_(),
      98                 :       bytes_per_bundle_(v.bytes_per_bundle_),
      99                 :       code_region_bytes_(v.code_region_bytes_),
     100                 :       data_region_bytes_(v.data_region_bytes_),
     101                 :       read_only_registers_(v.read_only_registers_),
     102                 :       data_address_registers_(v.data_address_registers_),
     103                 :       decode_state_(),
     104                 :       construction_failed_(v.construction_failed_),
     105               0 :       is_position_independent_(v.is_position_independent_) {
     106               0 :   NaClCopyCPUFeaturesArm(&cpu_features_, v.CpuFeatures());
     107               0 : }
     108                 : 
     109               0 : SfiValidator& SfiValidator::operator=(const SfiValidator& v) {
     110               0 :   NaClCopyCPUFeaturesArm(&cpu_features_, v.CpuFeatures());
     111               0 :   bytes_per_bundle_ = v.bytes_per_bundle_;
     112               0 :   code_region_bytes_ = v.code_region_bytes_;
     113               0 :   data_region_bytes_ = v.data_region_bytes_;
     114               0 :   read_only_registers_.Copy(v.read_only_registers_);
     115               0 :   data_address_registers_.Copy(v.data_address_registers_);
     116               0 :   construction_failed_ = v.construction_failed_;
     117               0 :   is_position_independent_ = v.is_position_independent_;
     118               0 :   return *this;
     119               0 : }
     120                 : 
     121                 : nacl_arm_dec::ViolationSet SfiValidator::
     122                 : find_violations(const vector<CodeSegment>& segments,
     123               0 :                 ProblemSink* out) {
     124               0 :   if (ConstructionFailed(out))
     125               0 :     return nacl_arm_dec::ViolationBit(nacl_arm_dec::OTHER_VIOLATION);
     126                 : 
     127               0 :   uint32_t base = segments[0].begin_addr();
     128               0 :   uint32_t size = segments.back().end_addr() - base;
     129               0 :   AddressSet branches(base, size);
     130               0 :   AddressSet critical(base, size);
     131                 : 
     132               0 :   nacl_arm_dec::ViolationSet found_violations = nacl_arm_dec::kNoViolations;
     133                 : 
     134               0 :   for (vector<CodeSegment>::const_iterator it = segments.begin();
     135               0 :       it != segments.end(); ++it) {
     136                 :     nacl_arm_dec::ViolationSet segment_violations =
     137               0 :         validate_fallthrough(*it, out, &branches, &critical);
     138                 :     found_violations =
     139               0 :         nacl_arm_dec::ViolationUnion(found_violations, segment_violations);
     140               0 :     if (segment_violations && (out == NULL)) return found_violations;
     141               0 :   }
     142                 : 
     143                 :   return
     144                 :       nacl_arm_dec::ViolationUnion(
     145                 :           found_violations,
     146               0 :           validate_branches(segments, branches, critical, out));
     147               0 : }
     148                 : 
     149                 : bool SfiValidator::ValidateSegmentPair(const CodeSegment& old_code,
     150                 :                                        const CodeSegment& new_code,
     151               0 :                                        ProblemSink* out) {
     152                 :   // This code verifies that the new code is just like the old code,
     153                 :   // except a few (acceptable) literal constants have been replaced
     154                 :   // in the new code segment. Hence, checking of safety etc. is not
     155                 :   // necessary. We assume that this was done on the old code, and
     156                 :   // does not need to be done again.
     157               0 :   if (ConstructionFailed(out))
     158               0 :     return false;
     159                 : 
     160                 :   if ((old_code.begin_addr() != new_code.begin_addr()) ||
     161               0 :       (old_code.end_addr() != new_code.end_addr())) {
     162               0 :     return false;
     163                 :   }
     164                 : 
     165               0 :   bool complete_success = true;
     166               0 :   bool current_bundle_is_literal_pool = false;
     167                 : 
     168                 :   // The following loop expects the first address to be
     169                 :   // bundle-aligned. This invariant is checked in the validator's C
     170                 :   // interface and it therefore not checked again.
     171               0 :   NACL_COMPILE_TIME_ASSERT((nacl_arm_dec::kArm32InstSize / CHAR_BIT) == 4);
     172               0 :   for (uint32_t va = old_code.begin_addr();
     173               0 :        va != old_code.end_addr();
     174               0 :        va += nacl_arm_dec::kArm32InstSize / CHAR_BIT) {
     175               0 :     Instruction old_insn = old_code[va];
     176               0 :     Instruction new_insn = new_code[va];
     177                 : 
     178                 :     // Keep track of literal pools: it's valid to replace any value in them.
     179                 :     // Literal pools should still be at the same place in the old and new code.
     180               0 :     if (is_bundle_head(va)) {
     181               0 :       const ClassDecoder& old_decoder = decode_state_.decode(old_insn);
     182                 :       current_bundle_is_literal_pool =
     183                 :           (old_decoder.is_literal_pool_head(old_insn) &&
     184               0 :            new_insn.Equals(old_insn));
     185                 :     }
     186                 : 
     187                 :     // Accept any change inside a literal pool.
     188               0 :     if (current_bundle_is_literal_pool)
     189               0 :       continue;
     190                 : 
     191                 :     // See if the instruction has changed in the new version. If not,
     192                 :     // there is nothing to check, and we can skip to the next
     193                 :     // instruction.
     194               0 :     if (new_insn.Equals(old_insn))
     195               0 :       continue;
     196                 : 
     197                 :     // Decode instructions and get corresponding decoders.
     198               0 :     const ClassDecoder& old_decoder = decode_state_.decode(old_insn);
     199               0 :     const ClassDecoder& new_decoder = decode_state_.decode(new_insn);
     200                 : 
     201                 :     // Convert the instructions into their sentinel form (i.e.
     202                 :     // convert immediate values to zero if applicable).
     203                 :     Instruction old_sentinel(
     204               0 :         old_decoder.dynamic_code_replacement_sentinel(old_insn));
     205                 :     Instruction new_sentinel(
     206               0 :         new_decoder.dynamic_code_replacement_sentinel(new_insn));
     207                 : 
     208                 :     // Report problem if the sentinels differ, and reject the replacement.
     209               0 :     if (!new_sentinel.Equals(old_sentinel)) {
     210               0 :       if (out == NULL) return false;
     211                 :       out->ReportProblemDiagnostic(nacl_arm_dec::OTHER_VIOLATION,
     212                 :                                    va,
     213                 :                                    "Sentinels at %08" NACL_PRIx32 " differ.",
     214               0 :                                    va);
     215               0 :       complete_success = false;
     216                 :     }
     217               0 :   }
     218                 : 
     219               0 :   return complete_success;
     220               0 : }
     221                 : 
     222                 : bool SfiValidator::CopyCode(const CodeSegment& source_code,
     223                 :                             CodeSegment& dest_code,
     224                 :                             NaClCopyInstructionFunc copy_func,
     225               0 :                             ProblemSink* out) {
     226               0 :   if (ConstructionFailed(out))
     227               0 :     return false;
     228                 : 
     229               0 :   vector<CodeSegment> segments;
     230               0 :   segments.push_back(source_code);
     231               0 :   if (!validate(segments, out))
     232               0 :       return false;
     233                 : 
     234                 :   // As on ARM all instructions are 4 bytes in size and aligned
     235                 :   // we don't have to check instruction boundary invariant.
     236               0 :   for (uintptr_t va = source_code.begin_addr();
     237               0 :        va != source_code.end_addr();
     238               0 :        va += nacl_arm_dec::kArm32InstSize / CHAR_BIT) {
     239               0 :     intptr_t offset = va - source_code.begin_addr();
     240                 :     // TODO(olonho): this const cast is a bit ugly, but we
     241                 :     // need to write to dest segment.
     242                 :     copy_func(const_cast<uint8_t*>(dest_code.base()) + offset,
     243                 :               const_cast<uint8_t*>(source_code.base()) + offset,
     244               0 :               nacl_arm_dec::kArm32InstSize / CHAR_BIT);
     245               0 :   }
     246                 : 
     247               0 :   return true;
     248               0 : }
     249                 : 
     250               0 : bool SfiValidator::ConstructionFailed(ProblemSink* out) {
     251               0 :   if (construction_failed_ && (out != NULL)) {
     252               0 :     uint32_t invalid_addr = ~(uint32_t)0;
     253                 :     out->ReportProblemDiagnostic(nacl_arm_dec::OTHER_VIOLATION,
     254                 :                                  invalid_addr,
     255               0 :                                  "Construction of validator failed!");
     256                 :   }
     257               0 :   return construction_failed_;
     258               0 : }
     259                 : 
     260                 : nacl_arm_dec::ViolationSet SfiValidator::validate_fallthrough(
     261                 :     const CodeSegment& segment,
     262                 :     ProblemSink* out,
     263                 :     AddressSet* branches,
     264               0 :     AddressSet* critical) {
     265               0 :   nacl_arm_dec::ViolationSet found_violations = nacl_arm_dec::kNoViolations;
     266                 : 
     267                 :   // Initialize the previous instruction so it always fails validation.
     268                 :   DecodedInstruction pred(
     269                 :       0,  // Virtual address 0, which will be in a different bundle;
     270                 :       Instruction(nacl_arm_dec::kFailValidation),
     271               0 :       decode_state_.fictitious_decoder());
     272                 : 
     273                 :   // Validate each instruction.
     274               0 :   uint32_t va = segment.begin_addr();
     275               0 :   while (va < segment.end_addr()) {
     276               0 :     const ClassDecoder& decoder = decode_state_.decode(segment[va]);
     277               0 :     DecodedInstruction inst(va, segment[va], decoder);
     278                 :     // Note: get_violations is expecting the address of the next instruction
     279                 :     // to be validated as its last argument. This address can be updated by
     280                 :     // by that routine (as with constant pool heads). Hence, rather than
     281                 :     // updating va at the end of the loop, we update it here and pass it
     282                 :     // through to get_violations.
     283               0 :     va += 4;
     284                 :     nacl_arm_dec::ViolationSet violations =
     285               0 :         decoder.get_violations(pred, inst, *this, branches, critical, &va);
     286               0 :     if (violations) {
     287                 :       found_violations =
     288               0 :           nacl_arm_dec::ViolationUnion(found_violations, violations);
     289               0 :       if (out == NULL) return found_violations;
     290               0 :       decoder.generate_diagnostics(violations, pred, inst, *this, out);
     291                 :     }
     292               0 :     pred.Copy(inst);
     293               0 :   }
     294                 : 
     295                 :   // Validate the last instruction, paired with a nop.
     296               0 :   const Instruction nop(nacl_arm_dec::kNop);
     297               0 :   const ClassDecoder& nop_decoder = decode_state_.decode(nop);
     298               0 :   DecodedInstruction one_past_end(va, nop, nop_decoder);
     299                 :   // Note: Like above, we update va to point to the instruction after the nop,
     300                 :   // so that it meets the requirements of get_violations.
     301               0 :   va += 4;
     302                 :   nacl_arm_dec::ViolationSet violations =
     303                 :       nop_decoder.get_violations(pred, one_past_end, *this,
     304               0 :                                  branches, critical, &va);
     305               0 :   if (violations) {
     306                 :     found_violations =
     307               0 :         nacl_arm_dec::ViolationUnion(found_violations, violations);
     308               0 :     if (out == NULL) return found_violations;
     309                 :     nop_decoder.generate_diagnostics(violations, pred, one_past_end,
     310               0 :                                      *this, out);
     311                 :   }
     312                 : 
     313               0 :   return found_violations;
     314               0 : }
     315                 : 
     316               0 : static bool address_contained(uint32_t va, const vector<CodeSegment>& segs) {
     317               0 :   for (vector<CodeSegment>::const_iterator it = segs.begin(); it != segs.end();
     318               0 :       ++it) {
     319               0 :     if (it->contains_address(va)) return true;
     320               0 :   }
     321               0 :   return false;
     322               0 : }
     323                 : 
     324                 : nacl_arm_dec::ViolationSet SfiValidator::validate_branches(
     325                 :     const vector<CodeSegment>& segments,
     326                 :     const AddressSet& branches,
     327                 :     const AddressSet& critical,
     328               0 :     ProblemSink* out) {
     329               0 :   nacl_arm_dec::ViolationSet found_violations = nacl_arm_dec::kNoViolations;
     330                 : 
     331               0 :   vector<CodeSegment>::const_iterator seg_it = segments.begin();
     332                 : 
     333               0 :   if (segments.size() > 1) {
     334                 :     // If there are multiple segments, their relative positioning matters.
     335               0 :     is_position_independent_ = false;
     336                 :   }
     337                 : 
     338               0 :   for (AddressSet::Iterator it = branches.begin(); it != branches.end(); ++it) {
     339               0 :     uint32_t va = *it;
     340                 : 
     341                 :     // Invariant: all addresses in branches are covered by some segment;
     342                 :     // segments are in sorted order.
     343               0 :     while (!seg_it->contains_address(va)) {
     344               0 :       ++seg_it;
     345               0 :     }
     346                 : 
     347               0 :     const CodeSegment &segment = *seg_it;
     348                 : 
     349                 :     DecodedInstruction inst(va, segment[va],
     350               0 :                             decode_state_.decode(segment[va]));
     351                 : 
     352                 :     // We know it is_relative_branch(), so we can simply call:
     353               0 :     uint32_t target_va = inst.branch_target();
     354               0 :     if (address_contained(target_va, segments)) {
     355               0 :       if (critical.contains(target_va)) {
     356                 :         found_violations =
     357                 :             nacl_arm_dec::ViolationUnion(
     358                 :                 found_violations,
     359                 :                 nacl_arm_dec::ViolationBit(
     360               0 :                     nacl_arm_dec::BRANCH_SPLITS_PATTERN_VIOLATION));
     361               0 :         if (out == NULL) return found_violations;
     362                 :         out->ReportProblemDiagnostic(
     363                 :             nacl_arm_dec::BRANCH_SPLITS_PATTERN_VIOLATION,
     364                 :             va,
     365                 :             "Instruction branches into middle of 2-instruction "
     366                 :             "pattern at %08" NACL_PRIx32 ".",
     367               0 :             target_va);
     368                 :       }
     369               0 :     } else {
     370                 :       // If the jump is outside the segment, absolute position matters.
     371               0 :       is_position_independent_ = false;
     372                 : 
     373               0 :       if ((target_va & code_address_mask()) == 0) {
     374                 :         // Ensure that relative direct branches which don't go to known
     375                 :         // segments are to bundle-aligned targets, and that the branch
     376                 :         // doesn't escape from the sandbox. ARM relative direct branches
     377                 :         // have a +/-32MiB range, code at the edges of the sandbox could
     378                 :         // therefore potentially escape if left unchecked. This implies
     379                 :         // that validation is position-dependent, which matters for
     380                 :         // validation caching: code segments need to be mapped at the
     381                 :         // same addresses as the ones at which they were validated.
     382                 :         //
     383                 :         // We could make it a sandbox invariant that user code cannot be
     384                 :         // mapped within 32MiB of the sandbox's edges (and then only check
     385                 :         // bundle alignment with is_bundle_head(target_va)), but this may
     386                 :         // break some assumptions in user code.
     387                 :         //
     388                 :         // We could also track the furthest negative and positive relative
     389                 :         // direct branches seen per segment and record that
     390                 :         // information. This information would then allow validation
     391                 :         // caching to be mostly position independent, as long as code
     392                 :         // segments are mapped far enough from the sandbox's edges.
     393                 :         //
     394                 :         // Branches leaving the segment could be useful for dynamic code
     395                 :         // generation as well as to directly branch to the runtime's
     396                 :         // trampolines. The IRT curently doesn't do the latter because the
     397                 :         // compiler doesn't know that the trampolines will be in range of
     398                 :         // relative direct branch immediates. Indirect branches are
     399                 :         // instead used and the loader doesn't reoptimize the code.
     400               0 :       } else {
     401                 :         found_violations =
     402                 :             nacl_arm_dec::ViolationUnion(
     403                 :                 found_violations,
     404                 :                 nacl_arm_dec::ViolationBit(
     405               0 :                     nacl_arm_dec::BRANCH_OUT_OF_RANGE_VIOLATION));
     406               0 :         if (out == NULL) return found_violations;
     407                 :         out->ReportProblemDiagnostic(
     408                 :             nacl_arm_dec::BRANCH_OUT_OF_RANGE_VIOLATION,
     409                 :             va,
     410                 :             "Instruction branches to invalid address %08" NACL_PRIx32 ".",
     411               0 :             target_va);
     412                 :       }
     413                 :     }
     414               0 :   }
     415                 : 
     416               0 :   return found_violations;
     417               0 : }
     418                 : 
     419                 : }  // namespace nacl_arm_val

Generated by: LCOV version 1.7