| OLD | NEW |
| (Empty) |
| 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_details.c | |
| 9 * Attach detailed error reporter to the NaCl validator. Does a second | |
| 10 * walk of the instructions to find instructions that explicitly branch | |
| 11 * to illegal addresses. | |
| 12 * | |
| 13 * See function NCJumpSummarize in ncvalidate.c for a the terse version | |
| 14 * which doesn't require a second pass. | |
| 15 */ | |
| 16 | |
| 17 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_detai
led.h" | |
| 18 | |
| 19 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h" | |
| 20 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_inter
naltypes.h" | |
| 21 | |
| 22 static void NCJumpSummarizeDetailed(struct NCValidatorState* vstate); | |
| 23 | |
| 24 | |
| 25 /* Null method for decoder state. */ | |
| 26 static void NCNullDecoderStateMethod(struct NCValidatorState* vstate) { | |
| 27 } | |
| 28 | |
| 29 /* Detailed (summary) error check on target value, defined in the given decoder | |
| 30 * instruction. | |
| 31 */ | |
| 32 static void NCJumpCheck(struct NCValidatorState* vstate, | |
| 33 const NCDecoderInst* dinst, | |
| 34 int32_t jump_offset) { | |
| 35 NaClPcAddress target = (dinst->inst_addr + dinst->inst.bytes.length | |
| 36 + jump_offset); | |
| 37 | |
| 38 if (target < vstate->codesize && !NCGetAdrTable(target, vstate->vttable)) { | |
| 39 if (NCGetAdrTable(target, vstate->pattern_nonfirst_insts_table)) { | |
| 40 NCBadInstructionError(dinst, "Jumps into middle of nacl pattern"); | |
| 41 } else { | |
| 42 NCBadInstructionError(dinst, "Doesn't jump to instruction address"); | |
| 43 } | |
| 44 NCStatsBadTarget(vstate); | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 /* Detailed (summary) error check for a byte jump instruction. | |
| 49 * Note: This code should match the corresponding validator check | |
| 50 * function ValidateJmp8 in ncvalidate.c. | |
| 51 */ | |
| 52 static void NCInstCheckJmp8(const NCDecoderInst* dinst) { | |
| 53 int8_t offset = NCInstBytesByte(&dinst->inst_bytes, | |
| 54 dinst->inst.prefixbytes+1); | |
| 55 struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); | |
| 56 NCJumpCheck(vstate, dinst, offset); | |
| 57 } | |
| 58 | |
| 59 /* Detailed (summary) error check for a jump condition instruction. | |
| 60 * Note: This code should match the corresponding validator check | |
| 61 * function ValidateJmpz in ncvalidate.c. | |
| 62 */ | |
| 63 static void NCInstCheckJmpz(const NCDecoderInst* dinst) { | |
| 64 NCInstBytesPtr opcode; | |
| 65 uint8_t opcode0; | |
| 66 int32_t offset; | |
| 67 NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); | |
| 68 NCInstBytesPtrInitInc(&opcode, &dinst->inst_bytes, | |
| 69 dinst->inst.prefixbytes); | |
| 70 opcode0 = NCInstBytesByte(&opcode, 0); | |
| 71 if (opcode0 == 0x0f) { | |
| 72 /* Multbyte opcode. Intruction is of form: | |
| 73 * 0F80 .. 0F8F: jCC $Jz | |
| 74 */ | |
| 75 NCInstBytesPtr opcode_2; | |
| 76 NCInstBytesPtrInitInc(&opcode_2, &opcode, 2); | |
| 77 offset = NCInstBytesInt32(&opcode_2, dinst->inst.immbytes); | |
| 78 } else { | |
| 79 /* Single byte opcode. Must be one of: | |
| 80 * E8: call $Jz | |
| 81 * E9: jmp $Jx | |
| 82 */ | |
| 83 NCInstBytesPtr opcode_1; | |
| 84 NCInstBytesPtrInitInc(&opcode_1, &opcode, 1); | |
| 85 offset = NCInstBytesInt32(&opcode_1, dinst->inst.immbytes); | |
| 86 } | |
| 87 NCJumpCheck(vstate, dinst, offset); | |
| 88 } | |
| 89 | |
| 90 /* Decoder action to perform to detect bad jumps during detailed | |
| 91 * (summarization) error checking. | |
| 92 */ | |
| 93 static Bool NCInstLayoutCheck(const NCDecoderInst* dinst) { | |
| 94 NCValidatorState* vstate; | |
| 95 NaClPcAddress start; | |
| 96 NaClPcAddress end; | |
| 97 NaClPcAddress i; | |
| 98 if (dinst == NULL) return TRUE; | |
| 99 vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); | |
| 100 | |
| 101 /* Check that if first instruction is a basic block, it isn't in the middle | |
| 102 * of a pattern. | |
| 103 */ | |
| 104 start = dinst->inst_addr; | |
| 105 if ((0 == (start % vstate->bundle_size)) && | |
| 106 NCGetAdrTable(start, vstate->pattern_nonfirst_insts_table)) { | |
| 107 NCBadInstructionError( | |
| 108 dinst, | |
| 109 "Instruction begins basic block, but in middle of nacl pattern\n"); | |
| 110 NCStatsBadAlignment(vstate); | |
| 111 } | |
| 112 | |
| 113 /* Check that instruction doesn't cross block boundaries. */ | |
| 114 end = start + NCInstBytesLength(&dinst->inst_bytes); | |
| 115 for (i = start + 1; i < end; ++i) { | |
| 116 if (0 == (i % vstate->bundle_size)) { | |
| 117 NCBadInstructionError(dinst, "Instruction crosses basic block alignment"); | |
| 118 NCStatsBadAlignment(vstate); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 /* Check jump targets. */ | |
| 123 switch (dinst->opinfo->insttype) { | |
| 124 case NACLi_JMP8: | |
| 125 NCInstCheckJmp8(dinst); | |
| 126 break; | |
| 127 case NACLi_JMPZ: | |
| 128 NCInstCheckJmpz(dinst); | |
| 129 break; | |
| 130 default: | |
| 131 break; | |
| 132 } | |
| 133 return TRUE; | |
| 134 } | |
| 135 | |
| 136 /* Detailed (summary) error reporting. Rather than looking at summary | |
| 137 * information collected during the first pass, this code rewalks the | |
| 138 * instructions are reports each instruction that causes a problem. | |
| 139 */ | |
| 140 static void NCJumpSummarizeDetailed(struct NCValidatorState* vstate) { | |
| 141 /* Rewalk the code to find instructions that break rules. */ | |
| 142 NCDecoderState* dstate = &vstate->dstate; | |
| 143 NaClErrorReporter* reporter = dstate->error_reporter; | |
| 144 NCDecoderStateConstruct(dstate, dstate->mbase, dstate->vbase, dstate->size, | |
| 145 vstate->inst_buffer, kNCValidatorInstBufferSize); | |
| 146 dstate->action_fn = NCInstLayoutCheck; | |
| 147 dstate->new_segment_fn = (NCDecoderStateMethod) NCNullDecoderStateMethod; | |
| 148 dstate->internal_error_fn = (NCDecoderStateMethod) NCNullDecoderStateMethod; | |
| 149 dstate->internal_error_fn = (NCDecoderStateMethod) NCStatsInternalError; | |
| 150 NCDecoderStateSetErrorReporter(dstate, reporter); | |
| 151 NCDecoderStateDecode(dstate); | |
| 152 } | |
| 153 | |
| 154 struct NCValidatorState *NCValidateInitDetailed( | |
| 155 const NaClPcAddress vbase, | |
| 156 const NaClMemorySize codesize, | |
| 157 const NaClCPUFeaturesX86 *features) { | |
| 158 struct NCValidatorState *vstate = NCValidateInit(vbase, codesize, | |
| 159 FALSE, features); | |
| 160 if (NULL != vstate) { | |
| 161 vstate->summarize_fn = NCJumpSummarizeDetailed; | |
| 162 vstate->pattern_nonfirst_insts_table = | |
| 163 (uint8_t *)calloc(NCIATOffset(codesize) + 1, 1); | |
| 164 if (NULL == vstate->pattern_nonfirst_insts_table) { | |
| 165 if (NULL != vstate->kttable) free(vstate->kttable); | |
| 166 if (NULL != vstate->vttable) free(vstate->vttable); | |
| 167 free(vstate); | |
| 168 return NULL; | |
| 169 } | |
| 170 } | |
| 171 return vstate; | |
| 172 } | |
| OLD | NEW |