OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 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 | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
| 7 /* |
| 8 * This is the core of amd64-mode validator. Please note that this file |
| 9 * combines ragel machine description and C language actions. Please read |
| 10 * validator_internals.html first to understand how the whole thing is built: |
| 11 * it explains how the byte sequences are constructed, what constructs like |
| 12 * “@{}” or “REX_WRX?” mean, etc. |
| 13 */ |
| 14 |
7 #include <assert.h> | 15 #include <assert.h> |
8 #include <errno.h> | 16 #include <errno.h> |
9 #include <stddef.h> | 17 #include <stddef.h> |
10 #include <stdio.h> | 18 #include <stdio.h> |
11 #include <stdlib.h> | 19 #include <stdlib.h> |
12 #include <string.h> | 20 #include <string.h> |
13 | 21 |
14 #include "native_client/src/trusted/validator_ragel/unreviewed/validator_interna
l.h" | 22 #include "native_client/src/trusted/validator_ragel/validator_internal.h" |
15 | 23 |
16 %%{ | 24 %%{ |
17 machine x86_64_validator; | 25 machine x86_64_validator; |
18 alphtype unsigned char; | 26 alphtype unsigned char; |
19 variable p current_position; | 27 variable p current_position; |
20 variable pe end_of_bundle; | 28 variable pe end_of_bundle; |
21 variable eof end_of_bundle; | 29 variable eof end_of_bundle; |
22 variable cs current_state; | 30 variable cs current_state; |
23 | 31 |
24 include byte_machine "byte_machines.rl"; | 32 include byte_machine "byte_machines.rl"; |
(...skipping 17 matching lines...) Expand all Loading... |
42 include modrm_actions_amd64 | 50 include modrm_actions_amd64 |
43 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | 51 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; |
44 include modrm_parsing_amd64 | 52 include modrm_parsing_amd64 |
45 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | 53 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; |
46 include operand_actions_amd64 | 54 include operand_actions_amd64 |
47 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | 55 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; |
48 include immediate_fields_actions | 56 include immediate_fields_actions |
49 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | 57 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; |
50 include immediate_fields_parsing_amd64 | 58 include immediate_fields_parsing_amd64 |
51 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | 59 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; |
| 60 # rel8 actions are used in relative jumps with 8-bit offset. |
52 action rel8_operand { | 61 action rel8_operand { |
53 rel8_operand(current_position + 1, data, jump_dests, size, | 62 rel8_operand(current_position + 1, data, jump_dests, size, |
54 &instruction_info_collected); | 63 &instruction_info_collected); |
55 } | 64 } |
| 65 # rel16 actions are used in relative jums with 16-bit offset. |
| 66 # |
| 67 # Such instructions should be included in the validator's DFA, but we can not |
| 68 # just exlude them because they are refenced in relative_fields_parsing ragel |
| 69 # machine. Ensure compilations error in case of usage. |
56 action rel16_operand { | 70 action rel16_operand { |
57 #error rel16_operand should never be used in nacl | 71 #error rel16_operand should never be used in nacl |
58 } | 72 } |
| 73 # rel32 actions are used in relative calls and jumps with 32-bit offset. |
59 action rel32_operand { | 74 action rel32_operand { |
60 rel32_operand(current_position + 1, data, jump_dests, size, | 75 rel32_operand(current_position + 1, data, jump_dests, size, |
61 &instruction_info_collected); | 76 &instruction_info_collected); |
62 } | 77 } |
63 include relative_fields_parsing | 78 include relative_fields_parsing |
64 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | 79 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; |
65 include cpuid_actions | 80 include cpuid_actions |
66 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | 81 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; |
67 | 82 |
68 action check_access { | 83 action check_access { |
69 check_access(instruction_start - data, base, index, restricted_register, | 84 check_access(instruction_start - data, base, index, restricted_register, |
70 valid_targets, &instruction_info_collected); | 85 valid_targets, &instruction_info_collected); |
71 } | 86 } |
72 | 87 |
73 action last_byte_is_not_immediate { | 88 action last_byte_is_not_immediate { |
74 instruction_info_collected |= LAST_BYTE_IS_NOT_IMMEDIATE; | 89 instruction_info_collected |= LAST_BYTE_IS_NOT_IMMEDIATE; |
75 } | 90 } |
76 | 91 |
77 action modifiable_instruction { | 92 action modifiable_instruction { |
78 instruction_info_collected |= MODIFIABLE_INSTRUCTION; | 93 instruction_info_collected |= MODIFIABLE_INSTRUCTION; |
79 } | 94 } |
80 | 95 |
81 action process_0_operands { | 96 action process_0_operands { |
82 process_0_operands(&restricted_register, &instruction_info_collected); | 97 Process0Operands(&restricted_register, &instruction_info_collected); |
83 } | 98 } |
84 action process_1_operand { | 99 action process_1_operand { |
85 process_1_operand(&restricted_register, &instruction_info_collected, | 100 Process1Operand(&restricted_register, &instruction_info_collected, |
86 rex_prefix, operand_states); | 101 rex_prefix, operand_states); |
87 } | 102 } |
88 action process_1_operand_zero_extends { | 103 action process_1_operand_zero_extends { |
89 process_1_operand_zero_extends(&restricted_register, | 104 Process1OperandZeroExtends(&restricted_register, |
90 &instruction_info_collected, rex_prefix, | 105 &instruction_info_collected, rex_prefix, |
91 operand_states); | 106 operand_states); |
92 } | 107 } |
93 action process_2_operands { | 108 action process_2_operands { |
94 process_2_operands(&restricted_register, &instruction_info_collected, | 109 Process2Operands(&restricted_register, &instruction_info_collected, |
95 rex_prefix, operand_states); | 110 rex_prefix, operand_states); |
96 } | 111 } |
97 action process_2_operands_zero_extends { | 112 action process_2_operands_zero_extends { |
98 process_2_operands_zero_extends(&restricted_register, | 113 Process2OperandsZeroExtends(&restricted_register, |
99 &instruction_info_collected, rex_prefix, | 114 &instruction_info_collected, rex_prefix, |
100 operand_states); | 115 operand_states); |
101 } | 116 } |
102 | 117 |
103 include decode_x86_64 "validator_x86_64_instruction.rl"; | 118 include decode_x86_64 "validator_x86_64_instruction.rl"; |
104 | 119 |
105 data16condrep = (data16 | condrep data16 | data16 condrep); | 120 data16condrep = (data16 | condrep data16 | data16 condrep); |
106 data16rep = (data16 | rep data16 | data16 rep); | 121 data16rep = (data16 | rep data16 | data16 rep); |
107 | 122 |
108 # Special %rbp modifications without required sandboxing | 123 # Special %rbp modifications—the ones which don't need a sandboxing. |
| 124 # |
| 125 # Note that there are two different opcodes for “mov”: “mov” with opcode |
| 126 # “0x89” moves from “A” to “B” while “mov” with opcode “0x8b” moves from |
| 127 # “B” to “A”. |
109 rbp_modifications = | 128 rbp_modifications = |
110 (b_0100_10x0 0x89 0xe5) | # mov %rsp,%rbp | 129 (b_0100_10x0 0x89 0xe5) | # mov %rsp,%rbp |
111 (b_0100_10x0 0x8b 0xec) # | mov %rsp,%rbp | 130 (b_0100_10x0 0x8b 0xec) # mov %rsp,%rbp |
112 #(b_0100_1xx0 0x81 0xe5 any{3} (0x80 .. 0xff)) | # and $XXX,%rbp | |
113 #(b_0100_1xx0 0x83 0xe5 (0x80 .. 0xff)) # and $XXX,%rbp | |
114 @process_0_operands; | 131 @process_0_operands; |
115 | 132 |
116 # Special instructions used for %rbp sandboxing | 133 # Special instructions used for %rbp sandboxing. |
| 134 # |
| 135 # This is the “second half” of the %rbp sandboxing. Any zero-extending |
| 136 # instruction which stores the data in %ebp can be first part, but unlike |
| 137 # the situation with other “normal” registers you can not just write to |
| 138 # %ebp and continue: such activity MUST restore the status quo immediately |
| 139 # via one of these instructions. |
117 rbp_sandboxing = | 140 rbp_sandboxing = |
118 (b_0100_11x0 0x01 0xfd | # add %r15,%rbp | 141 (b_0100_11x0 0x01 0xfd | # add %r15,%rbp |
119 b_0100_10x1 0x03 0xef | # add %r15,%rbp | 142 b_0100_10x1 0x03 0xef | # add %r15,%rbp |
120 0x49 0x8d 0x2c 0x2f | # lea (%r15,%rbp,1),%rbp | 143 0x49 0x8d 0x2c 0x2f | # lea (%r15,%rbp,1),%rbp |
121 0x4a 0x8d 0x6c 0x3d 0x00) # lea 0x0(%rbp,%r15,1),%rbp | 144 0x4a 0x8d 0x6c 0x3d 0x00) # lea 0x0(%rbp,%r15,1),%rbp |
| 145 # “Normal” instructions detect an error when confronted with restricted |
| 146 # register %rbp. These instructions require this state instead. |
| 147 # |
| 148 # Check this precondition and mark the beginning of the instruction as |
| 149 # invalid jump for target. |
122 @{ if (restricted_register == REG_RBP) | 150 @{ if (restricted_register == REG_RBP) |
123 instruction_info_collected |= RESTRICTED_REGISTER_USED; | 151 instruction_info_collected |= RESTRICTED_REGISTER_USED; |
124 else | 152 else |
125 instruction_info_collected |= UNRESTRICTED_RBP_PROCESSED; | 153 instruction_info_collected |= UNRESTRICTED_RBP_PROCESSED; |
126 restricted_register = NO_REG; | 154 restricted_register = NO_REG; |
127 BitmapClearBit(valid_targets, (instruction_start - data)); | 155 MakeInvalidJumpTarget((instruction_start - data), valid_targets); |
128 }; | 156 }; |
129 | 157 |
130 # Special %rbp modifications without required sandboxing | 158 # Special %rsp modifications—the ones which don't need a sandboxing. |
| 159 # |
| 160 # Note that there are two different opcodes for “mov”: “mov” with opcode |
| 161 # “0x89” moves from “A” to “B” while “mov” with opcode “0x8b” moves from |
| 162 # “B” to “A”. |
131 rsp_modifications = | 163 rsp_modifications = |
132 (b_0100_10x0 0x89 0xec) | # mov %rbp,%rsp | 164 (b_0100_10x0 0x89 0xec) | # mov %rbp,%rsp |
133 (b_0100_10x0 0x8b 0xe5) | # mov %rbp,%rsp | 165 (b_0100_10x0 0x8b 0xe5) | # mov %rbp,%rsp |
134 #(b_0100_1xx0 0x81 0xe4 any{3} (0x80 .. 0xff)) | # and $XXX,%rsp | 166 #(b_0100_1xx0 0x81 0xe4 any{3} (0x80 .. 0xff)) | # and $XXX,%rsp |
135 #Superfluous bits are not supported: | 167 #Superfluous bits are not supported: |
136 # http://code.google.com/p/nativeclient/issues/detail?id=3012 | 168 # http://code.google.com/p/nativeclient/issues/detail?id=3012 |
137 (b_0100_1000 0x83 0xe4 (0x80 .. 0xff)) # and $XXX,%rsp | 169 (b_0100_1000 0x83 0xe4 (0x80 .. 0xff)) # and $XXX,%rsp |
138 @process_0_operands; | 170 @process_0_operands; |
139 | 171 |
140 # Special instructions used for %rbp sandboxing | 172 # Special instructions used for %rsp sandboxing. |
| 173 # |
| 174 # This is the “second half” of the %rsp sandboxing. Any zero-extending |
| 175 # instruction which stores the data in %esp can be first part, but unlike |
| 176 # the situation with other “normal” registers you can not just write to |
| 177 # %esp and continue: such activity MUST restore the status quo immediately |
| 178 # via one of these instructions. |
141 rsp_sandboxing = | 179 rsp_sandboxing = |
142 (b_0100_11x0 0x01 0xfc | # add %r15,%rsp | 180 (b_0100_11x0 0x01 0xfc | # add %r15,%rsp |
143 b_0100_10x1 0x03 0xe7 | # add %r15,%rbp | 181 b_0100_10x1 0x03 0xe7 | # add %r15,%rsp |
144 0x4a 0x8d 0x24 0x3c) # lea (%rsp,%r15,1),%rsp | 182 0x4a 0x8d 0x24 0x3c) # lea (%rsp,%r15,1),%rsp |
| 183 # “Normal” instructions detect an error when confronted with restricted |
| 184 # register %rsp. These instructions require this state instead. |
| 185 # |
| 186 # Check this precondition and mark the beginning of the instruction as |
| 187 # invalid jump for target. |
145 @{ if (restricted_register == REG_RSP) | 188 @{ if (restricted_register == REG_RSP) |
146 instruction_info_collected |= RESTRICTED_REGISTER_USED; | 189 instruction_info_collected |= RESTRICTED_REGISTER_USED; |
147 else | 190 else |
148 instruction_info_collected |= UNRESTRICTED_RSP_PROCESSED; | 191 instruction_info_collected |= UNRESTRICTED_RSP_PROCESSED; |
149 restricted_register = NO_REG; | 192 restricted_register = NO_REG; |
150 BitmapClearBit(valid_targets, (instruction_start - data)); | 193 MakeInvalidJumpTarget((instruction_start - data), valid_targets); |
151 }; | 194 }; |
152 | 195 |
153 # naclcall or nacljmp. Note: first "and $~0x1f, %eXX" is a normal instruction | 196 # naclcall or nacljmp. These are three-instruction indirection-jump sequences. |
154 # and as such will detect case where %rbp/%rsp is illegally modified. | 197 # and $~0x1f, %eXX |
| 198 # and RBASE, %rXX |
| 199 # jmpq *%rXX (or: callq *%rXX) |
| 200 # Note: first "and $~0x1f, %eXX" is a normal instruction and as such will |
| 201 # detect case where %rbp/%rsp is illegally modified when this machine will be |
| 202 # combined with normal_instruction machine. |
| 203 # |
| 204 # There are number of variants present which differ by the REX prefix usage: |
| 205 # we need to make sure “%eXX” in “and”, “%rXX” in “add”, and “%eXX” in “jmpq” |
| 206 # or “callq” is the same register and it's much simpler to do if one single |
| 207 # action handles only fixed number of bytes. |
| 208 # |
| 209 # Additional complication arises because x86-64 contains two different “add” |
| 210 # instruction: with “0x01” and “0x03” opcode. They differ in the direction |
| 211 # used: both can add “A” and “B” but one of them stores the result in “A” and |
| 212 # other stores the result in “B” (see AMD/Intel manual for clarification). |
| 213 # Both should be allowed. |
| 214 # |
| 215 # REGISTER USAGE ABBREVIATIONS: |
| 216 # E86: legacy ia32 registers (all eight: %eax to %edi) |
| 217 # R86: 64-bit counterparts for legacy 386 registers (%rax to %rdi) |
| 218 # E64: 32-bit counterparts for new amd64 registers (%r8d to %r14d) |
| 219 # R64: new amd64 registers (only seven: %r8 to %r14) |
| 220 # RBASE: %r15 (used as “base of untrusted world” in NaCl for amd64) |
155 naclcall_or_nacljmp = | 221 naclcall_or_nacljmp = |
156 # and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | 222 # This block encodes call and jump superinstructions of the form: |
157 (0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | 223 # 0: 83 e_ e0 and $~0x1f,E86 |
158 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 224 # 3: 4_ 01 f_ add RBASE,R86 |
159 b_0100_11x0 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe|0xff) | 225 # 6: ff e_ jmpq *R86 |
160 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 226 #### INSTRUCTION ONE (three bytes) |
161 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | 227 # and $~0x1f, E86 |
162 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 228 (0x83 b_11_100_xxx 0xe0 |
163 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | 229 #### INSTRUCTION TWO (three bytes) |
164 @{ | 230 # add RBASE, R86 (0x01 opcode) |
165 instruction_start -= 6; | 231 b_0100_11x0 0x01 b_11_111_xxx |
166 if (RMFromModRM(instruction_start[1]) != | 232 #### INSTRUCTION THREE: call (two bytes plus optional REX prefix) |
167 RMFromModRM(instruction_start[5]) || | 233 # callq R86 |
168 RMFromModRM(instruction_start[1]) != RMFromModRM(*current_position)) | 234 ((REX_WRX? 0xff b_11_010_xxx) | |
169 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | 235 #### INSTRUCTION THREE: jmp (two bytes plus optional REX prefix) |
170 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | 236 # jmpq R86 |
171 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | 237 (REX_WRX? 0xff b_11_100_xxx))) |
172 restricted_register = NO_REG; | 238 @{ |
173 } | | 239 ProcessNaclCallOrJmpAddToRMNoRex(&instruction_info_collected, |
| 240 &instruction_start, current_position, |
| 241 data, valid_targets); |
| 242 } | |
174 | 243 |
175 # and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | 244 # This block encodes call and jump superinstructions of the form: |
176 (0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | 245 # 0: 83 e_ e0 and $~0x1f,E86 |
177 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 246 # 3: 4_ 03 f_ add RBASE,R86 |
178 b_0100_10x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7|0xff) | 247 # 6: ff e_ jmpq *R86 |
179 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 248 #### INSTRUCTION ONE (three bytes) |
180 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | 249 # and $~0x1f, E86 |
181 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 250 (0x83 b_11_100_xxx 0xe0 |
182 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | 251 #### INSTRUCTION TWO (three bytes) |
183 @{ | 252 # add RBASE, R86 (0x03 opcode) |
184 instruction_start -= 6; | 253 b_0100_10x1 0x03 b_11_xxx_111 |
185 if (RMFromModRM(instruction_start[1]) != | 254 #### INSTRUCTION THREE: call (two bytes plus optional REX prefix) |
186 RegFromModRM(instruction_start[5]) || | 255 # callq R86 |
187 RMFromModRM(instruction_start[1]) != RMFromModRM(*current_position)) | 256 ((REX_WRX? 0xff b_11_010_xxx) | |
188 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | 257 #### INSTRUCTION THREE: jmp (two bytes plus optional REX prefix) |
189 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | 258 # jmpq R86 |
190 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | 259 (REX_WRX? 0xff b_11_100_xxx))) |
191 restricted_register = NO_REG; | 260 @{ |
192 } | | 261 ProcessNaclCallOrJmpAddToRegNoRex(&instruction_info_collected, |
| 262 &instruction_start, current_position, |
| 263 data, valid_targets); |
| 264 } | |
193 | 265 |
194 # rex.R?X? and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | 266 # This block encodes call and jump superinstructions of the form: |
195 ((REX_RX 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | 267 # 0: 4_ 83 e_ e0 and $~0x1f,E86 |
196 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 268 # 4: 4_ 01 f_ add RBASE,R86 |
197 b_0100_11x0 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe|0xff) | 269 # 7: ff e_ jmpq *R86 |
198 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 270 #### INSTRUCTION ONE (four bytes) |
199 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | 271 # and $~0x1f, E86 |
200 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 272 ((REX_RX 0x83 b_11_100_xxx 0xe0 |
201 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | | 273 #### INSTRUCTION TWO (three bytes) |
| 274 # add RBASE, R86 (0x01 opcode) |
| 275 b_0100_11x0 0x01 b_11_111_xxx |
| 276 #### INSTRUCTION THREE: call (two bytes plus optional REX prefix) |
| 277 # callq R86 |
| 278 ((REX_WRX? 0xff b_11_010_xxx) | |
| 279 #### INSTRUCTION THREE: jmp (two bytes plus optional REX prefix) |
| 280 # jmpq R86 |
| 281 (REX_WRX? 0xff b_11_100_xxx))) | |
202 | 282 |
203 # and $~0x1f, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | 283 # This block encodes call and jump superinstructions of the form: |
204 (b_0100_0xx1 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6) 0xe0 | 284 # 0: 4_ 83 e_ e0 and $~0x1f,E64 |
205 # add %r15, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | 285 # 4: 4_ 01 f_ add RBASE,R64 |
206 b_0100_11x1 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe) | 286 # 7: 4_ ff e_ jmpq *R64 |
207 # callq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | 287 #### INSTRUCTION ONE (four bytes) |
208 ((b_0100_xxx1 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6)) | | 288 # and $~0x1f, E64 |
209 # jmpq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | 289 (b_0100_0xx1 0x83 (b_11_100_xxx - b_11_100_111) 0xe0 |
210 (b_0100_xxx1 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6))))) | 290 #### INSTRUCTION TWO (three bytes) |
211 @{ | 291 # add RBASE, R64 (0x01 opcode) |
212 instruction_start -= 7; | 292 b_0100_11x1 0x01 (b_11_111_xxx - b_11_111_111) |
213 if (RMFromModRM(instruction_start[2]) != | 293 #### INSTRUCTION THREE: call (three bytes) |
214 RMFromModRM(instruction_start[6]) || | 294 # callq R64 |
215 RMFromModRM(instruction_start[2]) != RMFromModRM(*current_position)) | 295 ((b_0100_xxx1 0xff (b_11_010_xxx - b_11_010_111)) | |
216 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | 296 #### INSTRUCTION THREE: jmp (three bytes) |
217 BitmapClearBit(valid_targets, (instruction_start - data) + 4); | 297 # jmpq R64 |
218 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | 298 (b_0100_xxx1 0xff (b_11_100_xxx - b_11_100_111))))) |
219 restricted_register = NO_REG; | 299 @{ |
220 } | | 300 ProcessNaclCallOrJmpAddToRMWithRex(&instruction_info_collected, |
| 301 &instruction_start, current_position, |
| 302 data, valid_targets); |
| 303 } | |
221 | 304 |
222 # rex.R?X? and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | 305 # This block encodes call and jump superinstructions of the form: |
223 ((REX_RX 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | 306 # 0: 4_ 83 e_ e0 and $~0x1f,E86 |
224 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 307 # 4: 4_ 03 f_ add RBASE,R86 |
225 b_0100_10x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7|0xff) | 308 # 7: ff e_ jmpq *R86 |
226 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 309 #### INSTRUCTION ONE (four bytes) |
227 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | 310 # and $~0x1f, E86 |
228 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | 311 ((REX_RX 0x83 b_11_100_xxx 0xe0 |
229 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | | 312 #### INSTRUCTION TWO (three bytes) |
| 313 # add RBASE, R86 (0x03 opcode) |
| 314 b_0100_10x1 0x03 b_11_xxx_111 |
| 315 #### INSTRUCTION THREE: call (two bytes plus optional REX prefix) |
| 316 # callq R86 |
| 317 ((REX_WRX? 0xff b_11_010_xxx) | |
| 318 #### INSTRUCTION THREE: jmp (two bytes plus optional REX prefix) |
| 319 # jmpq R86 |
| 320 (REX_WRX? 0xff b_11_100_xxx))) | |
230 | 321 |
231 # and $~0x1f, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | 322 # This block encodes call and jump superinstructions of the form: |
232 (b_0100_0xx1 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6) 0xe0 | 323 # 0: 4_ 83 e_ e0 and $~0x1f,E64 |
233 # add %r15, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | 324 # 4: 4_ 03 f_ add RBASE,R64 |
234 b_0100_11x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7) | 325 # 7: 4_ ff e_ jmpq *R64 |
235 # callq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | 326 #### INSTRUCTION ONE (four bytes) |
236 ((b_0100_xxx1 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6)) | | 327 # and $~0x1f, E64 |
237 # jmpq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | 328 (b_0100_0xx1 0x83 (b_11_100_xxx - b_11_100_111) 0xe0 |
238 (b_0100_xxx1 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6))))) | 329 #### INSTRUCTION TWO (three bytes) |
239 @{ | 330 # add RBASE, R64 (0x03 opcode) |
240 instruction_start -= 7; | 331 b_0100_11x1 0x03 (b_11_xxx_111 - b_11_111_111) |
241 if (RMFromModRM(instruction_start[2]) != | 332 #### INSTRUCTION THREE: call (three bytes) |
242 RegFromModRM(instruction_start[6]) || | 333 # callq R64 |
243 RMFromModRM(instruction_start[2]) != RMFromModRM(*current_position)) | 334 ((b_0100_xxx1 0xff (b_11_010_xxx - b_11_010_111)) | |
244 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | 335 #### INSTRUCTION THREE: jmp (three bytes) |
245 BitmapClearBit(valid_targets, (instruction_start - data) + 4); | 336 # jmpq R64 |
246 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | 337 (b_0100_xxx1 0xff (b_11_100_xxx - b_11_100_111))))) |
247 restricted_register = NO_REG; | 338 @{ |
248 }; | 339 ProcessNaclCallOrJmpAddToRegWithRex(&instruction_info_collected, |
| 340 &instruction_start, current_position, |
| 341 data, valid_targets); |
| 342 }; |
249 | 343 |
250 # EMMS/SSE2/AVX instructions which have implicit %ds:(%rsi) operand | 344 # EMMS/SSE2/AVX instructions which have implicit %ds:(%rsi) operand |
251 # maskmovq %mmX,%mmY | 345 # maskmovq %mmX,%mmY |
252 maskmovq = | 346 maskmovq = |
253 REX_WRXB? (0x0f 0xf7) | 347 REX_WRXB? (0x0f 0xf7) |
254 @CPUFeature_EMMX modrm_registers; | 348 @CPUFeature_EMMX modrm_registers; |
255 # maskmovdqu %xmmX, %xmmY | 349 # maskmovdqu %xmmX, %xmmY |
256 maskmovdqu = | 350 maskmovdqu = |
257 0x66 REX_WRXB? (0x0f 0xf7) @not_data16_prefix | 351 0x66 REX_WRXB? (0x0f 0xf7) @not_data16_prefix |
258 @CPUFeature_SSE2 modrm_registers; | 352 @CPUFeature_SSE2 modrm_registers; |
259 # vmaskmovdqu %xmmX, %xmmY | 353 # vmaskmovdqu %xmmX, %xmmY |
260 vmaskmovdqu = | 354 vmaskmovdqu = |
261 ((0xc4 (VEX_RB & VEX_map00001) 0x79 @vex_prefix3) | | 355 ((0xc4 (VEX_RB & VEX_map00001) 0x79 @vex_prefix3) | |
262 (0xc5 (0x79 | 0xf9) @vex_prefix_short)) 0xf7 | 356 (0xc5 (0x79 | 0xf9) @vex_prefix_short)) 0xf7 |
263 @CPUFeature_AVX modrm_registers; | 357 @CPUFeature_AVX modrm_registers; |
264 mmx_sse_rdi_instruction = maskmovq | maskmovdqu | vmaskmovdqu; | 358 mmx_sse_rdi_instruction = maskmovq | maskmovdqu | vmaskmovdqu; |
265 | 359 |
266 # String instructions which use only %ds:(%rsi) | 360 # String instructions which use only %ds:(%rsi) |
267 string_instruction_rsi_no_rdi = | 361 string_instruction_rsi_no_rdi = |
268 (rep? 0xac | # lods %ds:(%rsi),%al | 362 (rep? 0xac | # lods %ds:(%rsi),%al |
269 data16rep 0xad | # lods %ds:(%rsi),%ax | 363 data16rep 0xad | # lods %ds:(%rsi),%ax |
270 rep? REXW_NONE? 0xad) ; # lods %ds:(%rsi),%eax/%rax | 364 rep? REXW_NONE? 0xad); # lods %ds:(%rsi),%eax/%rax |
271 | 365 |
272 # String instructions which use only %ds:(%rdi) | 366 # String instructions which use only %ds:(%rdi) |
273 string_instruction_rdi_no_rsi = | 367 string_instruction_rdi_no_rsi = |
274 condrep? 0xae | # scas %es:(%rdi),%al | 368 condrep? 0xae | # scas %es:(%rdi),%al |
275 data16condrep 0xaf | # scas %es:(%rdi),%ax | 369 data16condrep 0xaf | # scas %es:(%rdi),%ax |
276 condrep? REXW_NONE? 0xaf | # scas %es:(%rdi),%eax/%rax | 370 condrep? REXW_NONE? 0xaf | # scas %es:(%rdi),%eax/%rax |
277 | 371 |
278 rep? 0xaa | # stos %al,%es:(%rdi) | 372 rep? 0xaa | # stos %al,%es:(%rdi) |
279 data16rep 0xab | # stos %ax,%es:(%rdi) | 373 data16rep 0xab | # stos %ax,%es:(%rdi) |
280 rep? REXW_NONE? 0xab ; # stos %eax/%rax,%es:(%rdi) | 374 rep? REXW_NONE? 0xab; # stos %eax/%rax,%es:(%rdi) |
281 | 375 |
282 # String instructions which use both %ds:(%rsi) and %ds:(%rdi) | 376 # String instructions which use both %ds:(%rsi) and %ds:(%rdi) |
283 string_instruction_rsi_rdi = | 377 string_instruction_rsi_rdi = |
284 condrep? 0xa6 | # cmpsb %es:(%rdi),%ds:(%rsi) | 378 condrep? 0xa6 | # cmpsb %es:(%rdi),%ds:(%rsi) |
285 data16condrep 0xa7 | # cmpsw %es:(%rdi),%ds:(%rsi) | 379 data16condrep 0xa7 | # cmpsw %es:(%rdi),%ds:(%rsi) |
286 condrep? REXW_NONE? 0xa7 | # cmps[lq] %es:(%rdi),%ds:(%rsi) | 380 condrep? REXW_NONE? 0xa7 | # cmps[lq] %es:(%rdi),%ds:(%rsi) |
287 | 381 |
288 rep? 0xa4 | # movsb %es:(%rdi),%ds:(%rsi) | 382 rep? 0xa4 | # movsb %es:(%rdi),%ds:(%rsi) |
289 data16rep 0xa5 | # movsw %es:(%rdi),%ds:(%rsi) | 383 data16rep 0xa5 | # movsw %es:(%rdi),%ds:(%rsi) |
290 rep? REXW_NONE? 0xa5 ; # movs[lq] %es:(%rdi),%ds:(%rsi) | 384 rep? REXW_NONE? 0xa5; # movs[lq] %es:(%rdi),%ds:(%rsi) |
291 | 385 |
| 386 # Superinstruction which handle instructions which require sandboxed %rsi. |
| 387 # |
| 388 # There are two variants which handle spurious REX prefixes. |
| 389 # |
| 390 # Note that both “0x89 0xf6” and “0x8b 0xf6” encode “mov %esi,%esi”: |
| 391 # “mov” with opcode “0x89” moves from “A” to “B” while “mov” with opcode |
| 392 # “0x8b” moves from “B” to “A” but when “A” and “B” happen to denote the |
| 393 # same register there are no functional difference between these opcodes. |
292 sandbox_instruction_rsi_no_rdi = | 394 sandbox_instruction_rsi_no_rdi = |
293 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | 395 (0x89 | 0x8b) 0xf6 # mov %esi,%esi |
294 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | 396 0x49 0x8d 0x34 0x37 # lea (%r15,%rsi,1),%rsi |
295 string_instruction_rsi_no_rdi | 397 string_instruction_rsi_no_rdi |
296 @{ | 398 @{ |
297 instruction_start -= 6; | 399 SandboxRxiSuperInstNoRexOnMov(&instruction_start, data, valid_targets); |
298 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
299 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
300 restricted_register = NO_REG; | |
301 } | | 400 } | |
302 | 401 |
303 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | 402 REX_X (0x89 | 0x8b) 0xf6 # mov %esi,%esi |
304 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | 403 0x49 0x8d 0x34 0x37 # lea (%r15,%rsi,1),%rsi |
305 string_instruction_rsi_no_rdi | 404 string_instruction_rsi_no_rdi |
306 @{ | 405 @{ |
307 instruction_start -= 7; | 406 SandboxRxiSuperInstWithRexOnMov(&instruction_start, data, valid_targets); |
308 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
309 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
310 restricted_register = NO_REG; | |
311 }; | 407 }; |
312 | 408 |
| 409 # Superinstruction which handle instructions which require sandboxed %rdi. |
| 410 # |
| 411 # There are two variants which handle spurious REX prefixes. |
| 412 # |
| 413 # Note that both “0x89 0xff” and “0x8b 0xff” encode “mov %edi,%edi”: |
| 414 # “mov” with opcode “0x89” moves from “A” to “B” while “mov” with opcode |
| 415 # “0x8b” moves from “B” to “A” but when “A” and “B” happen to denote the |
| 416 # same register there are no functional difference between these opcodes. |
313 sandbox_instruction_rdi_no_rsi = | 417 sandbox_instruction_rdi_no_rsi = |
314 (0x89 | 0x8b) 0xff . # mov %edi,%edi | 418 (0x89 | 0x8b) 0xff # mov %edi,%edi |
315 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | 419 0x49 0x8d 0x3c 0x3f # lea (%r15,%rdi,1),%rdi |
316 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) | 420 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) |
317 @{ | 421 @{ |
318 instruction_start -= 6; | 422 SandboxRxiSuperInstNoRexOnMov(&instruction_start, data, valid_targets); |
319 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
320 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
321 restricted_register = NO_REG; | |
322 } | | 423 } | |
323 | 424 |
324 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | 425 REX_X (0x89 | 0x8b) 0xff # mov %edi,%edi |
325 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | 426 0x49 0x8d 0x3c 0x3f # lea (%r15,%rdi,1),%rdi |
326 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) | 427 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) |
327 @{ | 428 @{ |
328 instruction_start -= 7; | 429 SandboxRxiSuperInstWithRexOnMov(&instruction_start, data, valid_targets); |
329 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
330 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
331 restricted_register = NO_REG; | |
332 }; | 430 }; |
333 | 431 |
334 | 432 |
335 # String instructions which use both %ds:(%rsi) and %ds:(%rdi) | 433 # Superinstruction which handle instructions which require both sandboxed %rsi |
| 434 # and sandboxed %rdi. |
| 435 # |
| 436 # There are four variants which handle spurious REX prefixes. |
| 437 # |
| 438 # Note that both “0x89 0xf6” and “0x8b 0xf6” encode “mov %esi,%esi” while both |
| 439 # “0x89 0xff” and “0x8b 0xff” encode “mov %edi,%edi”: “mov” with opcode “0x89” |
| 440 # moves from “A” to “B” while “mov” with opcode “0x8b” moves from “B” to “A” |
| 441 # but when “A” and “B” happen to denote the same register there are no |
| 442 # functional difference between these opcodes. |
| 443 # |
| 444 # Note: we call SandboxRxiSuperInst in actions here twice because we have two |
| 445 # sandboxings here - one for %rsi and one for %rdi. |
336 sandbox_instruction_rsi_rdi = | 446 sandbox_instruction_rsi_rdi = |
337 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | 447 (0x89 | 0x8b) 0xf6 # mov %esi,%esi |
338 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | 448 0x49 0x8d 0x34 0x37 # lea (%r15,%rsi,1),%rsi |
339 (0x89 | 0x8b) 0xff . # mov %edi,%edi | 449 (0x89 | 0x8b) 0xff # mov %edi,%edi |
340 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | 450 0x49 0x8d 0x3c 0x3f # lea (%r15,%rdi,1),%rdi |
341 string_instruction_rsi_rdi | 451 string_instruction_rsi_rdi |
342 @{ | 452 @{ |
343 instruction_start -= 12; | 453 SandboxRxiSuperInstNoRexOnMov(&instruction_start, data, valid_targets); |
344 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | 454 SandboxRxiSuperInstNoRexOnMov(&instruction_start, data, valid_targets); |
345 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
346 BitmapClearBit(valid_targets, (instruction_start - data) + 8); | |
347 BitmapClearBit(valid_targets, (instruction_start - data) + 12); | |
348 restricted_register = NO_REG; | |
349 } | | 455 } | |
350 | 456 |
351 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | 457 (0x89 | 0x8b) 0xf6 # mov %esi,%esi |
352 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | 458 0x49 0x8d 0x34 0x37 # lea (%r15,%rsi,1),%rsi |
353 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | 459 REX_X (0x89 | 0x8b) 0xff # mov %edi,%edi |
354 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | 460 0x49 0x8d 0x3c 0x3f # lea (%r15,%rdi,1),%rdi |
355 string_instruction_rsi_rdi | 461 string_instruction_rsi_rdi |
356 @{ | 462 @{ |
357 instruction_start -= 13; | 463 SandboxRxiSuperInstWithRexOnMov(&instruction_start, data, valid_targets); |
358 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | 464 SandboxRxiSuperInstNoRexOnMov(&instruction_start, data, valid_targets); |
359 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
360 BitmapClearBit(valid_targets, (instruction_start - data) + 9); | |
361 BitmapClearBit(valid_targets, (instruction_start - data) + 13); | |
362 restricted_register = NO_REG; | |
363 } | | 465 } | |
364 | 466 |
365 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | 467 REX_X (0x89 | 0x8b) 0xf6 # mov %esi,%esi |
366 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | 468 0x49 0x8d 0x34 0x37 # lea (%r15,%rsi,1),%rsi |
367 (0x89 | 0x8b) 0xff . # mov %edi,%edi | 469 (0x89 | 0x8b) 0xff # mov %edi,%edi |
368 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | 470 0x49 0x8d 0x3c 0x3f # lea (%r15,%rdi,1),%rdi |
369 string_instruction_rsi_rdi | 471 string_instruction_rsi_rdi |
370 @{ | 472 @{ |
371 instruction_start -= 13; | 473 SandboxRxiSuperInstNoRexOnMov(&instruction_start, data, valid_targets); |
372 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | 474 SandboxRxiSuperInstWithRexOnMov(&instruction_start, data, valid_targets); |
373 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
374 BitmapClearBit(valid_targets, (instruction_start - data) + 9); | |
375 BitmapClearBit(valid_targets, (instruction_start - data) + 13); | |
376 restricted_register = NO_REG; | |
377 } | | 475 } | |
378 | 476 |
379 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | 477 REX_X (0x89 | 0x8b) 0xf6 # mov %esi,%esi |
380 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | 478 0x49 0x8d 0x34 0x37 # lea (%r15,%rsi,1),%rsi |
381 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | 479 REX_X (0x89 | 0x8b) 0xff # mov %edi,%edi |
382 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | 480 0x49 0x8d 0x3c 0x3f # lea (%r15,%rdi,1),%rdi |
383 string_instruction_rsi_rdi | 481 string_instruction_rsi_rdi |
384 @{ | 482 @{ |
385 instruction_start -= 14; | 483 SandboxRxiSuperInstWithRexOnMov(&instruction_start, data, valid_targets); |
386 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | 484 SandboxRxiSuperInstWithRexOnMov(&instruction_start, data, valid_targets); |
387 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
388 BitmapClearBit(valid_targets, (instruction_start - data) + 10); | |
389 BitmapClearBit(valid_targets, (instruction_start - data) + 14); | |
390 restricted_register = NO_REG; | |
391 }; | 485 }; |
392 | 486 |
393 special_instruction = | 487 special_instruction = |
394 (rbp_modifications | | 488 (rbp_modifications | |
395 rsp_modifications | | 489 rsp_modifications | |
396 rbp_sandboxing | | 490 rbp_sandboxing | |
397 rsp_sandboxing | | 491 rsp_sandboxing | |
398 naclcall_or_nacljmp | | 492 naclcall_or_nacljmp | |
399 sandbox_instruction_rsi_no_rdi | | 493 sandbox_instruction_rsi_no_rdi | |
400 sandbox_instruction_rdi_no_rsi | | 494 sandbox_instruction_rdi_no_rsi | |
401 sandbox_instruction_rsi_rdi) | 495 sandbox_instruction_rsi_rdi) |
| 496 # Mark the instruction as special—currently this information is used only in |
| 497 # tests, but in the future we may use it for dynamic code modification |
| 498 # support. |
402 @{ | 499 @{ |
403 instruction_info_collected |= SPECIAL_INSTRUCTION; | 500 instruction_info_collected |= SPECIAL_INSTRUCTION; |
404 }; | 501 }; |
405 | 502 |
406 # Remove special instructions which are only allowed in special cases. | 503 # Remove special instructions which are only allowed in special cases. |
407 normal_instruction = one_instruction - special_instruction; | 504 normal_instruction = one_instruction - special_instruction; |
408 | 505 |
409 # Check if call is properly aligned | 506 # Check if call is properly aligned. |
| 507 # |
| 508 # For direct call we explicitly encode all variations. For indirect call |
| 509 # we accept all the special instructions which ends with indirect call. |
410 call_alignment = | 510 call_alignment = |
411 ((normal_instruction & | 511 ((normal_instruction & |
412 # Direct call | 512 # Direct call |
413 ((data16 REX_RXB? 0xe8 rel16) | | 513 ((data16 REX_RXB? 0xe8 rel16) | |
414 (REX_WRXB? 0xe8 rel32) | | 514 (REX_WRXB? 0xe8 rel32) | |
415 (data16 REXW_RXB 0xe8 rel32))) | | 515 (data16 REXW_RXB 0xe8 rel32))) | |
416 (special_instruction & | 516 (special_instruction & |
417 # Indirect call | 517 # Indirect call |
418 (any* data16? REX_WRXB? 0xff ((opcode_2 | opcode_3) any* & | 518 (any* data16? REX_WRXB? 0xff ((opcode_2 | opcode_3) any* & |
419 (modrm_memory | modrm_registers))))) | 519 (modrm_memory | modrm_registers))))) |
| 520 # Call instruction must aligned to the end of bundle. Previously this was |
| 521 # strict requirement, today it's just warning to aid with debugging. |
420 @{ | 522 @{ |
421 if (((current_position - data) & kBundleMask) != kBundleMask) | 523 if (((current_position - data) & kBundleMask) != kBundleMask) |
422 instruction_info_collected |= BAD_CALL_ALIGNMENT; | 524 instruction_info_collected |= BAD_CALL_ALIGNMENT; |
423 }; | 525 }; |
424 | 526 |
425 | 527 |
426 main := ((call_alignment | normal_instruction | special_instruction) | 528 main := ((call_alignment | normal_instruction | special_instruction) |
| 529 # Beginning of the instruction is always valid target for jump. If this |
| 530 # instruction is, in fact, part of the superinstruction then we'll clear |
| 531 # that bit later. |
427 >{ | 532 >{ |
428 BitmapSetBit(valid_targets, current_position - data); | 533 MakeJumpTargetValid(current_position - data, valid_targets); |
429 } | 534 } |
| 535 # Here we call the user callback if there are validation errors or if the |
| 536 # CALL_USER_CALLBACK_ON_EACH_INSTRUCTION option is used. |
| 537 # |
| 538 # After that we move instruction_start and clean all the variables which |
| 539 # only used in the processing of a single instruction (prefixes, operand |
| 540 # states and instruction_info_collected). |
430 @{ | 541 @{ |
431 if ((instruction_info_collected & VALIDATION_ERRORS_MASK) || | 542 if ((instruction_info_collected & VALIDATION_ERRORS_MASK) || |
432 (options & CALL_USER_CALLBACK_ON_EACH_INSTRUCTION)) { | 543 (options & CALL_USER_CALLBACK_ON_EACH_INSTRUCTION)) { |
433 result &= user_callback( | 544 result &= user_callback( |
434 instruction_start, current_position, | 545 instruction_start, current_position, |
435 instruction_info_collected | | 546 instruction_info_collected | |
436 ((restricted_register << RESTRICTED_REGISTER_SHIFT) & | 547 ((restricted_register << RESTRICTED_REGISTER_SHIFT) & |
437 RESTRICTED_REGISTER_MASK), callback_data); | 548 RESTRICTED_REGISTER_MASK), callback_data); |
438 } | 549 } |
439 /* On successful match the instruction start must point to the next byte | 550 /* On successful match the instruction start must point to the next byte |
440 * to be able to report the new offset as the start of instruction | 551 * to be able to report the new offset as the start of instruction |
441 * causing error. */ | 552 * causing error. */ |
442 instruction_start = current_position + 1; | 553 instruction_start = current_position + 1; |
443 instruction_info_collected = 0; | 554 instruction_info_collected = 0; |
444 SET_REX_PREFIX(FALSE); | 555 SET_REX_PREFIX(FALSE); |
| 556 /* Top three bis of VEX2 are inverted: see AMD/Intel manual. */ |
445 SET_VEX_PREFIX2(0xe0); | 557 SET_VEX_PREFIX2(0xe0); |
446 SET_VEX_PREFIX3(0x00); | 558 SET_VEX_PREFIX3(0x00); |
447 operand_states = 0; | 559 operand_states = 0; |
448 })* | 560 })* |
449 $err{ | 561 $err{ |
450 result &= user_callback(instruction_start, current_position, | 562 result &= user_callback(instruction_start, current_position, |
451 UNRECOGNIZED_INSTRUCTION, callback_data); | 563 UNRECOGNIZED_INSTRUCTION, callback_data); |
452 continue; | 564 continue; |
453 }; | 565 }; |
454 | 566 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 user_callback, callback_data); | 644 user_callback, callback_data); |
533 | 645 |
534 /* We only use malloc for a large code sequences */ | 646 /* We only use malloc for a large code sequences */ |
535 if (size > sizeof valid_targets_small) { | 647 if (size > sizeof valid_targets_small) { |
536 free(jump_dests); | 648 free(jump_dests); |
537 free(valid_targets); | 649 free(valid_targets); |
538 } | 650 } |
539 if (!result) errno = EINVAL; | 651 if (!result) errno = EINVAL; |
540 return result; | 652 return result; |
541 } | 653 } |
OLD | NEW |