| 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 #include <assert.h> | 7 #include <assert.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdio.h> | 9 #include <stdio.h> |
| 10 #include <stdlib.h> | 10 #include <stdlib.h> |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 81 action rel16_operand { | 81 action rel16_operand { |
| 82 assert(FALSE); | 82 assert(FALSE); |
| 83 } | 83 } |
| 84 action rel32_operand { | 84 action rel32_operand { |
| 85 int32_t offset = | 85 int32_t offset = |
| 86 (uint32_t) (p[-3] + 256U * (p[-2] + 256U * (p[-1] + 256U * (p[0])))); | 86 (uint32_t) (p[-3] + 256U * (p[-2] + 256U * (p[-1] + 256U * (p[0])))); |
| 87 size_t jump_dest = offset + (p - data); | 87 size_t jump_dest = offset + (p - data); |
| 88 check_jump_dest; | 88 check_jump_dest; |
| 89 } | 89 } |
| 90 | 90 |
| 91 include decode_x86_64 "validator-x86_64-instruction.rl"; | 91 action process_0_operands { |
| 92 | |
| 93 action process_normal_instruction { | |
| 94 /* Restricted %rsp or %rbp must be processed by appropriate nacl-special | 92 /* Restricted %rsp or %rbp must be processed by appropriate nacl-special |
| 95 instruction, not with regular instruction. */ | 93 * instruction, not with regular instruction. */ |
| 96 if (restricted_register == REG_RSP) { | 94 if (restricted_register == REG_RSP) { |
| 97 PrintError("Incorrectly modified register %%rsp\n", begin - data); | 95 PrintError("Incorrectly modified register %%rsp\n", begin - data); |
| 98 result = 1; | 96 result = 1; |
| 97 goto error_detected; |
| 98 } else if (restricted_register == REG_RBP) { |
| 99 PrintError("Incorrectly modified register %%rbp\n", begin - data); |
| 100 result = 1; |
| 101 goto error_detected; |
| 102 } |
| 103 restricted_register = kNoRestrictedReg; |
| 104 } |
| 105 |
| 106 action process_1_operands { |
| 107 /* Restricted %rsp or %rbp must be processed by appropriate nacl-special |
| 108 * instruction, not with regular instruction. */ |
| 109 if (restricted_register == REG_RSP) { |
| 110 PrintError("Incorrectly modified register %%rsp\n", begin - data); |
| 111 result = 1; |
| 99 goto error_detected; | 112 goto error_detected; |
| 100 } else if (restricted_register == REG_RBP) { | 113 } else if (restricted_register == REG_RBP) { |
| 101 PrintError("Incorrectly modified register %%rbp\n", begin - data); | 114 PrintError("Incorrectly modified register %%rbp\n", begin - data); |
| 102 result = 1; | 115 result = 1; |
| 103 goto error_detected; | 116 goto error_detected; |
| 104 } | 117 } |
| 105 /* If Sandboxed Rsi is destroyed then we must note that. */ | 118 /* If Sandboxed Rsi is destroyed then we must detect that. */ |
| 119 if (restricted_register == kSandboxedRsi) { |
| 120 if (CHECK_OPERAND(0, REG_RSI, OperandSandboxRestricted) || |
| 121 CHECK_OPERAND(0, REG_RSI, OperandSandboxUnrestricted)) { |
| 122 restricted_register = kNoRestrictedReg; |
| 123 } |
| 124 } |
| 125 if (restricted_register == kSandboxedRsi) { |
| 126 if (CHECK_OPERAND(0, REG_RDI, OperandSandboxRestricted)) { |
| 127 sandboxed_rsi_restricted_rdi = begin; |
| 128 restricted_register = kSandboxedRsiRestrictedRdi; |
| 129 } |
| 130 } |
| 131 if (restricted_register != kSandboxedRsiRestrictedRdi) { |
| 132 restricted_register = kNoRestrictedReg; |
| 133 if (CHECK_OPERAND(0, REG_R15, OperandSandbox8bit) || |
| 134 CHECK_OPERAND(0, REG_R15, OperandSandboxRestricted) || |
| 135 CHECK_OPERAND(0, REG_R15, OperandSandboxUnrestricted)) { |
| 136 PrintError("Incorrectly modified register %%r15\n", begin - data); |
| 137 result = 1; |
| 138 goto error_detected; |
| 139 } else if ((CHECK_OPERAND(0, REG_RBP, OperandSandbox8bit) && |
| 140 GET_REX_PREFIX()) || |
| 141 CHECK_OPERAND(0, REG_RBP, OperandSandboxUnrestricted)) { |
| 142 PrintError("Incorrectly modified register %%rbp\n", begin - data); |
| 143 result = 1; |
| 144 goto error_detected; |
| 145 } else if ((CHECK_OPERAND(0, REG_RSP, OperandSandbox8bit) && |
| 146 GET_REX_PREFIX()) || |
| 147 CHECK_OPERAND(0, REG_RSP, OperandSandboxUnrestricted)) { |
| 148 PrintError("Incorrectly modified register %%rsp\n", begin - data); |
| 149 result = 1; |
| 150 goto error_detected; |
| 151 /* Take 2 bits of operand type from operand_states as restricted_register, |
| 152 * make sure operand_states denotes a register (4th bit == 0). */ |
| 153 } else if ((operand_states & 0x70) == (OperandSandboxRestricted << 5)) { |
| 154 restricted_register = operand_states & 0x0f; |
| 155 } |
| 156 } |
| 157 } |
| 158 |
| 159 action process_2_operands { |
| 160 /* Restricted %rsp or %rbp must be processed by appropriate nacl-special |
| 161 * instruction, not with regular instruction. */ |
| 162 if (restricted_register == REG_RSP) { |
| 163 PrintError("Incorrectly modified register %%rsp\n", begin - data); |
| 164 result = 1; |
| 165 goto error_detected; |
| 166 } else if (restricted_register == REG_RBP) { |
| 167 PrintError("Incorrectly modified register %%rbp\n", begin - data); |
| 168 result = 1; |
| 169 goto error_detected; |
| 170 } |
| 171 /* If Sandboxed Rsi is destroyed then we must detect that. */ |
| 106 if (restricted_register == kSandboxedRsi) { | 172 if (restricted_register == kSandboxedRsi) { |
| 107 if (CHECK_OPERAND(0, REG_RSI, OperandSandboxRestricted) || | 173 if (CHECK_OPERAND(0, REG_RSI, OperandSandboxRestricted) || |
| 108 CHECK_OPERAND(0, REG_RSI, OperandSandboxUnrestricted) || | 174 CHECK_OPERAND(0, REG_RSI, OperandSandboxUnrestricted) || |
| 109 CHECK_OPERAND(1, REG_RSI, OperandSandboxRestricted) || | 175 CHECK_OPERAND(1, REG_RSI, OperandSandboxRestricted) || |
| 110 CHECK_OPERAND(1, REG_RSI, OperandSandboxUnrestricted)) { | 176 CHECK_OPERAND(1, REG_RSI, OperandSandboxUnrestricted)) { |
| 111 restricted_register = kNoRestrictedReg; | 177 restricted_register = kNoRestrictedReg; |
| 112 } | 178 } |
| 113 } | 179 } |
| 114 if (restricted_register == kSandboxedRsi) { | 180 if (restricted_register == kSandboxedRsi) { |
| 115 if (CHECK_OPERAND(0, REG_RDI, OperandSandboxRestricted) || | 181 if (CHECK_OPERAND(0, REG_RDI, OperandSandboxRestricted) || |
| (...skipping 24 matching lines...) Expand all Loading... |
| 140 goto error_detected; | 206 goto error_detected; |
| 141 } else if ((CHECK_OPERAND(0, REG_RSP, OperandSandbox8bit) && | 207 } else if ((CHECK_OPERAND(0, REG_RSP, OperandSandbox8bit) && |
| 142 GET_REX_PREFIX()) || | 208 GET_REX_PREFIX()) || |
| 143 CHECK_OPERAND(0, REG_RSP, OperandSandboxUnrestricted) || | 209 CHECK_OPERAND(0, REG_RSP, OperandSandboxUnrestricted) || |
| 144 (CHECK_OPERAND(1, REG_RSP, OperandSandbox8bit) && | 210 (CHECK_OPERAND(1, REG_RSP, OperandSandbox8bit) && |
| 145 GET_REX_PREFIX()) || | 211 GET_REX_PREFIX()) || |
| 146 CHECK_OPERAND(1, REG_RSP, OperandSandboxUnrestricted)) { | 212 CHECK_OPERAND(1, REG_RSP, OperandSandboxUnrestricted)) { |
| 147 PrintError("Incorrectly modified register %%rsp\n", begin - data); | 213 PrintError("Incorrectly modified register %%rsp\n", begin - data); |
| 148 result = 1; | 214 result = 1; |
| 149 goto error_detected; | 215 goto error_detected; |
| 216 /* Take 2 bits of operand type from operand_states as restricted_register, |
| 217 * make sure operand_states denotes a register (4th bit == 0). */ |
| 150 } else if ((operand_states & 0x70) == (OperandSandboxRestricted << 5)) { | 218 } else if ((operand_states & 0x70) == (OperandSandboxRestricted << 5)) { |
| 151 restricted_register = operand_states & 0x0f; | 219 restricted_register = operand_states & 0x0f; |
| 220 /* Take 2 bits of operand type from operand_states as restricted_register, |
| 221 * make sure operand_states denotes a register (12th bit == 0). */ |
| 152 } else if ((operand_states & 0x7000) == | 222 } else if ((operand_states & 0x7000) == |
| 153 (OperandSandboxRestricted << (5 + 8))) { | 223 (OperandSandboxRestricted << (5 + 8))) { |
| 154 restricted_register = (operand_states & 0x0f00) >> 8; | 224 restricted_register = (operand_states & 0x0f00) >> 8; |
| 155 } | 225 } |
| 156 } | 226 } |
| 157 } | 227 } |
| 158 | 228 |
| 229 include decode_x86_64 "validator-x86_64-instruction.rl"; |
| 230 |
| 159 # Remove special instructions which are only allowed in special cases. | 231 # Remove special instructions which are only allowed in special cases. |
| 160 normal_instruction = (one_instruction - ( | 232 normal_instruction = one_instruction - ( |
| 161 (0x48 0x89 0xe5) | # mov %rsp,%rbp | 233 (0x48 0x89 0xe5) | # mov %rsp,%rbp |
| 162 (0x48 0x89 0xec) | # mov %rbp,%rsp | 234 (0x48 0x89 0xec) | # mov %rbp,%rsp |
| 163 (0x48 0x81 0xe4 any{4}) | # and $XXX,%rsp | 235 (0x48 0x81 0xe4 any{4}) | # and $XXX,%rsp |
| 164 (0x48 0x83 0xe4 any) | # and $XXX,%rsp | 236 (0x48 0x83 0xe4 any) | # and $XXX,%rsp |
| 165 (0x4c 0x01 0xfd) | # add %r15,%rbp | 237 (0x4c 0x01 0xfd) | # add %r15,%rbp |
| 166 (0x49 0x8d 0x2c 0x2f) | # lea (%r15,%rbp,1),%rbp | 238 (0x49 0x8d 0x2c 0x2f) | # lea (%r15,%rbp,1),%rbp |
| 167 (0x4a 0x8d 0x6c 0x3d any) | # lea 0x0(%rbp,%r15,1),%rbp | 239 (0x4a 0x8d 0x6c 0x3d any) | # lea 0x0(%rbp,%r15,1),%rbp |
| 168 (0x48 0x81 0xe5 any{4}) | # and $XXX,%rsp | 240 (0x48 0x81 0xe5 any{4}) | # and $XXX,%rsp |
| 169 (0x48 0x83 0xe5 any) | # and $XXX,%rsp | 241 (0x48 0x83 0xe5 any) | # and $XXX,%rsp |
| 170 (0x4c 0x01 0xfc) | # add %r15,%rsp | 242 (0x4c 0x01 0xfc) | # add %r15,%rsp |
| 171 (0x4a 0x8d 0x24 0x3c) | # lea (%rsp,%r15,1),%rsp | 243 (0x4a 0x8d 0x24 0x3c) | # lea (%rsp,%r15,1),%rsp |
| 172 (0x49 0x8d 0x34 0x37) | # lea (%r15,%rsi,1),%rsi | 244 (0x49 0x8d 0x34 0x37) | # lea (%r15,%rsi,1),%rsi |
| 173 (0x49 0x8d 0x3c 0x3f) # lea (%r15,%rdi,1),%rdi | 245 (0x49 0x8d 0x3c 0x3f) # lea (%r15,%rdi,1),%rdi |
| 174 )) @process_normal_instruction; | 246 ); |
| 175 | 247 |
| 176 data16condrep = (data16 | condrep data16 | data16 condrep); | 248 data16condrep = (data16 | condrep data16 | data16 condrep); |
| 177 data16rep = (data16 | rep data16 | data16 rep); | 249 data16rep = (data16 | rep data16 | data16 rep); |
| 178 | 250 |
| 179 special_instruction = | 251 special_instruction = |
| 180 (0x48 0x89 0xe5) | # mov %rsp,%rbp | 252 (0x48 0x89 0xe5) | # mov %rsp,%rbp |
| 181 (0x48 0x81 0xe4 any{3} (0x80 .. 0xff)) | # and $XXX,%rsp | 253 (0x48 0x81 0xe4 any{3} (0x80 .. 0xff)) | # and $XXX,%rsp |
| 182 (0x48 0x83 0xe4 (0x80 .. 0xff)) # and $XXX,%rsp | 254 (0x48 0x83 0xe4 (0x80 .. 0xff)) # and $XXX,%rsp |
| 183 @{ if (restricted_register == REG_RSP) { | 255 @{ if (restricted_register == REG_RSP) { |
| 184 PrintError("Incorrectly modified register %%rsp\n", begin - data); | 256 PrintError("Incorrectly modified register %%rsp\n", begin - data); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 * OperandSandboxUnrestricted to match the behavior of the old validator. | 444 * OperandSandboxUnrestricted to match the behavior of the old validator. |
| 373 * | 445 * |
| 374 * 8bit operands must be distinguished from other types because the REX prefix | 446 * 8bit operands must be distinguished from other types because the REX prefix |
| 375 * regulates the choice between %ah and %spl, as well as %ch and %bpl. | 447 * regulates the choice between %ah and %spl, as well as %ch and %bpl. |
| 376 */ | 448 */ |
| 377 OperandSandbox8bit, | 449 OperandSandbox8bit, |
| 378 OperandSandboxRestricted, | 450 OperandSandboxRestricted, |
| 379 OperandSandboxUnrestricted | 451 OperandSandboxUnrestricted |
| 380 }; | 452 }; |
| 381 | 453 |
| 382 /* Define SET_OPERAND_NAME as SET_OPERAND_NAME_0, SET_OPERAND_NAME_1 to detect | 454 #define SET_OPERAND_NAME(N, S) operand_states |= ((S) << ((N) << 3)) |
| 383 * cases where more than two general purpose registers are affected. This will | |
| 384 * produce a compile-time error if an operand with unexpected number is | |
| 385 * encountered. */ | |
| 386 #define SET_OPERAND_NAME(N, S) SET_OPERAND_NAME_ ## N(S) | |
| 387 #define SET_OPERAND_NAME_0(S) operand_states |= (S) | |
| 388 #define SET_OPERAND_NAME_1(S) operand_states |= ((S) << 8) | |
| 389 #define SET_OPERAND_TYPE(N, T) SET_OPERAND_TYPE_ ## T(N) | 455 #define SET_OPERAND_TYPE(N, T) SET_OPERAND_TYPE_ ## T(N) |
| 390 #define SET_OPERAND_TYPE_OperandSize8bit(N) \ | 456 #define SET_OPERAND_TYPE_OperandSize8bit(N) \ |
| 391 operand_states |= OperandSandbox8bit << (5 + ((N) << 3)) | 457 operand_states |= OperandSandbox8bit << (5 + ((N) << 3)) |
| 392 #define SET_OPERAND_TYPE_OperandSize16bit(N) \ | 458 #define SET_OPERAND_TYPE_OperandSize16bit(N) \ |
| 393 operand_states |= OperandSandboxUnrestricted << (5 + ((N) << 3)) | 459 operand_states |= OperandSandboxUnrestricted << (5 + ((N) << 3)) |
| 394 #define SET_OPERAND_TYPE_OperandSize32bit(N) \ | 460 #define SET_OPERAND_TYPE_OperandSize32bit(N) \ |
| 395 operand_states |= OperandSandboxRestricted << (5 + ((N) << 3)) | 461 operand_states |= OperandSandboxRestricted << (5 + ((N) << 3)) |
| 396 #define SET_OPERAND_TYPE_OperandSize64bit(N) \ | 462 #define SET_OPERAND_TYPE_OperandSize64bit(N) \ |
| 397 operand_states |= OperandSandboxUnrestricted << (5 + ((N) << 3)) | 463 operand_states |= OperandSandboxUnrestricted << (5 + ((N) << 3)) |
| 398 #define CHECK_OPERAND(N, S, T) \ | 464 #define CHECK_OPERAND(N, S, T) \ |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 uint8_t rex_prefix = FALSE; | 585 uint8_t rex_prefix = FALSE; |
| 520 uint8_t vex_prefix2 = 0xe0; | 586 uint8_t vex_prefix2 = 0xe0; |
| 521 uint8_t vex_prefix3 = 0x00; | 587 uint8_t vex_prefix3 = 0x00; |
| 522 /* Keeps one byte of information per operand in the current instruction: | 588 /* Keeps one byte of information per operand in the current instruction: |
| 523 * 2 bits for register kinds, | 589 * 2 bits for register kinds, |
| 524 * 5 bits for register numbers (16 regs plus RIZ). */ | 590 * 5 bits for register numbers (16 regs plus RIZ). */ |
| 525 int operand_states = 0; | 591 int operand_states = 0; |
| 526 enum register_name base = NO_REG; | 592 enum register_name base = NO_REG; |
| 527 enum register_name index = NO_REG; | 593 enum register_name index = NO_REG; |
| 528 int result = 0; | 594 int result = 0; |
| 529 /* | 595 /* These are borders of the appropriate instructions. Initialize them to make |
| 530 * These are borders of the appropriate instructions. Initialize them to make | |
| 531 * compiler happy: they are never used uninitialized even without explicit | 596 * compiler happy: they are never used uninitialized even without explicit |
| 532 * initialization but GCC is not sophysicated enough to prove that. | 597 * initialization but GCC is not sophysicated enough to prove that. */ |
| 533 */ | |
| 534 const uint8_t *sandboxed_rsi = 0; | 598 const uint8_t *sandboxed_rsi = 0; |
| 535 const uint8_t *sandboxed_rsi_restricted_rdi = 0; | 599 const uint8_t *sandboxed_rsi_restricted_rdi = 0; |
| 536 const uint8_t *sandboxed_rdi = 0; | 600 const uint8_t *sandboxed_rdi = 0; |
| 537 | 601 |
| 538 assert(size % bundle_size == 0); | 602 assert(size % bundle_size == 0); |
| 539 | 603 |
| 540 while (p < data + size) { | 604 while (p < data + size) { |
| 541 const uint8_t *pe = p + bundle_size; | 605 const uint8_t *pe = p + bundle_size; |
| 542 const uint8_t *eof = pe; | 606 const uint8_t *eof = pe; |
| 543 int cs; | 607 int cs; |
| 544 enum { | 608 enum { |
| 545 kNoRestrictedReg = 32, | 609 kNoRestrictedReg = 32, |
| 546 kSandboxedRsi, | 610 kSandboxedRsi, |
| 547 kSandboxedRdi, | 611 kSandboxedRdi, |
| 548 kSandboxedRsiRestrictedRdi, | 612 kSandboxedRsiRestrictedRdi, |
| 549 kSandboxedRsiSandboxedRdi | 613 kSandboxedRsiSandboxedRdi |
| 550 }; uint8_t restricted_register = kNoRestrictedReg; | 614 }; uint8_t restricted_register = kNoRestrictedReg; |
| 551 | 615 |
| 552 %% write init; | 616 %% write init; |
| 553 /* Ragel-generated code stores a difference between pointers into an "int" | 617 /* Ragel-generated code stores a difference between pointers into an "int" |
| 554 variable. This produces C4244 warning on Windows x64. */ | 618 * variable. This produces C4244 warning on Windows x64. */ |
| 555 #ifdef _MSC_VER | 619 #ifdef _MSC_VER |
| 556 #pragma warning(push) | 620 #pragma warning(push) |
| 557 #pragma warning(disable: 4244) // possible loss of data | 621 #pragma warning(disable: 4244) // possible loss of data |
| 558 #endif | 622 #endif |
| 559 %% write exec; | 623 %% write exec; |
| 560 #ifdef _MSC_VER | 624 #ifdef _MSC_VER |
| 561 #pragma warning(pop) | 625 #pragma warning(pop) |
| 562 #endif | 626 #endif |
| 563 | 627 |
| 564 if (restricted_register == REG_RBP) { | 628 if (restricted_register == REG_RBP) { |
| 565 PrintError("Incorrectly sandboxed %%rbp\n", begin - data); | 629 PrintError("Incorrectly sandboxed %%rbp\n", begin - data); |
| 566 result = 1; | 630 result = 1; |
| 567 goto error_detected; | 631 goto error_detected; |
| 568 } else if (restricted_register == REG_RSP) { | 632 } else if (restricted_register == REG_RSP) { |
| 569 PrintError("Incorrectly sandboxed %%rsp\n", begin - data); | 633 PrintError("Incorrectly sandboxed %%rsp\n", begin - data); |
| 570 result = 1; | 634 result = 1; |
| 571 goto error_detected; | 635 goto error_detected; |
| 572 } | 636 } |
| 573 } | 637 } |
| 574 | 638 |
| 575 if (CheckJumpTargets(valid_targets, jump_dests, size)) { | 639 if (CheckJumpTargets(valid_targets, jump_dests, size)) { |
| 576 return 1; | 640 return 1; |
| 577 } | 641 } |
| 578 | 642 |
| 579 error_detected: | 643 error_detected: |
| 580 return result; | 644 return result; |
| 581 } | 645 } |
| OLD | NEW |