OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 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 /* | 7 /* |
8 * ncvalidate.c | 8 * ncvalidate.c |
9 * Validate x86 instructions for Native Client | 9 * Validate x86 instructions for Native Client |
10 * | 10 * |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 vprint(vstate, (reporter, | 398 vprint(vstate, (reporter, |
399 "RememberIP: Saw inst at %"NACL_PRIxNaClPcAddressAll | 399 "RememberIP: Saw inst at %"NACL_PRIxNaClPcAddressAll |
400 " twice\n", ip)); | 400 " twice\n", ip)); |
401 NCStatsInternalError(vstate); | 401 NCStatsInternalError(vstate); |
402 return; | 402 return; |
403 } | 403 } |
404 NCStatsInst(vstate); | 404 NCStatsInst(vstate); |
405 NCSetAdrTable(ioffset, vstate->vttable); | 405 NCSetAdrTable(ioffset, vstate->vttable); |
406 } | 406 } |
407 | 407 |
408 static void RememberTP(const NaClPcAddress src, NaClPcAddress target, | 408 static void RememberTP(const NCDecoderInst *dinst, const NaClPcAddress src, |
409 struct NCValidatorState *vstate) { | 409 NaClPcAddress target, struct NCValidatorState *vstate) { |
410 const NaClMemorySize ioffset = target - vstate->iadrbase; | 410 const NaClMemorySize ioffset = target - vstate->iadrbase; |
411 | 411 |
412 if (NCAddressInMemoryRange(target, vstate)) { | 412 if (NCAddressInMemoryRange(target, vstate)) { |
413 NCSetAdrTable(ioffset, vstate->kttable); | 413 NCSetAdrTable(ioffset, vstate->kttable); |
414 } | 414 } |
415 else if ((target & vstate->alignmask) == 0) { | 415 else if ((target & vstate->alignmask) == 0) { |
416 /* Allow bundle-aligned jumps. */ | 416 /* Allow bundle-aligned jumps. */ |
417 } | 417 } else if (dinst->unchanged) { |
418 else { | 418 /* If we are replacing this instruction during dynamic code modification |
| 419 * and it has not changed, the jump target must be valid because the |
| 420 * instruction has been previously validated. However, we may be only |
| 421 * replacing a subsection of the code segment and therefore may not have |
| 422 * information about instruction boundries outside of the code being |
| 423 * replaced. Therefore, we allow unaligned direct jumps outside of the code |
| 424 * being validated if and only if the instruction is unchanged. |
| 425 * If dynamic code replacement is not being performed, inst->unchanged |
| 426 * should always be false. |
| 427 */ |
| 428 } else { |
419 ValidatePrintError(src, "JUMP TARGET out of range", vstate); | 429 ValidatePrintError(src, "JUMP TARGET out of range", vstate); |
420 NCStatsBadTarget(vstate); | 430 NCStatsBadTarget(vstate); |
421 } | 431 } |
422 } | 432 } |
423 | 433 |
424 static void ForgetIP(const NaClPcAddress ip, | 434 static void ForgetIP(const NaClPcAddress ip, |
425 struct NCValidatorState *vstate) { | 435 struct NCValidatorState *vstate) { |
426 NaClMemorySize ioffset = ip - vstate->iadrbase; | 436 NaClMemorySize ioffset = ip - vstate->iadrbase; |
427 if (!NCAddressInMemoryRange(ip, vstate)) { | 437 if (!NCAddressInMemoryRange(ip, vstate)) { |
428 ValidatePrintError(ip, "JUMP TARGET out of range in ForgetIP", vstate); | 438 ValidatePrintError(ip, "JUMP TARGET out of range in ForgetIP", vstate); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 } | 513 } |
504 } | 514 } |
505 | 515 |
506 static void ValidateJmp8(const NCDecoderInst *dinst) { | 516 static void ValidateJmp8(const NCDecoderInst *dinst) { |
507 int8_t offset = NCInstBytesByteInline(&dinst->inst_bytes, | 517 int8_t offset = NCInstBytesByteInline(&dinst->inst_bytes, |
508 dinst->inst.prefixbytes+1); | 518 dinst->inst.prefixbytes+1); |
509 struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); | 519 struct NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); |
510 NaClPcAddress target = | 520 NaClPcAddress target = |
511 dinst->vpc + dinst->inst.bytes.length + offset; | 521 dinst->vpc + dinst->inst.bytes.length + offset; |
512 NCStatsCheckTarget(vstate); | 522 NCStatsCheckTarget(vstate); |
513 RememberTP(dinst->vpc, target, vstate); | 523 RememberTP(dinst, dinst->vpc, target, vstate); |
514 } | 524 } |
515 | 525 |
516 static void ValidateJmpz(const NCDecoderInst *dinst) { | 526 static void ValidateJmpz(const NCDecoderInst *dinst) { |
517 NCInstBytesPtr opcode; | 527 NCInstBytesPtr opcode; |
518 uint8_t opcode0; | 528 uint8_t opcode0; |
519 int32_t offset; | 529 int32_t offset; |
520 NaClPcAddress target; | 530 NaClPcAddress target; |
521 NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); | 531 NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); |
522 NCInstBytesPtrInitInc(&opcode, &dinst->inst_bytes, | 532 NCInstBytesPtrInitInc(&opcode, &dinst->inst_bytes, |
523 dinst->inst.prefixbytes); | 533 dinst->inst.prefixbytes); |
(...skipping 11 matching lines...) Expand all Loading... |
535 * E8: call $Jz | 545 * E8: call $Jz |
536 * E9: jmp $Jx | 546 * E9: jmp $Jx |
537 */ | 547 */ |
538 NCInstBytesPtr opcode_1; | 548 NCInstBytesPtr opcode_1; |
539 NCInstBytesPtrInitInc(&opcode_1, &opcode, 1); | 549 NCInstBytesPtrInitInc(&opcode_1, &opcode, 1); |
540 offset = NCInstBytesInt32(&opcode_1); | 550 offset = NCInstBytesInt32(&opcode_1); |
541 /* as a courtesy, check call alignment correctness */ | 551 /* as a courtesy, check call alignment correctness */ |
542 if (opcode0 == 0xe8) ValidateCallAlignment(dinst); | 552 if (opcode0 == 0xe8) ValidateCallAlignment(dinst); |
543 } | 553 } |
544 target = dinst->vpc + dinst->inst.bytes.length + offset; | 554 target = dinst->vpc + dinst->inst.bytes.length + offset; |
545 RememberTP(dinst->vpc, target, vstate); | 555 RememberTP(dinst, dinst->vpc, target, vstate); |
546 } | 556 } |
547 | 557 |
548 /* | 558 /* |
549 * The NaCl five-byte safe indirect calling sequence looks like this: | 559 * The NaCl five-byte safe indirect calling sequence looks like this: |
550 * 83 e0 e0 and $0xe0,%eax | 560 * 83 e0 e0 and $0xe0,%eax |
551 * ff d0 call *%eax | 561 * ff d0 call *%eax |
552 * The call may be replaced with a ff e0 jmp. Any register may | 562 * The call may be replaced with a ff e0 jmp. Any register may |
553 * be used, not just eax. The validator requires exactly this | 563 * be used, not just eax. The validator requires exactly this |
554 * sequence. | 564 * sequence. |
555 * Note: The code above assumes 32-bit alignment. Change e0 as appropriate | 565 * Note: The code above assumes 32-bit alignment. Change e0 as appropriate |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
888 NCStatsUnsafeIndirect(NCVALIDATOR_STATE_DOWNCAST(dinst_new->dstate)); | 898 NCStatsUnsafeIndirect(NCVALIDATOR_STATE_DOWNCAST(dinst_new->dstate)); |
889 } | 899 } |
890 | 900 |
891 /* | 901 /* |
892 * Check that mstate_new is a valid replacement instruction for mstate_old. | 902 * Check that mstate_new is a valid replacement instruction for mstate_old. |
893 * Note that mstate_old was validated when it was inserted originally. | 903 * Note that mstate_old was validated when it was inserted originally. |
894 */ | 904 */ |
895 static Bool ValidateInstReplacement(NCDecoderStatePair* tthis, | 905 static Bool ValidateInstReplacement(NCDecoderStatePair* tthis, |
896 NCDecoderInst *dinst_old, | 906 NCDecoderInst *dinst_old, |
897 NCDecoderInst *dinst_new) { | 907 NCDecoderInst *dinst_new) { |
| 908 |
| 909 |
898 /* Only validate individual instructions that have changed. */ | 910 /* Only validate individual instructions that have changed. */ |
899 if (memcmp(dinst_old->inst.bytes.byte, | 911 dinst_new->unchanged = memcmp(dinst_old->inst.bytes.byte, |
900 dinst_new->inst.bytes.byte, | 912 dinst_new->inst.bytes.byte, |
901 dinst_new->inst.bytes.length)) { | 913 dinst_new->inst.bytes.length) == 0; |
902 /* Call single instruction validator first, will call ValidateIndirect5() */ | 914 ValidateInst(dinst_new); |
903 ValidateInst(dinst_new); | |
904 } else { | |
905 /* Still need to record there is an intruction here for NCValidateFinish() | |
906 * to verify basic block alignment. | |
907 */ | |
908 RememberIP(dinst_new->vpc, NCVALIDATOR_STATE_DOWNCAST(dinst_new->dstate)); | |
909 } | |
910 | 915 |
911 if (dinst_old->opinfo->insttype == NACLi_INDIRECT | 916 if (dinst_old->opinfo->insttype == NACLi_INDIRECT |
912 || dinst_new->opinfo->insttype == NACLi_INDIRECT) { | 917 || dinst_new->opinfo->insttype == NACLi_INDIRECT) { |
913 /* Verify that nacljmps never change */ | 918 /* Verify that nacljmps never change */ |
914 ValidateIndirect5Replacement(dinst_old, dinst_new); | 919 ValidateIndirect5Replacement(dinst_old, dinst_new); |
915 } | 920 } |
916 return TRUE; | 921 return TRUE; |
917 } | 922 } |
918 | 923 |
919 /* Create the decoder state for the validator state, using the | 924 /* Create the decoder state for the validator state, using the |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 /* check basic block boundaries */ | 1031 /* check basic block boundaries */ |
1027 for (offset = 0; offset < vstate->iadrlimit - vstate->iadrbase; | 1032 for (offset = 0; offset < vstate->iadrlimit - vstate->iadrbase; |
1028 offset += vstate->alignment) { | 1033 offset += vstate->alignment) { |
1029 if (!NCGetAdrTable(offset, vstate->vttable)) { | 1034 if (!NCGetAdrTable(offset, vstate->vttable)) { |
1030 ValidatePrintError(vstate->iadrbase + offset, | 1035 ValidatePrintError(vstate->iadrbase + offset, |
1031 "Bad basic block alignment", vstate); | 1036 "Bad basic block alignment", vstate); |
1032 NCStatsBadAlignment(vstate); | 1037 NCStatsBadAlignment(vstate); |
1033 } | 1038 } |
1034 } | 1039 } |
1035 } | 1040 } |
OLD | NEW |