OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2011 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 * Simplifies instruction set to what is needed for the | |
9 * (x86-64) ncval_reg_sfi validator. | |
10 * | |
11 * There are two parts to this story. First, the decoder used by the | |
12 * ncval_reg_sfi validator use the decoder in: | |
13 * native_client/src/trusted/validator/x86/decoder | |
14 * | |
15 * This decoder is based on instruction flags. If the instruction flags | |
16 * are not changed, the same sequence of bytes will be parsed, independent | |
17 * of the instruction mnemonic. Therefore, it is safe to change the | |
18 * instruction mnemonic to a "don't care" name unless it is explicitly | |
19 * used in some rule of the validator. The static validator validator_names | |
20 * in function NaClNcvalSimplifyMnemonic lists all instruction mnemonics that | |
21 * are currently used by the validator. | |
22 * | |
23 * Secondly, the ncval_reg_sfi validator checks general purpose registers, | |
24 * segment registers, and memory references to make sure that data and | |
25 * branching have been sandboxed properly. Hence, any argument to an x86 | |
26 * instruction that can be shown that it will never access one of these | |
27 * forms can be omitted without breaking the validator. Hence, this code | |
28 * removes all such arguments. See function NaClNcvalKeepOperand for details | |
29 * on what arguments are removed. | |
30 * | |
31 * Finally, for pragmatic reasons (i.e. readability), if an instruction is | |
32 * modified by this simplification, it is marked as a "partial instruction", | |
33 * so that the corresponding (ncdis) disassembler can correctly communicate | |
34 * that a partial match (rather than an actual instruction decoding) was applied | |
35 * to the given bits. The printed partial match communicates what was kept for | |
36 * validation purposes. | |
37 */ | |
38 | |
39 #ifndef NACL_TRUSTED_BUT_NOT_TCB | |
40 #error("This file is not meant for use in the TCB") | |
41 #endif | |
42 | |
43 #include "native_client/src/trusted/validator/x86/decoder/generator/ncval_simpli
fy.h" | |
44 | |
45 #include <string.h> | |
46 #include "native_client/src/include/nacl_macros.h" | |
47 #include "native_client/src/trusted/validator/x86/x86_insts.h" | |
48 #include "native_client/src/trusted/validator/x86/decoder/generator/nc_compress.
h" | |
49 | |
50 /* To turn on debugging of instruction decoding, change value of | |
51 * DEBUGGING to 1. | |
52 */ | |
53 #define DEBUGGING 0 | |
54 | |
55 #include "native_client/src/shared/utils/debugging.h" | |
56 | |
57 /* Returns true if the data extracted by the operand may be needed | |
58 * for register sfi sandboxing. | |
59 */ | |
60 static Bool NaClNcvalKeepOperand(NaClOp *operand) { | |
61 /* Operands in the ncval_seg_sfi (x86-64) validator are not inspected | |
62 * by the validator, unless they are general purpose register, segment | |
63 * registers, or memory references. The following list are all operand | |
64 * specifiers that can't contain any of the above, and hence, are not | |
65 * used by the validator. This list is used to safely determine if | |
66 * an operand can be removed. | |
67 */ | |
68 static NaClOpKind unnecessary_opkinds[] = { | |
69 RegDR0, /* Debug registers. */ | |
70 RegDR1, | |
71 RegDR2, | |
72 RegDR3, | |
73 RegDR4, | |
74 RegDR5, | |
75 RegDR6, | |
76 RegDR7, | |
77 RegDR8, | |
78 RegDR9, | |
79 RegDR10, | |
80 RegDR11, | |
81 RegDR12, | |
82 RegDR13, | |
83 RegDR14, | |
84 RegDR15, | |
85 RegEFLAGS, /* Program status and control registers. */ | |
86 RegRFLAGS, | |
87 St_Operand, /* Floating point stack registers. */ | |
88 RegST0, | |
89 RegST1, | |
90 RegST2, | |
91 RegST3, | |
92 RegST4, | |
93 RegST5, | |
94 RegST6, | |
95 RegST7, | |
96 Mmx_G_Operand, /* Mxx registers. */ | |
97 Mmx_Gd_Operand, | |
98 RegMMX0, | |
99 RegMMX1, | |
100 RegMMX2, | |
101 RegMMX3, | |
102 RegMMX4, | |
103 RegMMX5, | |
104 RegMMX6, | |
105 RegMMX7, | |
106 Xmm_G_Operand, /* Xmm registers. */ | |
107 Xmm_Go_Operand, | |
108 RegXMM0, | |
109 RegXMM1, | |
110 RegXMM2, | |
111 RegXMM3, | |
112 RegXMM4, | |
113 RegXMM5, | |
114 RegXMM6, | |
115 RegXMM7, | |
116 RegXMM8, | |
117 RegXMM9, | |
118 RegXMM10, | |
119 RegXMM11, | |
120 RegXMM12, | |
121 RegXMM13, | |
122 RegXMM14, | |
123 RegXMM15, | |
124 }; | |
125 size_t i; | |
126 for (i = 0; i < NACL_ARRAY_SIZE(unnecessary_opkinds); ++i) { | |
127 if (operand->kind == unnecessary_opkinds[i]) return FALSE; | |
128 } | |
129 return TRUE; | |
130 } | |
131 | |
132 /* Returns the instruction mnemonic to use for an instruction. The | |
133 * mnemonic is changed only if the (x86-64) ncval_reg_sfi validator | |
134 * doesn't need to know the corresponding instruction mnemonic. | |
135 */ | |
136 static NaClMnemonic NaClNcvalSimplifyMnemonic(NaClModeledInst *inst) { | |
137 /* List of white listed names that must be kept for the validator, | |
138 * since they are used as part of the pattern checking of the validator. | |
139 */ | |
140 static NaClMnemonic validator_names[] = { | |
141 InstAnd, | |
142 InstAdd, | |
143 InstCall, | |
144 InstInvalid, | |
145 InstLea, | |
146 InstMov, | |
147 InstOr, | |
148 InstPop, | |
149 InstPush, | |
150 InstSub | |
151 }; | |
152 NaClMnemonic name = inst->name; | |
153 size_t i; | |
154 for (i = 0; i < NACL_ARRAY_SIZE(validator_names); ++i) { | |
155 if (name == validator_names[i]) return name; | |
156 } | |
157 /* If not white listed, change to dont care. */ | |
158 if (NaClHasBit(inst->flags, NACL_IFLAG(ConditionalJump))) { | |
159 return InstDontCareCondJump; | |
160 } | |
161 if (NaClHasBit(inst->flags, NACL_IFLAG(JumpInstruction))) { | |
162 return InstDontCareJump; | |
163 } | |
164 return InstDontCare; | |
165 } | |
166 | |
167 /* Fixes format strings used to define the instruction operand | |
168 * to its simplified form, by removing any implicit braces used | |
169 * when defining the operand for the instruction. | |
170 */ | |
171 static const char* RemoveImplicitFromFormat(const char* str) { | |
172 size_t str_len = strlen(str); | |
173 if ((str_len > 0) && (str[0] == '{') && (str[str_len-1] == '}')) { | |
174 char* simp_str = (char*) malloc(str_len-1); | |
175 if (NULL == simp_str) return str; /* This should not happen. */ | |
176 strncpy(simp_str, str+1, str_len-1); | |
177 simp_str[str_len-2] = '\0'; | |
178 return simp_str; | |
179 } | |
180 return str; | |
181 } | |
182 | |
183 /* Simplify the given instruction and return the simplified instruction, | |
184 * based on expectations of the (x86-64) ncval_reg_sfi validator. | |
185 */ | |
186 static void NaClNcvalSimplifyInst(NaClInstTables *inst_tables, | |
187 NaClModeledInst *inst) { | |
188 size_t i; | |
189 NaClMnemonic simplified_name; | |
190 size_t fill = 0; | |
191 Bool is_partial = FALSE; | |
192 | |
193 if (NULL == inst) return; | |
194 | |
195 /* First simplify additional rules associated with the given instruction. */ | |
196 NaClNcvalSimplifyInst(inst_tables, inst->next_rule); | |
197 | |
198 /* Ignore invalid instructions. */ | |
199 if (NACLi_INVALID == inst->insttype) return; | |
200 | |
201 /* Remove unnecessary operands. */ | |
202 if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) { | |
203 /* Remove all arguments. We don't need to process arguments. | |
204 * Validation will fail regardless. | |
205 */ | |
206 inst->num_operands = 0; | |
207 inst->name = InstDontCare; | |
208 is_partial = TRUE; | |
209 } else { | |
210 /* Simplify the instruction mnemonic. */ | |
211 simplified_name = NaClNcvalSimplifyMnemonic(inst); | |
212 if (simplified_name != inst->name) { | |
213 uint8_t num_operands; | |
214 inst->name = simplified_name; | |
215 is_partial = TRUE; | |
216 | |
217 /* We have simplified the modeled instruction, and hence | |
218 * the modeled instruction is now a pattern, rather than' | |
219 * an x86 instruction. Remove operands that aren't needed, | |
220 * because the operand is never going to be used by the validator. | |
221 */ | |
222 num_operands = inst->num_operands; | |
223 for (i = 0; i < num_operands; i++) { | |
224 if (NaClNcvalKeepOperand(&inst->operands[i])) { | |
225 inst->operands[fill++] = inst->operands[i]; | |
226 } else { | |
227 inst->num_operands--; | |
228 is_partial = TRUE; | |
229 } | |
230 } | |
231 } | |
232 } | |
233 | |
234 /* Check if we modified anything. If so, we need to clean | |
235 * up the instruction so that (all) useful information is printed | |
236 * by the decoder print functions (i.e. as a pattern rather than | |
237 * an x86 instruction). | |
238 */ | |
239 if (is_partial) { | |
240 uint8_t num_operands = inst->num_operands; | |
241 NaClAddBits(inst->flags, NACL_IFLAG(PartialInstruction)); | |
242 for (i = 0; i < num_operands; i++) { | |
243 if (NaClHasBit(inst->operands[i].flags, NACL_OPFLAG(OpImplicit))) { | |
244 NaClRemoveBits(inst->operands[i].flags, NACL_OPFLAG(OpImplicit)); | |
245 inst->operands[i].format_string = | |
246 RemoveImplicitFromFormat(inst->operands[i].format_string); | |
247 } | |
248 } | |
249 } | |
250 } | |
251 | |
252 /* Simplify instructions in the given trie node. */ | |
253 static void NaClNcvalSimplifyNode(NaClInstTables *inst_tables, | |
254 NaClModeledInstNode* node) { | |
255 if (NULL == node) return; | |
256 NaClNcvalSimplifyInst(inst_tables, node->matching_inst); | |
257 NaClNcvalSimplifyNode(inst_tables, node->success); | |
258 NaClNcvalSimplifyNode(inst_tables, node->fail); | |
259 } | |
260 | |
261 void NaClNcvalInstSimplify(NaClInstTables* inst_tables) { | |
262 int i; | |
263 NaClInstPrefix prefix; | |
264 | |
265 /* Simplify the undefined instruction. */ | |
266 NaClNcvalSimplifyInst(inst_tables, inst_tables->undefined_inst); | |
267 | |
268 /* Simplify all instructions in the instruction opcode table. */ | |
269 for (prefix = NoPrefix; prefix < NaClInstPrefixEnumSize; ++prefix) { | |
270 for (i = 0; i < NCDTABLESIZE; ++i) { | |
271 NaClNcvalSimplifyInst(inst_tables, inst_tables->inst_table[i][prefix]); | |
272 } | |
273 } | |
274 | |
275 /* Simplify instructions in the instruction trie. */ | |
276 NaClNcvalSimplifyNode(inst_tables, inst_tables->inst_node_root); | |
277 } | |
OLD | NEW |