OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2009 The Native Client Authors. All rights reserved. | 2 * Copyright 2009 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can | 3 * Use of this source code is governed by a BSD-style license that can |
4 * be found in the LICENSE file. | 4 * be found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* | 7 /* |
8 * ncvalidate_iter.c | 8 * ncvalidate_iter.c |
9 * Validate x86 instructions for Native Client | 9 * Validate x86 instructions for Native Client |
10 * | 10 * |
11 */ | 11 */ |
12 | 12 |
13 #include <assert.h> | 13 #include <assert.h> |
14 #include <string.h> | 14 #include <string.h> |
15 | 15 |
16 #include "native_client/src/trusted/validator_x86/ncvalidate_iter.h" | 16 #include "native_client/src/trusted/validator_x86/ncvalidate_iter.h" |
17 | 17 #include "native_client/src/shared/platform/nacl_check.h" |
18 #include "native_client/src/shared/platform/nacl_log.h" | 18 #include "native_client/src/shared/platform/nacl_log.h" |
19 #include "native_client/src/trusted/validator_x86/nc_inst_iter.h" | 19 #include "native_client/src/trusted/validator_x86/nc_inst_iter.h" |
20 #include "native_client/src/trusted/validator_x86/nc_inst_state_internal.h" | 20 #include "native_client/src/trusted/validator_x86/nc_inst_state_internal.h" |
21 #include "native_client/src/trusted/validator_x86/nc_segment.h" | 21 #include "native_client/src/trusted/validator_x86/nc_segment.h" |
22 #include "native_client/src/trusted/validator_x86/ncop_exps.h" | 22 #include "native_client/src/trusted/validator_x86/ncop_exps.h" |
23 #include "native_client/src/trusted/validator_x86/ncvalidate_iter_internal.h" | 23 #include "native_client/src/trusted/validator_x86/ncvalidate_iter_internal.h" |
24 #include "native_client/src/trusted/validator_x86/ncvalidator_registry.h" | 24 #include "native_client/src/trusted/validator_x86/ncvalidator_registry.h" |
25 | 25 |
26 /* To turn on debugging of instruction decoding, change value of | 26 /* To turn on debugging of instruction decoding, change value of |
27 * DEBUGGING to 1. | 27 * DEBUGGING to 1. |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 NaClLogV_mu(level, format, ap); | 251 NaClLogV_mu(level, format, ap); |
252 va_end(ap); | 252 va_end(ap); |
253 NaClLogUnlock(); | 253 NaClLogUnlock(); |
254 NaClRecordErrorReported(state, level); | 254 NaClRecordErrorReported(state, level); |
255 } | 255 } |
256 if (state->do_stub_out && (level <= LOG_ERROR)) { | 256 if (state->do_stub_out && (level <= LOG_ERROR)) { |
257 memset(inst->mpc, kNaClFullStop, inst->length); | 257 memset(inst->mpc, kNaClFullStop, inst->length); |
258 } | 258 } |
259 } | 259 } |
260 | 260 |
| 261 void NaClValidatorTwoInstMessage(int level, |
| 262 NaClValidatorState* state, |
| 263 NaClInstState* inst1, |
| 264 NaClInstState* inst2, |
| 265 const char* format, |
| 266 ...) { |
| 267 level = NaClRecordIfValidatorError(state, level); |
| 268 if (NaClPrintValidatorMessages(state, level)) { |
| 269 va_list ap; |
| 270 struct Gio* g = NaClLogGetGio(); |
| 271 |
| 272 NaClLogLock(); |
| 273 /* TODO(karl) - Make printing of instruction state possible via format. */ |
| 274 va_start(ap, format); |
| 275 NaClLog_mu(level, "VALIDATOR: %s", NaClLogLevelLabel(level)); |
| 276 NaClLogV_mu(level, format, ap); |
| 277 va_end(ap); |
| 278 |
| 279 /* TODO(karl): empty fmt strings not allowed */ |
| 280 NaClLog_mu(level, "\n%45s ", "VALIDATOR:"); |
| 281 NaClInstStateInstPrint(g, inst1); |
| 282 /* TODO(karl): empty fmt strings not allowed */ |
| 283 NaClLog_mu(level, "%45s ", "VALIDATOR:"); |
| 284 NaClInstStateInstPrint(g, inst2); |
| 285 |
| 286 NaClLogUnlock(); |
| 287 NaClRecordErrorReported(state, level); |
| 288 } |
| 289 if (state->do_stub_out && (level <= LOG_ERROR)) { |
| 290 memset(inst1->mpc, kNaClFullStop, inst1->length); |
| 291 memset(inst2->mpc, kNaClFullStop, inst2->length); |
| 292 } |
| 293 } |
| 294 |
261 Bool NaClValidatorQuit(NaClValidatorState* state) { | 295 Bool NaClValidatorQuit(NaClValidatorState* state) { |
262 return !state->validates_ok && (state->quit_after_error_count == 0); | 296 return !state->validates_ok && (state->quit_after_error_count == 0); |
263 } | 297 } |
264 | 298 |
265 void NaClRegisterValidator( | 299 void NaClRegisterValidator( |
266 NaClValidatorState* state, | 300 NaClValidatorState* state, |
267 NaClValidator validator, | 301 NaClValidator validator, |
268 NaClValidatorPostValidate post_validate, | 302 NaClValidatorPostValidate post_validate, |
269 NaClValidatorPrintStats print_stats, | 303 NaClValidatorPrintStats print_stats, |
270 NaClValidatorMemoryCreate create_memory, | 304 NaClValidatorMemoryCreate create_memory, |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 void* NaClGetValidatorLocalMemory(NaClValidator validator, | 476 void* NaClGetValidatorLocalMemory(NaClValidator validator, |
443 const NaClValidatorState* state) { | 477 const NaClValidatorState* state) { |
444 int i; | 478 int i; |
445 for (i = 0; i < state->number_validators; ++i) { | 479 for (i = 0; i < state->number_validators; ++i) { |
446 if (state->validators[i].validator == validator) { | 480 if (state->validators[i].validator == validator) { |
447 return state->local_memory[i]; | 481 return state->local_memory[i]; |
448 } | 482 } |
449 } | 483 } |
450 return NULL; | 484 return NULL; |
451 } | 485 } |
| 486 |
| 487 /* |
| 488 * Check that iter_new is a valid replacement for iter_old. |
| 489 * If a validation error occurs, state->validates_ok will be set to false by |
| 490 * NaClValidatorInstMessage when it is given LOG_ERROR, see the end of this |
| 491 * function. |
| 492 */ |
| 493 static void NaClValidateInstReplacement(NaClInstIter* iter_old, |
| 494 NaClInstIter* iter_new, |
| 495 struct NaClValidatorState* state) { |
| 496 NaClInstState *istate_old, *istate_new; |
| 497 NaClExpVector *exp_old, *exp_new; |
| 498 uint32_t i; |
| 499 |
| 500 istate_old = NaClInstIterGetState(iter_old); |
| 501 istate_new = NaClInstIterGetState(iter_new); |
| 502 |
| 503 /* Location/length must match */ |
| 504 if (istate_new->vpc != istate_old->vpc || |
| 505 istate_new->length != istate_old->length) { |
| 506 NaClValidatorTwoInstMessage(LOG_ERROR, state, istate_old, istate_new, |
| 507 "Code modification: instructions length/addresses do not match"); |
| 508 return; |
| 509 } |
| 510 |
| 511 |
| 512 do { |
| 513 /* fast check if the replacement is identical */ |
| 514 if (!memcmp(istate_old->mpc, istate_new->mpc, istate_old->length)) |
| 515 return; |
| 516 |
| 517 if (istate_old->num_prefix_bytes != istate_new->num_prefix_bytes) |
| 518 break; |
| 519 if (istate_old->num_rex_prefixes != istate_new->num_rex_prefixes) |
| 520 break; |
| 521 if (istate_old->rexprefix != istate_new->rexprefix) |
| 522 break; |
| 523 if (istate_old->modrm != istate_new->modrm) |
| 524 break; |
| 525 if (istate_old->has_sib != istate_new->has_sib) |
| 526 break; |
| 527 if (istate_old->has_sib && istate_old->sib != istate_new->sib) |
| 528 break; |
| 529 if (istate_old->operand_size != istate_new->operand_size) |
| 530 break; |
| 531 if (istate_old->address_size != istate_new->address_size) |
| 532 break; |
| 533 if (istate_old->prefix_mask != istate_new->prefix_mask) |
| 534 break; |
| 535 |
| 536 /* |
| 537 * these are pointers, but they reference entries in a static table, |
| 538 * so if the two instructions are the same, then these pointers must |
| 539 * reference the same entry |
| 540 */ |
| 541 if (istate_old->inst != istate_new->inst) |
| 542 break; |
| 543 |
| 544 exp_old = NaClInstStateExpVector(istate_old); |
| 545 exp_new = NaClInstStateExpVector(istate_new); |
| 546 |
| 547 /* check if the instruction operands are identical */ |
| 548 if (exp_old->number_expr_nodes != exp_new->number_expr_nodes) |
| 549 break; |
| 550 |
| 551 for (i = 0; i < exp_old->number_expr_nodes; i++) { |
| 552 if (exp_old->node[i].kind != exp_new->node[i].kind) |
| 553 break; |
| 554 if (exp_old->node[i].flags != exp_new->node[i].flags) |
| 555 break; |
| 556 |
| 557 /* |
| 558 * allow some constants to be different; however it is important not to |
| 559 * allow modification of sandboxing instructions. Note nether of the |
| 560 * instructions allowed for modification is used for sandboxing |
| 561 */ |
| 562 if (exp_old->node[i].value != exp_new->node[i].value) { |
| 563 if (exp_old->node[i].kind == ExprConstant) { |
| 564 |
| 565 /* allow different constants in direct calls */ |
| 566 if (istate_old->inst->name == InstCall) |
| 567 if (exp_old->node[i].flags & NACL_EFLAG(ExprJumpTarget)) |
| 568 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind |
| 569 == OperandReference) |
| 570 continue; |
| 571 |
| 572 /* |
| 573 * allow different constants in operand of mov |
| 574 * e.g. mov $rax, 0xdeadbeef |
| 575 */ |
| 576 if (istate_old->inst->name == InstMov) |
| 577 if (exp_old->node[i].flags & NACL_EFLAG(ExprUsed)) |
| 578 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind |
| 579 == OperandReference) |
| 580 continue; |
| 581 /* |
| 582 * allow different displacements in memory reference of mov |
| 583 * instructions e.g. mov $rax, [$r15+$rbx*2+0x7fff] |
| 584 */ |
| 585 if (istate_old->inst->name == InstMov) |
| 586 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind |
| 587 == ExprMemOffset) |
| 588 /* displacement is the fourth node after ExprMemOffset node */ |
| 589 if (i - NaClGetExpParentIndex(exp_old, i) == 4) |
| 590 continue; |
| 591 } |
| 592 break; |
| 593 } |
| 594 } |
| 595 |
| 596 return; |
| 597 } while (0); |
| 598 |
| 599 NaClValidatorTwoInstMessage(LOG_ERROR, state, istate_old, istate_new, |
| 600 "Code modification: failed to modify instruction"); |
| 601 } |
| 602 |
| 603 void NaClValidateSegmentPair(uint8_t* mbase_old, uint8_t* mbase_new, |
| 604 NaClPcAddress vbase, size_t size, |
| 605 struct NaClValidatorState* state) { |
| 606 NaClSegment segment_old, segment_new; |
| 607 NaClInstIter *iter_old, *iter_new; |
| 608 |
| 609 NaClValidatorStateInitializeValidators(state); |
| 610 NaClSegmentInitialize(mbase_old, vbase, size, &segment_old); |
| 611 NaClSegmentInitialize(mbase_new, vbase, size, &segment_new); |
| 612 iter_old = NaClInstIterCreateWithLookback(&segment_old, kLookbackSize); |
| 613 iter_new = NaClInstIterCreateWithLookback(&segment_new, kLookbackSize); |
| 614 while (NaClInstIterHasNext(iter_old) && |
| 615 NaClInstIterHasNext(iter_new)) { |
| 616 state->cur_inst_state = NaClInstIterGetState(iter_new); |
| 617 state->cur_inst = NaClInstStateInst(state->cur_inst_state); |
| 618 state->cur_inst_vector = NaClInstStateExpVector(state->cur_inst_state); |
| 619 NaClApplyValidators(state, iter_new); |
| 620 NaClValidateInstReplacement(iter_old, iter_new, state); |
| 621 if (state->quit) break; |
| 622 NaClInstIterAdvance(iter_old); |
| 623 NaClInstIterAdvance(iter_new); |
| 624 } |
| 625 |
| 626 if (NaClInstIterHasNext(iter_old) || |
| 627 NaClInstIterHasNext(iter_new)) { |
| 628 NaClValidatorMessage(LOG_ERROR, state, |
| 629 "Code modification: code segments have different number of instructions\n"); |
| 630 } |
| 631 |
| 632 state->cur_inst_state = NULL; |
| 633 state->cur_inst = NULL; |
| 634 state->cur_inst_vector = NULL; |
| 635 NaClApplyPostValidators(state, iter_new); |
| 636 NaClInstIterDestroy(iter_old); |
| 637 NaClInstIterDestroy(iter_new); |
| 638 NaClValidatorStatePrintStats(state); |
| 639 } |
| 640 |
OLD | NEW |