| 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 |