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 %rbp sandboxing | |
141 rsp_sandboxing = | |
142 (b_0100_11x0 0x01 0xfc | # add %r15,%rsp | |
143 b_0100_10x1 0x03 0xe7 | # add %r15,%rbp | |
144 0x4a 0x8d 0x24 0x3c) # lea (%rsp,%r15,1),%rsp | |
145 @{ if (restricted_register == REG_RSP) | |
146 instruction_info_collected |= RESTRICTED_REGISTER_USED; | |
147 else | |
148 instruction_info_collected |= UNRESTRICTED_RSP_PROCESSED; | |
149 restricted_register = NO_REG; | |
150 BitmapClearBit(valid_targets, (instruction_start - data)); | |
151 }; | |
152 | |
153 # naclcall or nacljmp. Note: first "and $~0x1f, %eXX" is a normal instruction | |
154 # and as such will detect case where %rbp/%rsp is illegally modified. | |
155 naclcall_or_nacljmp = | |
156 # and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
157 (0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
158 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
159 b_0100_11x0 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe|0xff) | |
160 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
161 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
162 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
163 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | |
164 @{ | |
165 instruction_start -= 6; | |
166 if (RMFromModRM(instruction_start[1]) != | |
167 RMFromModRM(instruction_start[5]) || | |
168 RMFromModRM(instruction_start[1]) != RMFromModRM(*current_position)) | |
169 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
170 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
171 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
172 restricted_register = NO_REG; | |
173 } | | |
174 | |
175 # and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
176 (0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
177 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
178 b_0100_10x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7|0xff) | |
179 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
180 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
181 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
182 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | |
183 @{ | |
184 instruction_start -= 6; | |
185 if (RMFromModRM(instruction_start[1]) != | |
186 RegFromModRM(instruction_start[5]) || | |
187 RMFromModRM(instruction_start[1]) != RMFromModRM(*current_position)) | |
188 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
189 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
190 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
191 restricted_register = NO_REG; | |
192 } | | |
193 | |
194 # rex.R?X? and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
195 ((REX_RX 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
196 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
197 b_0100_11x0 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe|0xff) | |
198 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
199 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
200 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
201 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | | |
202 | |
203 # and $~0x1f, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
204 (b_0100_0xx1 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6) 0xe0 | |
205 # add %r15, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
206 b_0100_11x1 0x01 (0xf8|0xf9|0xfa|0xfb|0xfc|0xfd|0xfe) | |
207 # callq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
208 ((b_0100_xxx1 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6)) | | |
209 # jmpq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
210 (b_0100_xxx1 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6))))) | |
211 @{ | |
212 instruction_start -= 7; | |
213 if (RMFromModRM(instruction_start[2]) != | |
214 RMFromModRM(instruction_start[6]) || | |
215 RMFromModRM(instruction_start[2]) != RMFromModRM(*current_position)) | |
216 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
217 BitmapClearBit(valid_targets, (instruction_start - data) + 4); | |
218 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
219 restricted_register = NO_REG; | |
220 } | | |
221 | |
222 # rex.R?X? and $~0x1f, %eax/%ecx/%edx/%ebx/%esp/%ebp/%esi/%edi | |
223 ((REX_RX 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7) 0xe0 | |
224 # add %r15,%rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
225 b_0100_10x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7|0xff) | |
226 # callq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
227 ((REX_WRX? 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6|0xd7)) | | |
228 # jmpq %rax/%rcx/%rdx/%rbx/%rsp/%rbp/%rsi/%rdi | |
229 (REX_WRX? 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6|0xe7)))) | | |
230 | |
231 # and $~0x1f, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
232 (b_0100_0xx1 0x83 (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6) 0xe0 | |
233 # add %r15, %r8d/%r9d/%r10d/%r11d/%r12d/%r13d/%r14d | |
234 b_0100_11x1 0x03 (0xc7|0xcf|0xd7|0xdf|0xe7|0xef|0xf7) | |
235 # callq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
236 ((b_0100_xxx1 0xff (0xd0|0xd1|0xd2|0xd3|0xd4|0xd5|0xd6)) | | |
237 # jmpq %r8/%r9/%r10/%r11/%r12/%r13/%r14 | |
238 (b_0100_xxx1 0xff (0xe0|0xe1|0xe2|0xe3|0xe4|0xe5|0xe6))))) | |
239 @{ | |
240 instruction_start -= 7; | |
241 if (RMFromModRM(instruction_start[2]) != | |
242 RegFromModRM(instruction_start[6]) || | |
243 RMFromModRM(instruction_start[2]) != RMFromModRM(*current_position)) | |
244 instruction_info_collected |= UNRECOGNIZED_INSTRUCTION; | |
245 BitmapClearBit(valid_targets, (instruction_start - data) + 4); | |
246 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
247 restricted_register = NO_REG; | |
248 }; | |
249 | |
250 # EMMS/SSE2/AVX instructions which have implicit %ds:(%rsi) operand | |
251 # maskmovq %mmX,%mmY | |
252 maskmovq = | |
253 REX_WRXB? (0x0f 0xf7) | |
254 @CPUFeature_EMMX modrm_registers; | |
255 # maskmovdqu %xmmX, %xmmY | |
256 maskmovdqu = | |
257 0x66 REX_WRXB? (0x0f 0xf7) @not_data16_prefix | |
258 @CPUFeature_SSE2 modrm_registers; | |
259 # vmaskmovdqu %xmmX, %xmmY | |
260 vmaskmovdqu = | |
261 ((0xc4 (VEX_RB & VEX_map00001) 0x79 @vex_prefix3) | | |
262 (0xc5 (0x79 | 0xf9) @vex_prefix_short)) 0xf7 | |
263 @CPUFeature_AVX modrm_registers; | |
264 mmx_sse_rdi_instruction = maskmovq | maskmovdqu | vmaskmovdqu; | |
265 | |
266 # String instructions which use only %ds:(%rsi) | |
267 string_instruction_rsi_no_rdi = | |
268 (rep? 0xac | # lods %ds:(%rsi),%al | |
269 data16rep 0xad | # lods %ds:(%rsi),%ax | |
270 rep? REXW_NONE? 0xad) ; # lods %ds:(%rsi),%eax/%rax | |
271 | |
272 # String instructions which use only %ds:(%rdi) | |
273 string_instruction_rdi_no_rsi = | |
274 condrep? 0xae | # scas %es:(%rdi),%al | |
275 data16condrep 0xaf | # scas %es:(%rdi),%ax | |
276 condrep? REXW_NONE? 0xaf | # scas %es:(%rdi),%eax/%rax | |
277 | |
278 rep? 0xaa | # stos %al,%es:(%rdi) | |
279 data16rep 0xab | # stos %ax,%es:(%rdi) | |
280 rep? REXW_NONE? 0xab ; # stos %eax/%rax,%es:(%rdi) | |
281 | |
282 # String instructions which use both %ds:(%rsi) and %ds:(%rdi) | |
283 string_instruction_rsi_rdi = | |
284 condrep? 0xa6 | # cmpsb %es:(%rdi),%ds:(%rsi) | |
285 data16condrep 0xa7 | # cmpsw %es:(%rdi),%ds:(%rsi) | |
286 condrep? REXW_NONE? 0xa7 | # cmps[lq] %es:(%rdi),%ds:(%rsi) | |
287 | |
288 rep? 0xa4 | # movsb %es:(%rdi),%ds:(%rsi) | |
289 data16rep 0xa5 | # movsw %es:(%rdi),%ds:(%rsi) | |
290 rep? REXW_NONE? 0xa5 ; # movs[lq] %es:(%rdi),%ds:(%rsi) | |
291 | |
292 sandbox_instruction_rsi_no_rdi = | |
293 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
294 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
295 string_instruction_rsi_no_rdi | |
296 @{ | |
297 instruction_start -= 6; | |
298 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
299 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
300 restricted_register = NO_REG; | |
301 } | | |
302 | |
303 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
304 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
305 string_instruction_rsi_no_rdi | |
306 @{ | |
307 instruction_start -= 7; | |
308 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
309 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
310 restricted_register = NO_REG; | |
311 }; | |
312 | |
313 sandbox_instruction_rdi_no_rsi = | |
314 (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
315 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
316 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) | |
317 @{ | |
318 instruction_start -= 6; | |
319 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
320 BitmapClearBit(valid_targets, (instruction_start - data) + 6); | |
321 restricted_register = NO_REG; | |
322 } | | |
323 | |
324 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
325 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
326 (string_instruction_rdi_no_rsi | mmx_sse_rdi_instruction) | |
327 @{ | |
328 instruction_start -= 7; | |
329 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
330 BitmapClearBit(valid_targets, (instruction_start - data) + 7); | |
331 restricted_register = NO_REG; | |
332 }; | |
333 | |
334 | |
335 # String instructions which use both %ds:(%rsi) and %ds:(%rdi) | |
336 sandbox_instruction_rsi_rdi = | |
337 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
338 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
339 (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
340 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
341 string_instruction_rsi_rdi | |
342 @{ | |
343 instruction_start -= 12; | |
344 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
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 } | | |
350 | |
351 (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
352 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
353 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
354 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
355 string_instruction_rsi_rdi | |
356 @{ | |
357 instruction_start -= 13; | |
358 BitmapClearBit(valid_targets, (instruction_start - data) + 2); | |
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 } | | |
364 | |
365 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
366 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
367 (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
368 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
369 string_instruction_rsi_rdi | |
370 @{ | |
371 instruction_start -= 13; | |
372 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
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 } | | |
378 | |
379 REX_X (0x89 | 0x8b) 0xf6 . # mov %esi,%esi | |
380 0x49 0x8d 0x34 0x37 . # lea (%r15,%rsi,1),%rsi | |
381 REX_X (0x89 | 0x8b) 0xff . # mov %edi,%edi | |
382 0x49 0x8d 0x3c 0x3f . # lea (%r15,%rdi,1),%rdi | |
383 string_instruction_rsi_rdi | |
384 @{ | |
385 instruction_start -= 14; | |
386 BitmapClearBit(valid_targets, (instruction_start - data) + 3); | |
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 }; | |
392 | |
393 special_instruction = | |
394 (rbp_modifications | | |
395 rsp_modifications | | |
396 rbp_sandboxing | | |
397 rsp_sandboxing | | |
398 naclcall_or_nacljmp | | |
399 sandbox_instruction_rsi_no_rdi | | |
400 sandbox_instruction_rdi_no_rsi | | |
401 sandbox_instruction_rsi_rdi) | |
402 @{ | |
403 instruction_info_collected |= SPECIAL_INSTRUCTION; | |
404 }; | |
405 | |
406 # Remove special instructions which are only allowed in special cases. | |
407 normal_instruction = one_instruction - special_instruction; | |
408 | |
409 # Check if call is properly aligned | |
410 call_alignment = | |
411 ((normal_instruction & | |
412 # Direct call | |
413 ((data16 REX_RXB? 0xe8 rel16) | | |
414 (REX_WRXB? 0xe8 rel32) | | |
415 (data16 REXW_RXB 0xe8 rel32))) | | |
416 (special_instruction & | |
417 # Indirect call | |
418 (any* data16? REX_WRXB? 0xff ((opcode_2 | opcode_3) any* & | |
419 (modrm_memory | modrm_registers))))) | |
420 @{ | |
421 if (((current_position - data) & kBundleMask) != kBundleMask) | |
422 instruction_info_collected |= BAD_CALL_ALIGNMENT; | |
423 }; | |
424 | |
425 | |
426 main := ((call_alignment | normal_instruction | special_instruction) | |
427 >{ | |
428 BitmapSetBit(valid_targets, current_position - data); | |
429 } | |
430 @{ | |
431 if ((instruction_info_collected & | |
432 (VALIDATION_ERRORS_MASK | BAD_CALL_ALIGNMENT)) || | |
433 (options & CALL_USER_CALLBACK_ON_EACH_INSTRUCTION)) { | |
434 result &= user_callback( | |
435 instruction_start, current_position, | |
436 instruction_info_collected | | |
437 ((restricted_register << RESTRICTED_REGISTER_SHIFT) & | |
438 RESTRICTED_REGISTER_MASK), callback_data); | |
439 } | |
440 /* On successful match the instruction start must point to the next byte | |
441 * to be able to report the new offset as the start of instruction | |
442 * causing error. */ | |
443 instruction_start = current_position + 1; | |
444 instruction_info_collected = 0; | |
445 SET_REX_PREFIX(FALSE); | |
446 SET_VEX_PREFIX2(0xe0); | |
447 SET_VEX_PREFIX3(0x00); | |
448 operand_states = 0; | |
449 })* | |
450 $err{ | |
451 result &= user_callback(instruction_start, current_position, | |
452 UNRECOGNIZED_INSTRUCTION, callback_data); | |
453 continue; | |
454 }; | |
455 | |
456 }%% | |
457 | |
458 %% write data; | |
459 | |
460 Bool ValidateChunkAMD64(const uint8_t *data, size_t size, | |
461 enum validation_options options, | |
462 const NaClCPUFeaturesX86 *cpu_features, | |
463 validation_callback_func user_callback, | |
464 void *callback_data) { | |
465 bitmap_word valid_targets_small; | |
466 bitmap_word jump_dests_small; | |
467 bitmap_word *valid_targets; | |
468 bitmap_word *jump_dests; | |
469 const uint8_t *current_position; | |
470 const uint8_t *end_of_bundle; | |
471 int result = TRUE; | |
472 | |
473 CHECK(sizeof valid_targets_small == sizeof jump_dests_small); | |
474 CHECK(size % kBundleSize == 0); | |
475 | |
476 /* For a very small sequence (one bundle) malloc is too expensive. */ | |
477 if (size <= sizeof valid_targets_small) { | |
478 valid_targets_small = 0; | |
479 valid_targets = &valid_targets_small; | |
480 jump_dests_small = 0; | |
481 jump_dests = &jump_dests_small; | |
482 } else { | |
483 valid_targets = BitmapAllocate(size); | |
484 jump_dests = BitmapAllocate(size); | |
485 if (!valid_targets || !jump_dests) { | |
486 free(jump_dests); | |
487 free(valid_targets); | |
488 errno = ENOMEM; | |
489 return FALSE; | |
490 } | |
491 } | |
492 | |
493 if (options & PROCESS_CHUNK_AS_A_CONTIGUOUS_STREAM) | |
494 end_of_bundle = data + size; | |
495 else | |
496 end_of_bundle = data + kBundleSize; | |
497 | |
498 for (current_position = data; | |
499 current_position < data + size; | |
500 current_position = end_of_bundle, | |
501 end_of_bundle = current_position + kBundleSize) { | |
502 /* Start of the instruction being processed. */ | |
503 const uint8_t *instruction_start = current_position; | |
504 int current_state; | |
505 uint32_t instruction_info_collected = 0; | |
506 /* Keeps one byte of information per operand in the current instruction: | |
507 * 2 bits for register kinds, | |
508 * 5 bits for register numbers (16 regs plus RIZ). */ | |
509 uint32_t operand_states = 0; | |
510 enum register_name base = NO_REG; | |
511 enum register_name index = NO_REG; | |
512 enum register_name restricted_register = NO_REG; | |
513 uint8_t rex_prefix = FALSE; | |
514 uint8_t vex_prefix2 = 0xe0; | |
515 uint8_t vex_prefix3 = 0x00; | |
516 | |
517 %% write init; | |
518 %% write exec; | |
519 | |
520 if (restricted_register == REG_RBP) | |
521 result &= user_callback(end_of_bundle, end_of_bundle, | |
522 RESTRICTED_RBP_UNPROCESSED | | |
523 ((REG_RBP << RESTRICTED_REGISTER_SHIFT) & | |
524 RESTRICTED_REGISTER_MASK), callback_data); | |
525 else if (restricted_register == REG_RSP) | |
526 result &= user_callback(end_of_bundle, end_of_bundle, | |
527 RESTRICTED_RSP_UNPROCESSED | | |
528 ((REG_RSP << RESTRICTED_REGISTER_SHIFT) & | |
529 RESTRICTED_REGISTER_MASK), callback_data); | |
530 } | |
531 | |
532 result &= ProcessInvalidJumpTargets(data, size, valid_targets, jump_dests, | |
533 user_callback, callback_data); | |
534 | |
535 /* We only use malloc for a large code sequences */ | |
536 if (size > sizeof valid_targets_small) { | |
537 free(jump_dests); | |
538 free(valid_targets); | |
539 } | |
540 if (!result) errno = EINVAL; | |
541 return result; | |
542 } | |
OLD | NEW |