OLD | NEW |
| (Empty) |
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 #include <assert.h> | |
8 #include <errno.h> | |
9 #include <stddef.h> | |
10 #include <stdio.h> | |
11 #include <stdlib.h> | |
12 #include <string.h> | |
13 | |
14 #include "native_client/src/trusted/validator_ragel/unreviewed/validator_interna
l.h" | |
15 | |
16 %%{ | |
17 machine x86_64_validator; | |
18 alphtype unsigned char; | |
19 variable p current_position; | |
20 variable pe end_of_bundle; | |
21 variable eof end_of_bundle; | |
22 variable cs current_state; | |
23 | |
24 include byte_machine "byte_machines.rl"; | |
25 | |
26 include prefix_actions | |
27 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
28 include prefixes_parsing | |
29 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
30 include rex_actions | |
31 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
32 include rex_parsing | |
33 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
34 include vex_actions_amd64 | |
35 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
36 include vex_parsing_amd64 | |
37 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
38 include displacement_fields_actions | |
39 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
40 include displacement_fields_parsing | |
41 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
42 include modrm_actions_amd64 | |
43 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
44 include modrm_parsing_amd64 | |
45 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
46 include operand_actions_amd64 | |
47 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
48 include immediate_fields_actions | |
49 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
50 include immediate_fields_parsing_amd64 | |
51 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
52 action rel8_operand { | |
53 rel8_operand(current_position + 1, data, jump_dests, size, | |
54 &instruction_info_collected); | |
55 } | |
56 action rel16_operand { | |
57 #error rel16_operand should never be used in nacl | |
58 } | |
59 action rel32_operand { | |
60 rel32_operand(current_position + 1, data, jump_dests, size, | |
61 &instruction_info_collected); | |
62 } | |
63 include relative_fields_parsing | |
64 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
65 include cpuid_actions | |
66 "native_client/src/trusted/validator_ragel/unreviewed/parse_instruction.rl"; | |
67 | |
68 action check_access { | |
69 check_access(instruction_start - data, base, index, restricted_register, | |
70 valid_targets, &instruction_info_collected); | |
71 } | |
72 | |
73 action last_byte_is_not_immediate { | |
74 instruction_info_collected |= LAST_BYTE_IS_NOT_IMMEDIATE; | |
75 } | |
76 | |
77 action modifiable_instruction { | |
78 instruction_info_collected |= MODIFIABLE_INSTRUCTION; | |
79 } | |
80 | |
81 action process_0_operands { | |
82 process_0_operands(&restricted_register, &instruction_info_collected); | |
83 } | |
84 action process_1_operand { | |
85 process_1_operand(&restricted_register, &instruction_info_collected, | |
86 rex_prefix, operand_states); | |
87 } | |
88 action process_1_operand_zero_extends { | |
89 process_1_operand_zero_extends(&restricted_register, | |
90 &instruction_info_collected, rex_prefix, | |
91 operand_states); | |
92 } | |
93 action process_2_operands { | |
94 process_2_operands(&restricted_register, &instruction_info_collected, | |
95 rex_prefix, operand_states); | |
96 } | |
97 action process_2_operands_zero_extends { | |
98 process_2_operands_zero_extends(&restricted_register, | |
99 &instruction_info_collected, rex_prefix, | |
100 operand_states); | |
101 } | |
102 | |
103 include decode_x86_64 "validator_x86_64_instruction.rl"; | |
104 | |
105 data16condrep = (data16 | condrep data16 | data16 condrep); | |
106 data16rep = (data16 | rep data16 | data16 rep); | |
107 | |
108 # Special %rbp modifications without required sandboxing | |
109 rbp_modifications = | |
110 (b_0100_10x0 0x89 0xe5) | # mov %rsp,%rbp | |
111 (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; | |
115 | |
116 # Special instructions used for %rbp sandboxing | |
117 rbp_sandboxing = | |
118 (b_0100_11x0 0x01 0xfd | # add %r15,%rbp | |
119 b_0100_10x1 0x03 0xef | # add %r15,%rbp | |
120 0x49 0x8d 0x2c 0x2f | # lea (%r15,%rbp,1),%rbp | |
121 0x4a 0x8d 0x6c 0x3d 0x00) # lea 0x0(%rbp,%r15,1),%rbp | |
122 @{ if (restricted_register == REG_RBP) | |
123 instruction_info_collected |= RESTRICTED_REGISTER_USED; | |
124 else | |
125 instruction_info_collected |= UNRESTRICTED_RBP_PROCESSED; | |
126 restricted_register = NO_REG; | |
127 BitmapClearBit(valid_targets, (instruction_start - data)); | |
128 }; | |
129 | |
130 # Special %rbp modifications without required sandboxing | |
131 rsp_modifications = | |
132 (b_0100_10x0 0x89 0xec) | # mov %rbp,%rsp | |
133 (b_0100_10x0 0x8b 0xe5) | # mov %rbp,%rsp | |
134 #(b_0100_1xx0 0x81 0xe4 any{3} (0x80 .. 0xff)) | # and $XXX,%rsp | |
135 #Superfluous bits are not supported: | |
136 # http://code.google.com/p/nativeclient/issues/detail?id=3012 | |
137 (b_0100_1000 0x83 0xe4 (0x80 .. 0xff)) # and $XXX,%rsp | |
138 @process_0_operands; | |
139 | |
140 # Special instructions used for %rsp sandboxing | |
141 rsp_sandboxing = | |
142 (b_0100_11x0 0x01 0xfc | # add %r15,%rsp | |
143 b_0100_10x1 0x03 0xe7 | # add %r15,%rsp | |
144 # OR can be used as well, see | |
145 # http://code.google.com/p/nativeclient/issues/detail?id=3070 | |
146 b_0100_11x0 0x09 0xfc | # or %r15,%rsp | |
147 b_0100_10x1 0x0b 0xe7 | # or %r15,%rsp | |
148 0x4a 0x8d 0x24 0x3c) # lea (%rsp,%r15,1),%rsp | |
149 @{ if (restricted_register == REG_RSP) | |
150 instruction_info_collected |= RESTRICTED_REGISTER_USED; | |
151 else | |
152 instruction_info_collected |= UNRESTRICTED_RSP_PROCESSED; | |
153 restricted_register = NO_REG; | |
154 BitmapClearBit(valid_targets, (instruction_start - data)); | |
155 }; | |
156 | |
157 # naclcall or nacljmp. Note: first "and $~0x1f, %eXX" is a normal instruction | |
158 # and as such will detect case where %rbp/%rsp is illegally modified. | |
159 naclcall_or_nacljmp = | |
160 # and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
161 (0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
162 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
163 b_0100_11x0 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe|0xff) | |
164 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
165 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
166 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
167 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | |
168 @{ | |
169 instruction_start -= 6; | |
170 if (RMFromModRM(instruction_start[1]) != | |
171 RMFromModRM(instruction_start[5]) || | |
172 RMFromModRM(instruction_start[1]) != RMFromModRM(*current_position)) | |
173 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
174 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
175 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
176 restricted_register = NO_REG; | |
177 } | | |
178 | |
179 # and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
180 (0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
181 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
182 b_0100_10x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7|0xff) | |
183 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
184 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
185 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
186 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | |
187 @{ | |
188 instruction_start -= 6; | |
189 if (RMFromModRM(instruction_start[1]) != | |
190 RegFromModRM(instruction_start[5]) || | |
191 RMFromModRM(instruction_start[1]) != RMFromModRM(*current_position)) | |
192 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
193 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
194 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
195 restricted_register = NO_REG; | |
196 } | | |
197 | |
198 # rex.R?X? and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
199 ((REX_RX 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
200 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
201 b_0100_11x0 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe|0xff) | |
202 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
203 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
204 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
205 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | | |
206 | |
207 # and $~0x1f, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
208 (b_0100_0xx1 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6) 0xe0 | |
209 # add %r15, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
210 b_0100_11x1 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe) | |
211 # callq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
212 ((b_0100_xxx1 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6)) | | |
213 # jmpq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
214 (b_0100_xxx1 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6))))) | |
215 @{ | |
216 instruction_start -= 7; | |
217 if (RMFromModRM(instruction_start[2]) != | |
218 RMFromModRM(instruction_start[6]) || | |
219 RMFromModRM(instruction_start[2]) != RMFromModRM(*current_position)) | |
220 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
221 BitmapClearBit(valid_targets, (instruction_start - data) + 4); | |
222 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
223 restricted_register = NO_REG; | |
224 } | | |
225 | |
226 # rex.R?X? and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
227 ((REX_RX 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
228 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
229 b_0100_10x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7|0xff) | |
230 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
231 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
232 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
233 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | | |
234 | |
235 # and $~0x1f, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
236 (b_0100_0xx1 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6) 0xe0 | |
237 # add %r15, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
238 b_0100_11x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7) | |
239 # callq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
240 ((b_0100_xxx1 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6)) | | |
241 # jmpq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
242 (b_0100_xxx1 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6))))) | |
243 @{ | |
244 instruction_start -= 7; | |
245 if (RMFromModRM(instruction_start[2]) != | |
246 RegFromModRM(instruction_start[6]) || | |
247 RMFromModRM(instruction_start[2]) != RMFromModRM(*current_position)) | |
248 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
249 BitmapClearBit(valid_targets, (instruction_start - data) + 4); | |
250 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
251 restricted_register = NO_REG; | |
252 }; | |
253 | |
254 # EMMS/SSE2/AVX instructions which have implicit %ds:(%rsi) operand | |
255 # maskmovq %mmX,%mmY | |
256 maskmovq = | |
257 REX_WRXB? (0x0f 0xf7) | |
258 @CPUFeature_EMMX modrm_registers; | |
259 # maskmovdqu %xmmX, %xmmY | |
260 maskmovdqu = | |
261 0x66 REX_WRXB? (0x0f 0xf7) @not_data16_prefix | |
262 @CPUFeature_SSE2 modrm_registers; | |
263 # vmaskmovdqu %xmmX, %xmmY | |
264 vmaskmovdqu = | |
265 ((0xc4 (VEX_RB & VEX_map00001) 0x79 @vex_prefix3) | | |
266 (0xc5 (0x79 | 0xf9) @vex_prefix_short)) 0xf7 | |
267 @CPUFeature_AVX modrm_registers; | |
268 mmx_sse_rdi_instruction = maskmovq | maskmovdqu | vmaskmovdqu; | |
269 | |
270 # String instructions which use only %ds:(%rsi) | |
271 string_instruction_rsi_no_rdi = | |
272 (rep? 0xac | # lods %ds:(%rsi),%al | |
273 data16rep 0xad | # lods %ds:(%rsi),%ax | |
274 rep? REXW_NONE? 0xad) ; # lods %ds:(%rsi),%eax/%rax | |
275 | |
276 # String instructions which use only %ds:(%rdi) | |
277 string_instruction_rdi_no_rsi = | |
278 condrep? 0xae | # scas %es:(%rdi),%al | |
279 data16condrep 0xaf | # scas %es:(%rdi),%ax | |
280 condrep? REXW_NONE? 0xaf | # scas %es:(%rdi),%eax/%rax | |
281 | |
282 rep? 0xaa | # stos %al,%es:(%rdi) | |
283 data16rep 0xab | # stos %ax,%es:(%rdi) | |
284 rep? REXW_NONE? 0xab ; # stos %eax/%rax,%es:(%rdi) | |
285 | |
286 # String instructions which use both %ds:(%rsi) and %ds:(%rdi) | |
287 string_instruction_rsi_rdi = | |
288 condrep? 0xa6 | # cmpsb %es:(%rdi),%ds:(%rsi) | |
289 data16condrep 0xa7 | # cmpsw %es:(%rdi),%ds:(%rsi) | |
290 condrep? REXW_NONE? 0xa7 | # cmps[lq] %es:(%rdi),%ds:(%rsi) | |
291 | |
292 rep? 0xa4 | # movsb %es:(%rdi),%ds:(%rsi) | |
293 data16rep 0xa5 | # movsw %es:(%rdi),%ds:(%rsi) | |
294 rep? REXW_NONE? 0xa5 ; # movs[lq] %es:(%rdi),%ds:(%rsi) | |
295 | |
296 sandbox_instruction_rsi_no_rdi = | |
297 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
298 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
299 string_instruction_rsi_no_rdi | |
300 @{ | |
301 instruction_start -= 6; | |
302 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
303 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
304 restricted_register = NO_REG; | |
305 } | | |
306 | |
307 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
308 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
309 string_instruction_rsi_no_rdi | |
310 @{ | |
311 instruction_start -= 7; | |
312 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
313 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
314 restricted_register = NO_REG; | |
315 }; | |
316 | |
317 sandbox_instruction_rdi_no_rsi = | |
318 (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
319 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
320 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) | |
321 @{ | |
322 instruction_start -= 6; | |
323 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
324 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
325 restricted_register = NO_REG; | |
326 } | | |
327 | |
328 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
329 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
330 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) | |
331 @{ | |
332 instruction_start -= 7; | |
333 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
334 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
335 restricted_register = NO_REG; | |
336 }; | |
337 | |
338 | |
339 # String instructions which use both %ds:(%rsi) and %ds:(%rdi) | |
340 sandbox_instruction_rsi_rdi = | |
341 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
342 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
343 (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
344 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
345 string_instruction_rsi_rdi | |
346 @{ | |
347 instruction_start -= 12; | |
348 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
349 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
350 BitmapClearBit(valid_targets, (instruction_start - data) + 8); | |
351 BitmapClearBit(valid_targets, (instruction_start - data) + 12); | |
352 restricted_register = NO_REG; | |
353 } | | |
354 | |
355 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
356 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
357 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
358 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
359 string_instruction_rsi_rdi | |
360 @{ | |
361 instruction_start -= 13; | |
362 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
363 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
364 BitmapClearBit(valid_targets, (instruction_start - data) + 9); | |
365 BitmapClearBit(valid_targets, (instruction_start - data) + 13); | |
366 restricted_register = NO_REG; | |
367 } | | |
368 | |
369 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
370 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
371 (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
372 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
373 string_instruction_rsi_rdi | |
374 @{ | |
375 instruction_start -= 13; | |
376 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
377 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
378 BitmapClearBit(valid_targets, (instruction_start - data) + 9); | |
379 BitmapClearBit(valid_targets, (instruction_start - data) + 13); | |
380 restricted_register = NO_REG; | |
381 } | | |
382 | |
383 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
384 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
385 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
386 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
387 string_instruction_rsi_rdi | |
388 @{ | |
389 instruction_start -= 14; | |
390 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
391 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
392 BitmapClearBit(valid_targets, (instruction_start - data) + 10); | |
393 BitmapClearBit(valid_targets, (instruction_start - data) + 14); | |
394 restricted_register = NO_REG; | |
395 }; | |
396 | |
397 special_instruction = | |
398 (rbp_modifications | | |
399 rsp_modifications | | |
400 rbp_sandboxing | | |
401 rsp_sandboxing | | |
402 naclcall_or_nacljmp | | |
403 sandbox_instruction_rsi_no_rdi | | |
404 sandbox_instruction_rdi_no_rsi | | |
405 sandbox_instruction_rsi_rdi) | |
406 @{ | |
407 instruction_info_collected |= SPECIAL_INSTRUCTION; | |
408 }; | |
409 | |
410 # Remove special instructions which are only allowed in special cases. | |
411 normal_instruction = one_instruction - special_instruction; | |
412 | |
413 # Check if call is properly aligned | |
414 call_alignment = | |
415 ((normal_instruction & | |
416 # Direct call | |
417 ((data16 REX_RXB? 0xe8 rel16) | | |
418 (REX_WRXB? 0xe8 rel32) | | |
419 (data16 REXW_RXB 0xe8 rel32))) | | |
420 (special_instruction & | |
421 # Indirect call | |
422 (any* data16? REX_WRXB? 0xff ((opcode_2 | opcode_3) any* & | |
423 (modrm_memory | modrm_registers))))) | |
424 @{ | |
425 if (((current_position - data) & kBundleMask) != kBundleMask) | |
426 instruction_info_collected |= BAD_CALL_ALIGNMENT; | |
427 }; | |
428 | |
429 | |
430 main := ((call_alignment | normal_instruction | special_instruction) | |
431 >{ | |
432 BitmapSetBit(valid_targets, current_position - data); | |
433 } | |
434 @{ | |
435 if ((instruction_info_collected & VALIDATION_ERRORS_MASK) || | |
436 (options & CALL_USER_CALLBACK_ON_EACH_INSTRUCTION)) { | |
437 result &= user_callback( | |
438 instruction_start, current_position, | |
439 instruction_info_collected | | |
440 ((restricted_register << RESTRICTED_REGISTER_SHIFT) & | |
441 RESTRICTED_REGISTER_MASK), callback_data); | |
442 } | |
443 /* On successful match the instruction start must point to the next byte | |
444 * to be able to report the new offset as the start of instruction | |
445 * causing error. */ | |
446 instruction_start = current_position + 1; | |
447 instruction_info_collected = 0; | |
448 SET_REX_PREFIX(FALSE); | |
449 SET_VEX_PREFIX2(0xe0); | |
450 SET_VEX_PREFIX3(0x00); | |
451 operand_states = 0; | |
452 })* | |
453 $err{ | |
454 result &= user_callback(instruction_start, current_position, | |
455 UNRECOGNIZED_INSTRUCTION, callback_data); | |
456 continue; | |
457 }; | |
458 | |
459 }%% | |
460 | |
461 %% write data; | |
462 | |
463 Bool ValidateChunkAMD64(const uint8_t *data, size_t size, | |
464 enum ValidationOptions options, | |
465 const NaClCPUFeaturesX86 *cpu_features, | |
466 ValidationCallbackFunc user_callback, | |
467 void *callback_data) { | |
468 bitmap_word valid_targets_small; | |
469 bitmap_word jump_dests_small; | |
470 bitmap_word *valid_targets; | |
471 bitmap_word *jump_dests; | |
472 const uint8_t *current_position; | |
473 const uint8_t *end_of_bundle; | |
474 int result = TRUE; | |
475 | |
476 CHECK(sizeof valid_targets_small == sizeof jump_dests_small); | |
477 CHECK(size % kBundleSize == 0); | |
478 | |
479 /* For a very small sequence (one bundle) malloc is too expensive. */ | |
480 if (size <= sizeof valid_targets_small) { | |
481 valid_targets_small = 0; | |
482 valid_targets = &valid_targets_small; | |
483 jump_dests_small = 0; | |
484 jump_dests = &jump_dests_small; | |
485 } else { | |
486 valid_targets = BitmapAllocate(size); | |
487 jump_dests = BitmapAllocate(size); | |
488 if (!valid_targets || !jump_dests) { | |
489 free(jump_dests); | |
490 free(valid_targets); | |
491 errno = ENOMEM; | |
492 return FALSE; | |
493 } | |
494 } | |
495 | |
496 if (options & PROCESS_CHUNK_AS_A_CONTIGUOUS_STREAM) | |
497 end_of_bundle = data + size; | |
498 else | |
499 end_of_bundle = data + kBundleSize; | |
500 | |
501 for (current_position = data; | |
502 current_position < data + size; | |
503 current_position = end_of_bundle, | |
504 end_of_bundle = current_position + kBundleSize) { | |
505 /* Start of the instruction being processed. */ | |
506 const uint8_t *instruction_start = current_position; | |
507 int current_state; | |
508 uint32_t instruction_info_collected = 0; | |
509 /* Keeps one byte of information per operand in the current instruction: | |
510 * 2 bits for register kinds, | |
511 * 5 bits for register numbers (16 regs plus RIZ). */ | |
512 uint32_t operand_states = 0; | |
513 enum OperandName base = NO_REG; | |
514 enum OperandName index = NO_REG; | |
515 enum OperandName restricted_register = NO_REG; | |
516 uint8_t rex_prefix = FALSE; | |
517 uint8_t vex_prefix2 = 0xe0; | |
518 uint8_t vex_prefix3 = 0x00; | |
519 | |
520 %% write init; | |
521 %% write exec; | |
522 | |
523 if (restricted_register == REG_RBP) | |
524 result &= user_callback(end_of_bundle, end_of_bundle, | |
525 RESTRICTED_RBP_UNPROCESSED | | |
526 ((REG_RBP << RESTRICTED_REGISTER_SHIFT) & | |
527 RESTRICTED_REGISTER_MASK), callback_data); | |
528 else if (restricted_register == REG_RSP) | |
529 result &= user_callback(end_of_bundle, end_of_bundle, | |
530 RESTRICTED_RSP_UNPROCESSED | | |
531 ((REG_RSP << RESTRICTED_REGISTER_SHIFT) & | |
532 RESTRICTED_REGISTER_MASK), callback_data); | |
533 } | |
534 | |
535 result &= ProcessInvalidJumpTargets(data, size, valid_targets, jump_dests, | |
536 user_callback, callback_data); | |
537 | |
538 /* We only use malloc for a large code sequences */ | |
539 if (size > sizeof valid_targets_small) { | |
540 free(jump_dests); | |
541 free(valid_targets); | |
542 } | |
543 if (!result) errno = EINVAL; | |
544 return result; | |
545 } | |
OLD | NEW |