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 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
234 NaClValidatorState* state, | 234 NaClValidatorState* state, |
235 NaClInstState* inst, | 235 NaClInstState* inst, |
236 const char* format, | 236 const char* format, |
237 ...) { | 237 ...) { |
238 level = NaClRecordIfValidatorError(state, level); | 238 level = NaClRecordIfValidatorError(state, level); |
239 if (NaClPrintValidatorMessages(state, level)) { | 239 if (NaClPrintValidatorMessages(state, level)) { |
240 va_list ap; | 240 va_list ap; |
241 struct Gio* g = NaClLogGetGio(); | 241 struct Gio* g = NaClLogGetGio(); |
242 | 242 |
243 NaClLogLock(); | 243 NaClLogLock(); |
244 /* TODO(karl): empty fmt strings not allowed */ | 244 /* TODO(karl): empty fmt strings not allowed */ |
bsy
2010/11/11 21:27:21
is this TODO still valid, given the check below?
petr
2010/11/12 18:11:06
I rolled back the check below, so it is valid
On
| |
245 NaClLog_mu(level, "VALIDATOR: %s", ""); | 245 NaClLog_mu(level, "VALIDATOR: %s", ""); |
246 /* TODO(karl) - Make printing of instruction state possible via format. */ | 246 /* TODO(karl) - Make printing of instruction state possible via format. */ |
247 NaClInstStateInstPrint(g, inst); | 247 NaClInstStateInstPrint(g, inst); |
248 | 248 |
249 va_start(ap, format); | 249 if (format != NULL) { |
bsy
2010/11/11 21:27:21
when do we get NULL format strings? this sounds l
petr
2010/11/12 18:11:06
I use this to print two instructions in a row, see
| |
250 NaClLog_mu(level, "VALIDATOR: %s", NaClLogLevelLabel(level)); | 250 va_start(ap, format); |
251 NaClLogV_mu(level, format, ap); | 251 NaClLog_mu(level, "VALIDATOR: %s", NaClLogLevelLabel(level)); |
252 va_end(ap); | 252 NaClLogV_mu(level, format, ap); |
253 va_end(ap); | |
254 } | |
253 NaClLogUnlock(); | 255 NaClLogUnlock(); |
254 NaClRecordErrorReported(state, level); | 256 NaClRecordErrorReported(state, level); |
255 } | 257 } |
256 if (state->do_stub_out && (level <= LOG_ERROR)) { | 258 if (state->do_stub_out && (level <= LOG_ERROR)) { |
257 memset(inst->mpc, kNaClFullStop, inst->length); | 259 memset(inst->mpc, kNaClFullStop, inst->length); |
258 } | 260 } |
259 } | 261 } |
260 | 262 |
261 Bool NaClValidatorQuit(NaClValidatorState* state) { | 263 Bool NaClValidatorQuit(NaClValidatorState* state) { |
262 return !state->validates_ok && (state->quit_after_error_count == 0); | 264 return !state->validates_ok && (state->quit_after_error_count == 0); |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
442 void* NaClGetValidatorLocalMemory(NaClValidator validator, | 444 void* NaClGetValidatorLocalMemory(NaClValidator validator, |
443 const NaClValidatorState* state) { | 445 const NaClValidatorState* state) { |
444 int i; | 446 int i; |
445 for (i = 0; i < state->number_validators; ++i) { | 447 for (i = 0; i < state->number_validators; ++i) { |
446 if (state->validators[i].validator == validator) { | 448 if (state->validators[i].validator == validator) { |
447 return state->local_memory[i]; | 449 return state->local_memory[i]; |
448 } | 450 } |
449 } | 451 } |
450 return NULL; | 452 return NULL; |
451 } | 453 } |
454 | |
455 /* | |
456 * Check that iter_new is a valid replacement for iter_old. | |
457 * If a validation error occurs, state->validates_ok will be set to false by | |
458 * NaClValidatorInstMessage when it is given LOG_ERROR, see the end of this | |
459 * function. | |
460 */ | |
461 static void NaClValidateInstReplacement(NaClInstIter* iter_old, | |
462 NaClInstIter* iter_new, | |
463 struct NaClValidatorState* state) { | |
464 NaClInstState *istate_old, *istate_new; | |
465 NaClExpVector *exp_old, *exp_new; | |
466 uint32_t i; | |
467 | |
468 istate_old = NaClInstIterGetState(iter_old); | |
469 istate_new = NaClInstIterGetState(iter_new); | |
470 | |
471 /* Location/length must match */ | |
472 if (istate_new->vpc != istate_old->vpc || | |
473 istate_new->length != istate_old->length) { | |
474 NaClValidatorMessage(LOG_ERROR, state, | |
475 "Code modification: instructions length/addresses do not match\n"); | |
476 NaClValidatorInstMessage(LOG_ERROR, state, istate_old, NULL); | |
477 NaClValidatorInstMessage(LOG_ERROR, state, istate_new, NULL); | |
478 return; | |
479 } | |
480 | |
481 | |
482 do { | |
483 /* fast check if the replacement is identical */ | |
484 if (!memcmp(istate_old->mpc, istate_new->mpc, istate_old->length)) | |
485 return; | |
486 | |
487 if (istate_old->num_prefix_bytes != istate_new->num_prefix_bytes) | |
488 break; | |
489 if (istate_old->num_rex_prefixes != istate_new->num_rex_prefixes) | |
490 break; | |
491 if (istate_old->rexprefix != istate_new->rexprefix) | |
492 break; | |
493 if (istate_old->modrm != istate_new->modrm) | |
494 break; | |
495 if (istate_old->has_sib != istate_new->has_sib) | |
496 break; | |
497 if (istate_old->has_sib && istate_old->sib != istate_new->sib) | |
498 break; | |
499 if (istate_old->operand_size != istate_new->operand_size) | |
500 break; | |
501 if (istate_old->address_size != istate_new->address_size) | |
502 break; | |
503 if (istate_old->prefix_mask != istate_new->prefix_mask) | |
504 break; | |
505 | |
506 /* | |
507 * these are pointers, but they reference entries in a static table, | |
508 * so if the two instructions are the same, then these pointers must | |
509 * reference the same entry | |
510 */ | |
511 if (istate_old->inst != istate_new->inst) | |
512 break; | |
513 | |
514 exp_old = NaClInstStateExpVector(istate_old); | |
515 exp_new = NaClInstStateExpVector(istate_new); | |
516 | |
517 /* check if the instruction operands are identical */ | |
518 if (exp_old->number_expr_nodes != exp_new->number_expr_nodes) | |
519 break; | |
520 | |
521 for (i = 0; i < exp_old->number_expr_nodes; i++) { | |
522 if (exp_old->node[i].kind != exp_new->node[i].kind) | |
523 break; | |
524 if (exp_old->node[i].flags != exp_new->node[i].flags) | |
525 break; | |
526 | |
527 /* | |
528 * allow some constants to be different; however it is important not to | |
529 * allow modification of sandboxing instructions. Note nether of the | |
530 * instructions allowed for modification is used for sandboxing | |
531 */ | |
532 if (exp_old->node[i].value != exp_new->node[i].value) { | |
533 if (exp_old->node[i].kind == ExprConstant) { | |
534 | |
535 /* allow different constants in direct calls */ | |
536 if (istate_old->inst->name == InstCall) | |
537 if (exp_old->node[i].flags & NACL_EFLAG(ExprJumpTarget)) | |
538 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind | |
539 == OperandReference) | |
540 continue; | |
541 | |
542 /* | |
543 * allow different constants in operand of mov | |
544 * e.g. mov $rax, 0xdeadbeef | |
545 */ | |
546 if (istate_old->inst->name == InstMov) | |
547 if (exp_old->node[i].flags & NACL_EFLAG(ExprUsed)) | |
548 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind | |
549 == OperandReference) | |
550 continue; | |
551 /* | |
552 * allow different displacements in memory reference of mov | |
553 * instructions e.g. mov $rax, [$r15+$rbx*2+0x7fff] | |
554 */ | |
555 if (istate_old->inst->name == InstMov) | |
556 if (exp_old->node[NaClGetExpParentIndex(exp_old, i)].kind | |
557 == ExprMemOffset) | |
558 /* displacement is the fourth node after ExprMemOffset node */ | |
559 if (i - NaClGetExpParentIndex(exp_old, i) == 4) | |
560 continue; | |
561 } | |
562 break; | |
563 } | |
564 } | |
565 | |
566 return; | |
567 } while (0); | |
568 | |
569 NaClValidatorMessage(LOG_ERROR, state, | |
570 "Code modification: failed to modify instructions\n"); | |
571 NaClValidatorInstMessage(LOG_ERROR, state, istate_old, NULL); | |
bsy
2010/11/11 21:27:21
are these two lines the only places where the form
Karl
2010/11/11 22:45:41
I think that you may just want to add a new "messa
petr
2010/11/12 18:11:06
Yes, they are
On 2010/11/11 21:27:21, bsy wrote:
petr
2010/11/12 18:11:06
Yes, I will do this
On 2010/11/11 22:45:41, Karl
| |
572 NaClValidatorInstMessage(LOG_ERROR, state, istate_new, NULL); | |
573 } | |
574 | |
575 void NaClValidateSegmentPair(uint8_t* mbase_old, uint8_t* mbase_new, | |
576 NaClPcAddress vbase, size_t size, | |
577 struct NaClValidatorState* state) { | |
578 NaClSegment segment_old, segment_new; | |
579 NaClInstIter *iter_old, *iter_new; | |
580 | |
581 NaClValidatorStateInitializeValidators(state); | |
582 NaClSegmentInitialize(mbase_old, vbase, size, &segment_old); | |
583 NaClSegmentInitialize(mbase_new, vbase, size, &segment_new); | |
584 iter_old = NaClInstIterCreateWithLookback(&segment_old, kLookbackSize); | |
585 iter_new = NaClInstIterCreateWithLookback(&segment_new, kLookbackSize); | |
586 while (NaClInstIterHasNext(iter_old) && | |
587 NaClInstIterHasNext(iter_new)) { | |
588 state->cur_inst_state = NaClInstIterGetState(iter_new); | |
589 state->cur_inst = NaClInstStateInst(state->cur_inst_state); | |
590 state->cur_inst_vector = NaClInstStateExpVector(state->cur_inst_state); | |
591 NaClApplyValidators(state, iter_new); | |
592 NaClValidateInstReplacement(iter_old, iter_new, state); | |
593 if (state->quit) break; | |
594 NaClInstIterAdvance(iter_old); | |
595 NaClInstIterAdvance(iter_new); | |
596 } | |
597 | |
598 if (NaClInstIterHasNext(iter_old) || | |
599 NaClInstIterHasNext(iter_new)) { | |
600 NaClValidatorMessage(LOG_ERROR, state, | |
601 "Code modification: code segments have different number of instructions\n"); | |
602 } | |
603 | |
604 state->cur_inst_state = NULL; | |
605 state->cur_inst = NULL; | |
606 state->cur_inst_vector = NULL; | |
607 NaClApplyPostValidators(state, iter_new); | |
608 NaClInstIterDestroy(iter_old); | |
609 NaClInstIterDestroy(iter_new); | |
610 NaClValidatorStatePrintStats(state); | |
611 } | |
612 | |
OLD | NEW |