Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / validator / x86 / ncval_seg_sfi / ncvalidate_detailed.c
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_detailed.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_internaltypes.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 }