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.
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.
13 * See function NCJumpSummarize in ncvalidate.c for a the terse version
14 * which doesn't require a second pass.
17 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncvalidate_detailed.h"
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_internaltypes.h"
22 static void NCJumpSummarizeDetailed(struct NCValidatorState* vstate);
25 /* Null method for decoder state. */
26 static void NCNullDecoderStateMethod(struct NCValidatorState* vstate) {
29 /* Detailed (summary) error check on target value, defined in the given decoder
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
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");
42 NCBadInstructionError(dinst, "Doesn't jump to instruction address");
44 NCStatsBadTarget(vstate);
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.
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);
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.
63 static void NCInstCheckJmpz(const NCDecoderInst* dinst) {
64 NCInstBytesPtr opcode;
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
75 NCInstBytesPtr opcode_2;
76 NCInstBytesPtrInitInc(&opcode_2, &opcode, 2);
77 offset = NCInstBytesInt32(&opcode_2, dinst->inst.immbytes);
79 /* Single byte opcode. Must be one of:
83 NCInstBytesPtr opcode_1;
84 NCInstBytesPtrInitInc(&opcode_1, &opcode, 1);
85 offset = NCInstBytesInt32(&opcode_1, dinst->inst.immbytes);
87 NCJumpCheck(vstate, dinst, offset);
90 /* Decoder action to perform to detect bad jumps during detailed
91 * (summarization) error checking.
93 static Bool NCInstLayoutCheck(const NCDecoderInst* dinst) {
94 NCValidatorState* vstate;
98 if (dinst == NULL) return TRUE;
99 vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);
101 /* Check that if first instruction is a basic block, it isn't in the middle
104 start = dinst->inst_addr;
105 if ((0 == (start % vstate->bundle_size)) &&
106 NCGetAdrTable(start, vstate->pattern_nonfirst_insts_table)) {
107 NCBadInstructionError(
109 "Instruction begins basic block, but in middle of nacl pattern\n");
110 NCStatsBadAlignment(vstate);
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);
122 /* Check jump targets. */
123 switch (dinst->opinfo->insttype) {
125 NCInstCheckJmp8(dinst);
128 NCInstCheckJmpz(dinst);
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.
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);
154 struct NCValidatorState *NCValidateInitDetailed(
155 const NaClPcAddress vbase,
156 const NaClMemorySize codesize,
157 const NaClCPUFeaturesX86 *features) {
158 struct NCValidatorState *vstate = NCValidateInit(vbase, codesize,
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);