LCOV - code coverage report
Current view: directory - src/trusted/validator/x86/ncval_seg_sfi - ncvalidate.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 476 383 80.5 %
Date: 2012-02-16 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                 : /*
       8                 :  * ncvalidate.c
       9                 :  * Validate x86 instructions for Native Client
      10                 :  *
      11                 :  */
      12                 : 
      13                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate.h"
      14                 : 
      15                 : #include <stdio.h>
      16                 : #include <stdlib.h>
      17                 : #include <errno.h>
      18                 : #include <string.h>
      19                 : #include <assert.h>
      20                 : 
      21                 : #include "native_client/src/include/portability.h"
      22                 : #include "native_client/src/shared/platform/nacl_check.h"
      23                 : #include "native_client/src/trusted/validator/x86/halt_trim.h"
      24                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h"
      25                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_internaltypes.h"
      26                 : 
      27                 : #include "native_client/src/trusted/validator/x86/ncinstbuffer_inl.c"
      28                 : #include "native_client/src/trusted/validator/x86/x86_insts_inl.c"
      29                 : 
      30                 : #if NACL_TARGET_SUBARCH == 64
      31                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncbadprefixmask_64.h"
      32                 : #else
      33                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncbadprefixmask_32.h"
      34                 : #endif
      35                 : 
      36                 : /* debugging stuff */
      37                 : #define DEBUGGING 0
      38                 : #if DEBUGGING
      39                 : #define dprint(args)        do { printf args; } while (0)
      40                 : #else
      41                 : #define dprint(args)        do { if (0) { printf args; } } while (0)
      42                 : /* allows DCE but compiler can still do format string checks */
      43                 : #endif  /* DEBUGGING */
      44                 : 
      45                 : /* TODO(bradchen) verbosity needs to be controllable via commandline flags */
      46                 : #define VERBOSE 1
      47                 : #if VERBOSE
      48                 : #define vprint(vstate, args) \
      49                 :   do { \
      50                 :     NaClErrorReporter* reporter = vstate->dstate.error_reporter; \
      51                 :     (*reporter->printf) args;                                    \
      52                 :   } while (0)
      53                 : #else
      54                 : #define vprint(vstate, args) \
      55                 :   do { \
      56                 :     if (0) { \
      57                 :       NaClErrorReporter* reporter = vstate->dstate.error_reporter; \
      58                 :       (*reporter->printf) args;                                    \
      59                 :     } \
      60                 :   } while (0)
      61                 : /* allows DCE but compiler can still do format string checks */
      62                 : #endif  /* VERBOSE */
      63                 : 
      64                 : static const uint8_t kNaClFullStop = 0xf4;   /* x86 HALT opcode */
      65                 : 
      66                 : /* Define how many diagnostic error messages are printed by the validator.
      67                 :  * A value of zero generates no diagnostics.
      68                 :  * A value >0 allows up to that many diagnostic error messages.
      69                 :  * A negative value prints all diagnostic error messages.
      70                 :  */
      71                 : static int kMaxDiagnostics = 0;
      72                 : 
      73               0 : int NCValidatorGetMaxDiagnostics() {
      74               0 :   return kMaxDiagnostics;
      75                 : }
      76                 : 
      77              68 : void NCValidatorSetMaxDiagnostics(int new_value) {
      78              68 :   kMaxDiagnostics = new_value;
      79              68 : }
      80                 : 
      81                 : /* This function is intended to only be called by ValidatePrintInstructionError
      82                 :  * and ValidatePrintOffsetError.
      83                 :  */
      84                 : static void ValidatePrintError(const NaClPcAddress addr,
      85                 :                                const char *msg,
      86            1376 :                                struct NCValidatorState *vstate) {
      87            1376 :   if (vstate->num_diagnostics != 0) {
      88             275 :     NaClErrorReporter* reporter = vstate->dstate.error_reporter;
      89             275 :     (*reporter->printf)(
      90                 :         reporter,
      91                 :         "VALIDATOR: %"NACL_PRIxNaClPcAddress": %s\n", addr, msg);
      92             275 :     --(vstate->num_diagnostics);
      93             275 :     if (vstate->num_diagnostics == 0) {
      94               0 :       (*reporter->printf)(
      95                 :           reporter,
      96                 :           "VALIDATOR: Error limit reached, turning off diagnostics!\n");
      97                 :     }
      98                 :   }
      99            1376 : }
     100                 : 
     101                 : static void ValidatePrintInstructionError(const struct NCDecoderInst *dinst,
     102                 :                                           const char *msg,
     103            1367 :                                           struct NCValidatorState *vstate) {
     104            1367 :   ValidatePrintError(NCPrintableInstructionAddress(dinst), msg, vstate);
     105            1367 : }
     106                 : 
     107                 : static void ValidatePrintOffsetError(const NaClPcAddress addr,
     108                 :                                      const char *msg,
     109               9 :                                      struct NCValidatorState *vstate) {
     110               9 :   ValidatePrintError(vstate->iadrbase + addr, msg, vstate);
     111               9 : }
     112                 : 
     113                 : /* The low-level implementation for stubbing out an instruction. Always use
     114                 :  * this function to (ultimately) stub out instructions. This makes it possible
     115                 :  * to detect when the validator modifies the code.
     116                 :  */
     117                 : static void NCStubOutMem(struct NCValidatorState *vstate, void *ptr,
     118            3786 :                          size_t num) {
     119            3786 :   vstate->stats.didstubout = 1;
     120            3786 :   memset(ptr, kNaClFullStop, num);
     121            3786 : }
     122                 : 
     123                 : void NCBadInstructionError(const struct NCDecoderInst *dinst,
     124            1309 :                            const char *msg) {
     125            1309 :   NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
     126            1309 :   ValidatePrintInstructionError(dinst, msg, vstate);
     127            1309 :   if (vstate->do_stub_out) {
     128            1002 :     NCStubOutMem(vstate, dinst->dstate->memory.mpc,
     129                 :                  dinst->dstate->memory.read_length);
     130                 :   }
     131            1309 : }
     132                 : 
     133                 : /* The set of cpu features to use, if non-NULL.
     134                 :  * NOTE: This global is used to allow the injection of
     135                 :  * a command-line override of CPU features, from that of the local
     136                 :  * CPU id, for the tool ncval. As such, when this global is non-null,
     137                 :  * it uses the injected value this pointer points to as the corresponding
     138                 :  * CPU id results to use.
     139                 :  */
     140                 : static NaClCPUFeaturesX86 *nc_validator_features = NULL;
     141                 : 
     142               0 : void NCValidateSetCPUFeatures(NaClCPUFeaturesX86 *new_features) {
     143               0 :   nc_validator_features = new_features;
     144               0 : }
     145                 : 
     146                 : /* opcode histogram */
     147                 : #if VERBOSE == 1
     148          733461 : void OpcodeHisto(const uint8_t byte1, struct NCValidatorState *vstate) {
     149          733461 :   vstate->opcodehisto[byte1] += 1;
     150          733461 : }
     151                 : 
     152             175 : static void InitOpcodeHisto(struct NCValidatorState *vstate) {
     153                 :   int i;
     154             175 :   for (i = 0; i < 256; i += 1) vstate->opcodehisto[i] = 0;
     155             175 : }
     156                 : 
     157             134 : static void PrintOpcodeHisto(struct NCValidatorState *vstate) {
     158                 :   int i;
     159             134 :   int printed_in_this_row = 0;
     160             134 :   NaClErrorReporter* reporter = vstate->dstate.error_reporter;
     161                 :   if (!VERBOSE) return;
     162             134 :   (*reporter->printf)(reporter, "\nOpcode Histogram;\n");
     163           34438 :   for (i = 0; i < 256; ++i) {
     164           34304 :     if (0 != vstate->opcodehisto[i]) {
     165             558 :       (*reporter->printf)(reporter, "%d\t0x%02x\t", vstate->opcodehisto[i], i);
     166             558 :       ++printed_in_this_row;
     167             558 :       if (printed_in_this_row > 3) {
     168              79 :         printed_in_this_row = 0;
     169              79 :         (*reporter->printf)(reporter, "\n");
     170                 :       }
     171                 :     }
     172                 :   }
     173             134 :   if (0 != printed_in_this_row) {
     174             118 :     (*reporter->printf)(reporter, "\n");
     175                 :   }
     176             134 : }
     177                 : #else
     178                 : #define OpcodeHisto(b, v)
     179                 : #define InitOpcodeHisto(v)
     180                 : #define PrintOpcodeHisto(f, v)
     181                 : #endif /* VERBOSE == 1 */
     182                 : 
     183                 : /* statistics code */
     184          733461 : static void NCStatsInst(struct NCValidatorState *vstate) {
     185          733461 :   vstate->stats.instructions += 1;
     186          733461 : }
     187                 : 
     188           80187 : static void NCStatsCheckTarget(struct NCValidatorState *vstate) {
     189           80187 :   vstate->stats.checktarget += 1;
     190           80187 : }
     191                 : 
     192            4229 : static void NCStatsTargetIndirect(struct NCValidatorState *vstate) {
     193            4229 :   vstate->stats.targetindirect += 1;
     194            4229 : }
     195                 : 
     196            1411 : static void NCStatsSawFailure(struct NCValidatorState *vstate) {
     197            1411 :   vstate->stats.sawfailure = 1;
     198            1411 : }
     199                 : 
     200              16 : void NCStatsInternalError(struct NCValidatorState *vstate) {
     201              16 :   vstate->stats.internalerrors += 1;
     202              16 :   NCStatsSawFailure(vstate);
     203              16 : }
     204                 : 
     205              38 : void NCStatsBadAlignment(struct NCValidatorState *vstate) {
     206              38 :   vstate->stats.badalignment += 1;
     207              38 :   NCStatsSawFailure(vstate);
     208              38 : }
     209                 : 
     210               7 : static void NCStatsSegFault(struct NCValidatorState *vstate) {
     211               7 :   vstate->stats.segfaults += 1;
     212               7 :   NCStatsSawFailure(vstate);
     213               7 : }
     214                 : 
     215             174 : static void NCStatsNewSegment(struct NCValidatorState *vstate) {
     216             174 :   vstate->stats.segments += 1;
     217             174 :   if (vstate->stats.segments > 1) {
     218               0 :     vprint(vstate, (reporter, "error: multiple segments\n"));
     219               0 :     NCStatsSawFailure(vstate);
     220                 :   }
     221             174 : }
     222                 : 
     223              32 : void NCStatsBadTarget(struct NCValidatorState *vstate) {
     224              32 :   vstate->stats.badtarget += 1;
     225              32 :   NCStatsSawFailure(vstate);
     226              32 : }
     227                 : 
     228              22 : static void NCStatsUnsafeIndirect(struct NCValidatorState *vstate) {
     229              22 :   vstate->stats.unsafeindirect += 1;
     230              22 :   NCStatsSawFailure(vstate);
     231              22 : }
     232                 : 
     233              13 : static void NCStatsReturn(struct NCValidatorState *vstate) {
     234              13 :   vstate->stats.returns += 1;
     235              13 :   NCStatsUnsafeIndirect(vstate);
     236              13 :   NCStatsSawFailure(vstate);
     237              13 : }
     238                 : 
     239            1245 : static void NCStatsIllegalInst(struct NCValidatorState *vstate) {
     240            1245 :   vstate->stats.illegalinst += 1;
     241            1245 :   NCStatsSawFailure(vstate);
     242            1245 : }
     243                 : 
     244              38 : static void NCStatsBadPrefix(struct NCValidatorState *vstate) {
     245              38 :   vstate->stats.badprefix += 1;
     246              38 :   vstate->stats.illegalinst += 1; /* a bad prefix is also an invalid inst */
     247              38 :   NCStatsSawFailure(vstate);
     248              38 : }
     249                 : 
     250               0 : static void NCStatsBadInstLength(struct NCValidatorState *vstate) {
     251               0 :   vstate->stats.badinstlength += 1;
     252               0 :   NCStatsSawFailure(vstate);
     253               0 : }
     254                 : 
     255             175 : static void NCStatsInit(struct NCValidatorState *vstate) {
     256             175 :   vstate->stats.instructions = 0;
     257             175 :   vstate->stats.segments = 0;
     258             175 :   vstate->stats.checktarget = 0;
     259             175 :   vstate->stats.targetindirect = 0;
     260             175 :   vstate->stats.badtarget = 0;
     261             175 :   vstate->stats.unsafeindirect = 0;
     262             175 :   vstate->stats.returns = 0;
     263             175 :   vstate->stats.illegalinst = 0;
     264             175 :   vstate->stats.badalignment = 0;
     265             175 :   vstate->stats.internalerrors = 0;
     266             175 :   vstate->stats.badinstlength = 0;
     267             175 :   vstate->stats.badprefix = 0;
     268             175 :   vstate->stats.didstubout = 0;
     269             175 :   vstate->stats.sawfailure = 0;
     270             175 :   InitOpcodeHisto(vstate);
     271             175 : }
     272                 : 
     273             134 : void NCStatsPrint(struct NCValidatorState *vstate) {
     274                 :   NaClErrorReporter* reporter;
     275             134 :   if (!VERBOSE || (vstate == NULL)) return;
     276             134 :   reporter = vstate->dstate.error_reporter;
     277             134 :   PrintOpcodeHisto(vstate);
     278             134 :   (*reporter->printf)(reporter, "Analysis Summary:\n");
     279             134 :   (*reporter->printf)(reporter, "%d Checked instructions\n",
     280                 :                       vstate->stats.instructions);
     281             134 :   (*reporter->printf)(reporter, "%d checked jump targets\n",
     282                 :                       vstate->stats.checktarget);
     283             134 :   (*reporter->printf)(
     284                 :       reporter, "%d calls/jumps need dynamic checking (%0.2f%%)\n",
     285                 :       vstate->stats.targetindirect,
     286                 :       vstate->stats.instructions ?
     287                 :       100.0 * vstate->stats.targetindirect/vstate->stats.instructions : 0);
     288             134 :   if (vstate->stats.didstubout) {
     289               1 :     (*reporter->printf)(reporter, "Some instructions were replaced with HLTs");
     290                 :   }
     291             134 :   (*reporter->printf)(reporter, "\nProblems:\n");
     292             134 :   (*reporter->printf)(reporter, "%d illegal instructions\n",
     293                 :                    vstate->stats.illegalinst);
     294             134 :   (*reporter->printf)(reporter,
     295                 :                       "%d bad jump targets\n", vstate->stats.badtarget);
     296             134 :   (*reporter->printf)(
     297                 :       reporter, "%d illegal unprotected indirect jumps (including ret)\n",
     298                 :       vstate->stats.unsafeindirect);
     299             134 :   (*reporter->printf)(reporter, "%d instruction alignment defects\n",
     300                 :                       vstate->stats.badalignment);
     301             134 :   (*reporter->printf)(reporter, "%d segmentation errors\n",
     302                 :                       vstate->stats.segfaults);
     303             134 :   (*reporter->printf)(reporter, "%d bad prefix\n",
     304                 :                       vstate->stats.badprefix);
     305             134 :   (*reporter->printf)(reporter, "%d bad instruction length\n",
     306                 :                       vstate->stats.badinstlength);
     307             134 :   (*reporter->printf)(reporter, "%d internal errors\n",
     308                 :                       vstate->stats.internalerrors);
     309                 : }
     310                 : 
     311                 : /***********************************************************************/
     312                 : /* jump target table                                                   */
     313                 : const uint8_t nc_iadrmasks[8] = {0x01, 0x02, 0x04, 0x08,
     314                 :                                  0x10, 0x20, 0x40, 0x80};
     315                 : 
     316                 : /* forward declarations, needed for registration */
     317                 : static Bool ValidateInst(const NCDecoderInst *dinst);
     318                 : static Bool ValidateInstReplacement(NCDecoderStatePair* tthis,
     319                 :                                     NCDecoderInst *dinst_old,
     320                 :                                     NCDecoderInst *dinst_new);
     321                 : static void NCJumpSummarize(struct NCValidatorState* vstate);
     322                 : 
     323                 : /*
     324                 :  * NCValidateInit: Initialize NaCl validator internal state
     325                 :  * Parameters:
     326                 :  *    vbase: base virtual address for code segment
     327                 :  *    codesize: size in bytes of code segment
     328                 :  *    alignment: 16 or 32, specifying alignment
     329                 :  * Returns:
     330                 :  *    an initialized struct NCValidatorState * if everything is okay,
     331                 :  *    else NULL
     332                 :  */
     333                 : struct NCValidatorState *NCValidateInit(const NaClPcAddress vbase,
     334                 :                                         const NaClPcAddress codesize,
     335                 :                                         const uint8_t alignment,
     336             177 :                                         NaClCPUFeaturesX86 *features) {
     337             177 :   struct NCValidatorState *vstate = NULL;
     338                 : 
     339                 :   dprint(("NCValidateInit(%"NACL_PRIxNaClPcAddressAll
     340                 :           ", %"NACL_PRIxNaClMemorySizeAll", %08x)\n", vbase, codesize,
     341                 :           alignment));
     342                 :   do {
     343             177 :     if (alignment != 16 && alignment != 32)
     344               1 :       break;
     345             176 :     if ((vbase & (alignment - 1)) != 0)
     346               1 :       break;
     347             175 :     if (features == NULL)
     348               0 :       break;
     349                 :     dprint(("ncv_init(%"NACL_PRIxNaClPcAddress", %"NACL_PRIxNaClMemorySize
     350                 :             ")\n", vbase, codesize));
     351             175 :     vstate = (struct NCValidatorState *)calloc(1, sizeof(*vstate));
     352             175 :     if (vstate == NULL)
     353               0 :       break;
     354                 :     /* Record default error reporter here, since we don't construct
     355                 :      * the decoder state until the call to NCValidateSegment. This allows
     356                 :      * us to update the error reporter in the decoder state properly.
     357                 :      */
     358             175 :     vstate->dstate.error_reporter = &kNCNullErrorReporter;
     359             175 :     vstate->num_diagnostics = kMaxDiagnostics;
     360             175 :     vstate->iadrbase = vbase;
     361             175 :     vstate->codesize = codesize;
     362             175 :     vstate->alignment = alignment;
     363             175 :     vstate->alignmask = alignment-1;
     364             175 :     vstate->vttable = (uint8_t *)calloc(NCIATOffset(codesize) + 1, 1);
     365             175 :     vstate->kttable = (uint8_t *)calloc(NCIATOffset(codesize) + 1, 1);
     366             175 :     vstate->pattern_nonfirst_insts_table = NULL;
     367             175 :     vstate->summarize_fn = NCJumpSummarize;
     368             175 :     vstate->do_stub_out = 0;
     369             175 :     if (vstate->vttable == NULL || vstate->kttable == NULL)
     370                 :       break;
     371                 :     dprint(("  allocated tables\n"));
     372             175 :     NCStatsInit(vstate);
     373             175 :     NaClCopyCPUFeatures(&vstate->cpufeatures, features);
     374             175 :     return vstate;
     375                 :   } while (0);
     376                 :   /* Failure. Clean up memory before returning. */
     377               2 :   if (NULL != vstate) {
     378               0 :     if (NULL != vstate->kttable)
     379               0 :       free(vstate->kttable);
     380               0 :     if (NULL != vstate->vttable)
     381               0 :       free(vstate->vttable);
     382               0 :     free(vstate);
     383                 :   }
     384               2 :   return NULL;
     385                 : }
     386                 : 
     387                 : void NCValidateSetStubOutMode(struct NCValidatorState *vstate,
     388               3 :                               int do_stub_out) {
     389               3 :   vstate->do_stub_out = do_stub_out;
     390                 :   /* We also turn off error diagnostics, under the assumption
     391                 :    * you don't want them. (Note: if the user wants them,
     392                 :    * you can run ncval to get them)/
     393                 :    */
     394               3 :   if (do_stub_out) {
     395               3 :     NCValidateSetNumDiagnostics(vstate, 0);
     396                 :   }
     397               3 : }
     398                 : 
     399                 : void NCValidateSetNumDiagnostics(struct NCValidatorState* vstate,
     400               6 :                                  int num_diagnostics) {
     401               6 :   vstate->num_diagnostics = num_diagnostics;
     402               6 : }
     403                 : 
     404                 : void NCValidateSetErrorReporter(struct NCValidatorState* state,
     405             168 :                                 NaClErrorReporter* error_reporter) {
     406             168 :   NCDecoderStateSetErrorReporter(&state->dstate, error_reporter);
     407             168 : }
     408                 : 
     409                 : static INLINE void RememberInstructionBoundary(const NCDecoderInst *dinst,
     410          733461 :                                               struct NCValidatorState *vstate) {
     411                 :   /* The decoder should never pass us an out-of-bounds instruction. */
     412          733461 :   CHECK(dinst->inst_addr < vstate->codesize);
     413          733461 :   if (NCGetAdrTable(dinst->inst_addr, vstate->vttable)) {
     414               0 :     vprint(vstate, (reporter,
     415                 :                     "RememberIP: Saw inst at %"NACL_PRIxNaClPcAddressAll
     416                 :                     " twice\n", NCPrintableInstructionAddress(dinst)));
     417               0 :     NCStatsInternalError(vstate);
     418               0 :     return;
     419                 :   }
     420          733461 :   NCStatsInst(vstate);
     421          733461 :   NCSetAdrTable(dinst->inst_addr, vstate->vttable);
     422                 : }
     423                 : 
     424                 : static void RememberJumpTarget(const NCDecoderInst *dinst, int32_t jump_offset,
     425           63629 :                                struct NCValidatorState *vstate) {
     426                 :   NaClPcAddress target = (dinst->inst_addr + dinst->inst.bytes.length
     427           63629 :                           + jump_offset);
     428                 : 
     429           63629 :   if (target < vstate->codesize) {
     430           63417 :     NCSetAdrTable(target, vstate->kttable);
     431             212 :   } else if ((target & vstate->alignmask) == 0) {
     432                 :     /* Allow bundle-aligned jumps. */
     433              27 :   } else if (dinst->unchanged) {
     434                 :     /* If we are replacing this instruction during dynamic code modification
     435                 :      * and it has not changed, the jump target must be valid because the
     436                 :      * instruction has been previously validated.  However, we may be only
     437                 :      * replacing a subsection of the code segment and therefore may not have
     438                 :      * information about instruction boundaries outside of the code being
     439                 :      * replaced. Therefore, we allow unaligned direct jumps outside of the code
     440                 :      * being validated if and only if the instruction is unchanged.
     441                 :      * If dynamic code replacement is not being performed, inst->unchanged
     442                 :      * should always be false.
     443                 :      */
     444                 :   } else {
     445              27 :     ValidatePrintInstructionError(dinst, "JUMP TARGET out of range", vstate);
     446              27 :     NCStatsBadTarget(vstate);
     447                 :   }
     448           63629 : }
     449                 : 
     450                 : static void ForgetInstructionBoundary(const NCDecoderInst *dinst,
     451            4226 :                                      struct NCValidatorState *vstate) {
     452                 :   /* The decoder should never pass us an out-of-bounds instruction. */
     453            4226 :   CHECK(dinst->inst_addr < vstate->codesize);
     454            4226 :   NCClearAdrTable(dinst->inst_addr, vstate->vttable);
     455            4226 :   if (NULL != vstate->pattern_nonfirst_insts_table) {
     456            2669 :     NCSetAdrTable(dinst->inst_addr, vstate->pattern_nonfirst_insts_table);
     457                 :   }
     458            4226 : }
     459                 : 
     460             174 : int NCValidateFinish(struct NCValidatorState *vstate) {
     461             174 :   if (vstate == NULL) {
     462                 :     dprint(("validator not initialized. Did you call ncvalidate_init()?\n"));
     463                 :     /* non-zero indicates failure */
     464               0 :     return 1;
     465                 :   }
     466                 : 
     467                 :   /* If we are stubbing out code, the following checks don't provide any
     468                 :    * usefull information, so quit early.
     469                 :    */
     470             174 :   if (vstate->do_stub_out) return vstate->stats.sawfailure;
     471                 : 
     472                 :   /* Double check that the base address matches the alignment constraint. */
     473             171 :   if (vstate->iadrbase & vstate->alignmask) {
     474                 :     /* This should never happen because the alignment of iadrbase is */
     475                 :     /* checked in NCValidateInit(). */
     476               0 :     ValidatePrintOffsetError(0, "Bad base address alignment", vstate);
     477               0 :     NCStatsBadAlignment(vstate);
     478                 :   }
     479                 : 
     480                 :   /* Apply summary analysis to collected data during pass over
     481                 :    * instructions.
     482                 :    */
     483             171 :   (*(vstate->summarize_fn))(vstate);
     484                 : 
     485                 :   /* Now that all the work is done, generate return code. */
     486                 :   /* Return zero if there are no problems.                */
     487             171 :   return (vstate->stats.sawfailure);
     488                 : }
     489                 : 
     490             175 : void NCValidateFreeState(struct NCValidatorState **vstate) {
     491             175 :   CHECK(*vstate != NULL);
     492             175 :   free((*vstate)->vttable);
     493             175 :   free((*vstate)->kttable);
     494             175 :   free((*vstate)->pattern_nonfirst_insts_table);
     495             175 :   free(*vstate);
     496             175 :   *vstate = NULL;
     497             175 : }
     498                 : 
     499                 : /* ValidateSFenceClFlush is called for the sfence/clflush opcode 0f ae /7 */
     500                 : /* It returns 0 if the current instruction is implemented, and 1 if not.  */
     501               2 : static int ValidateSFenceClFlush(const NCDecoderInst *dinst) {
     502               2 :   NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
     503               2 :   uint8_t mrm = NCInstBytesByteInline(&dinst->inst_bytes, 2);
     504                 : 
     505               2 :   if (modrm_modInline(mrm) == 3) {
     506                 :     /* this is an sfence */
     507               1 :     if (NaClGetCPUFeature(&vstate->cpufeatures, NaClCPUFeature_FXSR))
     508               1 :       return 0;
     509               0 :     return 1;
     510                 :   } else {
     511                 :     /* this is an clflush */
     512               1 :     if (NaClGetCPUFeature(&vstate->cpufeatures, NaClCPUFeature_CLFLUSH))
     513               1 :       return 0;
     514               0 :     return 1;
     515                 :   }
     516                 : }
     517                 : 
     518            9635 : static void ValidateCallAlignment(const NCDecoderInst *dinst) {
     519            9635 :   NaClPcAddress fallthru = dinst->inst_addr + dinst->inst.bytes.length;
     520            9635 :   struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
     521            9635 :   if (fallthru & vstate->alignmask) {
     522              31 :     ValidatePrintInstructionError(dinst, "Bad call alignment", vstate);
     523                 :     /* This makes bad call alignment a fatal error. */
     524              31 :     NCStatsBadAlignment(vstate);
     525                 :   }
     526            9635 : }
     527                 : 
     528           32725 : static void ValidateJmp8(const NCDecoderInst *dinst) {
     529                 :   int8_t offset = NCInstBytesByteInline(&dinst->inst_bytes,
     530           32725 :                                         dinst->inst.prefixbytes+1);
     531           32725 :   struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
     532           32725 :   NCStatsCheckTarget(vstate);
     533           32725 :   RememberJumpTarget(dinst, offset, vstate);
     534           32725 : }
     535                 : 
     536           30904 : static void ValidateJmpz(const NCDecoderInst *dinst) {
     537                 :   NCInstBytesPtr opcode;
     538                 :   uint8_t opcode0;
     539                 :   int32_t offset;
     540           30904 :   NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
     541           30904 :   NCInstBytesPtrInitInc(&opcode, &dinst->inst_bytes,
     542                 :                         dinst->inst.prefixbytes);
     543           30904 :   opcode0 = NCInstBytesByteInline(&opcode, 0);
     544           30904 :   NCStatsCheckTarget(vstate);
     545           30904 :   if (opcode0 == 0x0f) {
     546                 :     /* Multbyte opcode. Intruction is of form:
     547                 :      *    0F80 .. 0F8F: jCC $Jz
     548                 :      */
     549                 :     NCInstBytesPtr opcode_2;
     550           13623 :     NCInstBytesPtrInitInc(&opcode_2, &opcode, 2);
     551           13623 :     offset = NCInstBytesInt32(&opcode_2, dinst->inst.immbytes);
     552                 :   } else {
     553                 :     /* Single byte opcode. Must be one of:
     554                 :      *    E8: call $Jz
     555                 :      *    E9: jmp $Jx
     556                 :      */
     557                 :     NCInstBytesPtr opcode_1;
     558           17281 :     NCInstBytesPtrInitInc(&opcode_1, &opcode, 1);
     559           17281 :     offset = NCInstBytesInt32(&opcode_1, dinst->inst.immbytes);
     560                 :     /* as a courtesy, check call alignment correctness */
     561           17281 :     if (opcode0 == 0xe8) ValidateCallAlignment(dinst);
     562                 :   }
     563           30904 :   RememberJumpTarget(dinst, offset, vstate);
     564           30904 : }
     565                 : 
     566                 : /*
     567                 :  * The NaCl five-byte safe indirect calling sequence looks like this:
     568                 :  *   83 e0 e0                 and  $0xe0,%eax
     569                 :  *   ff d0                    call *%eax
     570                 :  * The call may be replaced with a ff e0 jmp. Any register may
     571                 :  * be used, not just eax. The validator requires exactly this
     572                 :  * sequence.
     573                 :  * Note: The code above assumes 32-bit alignment. Change e0 as appropriate
     574                 :  * if a different alignment is used.
     575                 :  */
     576            4235 : static void ValidateIndirect5(const NCDecoderInst *dinst) {
     577                 :   NCInstBytesPtr jmpopcode;
     578                 :   NCInstBytesPtr andopcode;
     579                 :   uint8_t               mrm;
     580                 :   uint8_t               targetreg;
     581            4235 :   const uint8_t         kReg_ESP = 4;
     582            4235 :   NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
     583                 : 
     584            4235 :   struct NCDecoderInst *andinst = PreviousInst(dinst, 1);
     585            4235 :   if ((andinst == NULL) || (andinst->inst.bytes.length != 3)) {
     586               6 :     NCBadInstructionError(dinst, "Unsafe indirect jump");
     587               6 :     NCStatsUnsafeIndirect(vstate);
     588               6 :     return;
     589                 :   }
     590                 :   /* note: no prefixbytes allowed */
     591            4229 :   NCInstBytesPtrInitInc(&jmpopcode, &dinst->inst_bytes, 0);
     592                 :   /* note: no prefixbytes allowed */
     593            4229 :   NCInstBytesPtrInitInc(&andopcode, &andinst->inst_bytes, 0);
     594            4229 :   mrm = NCInstBytesByteInline(&jmpopcode, 1);
     595                 :   /* Note that the modrm_rm field holds the
     596                 :    * target addr the modrm_reg is the opcode.
     597                 :    */
     598            4229 :   targetreg = modrm_rmInline(mrm);
     599            4229 :   NCStatsCheckTarget(vstate);
     600            4229 :   NCStatsTargetIndirect(vstate);
     601                 :   do {
     602                 :     /* no prefix bytes allowed */
     603            4229 :     if (dinst->inst.prefixbytes != 0) break;
     604            4229 :     if (dinst->inst.prefixbytes != 0) break;
     605                 :     /* Check all the opcodes. */
     606                 :     /* In GROUP5, 2 => call, 4 => jmp */
     607            4229 :     if (NCInstBytesByteInline(&jmpopcode, 0) != 0xff) break;
     608            4229 :     if ((modrm_regInline(mrm) != 2) && (modrm_regInline(mrm) != 4)) break;
     609                 :     /* Issue 32: disallow unsafe call/jump indirection */
     610                 :     /* example:    ff 12     call (*edx)               */
     611                 :     /* Reported by defend.the.world on 11 Dec 2008     */
     612            4229 :     if (modrm_modInline(mrm) != 3) break;
     613            4228 :     if (targetreg == kReg_ESP) break;
     614            4227 :     if (NCInstBytesByteInline(&andopcode, 0) != 0x83) break;
     615                 :     /* check modrm bytes of or and and instructions */
     616            4227 :     if (NCInstBytesByteInline(&andopcode, 1) != (0xe0 | targetreg)) break;
     617                 :     /* check mask */
     618            4227 :     if (NCInstBytesByteInline(&andopcode, 2) !=
     619               1 :         (0x0ff & ~vstate->alignmask)) break;
     620                 :     /* All checks look good. Make the sequence 'atomic.' */
     621            4226 :     ForgetInstructionBoundary(dinst, vstate);
     622                 :     /* as a courtesy, check call alignment correctness */
     623            4226 :     if (modrm_regInline(mrm) == 2) ValidateCallAlignment(dinst);
     624            4226 :     return;
     625                 :   } while (0);
     626               3 :   NCBadInstructionError(dinst, "Unsafe indirect jump");
     627               3 :   NCStatsUnsafeIndirect(vstate);
     628                 : }
     629                 : 
     630                 : /* Checks if the set of prefixes are allowed for the instruction.
     631                 :  * By default, we only allow prefixes if they have been allowed
     632                 :  * by the bad prefix mask generated inside ncdecode_table.c.
     633                 :  * These masks are defined by the NaClInstType of the instruction.
     634                 :  * See ncdecode_table.c for more details on how these masks are set.
     635                 :  *
     636                 :  * Currently:
     637                 :  * Only 386, 386L, 386R, 386RE instruction allow  Data 16
     638                 :  * (unless used as part of instruction selection in a multibyte instruction).
     639                 :  * Only 386, JMP8, and JMPZ allow segment registers prefixes.
     640                 :  * Only 386L and CMPXCHG8B allow the LOCK prefix.
     641                 :  * Only 386R and 386RE instructions allow the REP prefix.
     642                 :  * Only 386RE instructions allow the REPNE prefix.
     643                 :  *
     644                 :  * Note: The prefixmask does not include the prefix value (if any) used to
     645                 :  * select multiple byte instructions. Such prefixes have been moved to
     646                 :  * opcode_prefixmask, so that the selection (based on that prefix) has
     647                 :  * been recorded.
     648                 :  *
     649                 :  * In general, we do not allow multiple prefixes. Exceptions are as
     650                 :  * follows:
     651                 :  *   1 - Data 16 is allowed on lock instructions, so that 2 byte values
     652                 :  *       can be locked.
     653                 :  *   2 - Multibyte instructions that are selected
     654                 :  *       using prefix values Data 16, REP and REPNE, can only have
     655                 :  *       one of these prefixes (Combinations of these three prefixes
     656                 :  *       are not allowed for such multibyte instructions).
     657                 :  *   3 - Locks are only allowed on instructions with type 386L. The
     658                 :  *       exception is inst cmpxch8b, which also can have a lock.
     659                 :  *   4 - The only two prefix byte combination allowed is Data 16 and Lock.
     660                 :  *   5 - Long nops that are hard coded can contain more than one prefix.
     661                 :  *       See ncdecode.c for details (they don't use ValidatePrefixes).
     662                 :  */
     663          733461 : static Bool ValidatePrefixes(const NCDecoderInst *dinst) {
     664          733461 :   if (dinst->inst.prefixbytes == 0) return TRUE;
     665                 : 
     666            4323 :   if ((dinst->inst.prefixmask &
     667                 :        BadPrefixMask[dinst->opinfo->insttype]) != 0) {
     668              33 :     return FALSE;
     669                 :   }
     670                 : 
     671                 :   /* If a multibyte instruction is using a selection prefix, be
     672                 :    * sure that there is no conflict with other selection prefixes.
     673                 :    */
     674            4290 :   if ((dinst->inst.opcode_prefixmask != 0) &&
     675                 :       ((dinst->inst.prefixmask &
     676                 :         (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) != 0)) {
     677               0 :     return FALSE;
     678                 :   }
     679                 : 
     680                 :   /* Only allow a lock if it is a 386L instruction, or the special
     681                 :    * cmpxchg8b instruction.
     682                 :    */
     683            4290 :   if (dinst->inst.prefixmask & kPrefixLOCK) {
     684             115 :     if ((dinst->opinfo->insttype != NACLi_386L) &&
     685                 :         (dinst->opinfo->insttype != NACLi_CMPXCHG8B)) {
     686               0 :       return FALSE;
     687                 :     }
     688                 :   }
     689                 : 
     690                 :   /* Only allow more than one prefix if two prefixes, and they are
     691                 :    * data 16 and lock.
     692                 :    */
     693            4290 :   if ((dinst->inst.prefixbytes > 1) &&
     694                 :       !((dinst->inst.prefixbytes == 2) &&
     695                 :         (dinst->inst.prefixmask == (kPrefixLOCK | kPrefixDATA16)) &&
     696                 :         /* Be sure data 16 (66) appears before lock (f0) prefix. */
     697                 :         (dinst->inst.lock_prefix_index == 1))) {
     698               4 :     return FALSE;
     699                 :   }
     700                 : 
     701            4286 :   return TRUE;
     702                 : }
     703                 : 
     704                 : static const size_t kMaxValidInstLength = 11;
     705                 : 
     706                 : /* The modrm mod field is a two-bit value. Values 00, 01, and, 10
     707                 :  * define memory references. Value 11 defines register accesses instead
     708                 :  * of memory.
     709                 :  */
     710                 : static const int kModRmModFieldDefinesRegisterRef = 0x3;
     711                 : 
     712          733461 : static Bool ValidateInst(const NCDecoderInst *dinst) {
     713                 :   NaClCPUFeaturesX86 *cpufeatures;
     714          733461 :   int squashme = 0;
     715                 :   NCValidatorState* vstate;
     716          733461 :   if (dinst == NULL) return TRUE;
     717          733461 :   vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
     718                 : 
     719          733461 :   OpcodeHisto(NCInstBytesByteInline(&dinst->inst_bytes,
     720                 :                                     dinst->inst.prefixbytes),
     721                 :               vstate);
     722          733461 :   RememberInstructionBoundary(dinst, vstate);
     723                 : 
     724          733461 :   cpufeatures = &(vstate->cpufeatures);
     725                 : 
     726          733461 :   if (!ValidatePrefixes(dinst)) {
     727              37 :     NCBadInstructionError(dinst, "Bad prefix usage");
     728              37 :     NCStatsBadPrefix(vstate);
     729                 :   }
     730                 : 
     731          733461 :   if ((dinst->opinfo->insttype != NACLi_NOP) &&
     732                 :       ((size_t) (dinst->inst.bytes.length - dinst->inst.prefixbytes)
     733                 :        > kMaxValidInstLength)) {
     734               0 :     NCBadInstructionError(dinst, "Instruction too long");
     735               0 :     NCStatsBadInstLength(vstate);
     736                 :   }
     737                 : 
     738          733461 :   switch (dinst->opinfo->insttype) {
     739                 :     case NACLi_NOP:
     740                 :     case NACLi_386:
     741                 :     case NACLi_386L:
     742                 :     case NACLi_386R:
     743                 :     case NACLi_386RE:
     744          659291 :       break;
     745                 :     case NACLi_JMP8:
     746           32725 :       ValidateJmp8(dinst);
     747           32725 :       break;
     748                 :     case NACLi_JMPZ:
     749           30904 :       ValidateJmpz(dinst);
     750           30904 :       break;
     751                 :     case NACLi_INDIRECT:
     752            4235 :       ValidateIndirect5(dinst);
     753            4235 :       break;
     754                 :     case NACLi_X87:
     755            3605 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87);
     756            3605 :       break;
     757                 :     case NACLi_SFENCE_CLFLUSH:
     758               2 :       squashme = ValidateSFenceClFlush(dinst);
     759               2 :       break;
     760                 :     case NACLi_CMPXCHG8B:
     761                 :       /* Only allow if the modrm mod field accesses memory.
     762                 :        * This stops us from accepting f00f on multiple bytes.
     763                 :        * http://en.wikipedia.org/wiki/Pentium_F00F_bug
     764                 :        */
     765               2 :       if (modrm_modInline(dinst->inst.mrm)
     766                 :           == kModRmModFieldDefinesRegisterRef) {
     767               1 :         NCBadInstructionError(dinst, "Illegal instruction");
     768               1 :         NCStatsIllegalInst(vstate);
     769                 :       }
     770               2 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CX8);
     771               2 :       break;
     772                 :     case NACLi_CMOV:
     773             778 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV);
     774             778 :       break;
     775                 :     case NACLi_FCMOV:
     776              14 :       squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV) &&
     777                 :                    NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87));
     778              14 :       break;
     779                 :     case NACLi_RDTSC:
     780               0 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_TSC);
     781               0 :       break;
     782                 :     case NACLi_MMX:
     783               2 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX);
     784               2 :       break;
     785                 :     case NACLi_MMXSSE2:
     786                 :       /* Note: We accept these instructions if either MMX or SSE2 bits */
     787                 :       /* are set, in case MMX instructions go away someday...          */
     788               1 :       squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX) ||
     789                 :                    NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2));
     790               1 :       break;
     791                 :     case NACLi_SSE:
     792              10 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE);
     793              10 :       break;
     794                 :     case NACLi_SSE2:
     795             631 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2);
     796             631 :       break;
     797                 :     case NACLi_SSE3:
     798               1 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE3);
     799               1 :       break;
     800                 :     case NACLi_SSE4A:
     801               1 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE4A);
     802               1 :       break;
     803                 :     case NACLi_SSE41:
     804               3 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE41);
     805               3 :       break;
     806                 :     case NACLi_SSE42:
     807               2 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE42);
     808               2 :       break;
     809                 :     case NACLi_MOVBE:
     810               0 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MOVBE);
     811               0 :       break;
     812                 :     case NACLi_POPCNT:
     813               1 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_POPCNT);
     814               1 :       break;
     815                 :     case NACLi_LZCNT:
     816               1 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_LZCNT);
     817               1 :       break;
     818                 :     case NACLi_SSSE3:
     819               3 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSSE3);
     820               3 :       break;
     821                 :     case NACLi_3DNOW:
     822               2 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_3DNOW);
     823               2 :       break;
     824                 :     case NACLi_E3DNOW:
     825               1 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_E3DNOW);
     826               1 :       break;
     827                 :     case NACLi_SSE2x:
     828                 :       /* This case requires CPUID checking code */
     829                 :       /* Note: DATA16 prefix required. The generated table
     830                 :        * for group 14 (which the only 2 SSE2x instructions are in),
     831                 :        * allows instructions with and without a 66 prefix. However,
     832                 :        * the SSE2x instructions psrldq and pslldq are only allowed
     833                 :        * with the 66 prefix. Hence, this code has been added to
     834                 :        * do this check.
     835                 :        */
     836               2 :       if (!(dinst->inst.opcode_prefixmask & kPrefixDATA16)) {
     837               1 :         NCBadInstructionError(dinst, "Bad prefix usage");
     838               1 :         NCStatsBadPrefix(vstate);
     839                 :       }
     840               2 :       squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2);
     841               2 :       break;
     842                 : 
     843                 :     case NACLi_RETURN:
     844              13 :       NCBadInstructionError(dinst, "ret instruction (not allowed)");
     845              13 :       NCStatsReturn(vstate);
     846                 :       /* ... and fall through to illegal instruction code */
     847                 :     case NACLi_EMMX:
     848                 :       /* EMMX needs to be supported someday but isn't ready yet. */
     849                 :     case NACLi_INVALID:
     850                 :     case NACLi_ILLEGAL:
     851                 :     case NACLi_SYSTEM:
     852                 :     case NACLi_RDMSR:
     853                 :     case NACLi_RDTSCP:
     854                 :     case NACLi_SYSCALL:
     855                 :     case NACLi_SYSENTER:
     856                 :     case NACLi_LONGMODE:
     857                 :     case NACLi_SVM:
     858                 :     case NACLi_OPINMRM:
     859                 :     case NACLi_3BYTE:
     860                 :     case NACLi_CMPXCHG16B: {
     861            1228 :         NCBadInstructionError(dinst, "Illegal instruction");
     862            1228 :         NCStatsIllegalInst(vstate);
     863            1228 :         break;
     864                 :       }
     865                 :     case NACLi_UNDEFINED: {
     866              16 :         NCBadInstructionError(dinst, "Undefined instruction");
     867              16 :         NCStatsIllegalInst(vstate);
     868              16 :         NCStatsInternalError(vstate);
     869              16 :         break;
     870                 :       }
     871                 :     default:
     872               0 :       NCBadInstructionError(dinst, "Undefined instruction type");
     873               0 :       NCStatsInternalError(vstate);
     874                 :       break;
     875                 :   }
     876          733461 :   if (squashme) {
     877            2784 :     NCStubOutMem(vstate, dinst->dstate->memory.mpc,
     878                 :                  dinst->dstate->memory.read_length);
     879                 :   }
     880          733461 :   return TRUE;
     881                 : }
     882                 : 
     883                 : /*
     884                 :  * Validate that two nacljmps are byte-for-byte identical.  Note that
     885                 :  * one of the individual jumps must be validated in isolation with
     886                 :  * ValidateIndirect5() before this is called.
     887                 :  */
     888                 : static void ValidateIndirect5Replacement(NCDecoderInst *dinst_old,
     889               0 :                                          NCDecoderInst *dinst_new) {
     890                 :   do {
     891                 :     /* check that the and-guard is 3 bytes and bit-for-bit identical */
     892               0 :     NCDecoderInst *andinst_old = PreviousInst(dinst_old, 1);
     893               0 :     NCDecoderInst *andinst_new = PreviousInst(dinst_new, 1);
     894               0 :     if ((andinst_old == NULL) || (andinst_old->inst.bytes.length != 3)) break;
     895               0 :     if ((andinst_new == NULL) || (andinst_new->inst.bytes.length != 3)) break;
     896               0 :     if (memcmp(andinst_old->inst.bytes.byte,
     897               0 :                andinst_new->inst.bytes.byte, 3) != 0) break;
     898                 : 
     899                 :     /* check that the indirect-jmp is 2 bytes and bit-for-bit identical */
     900               0 :     if (dinst_old->inst.bytes.length != 2) break;
     901               0 :     if (dinst_new->inst.bytes.length != 2) break;
     902               0 :     if (memcmp(dinst_old->inst.bytes.byte,
     903               0 :                dinst_new->inst.bytes.byte, 2) != 0) break;
     904                 : 
     905               0 :     return;
     906                 :   } while (0);
     907               0 :   NCBadInstructionError(dinst_new,
     908                 :                         "Replacement indirect jump must match original");
     909               0 :   NCStatsUnsafeIndirect(NCVALIDATOR_STATE_DOWNCAST(dinst_new->dstate));
     910                 : }
     911                 : 
     912                 : /*
     913                 :  * Check that mstate_new is a valid replacement instruction for mstate_old.
     914                 :  * Note that mstate_old was validated when it was inserted originally.
     915                 :  */
     916                 : static Bool ValidateInstReplacement(NCDecoderStatePair* tthis,
     917                 :                                     NCDecoderInst *dinst_old,
     918               0 :                                     NCDecoderInst *dinst_new) {
     919               0 :   dinst_new->unchanged = memcmp(dinst_old->inst.bytes.byte,
     920                 :                                 dinst_new->inst.bytes.byte,
     921                 :                                 dinst_new->inst.bytes.length) == 0;
     922               0 :   ValidateInst(dinst_new);
     923                 : 
     924               0 :   if (dinst_old->opinfo->insttype == NACLi_INDIRECT
     925                 :     || dinst_new->opinfo->insttype == NACLi_INDIRECT) {
     926                 :     /* Verify that nacljmps never change */
     927               0 :     ValidateIndirect5Replacement(dinst_old, dinst_new);
     928                 :   }
     929               0 :   return TRUE;
     930                 : }
     931                 : 
     932                 : /* Create the decoder state for the validator state, using the
     933                 :  * given parameters.
     934                 :  */
     935                 : static void NCValidateDStateInit(NCValidatorState *vstate,
     936                 :                                  uint8_t *mbase, NaClPcAddress vbase,
     937             174 :                                  NaClMemorySize sz) {
     938             174 :   NCDecoderState* dstate = &vstate->dstate;
     939                 :   /* Note: Based on the current API, we must grab the error reporter
     940                 :    * and reinstall it, after the call to NCValidateDStateInit, so that
     941                 :    * we don't replace it with the default error reporter.
     942                 :    */
     943             174 :   NaClErrorReporter* reporter = dstate->error_reporter;
     944             174 :   NCDecoderStateConstruct(dstate, mbase, vbase, sz,
     945                 :                           vstate->inst_buffer, kNCValidatorInstBufferSize);
     946             174 :   dstate->action_fn = ValidateInst;
     947             174 :   dstate->new_segment_fn = (NCDecoderStateMethod) NCStatsNewSegment;
     948             174 :   dstate->segmentation_error_fn = (NCDecoderStateMethod) NCStatsSegFault;
     949             174 :   dstate->internal_error_fn = (NCDecoderStateMethod) NCStatsInternalError;
     950             174 :   NCDecoderStateSetErrorReporter(dstate, reporter);
     951             174 : }
     952                 : 
     953                 : void NCValidateSegment(uint8_t *mbase, NaClPcAddress vbase, NaClMemorySize sz,
     954             174 :                        struct NCValidatorState *vstate) {
     955                 :   /* Sanity checks */
     956                 :   /* TODO(ncbray): remove redundant vbase/size args. */
     957             174 :   if ((vbase & (vstate->alignment - 1)) != 0) {
     958               0 :     ValidatePrintOffsetError(0, "Bad vbase alignment", vstate);
     959               0 :     NCStatsSegFault(vstate);
     960               0 :     return;
     961                 :   }
     962             174 :   if (vbase != vstate->iadrbase) {
     963               0 :     ValidatePrintOffsetError(0, "Mismatched vbase addresses", vstate);
     964               0 :     NCStatsSegFault(vstate);
     965               0 :     return;
     966                 :   }
     967             174 :   if (sz != vstate->codesize) {
     968               0 :     ValidatePrintOffsetError(0, "Mismatched code size", vstate);
     969               0 :     NCStatsSegFault(vstate);
     970               0 :     return;
     971                 :   }
     972                 : 
     973             174 :   sz = NCHaltTrimSize(mbase, sz, vstate->alignment);
     974             174 :   vstate->codesize = sz;
     975                 : 
     976             174 :   if (sz == 0) {
     977               0 :     ValidatePrintOffsetError(0, "Bad text segment (zero size)", vstate);
     978               0 :     NCStatsSegFault(vstate);
     979               0 :     return;
     980                 :   }
     981             174 :   NCValidateDStateInit(vstate, mbase, vbase, sz);
     982             174 :   NCDecoderStateDecode(&vstate->dstate);
     983             174 :   NCDecoderStateDestruct(&vstate->dstate);
     984                 : }
     985                 : 
     986                 : int NCValidateSegmentPair(uint8_t *mbase_old, uint8_t *mbase_new,
     987                 :                           NaClPcAddress vbase, size_t sz, uint8_t alignment,
     988               0 :                           NaClCPUFeaturesX86 *features) {
     989                 :   /* TODO(karl): Refactor to use inheritance from NCDecoderStatePair? */
     990                 :   NCDecoderStatePair pair;
     991                 :   NCValidatorState* new_vstate;
     992                 :   NCValidatorState* old_vstate;
     993                 : 
     994               0 :   int result = 0;
     995                 : 
     996                 :   /* Verify that we actually have a segment to walk. */
     997               0 :   if (sz == 0) {
     998               0 :     printf("VALIDATOR: %"NACL_PRIxNaClPcAddress
     999                 :            ": Bad text segment (zero size)\n", vbase);
    1000               0 :     return 0;
    1001                 :   }
    1002                 : 
    1003               0 :   old_vstate = NCValidateInit(vbase, sz, alignment, features);
    1004               0 :   if (old_vstate != NULL) {
    1005               0 :     NCValidateDStateInit(old_vstate, mbase_old, vbase, sz);
    1006               0 :     new_vstate = NCValidateInit(vbase, sz, alignment, features);
    1007               0 :     if (new_vstate != NULL) {
    1008               0 :       NCValidateDStateInit(new_vstate, mbase_new, vbase, sz);
    1009                 : 
    1010               0 :       NCDecoderStatePairConstruct(&pair,
    1011                 :                                   &old_vstate->dstate,
    1012                 :                                   &new_vstate->dstate);
    1013               0 :       pair.action_fn = ValidateInstReplacement;
    1014               0 :       if (NCDecoderStatePairDecode(&pair)) {
    1015               0 :         result = 1;
    1016                 :       } else {
    1017               0 :         ValidatePrintOffsetError(0, "Replacement not applied!\n", new_vstate);
    1018                 :       }
    1019               0 :       if (NCValidateFinish(new_vstate)) {
    1020                 :         /* Errors occurred during validation. */
    1021               0 :         result = 0;
    1022                 :       }
    1023               0 :       NCDecoderStatePairDestruct(&pair);
    1024               0 :       NCDecoderStateDestruct(&new_vstate->dstate);
    1025               0 :       NCValidateFreeState(&new_vstate);
    1026                 :     }
    1027               0 :     NCDecoderStateDestruct(&old_vstate->dstate);
    1028               0 :     NCValidateFreeState(&old_vstate);
    1029                 :   }
    1030               0 :   return result;
    1031                 : }
    1032                 : 
    1033                 : /* Walk the collected information on instruction boundaries and jump targets,
    1034                 :  * and verify that they are legal.
    1035                 :  */
    1036             151 : static void NCJumpSummarize(struct NCValidatorState* vstate) {
    1037                 :   uint32_t offset;
    1038                 : 
    1039                 :   /* Verify that jumps are to the beginning of instructions, and that the
    1040                 :    * jumped to instruction is not in the middle of a native client pattern.
    1041                 :    */
    1042                 :   dprint(("CheckTargets: %"NACL_PRIxNaClPcAddress"-%"NACL_PRIxNaClPcAddress"\n",
    1043                 :           vstate->iadrbase, vstate->iadrbase+vstate->codesize));
    1044          573230 :   for (offset = 0; offset < vstate->codesize; offset += 1) {
    1045          573079 :     if (NCGetAdrTable(offset, vstate->kttable)) {
    1046           12329 :       NCStatsCheckTarget(vstate);
    1047           12329 :       if (!NCGetAdrTable(offset, vstate->vttable)) {
    1048               3 :         ValidatePrintOffsetError(offset, "Bad jump target", vstate);
    1049               3 :         NCStatsBadTarget(vstate);
    1050                 :       }
    1051                 :     }
    1052                 :   }
    1053                 : 
    1054                 :   /* check basic block boundaries */
    1055           18213 :   for (offset = 0; offset < vstate->codesize; offset += vstate->alignment) {
    1056           18062 :     if (!NCGetAdrTable(offset, vstate->vttable)) {
    1057               6 :       ValidatePrintOffsetError(offset, "Bad basic block alignment", vstate);
    1058               6 :       NCStatsBadAlignment(vstate);
    1059                 :     }
    1060                 :   }
    1061             151 : }

Generated by: LCOV version 1.7