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 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
252 NaClLogV_mu(level, format, ap); | 252 NaClLogV_mu(level, format, ap); |
253 va_end(ap); | 253 va_end(ap); |
254 NaClLogUnlock(); | 254 NaClLogUnlock(); |
255 NaClRecordErrorReported(state, level); | 255 NaClRecordErrorReported(state, level); |
256 } | 256 } |
257 if (state->do_stub_out && (level <= LOG_ERROR)) { | 257 if (state->do_stub_out && (level <= LOG_ERROR)) { |
258 memset(inst->mpc, kNaClFullStop, inst->length); | 258 memset(inst->mpc, kNaClFullStop, inst->length); |
259 } | 259 } |
260 } | 260 } |
261 | 261 |
262 void NaClValidatorTwoInstMessage(int level, | |
263 NaClValidatorState* state, | |
264 NaClInstState* inst1, | |
265 NaClInstState* inst2, | |
266 const char* format, | |
267 ...) { | |
268 level = NaClRecordIfValidatorError(state, level); | |
269 if (NaClPrintValidatorMessages(state, level)) { | |
270 va_list ap; | |
271 struct Gio* g = NaClLogGetGio(); | |
272 | |
273 NaClLogLock(); | |
274 /* TODO(karl) - Make printing of instruction state possible via format. */ | |
275 va_start(ap, format); | |
276 NaClLog_mu(level, "VALIDATOR: %s", NaClLogLevelLabel(level)); | |
277 NaClLogV_mu(level, format, ap); | |
278 va_end(ap); | |
279 | |
280 /* TODO(karl): empty fmt strings not allowed */ | |
281 NaClLog_mu(level, "\n%45s ", "VALIDATOR:"); | |
282 NaClInstStateInstPrint(g, inst1); | |
283 /* TODO(karl): empty fmt strings not allowed */ | |
284 NaClLog_mu(level, "%45s ", "VALIDATOR:"); | |
285 NaClInstStateInstPrint(g, inst2); | |
286 | |
287 NaClLogUnlock(); | |
288 NaClRecordErrorReported(state, level); | |
289 } | |
290 if (state->do_stub_out && (level <= LOG_ERROR)) { | |
bsy
2010/12/15 04:06:50
this appears to be dead code, since do_stub_out mu
elijahtaylor (use chromium)
2010/12/15 21:26:37
I'm very unfamiliar with this, so I haven't done t
| |
291 memset(inst1->mpc, kNaClFullStop, inst1->length); | |
292 memset(inst2->mpc, kNaClFullStop, inst2->length); | |
293 } | |
294 } | |
295 | |
262 Bool NaClValidatorQuit(NaClValidatorState* state) { | 296 Bool NaClValidatorQuit(NaClValidatorState* state) { |
263 return !state->validates_ok && (state->quit_after_error_count == 0); | 297 return !state->validates_ok && (state->quit_after_error_count == 0); |
264 } | 298 } |
265 | 299 |
266 void NaClRegisterValidator( | 300 void NaClRegisterValidator( |
267 NaClValidatorState* state, | 301 NaClValidatorState* state, |
268 NaClValidator validator, | 302 NaClValidator validator, |
269 NaClValidatorPostValidate post_validate, | 303 NaClValidatorPostValidate post_validate, |
270 NaClValidatorPrintStats print_stats, | 304 NaClValidatorPrintStats print_stats, |
271 NaClValidatorMemoryCreate create_memory, | 305 NaClValidatorMemoryCreate create_memory, |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
443 void* NaClGetValidatorLocalMemory(NaClValidator validator, | 477 void* NaClGetValidatorLocalMemory(NaClValidator validator, |
444 const NaClValidatorState* state) { | 478 const NaClValidatorState* state) { |
445 int i; | 479 int i; |
446 for (i = 0; i < state->number_validators; ++i) { | 480 for (i = 0; i < state->number_validators; ++i) { |
447 if (state->validators[i].validator == validator) { | 481 if (state->validators[i].validator == validator) { |
448 return state->local_memory[i]; | 482 return state->local_memory[i]; |
449 } | 483 } |
450 } | 484 } |
451 return NULL; | 485 return NULL; |
452 } | 486 } |
487 | |
488 /* | |
489 * Check that iter_new is a valid replacement for iter_old. | |
490 * If a validation error occurs, state->validates_ok will be set to false by | |
491 * NaClValidatorInstMessage when it is given LOG_ERROR, see the end of this | |
492 * function. | |
493 */ | |
494 static void NaClValidateInstReplacement(NaClInstIter* iter_old, | |
495 NaClInstIter* iter_new, | |
496 struct NaClValidatorState* state) { | |
497 NaClInstState *istate_old, *istate_new; | |
498 NaClExpVector *exp_old, *exp_new; | |
499 uint32_t i; | |
500 Bool error_in_nodes; | |
501 | |
502 istate_old = NaClInstIterGetState(iter_old); | |
503 istate_new = NaClInstIterGetState(iter_new); | |
504 | |
505 /* Location/length must match */ | |
506 if (istate_new->vpc != istate_old->vpc || | |
507 istate_new->length != istate_old->length) { | |
508 NaClValidatorTwoInstMessage(LOG_ERROR, state, istate_old, istate_new, | |
509 "Code modification: instructions length/addresses do not match"); | |
510 return; | |
511 } | |
512 | |
513 | |
514 do { | |
515 /* fast check if the replacement is identical */ | |
516 if (!memcmp(istate_old->mpc, istate_new->mpc, istate_old->length)) | |
517 return; | |
518 | |
519 if (istate_old->num_prefix_bytes != istate_new->num_prefix_bytes) | |
520 break; | |
521 if (istate_old->num_rex_prefixes != istate_new->num_rex_prefixes) | |
522 break; | |
523 if (istate_old->rexprefix != istate_new->rexprefix) | |
524 break; | |
525 if (istate_old->modrm != istate_new->modrm) | |
526 break; | |
527 if (istate_old->has_sib != istate_new->has_sib) | |
528 break; | |
529 if (istate_old->has_sib && istate_old->sib != istate_new->sib) | |
530 break; | |
531 if (istate_old->operand_size != istate_new->operand_size) | |
532 break; | |
533 if (istate_old->address_size != istate_new->address_size) | |
534 break; | |
535 if (istate_old->prefix_mask != istate_new->prefix_mask) | |
536 break; | |
537 | |
538 /* | |
539 * these are pointers, but they reference entries in a static table, | |
540 * so if the two instructions are the same, then these pointers must | |
541 * reference the same entry | |
542 */ | |
543 if (istate_old->inst != istate_new->inst) | |
544 break; | |
545 | |
546 exp_old = NaClInstStateExpVector(istate_old); | |
547 exp_new = NaClInstStateExpVector(istate_new); | |
548 | |
549 /* check if the instruction operands are identical */ | |
550 if (exp_old->number_expr_nodes != exp_new->number_expr_nodes) | |
551 break; | |
552 | |
553 error_in_nodes = FALSE; | |
554 for (i = 0; i < exp_old->number_expr_nodes; i++) { | |
555 if (exp_old->node[i].kind != exp_new->node[i].kind) { | |
556 error_in_nodes = TRUE; | |
bsy
2010/12/15 04:06:50
consider using a goto for the double break here an
elijahtaylor (use chromium)
2010/12/15 21:26:37
I am loath to "goto", but I agree that's clearer i
| |
557 break; | |
558 } | |
559 if (exp_old->node[i].flags != exp_new->node[i].flags) { | |
560 error_in_nodes = TRUE; | |
561 break; | |
562 } | |
563 | |
564 /* | |
565 * allow some constants to be different; however it is important not to | |
566 * allow modification of sandboxing instructions. Note neither of the | |
567 * instructions allowed for modification is used for sandboxing | |
568 */ | |
569 if (exp_old->node[i].value != exp_new->node[i].value) { | |
570 if (exp_old->node[i].kind == ExprConstant) { | |
571 | |
572 /* allow different constants in direct calls */ | |
573 if (istate_old->inst->name == InstCall) | |
574 if (exp_old->node[i].flags & NACL_EFLAG(ExprJumpTarget)) | |
575 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind | |
576 == OperandReference) | |
577 continue; | |
578 | |
579 /* | |
580 * allow different constants in operand of mov | |
581 * e.g. mov $rax, 0xdeadbeef | |
582 */ | |
583 if (istate_old->inst->name == InstMov) | |
584 if (exp_old->node[i].flags & NACL_EFLAG(ExprUsed)) | |
585 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind | |
586 == OperandReference) | |
587 continue; | |
588 /* | |
589 * allow different displacements in memory reference of mov | |
590 * instructions e.g. mov $rax, [$r15+$rbx*2+0x7fff] | |
591 */ | |
592 if (istate_old->inst->name == InstMov) | |
593 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind | |
594 == ExprMemOffset) | |
595 /* displacement is the fourth node after ExprMemOffset node */ | |
596 if (i - NaClGetExpParentIndex(exp_old, i) == 4) | |
bsy
2010/12/15 04:06:50
magic number -- do we need/want a kDisplacementNod
elijahtaylor (use chromium)
2010/12/15 21:26:37
Not done. I consider the comment good enough to e
| |
597 continue; | |
598 } | |
599 error_in_nodes = TRUE; | |
600 break; | |
601 } | |
602 } | |
603 | |
604 if (error_in_nodes) | |
bsy
2010/12/15 04:06:50
good catch! NaClValidatorTwoInstMessage -> NaClRe
elijahtaylor (use chromium)
2010/12/15 21:26:37
Commented both locations (valid return and error r
| |
605 break; | |
606 | |
607 return; | |
608 } while (0); | |
609 | |
610 NaClValidatorTwoInstMessage(LOG_ERROR, state, istate_old, istate_new, | |
611 "Code modification: failed to modify instruction"); | |
612 } | |
613 | |
614 void NaClValidateSegmentPair(uint8_t* mbase_old, uint8_t* mbase_new, | |
bsy
2010/12/15 04:06:50
a comment here about assumptions -- that vbase/siz
elijahtaylor (use chromium)
2010/12/15 21:26:37
Done.
On 2010/12/15 04:06:50, bsy wrote:
| |
615 NaClPcAddress vbase, size_t size, | |
616 struct NaClValidatorState* state) { | |
617 NaClSegment segment_old, segment_new; | |
618 NaClInstIter *iter_old, *iter_new; | |
619 | |
620 NaClValidatorStateInitializeValidators(state); | |
621 NaClSegmentInitialize(mbase_old, vbase, size, &segment_old); | |
622 NaClSegmentInitialize(mbase_new, vbase, size, &segment_new); | |
623 iter_old = NaClInstIterCreateWithLookback(&segment_old, kLookbackSize); | |
624 iter_new = NaClInstIterCreateWithLookback(&segment_new, kLookbackSize); | |
625 while (NaClInstIterHasNext(iter_old) && | |
626 NaClInstIterHasNext(iter_new)) { | |
627 state->cur_inst_state = NaClInstIterGetState(iter_new); | |
628 state->cur_inst = NaClInstStateInst(state->cur_inst_state); | |
629 state->cur_inst_vector = NaClInstStateExpVector(state->cur_inst_state); | |
630 NaClApplyValidators(state, iter_new); | |
631 NaClValidateInstReplacement(iter_old, iter_new, state); | |
632 if (state->quit) break; | |
633 NaClInstIterAdvance(iter_old); | |
634 NaClInstIterAdvance(iter_new); | |
635 } | |
636 | |
637 if (NaClInstIterHasNext(iter_old) || | |
638 NaClInstIterHasNext(iter_new)) { | |
639 NaClValidatorMessage(LOG_ERROR, state, | |
640 "Code modification: code segments have different number of instructions\n"); | |
641 } | |
642 | |
643 state->cur_inst_state = NULL; | |
644 state->cur_inst = NULL; | |
645 state->cur_inst_vector = NULL; | |
646 NaClApplyPostValidators(state, iter_new); | |
647 NaClInstIterDestroy(iter_old); | |
648 NaClInstIterDestroy(iter_new); | |
649 NaClValidatorStatePrintStats(state); | |
650 } | |
651 | |
OLD | NEW |