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.
8 * Simplifies instruction set to what is needed for the
9 * (x86-64) ncval_reg_sfi validator.
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
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.
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.
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.
39 #ifndef NACL_TRUSTED_BUT_NOT_TCB
40 #error("This file is not meant for use in the TCB")
43 #include "native_client/src/trusted/validator/x86/decoder/generator/ncval_simplify.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"
50 /* To turn on debugging of instruction decoding, change value of
55 #include "native_client/src/shared/utils/debugging.h"
57 /* Returns true if the data extracted by the operand may be needed
58 * for register sfi sandboxing.
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.
68 static NaClOpKind unnecessary_opkinds[] = {
69 RegDR0, /* Debug registers. */
85 RegEFLAGS, /* Program status and control registers. */
87 St_Operand, /* Floating point stack registers. */
96 Mmx_G_Operand, /* Mxx registers. */
106 Xmm_G_Operand, /* Xmm registers. */
126 for (i = 0; i < NACL_ARRAY_SIZE(unnecessary_opkinds); ++i) {
127 if (operand->kind == unnecessary_opkinds[i]) return FALSE;
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.
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.
140 static NaClMnemonic validator_names[] = {
152 NaClMnemonic name = inst->name;
154 for (i = 0; i < NACL_ARRAY_SIZE(validator_names); ++i) {
155 if (name == validator_names[i]) return name;
157 /* If not white listed, change to dont care. */
158 if (NaClHasBit(inst->flags, NACL_IFLAG(ConditionalJump))) {
159 return InstDontCareCondJump;
161 if (NaClHasBit(inst->flags, NACL_IFLAG(JumpInstruction))) {
162 return InstDontCareJump;
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.
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';
183 /* Simplify the given instruction and return the simplified instruction,
184 * based on expectations of the (x86-64) ncval_reg_sfi validator.
186 static void NaClNcvalSimplifyInst(NaClInstTables *inst_tables,
187 NaClModeledInst *inst) {
189 NaClMnemonic simplified_name;
191 Bool is_partial = FALSE;
193 if (NULL == inst) return;
195 /* First simplify additional rules associated with the given instruction. */
196 NaClNcvalSimplifyInst(inst_tables, inst->next_rule);
198 /* Ignore invalid instructions. */
199 if (NACLi_INVALID == inst->insttype) return;
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.
206 inst->num_operands = 0;
207 inst->name = InstDontCare;
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;
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.
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];
227 inst->num_operands--;
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).
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);
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);
261 void NaClNcvalInstSimplify(NaClInstTables* inst_tables) {
263 NaClInstPrefix prefix;
265 /* Simplify the undefined instruction. */
266 NaClNcvalSimplifyInst(inst_tables, inst_tables->undefined_inst);
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]);
275 /* Simplify instructions in the instruction trie. */
276 NaClNcvalSimplifyNode(inst_tables, inst_tables->inst_node_root);