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
4 * found in the LICENSE file.
9 * Validate x86 instructions for Native Client
13 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.h"
18 #include "native_client/src/include/portability_io.h"
19 #include "native_client/src/shared/platform/nacl_check.h"
20 #include "native_client/src/shared/platform/nacl_log.h"
21 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
22 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h"
23 #include "native_client/src/trusted/validator/x86/halt_trim.h"
24 #include "native_client/src/trusted/validator/x86/nc_segment.h"
25 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_internal.h"
26 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tables.h"
27 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_illegal.h"
28 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h"
29 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps_detailed.h"
30 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.h"
32 #include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_postconds.h"
34 #include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h"
36 /* To turn on debugging of instruction decoding, change value of
41 #include "native_client/src/shared/utils/debugging.h"
43 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter_inl.c"
45 /* When >= 0, only print that many errors before quiting. When
46 * < 0, print all errors.
48 int NACL_FLAGS_max_reported_errors =
50 /* Turn off error reporting when generating pre/post conditions.
51 * Note: conditional code for NCVAL_TESTING will reset the
52 * quit flag after each instruction. Hence, by using 0, we
53 * effectively turn off printing of errors as the default. However,
54 * one can override this on the command line to force errors to
63 Bool NACL_FLAGS_validator_trace_instructions = FALSE;
65 Bool NACL_FLAGS_validator_trace_inst_internals = FALSE;
67 Bool NACL_FLAGS_ncval_annotate = TRUE;
69 Bool NACL_FLAGS_unsafe_single_inst_mode = FALSE;
72 Bool NACL_FLAGS_report_conditions_on_all = FALSE;
74 void NaClConditionAppend(char* condition,
76 size_t* remaining_buffer_size) {
77 size_t bsize = strlen(condition);
78 *buffer = condition + bsize;
80 /* Add that we are adding an alternative. */
81 SNPRINTF(*buffer, NCVAL_CONDITION_SIZE - bsize,
83 bsize = strlen(condition);
84 *buffer = condition + bsize;
86 *remaining_buffer_size = NCVAL_CONDITION_SIZE - bsize;
90 /* Define the stop instruction. */
91 const uint8_t kNaClFullStop = 0xf4; /* x86 HALT opcode */
93 void NaClValidatorFlagsSetTraceVerbose(void) {
94 NACL_FLAGS_validator_trace_instructions = TRUE;
95 NACL_FLAGS_validator_trace_inst_internals = TRUE;
98 int NaClValidatorStateGetMaxReportedErrors(NaClValidatorState *vstate) {
99 return vstate->quit_after_error_count;
102 void NaClValidatorStateSetMaxReportedErrors(NaClValidatorState *vstate,
104 vstate->quit_after_error_count = new_value;
105 vstate->quit = NaClValidatorQuit(vstate);
108 Bool NaClValidatorStateGetTraceInstructions(NaClValidatorState *vstate) {
109 return vstate->trace_instructions;
112 void NaClValidatorStateSetTraceInstructions(NaClValidatorState *vstate,
114 vstate->trace_instructions = new_value;
117 Bool NaClValidatorStateGetTraceInstInternals(NaClValidatorState *vstate) {
118 return vstate->trace_inst_internals;
121 void NaClValidatorStateSetTraceInstInternals(NaClValidatorState *vstate,
123 vstate->trace_inst_internals = new_value;
126 static INLINE Bool NaClValidatorStateTraceInline(NaClValidatorState *vstate) {
127 return vstate->trace_instructions || vstate->trace_inst_internals;
131 Bool NaClValidatorStateTrace(NaClValidatorState *vstate) {
132 return NaClValidatorStateTraceInline(vstate);
135 void NaClValidatorStateSetTraceVerbose(NaClValidatorState *vstate) {
136 vstate->trace_instructions = TRUE;
137 vstate->trace_inst_internals = TRUE;
140 int NaClValidatorStateGetLogVerbosity(NaClValidatorState *vstate) {
141 return vstate->log_verbosity;
144 void NaClValidatorStateSetLogVerbosity(NaClValidatorState *vstate,
146 vstate->log_verbosity = new_value;
149 Bool NaClValidatorStateGetDoStubOut(NaClValidatorState *vstate) {
150 return vstate->do_stub_out;
153 void NaClValidatorStateSetDoStubOut(NaClValidatorState *vstate,
155 vstate->do_stub_out = new_value;
156 /* We also turn off error diagnostics, under the assumption
157 * you don't want them. (Note: if the user wants them,
158 * you can run ncval to get them).
161 NaClValidatorStateSetMaxReportedErrors(vstate, 0);
165 static void NaClValidatorTrace(NaClValidatorState* vstate) {
166 struct Gio* g = NaClLogGetGio();
167 NaClInstState* inst_state = NaClInstIterGetStateInline(vstate->cur_iter);
168 (*vstate->error_reporter->printf)
169 (vstate->error_reporter, "-> visit: ");
170 if (NaClValidatorStateGetTraceInstructions(vstate)) {
171 (*vstate->error_reporter->print_inst)(vstate->error_reporter,
172 (void*) NaClInstStateInst(inst_state));
174 if (NaClValidatorStateGetTraceInstInternals(vstate)) {
175 NaClExpVectorPrint(g, inst_state);
179 /* TODO(karl) Move the print routines to a separate module. */
181 /* Returns true if an error message should be printed for the given level, in
182 * the current validator state.
184 * vstate - The validator state (may be NULL).
185 * level - The log level of the validator message.
187 static INLINE Bool NaClPrintValidatorMessages(
188 NaClValidatorState *vstate, int level) {
189 if (NULL == vstate) {
190 /* Validator not defined yet, only used log verbosity to decide if message
193 return level <= NaClLogGetVerbosity();
195 return (vstate->quit_after_error_count != 0) &&
196 (level <= vstate->log_verbosity) &&
197 (level <= NaClLogGetVerbosity());
201 static INLINE const char *NaClLogLevelLabel(int level) {
214 /* Records that an error message has just been reported.
216 * vstate - The validator state (may be NULL).
217 * level - The log level of the validator message.
219 static void NaClRecordErrorReported(NaClValidatorState *vstate, int level) {
220 if ((vstate != NULL) && ((level == LOG_ERROR) || (level == LOG_FATAL)) &&
221 (vstate->quit_after_error_count > 0) &&
222 !vstate->do_stub_out) {
223 --(vstate->quit_after_error_count);
224 vstate->quit = NaClValidatorQuit(vstate);
225 if (vstate->quit_after_error_count == 0) {
226 (*vstate->error_reporter->printf)(
227 vstate->error_reporter,
228 "%sError limit reached. Validator quitting!\n",
229 NaClLogLevelLabel(LOG_INFO));
234 /* Records the number of error validator messages generated for the state.
236 * vstate - The validator state (may be NULL).
237 * level - The log level of the validator message.
238 * Returns - Updated error level, based on state.
240 static INLINE int NaClRecordIfValidatorError(NaClValidatorState *vstate,
242 /* Note: don't quit if stubbing out, so all problems are fixed. */
243 if (((level == LOG_ERROR) || (level == LOG_FATAL)) &&
244 (NULL != vstate) && !vstate->do_stub_out) {
245 vstate->validates_ok = FALSE;
246 vstate->quit = NaClValidatorQuit(vstate);
251 /* The low-level implementation for stubbing out an instruction. Always use
252 * this function to (ultimately) stub out instructions. This makes it possible
253 * to detect when the validator modifies the code.
255 void NCStubOutMem(NaClValidatorState *state, void *ptr, size_t num) {
256 state->did_stub_out = TRUE;
257 memset(ptr, kNaClFullStop, num);
260 /* Does stub out of instruction in validator state. */
261 static void NaClStubOutInst(NaClValidatorState *state, NaClInstState* inst) {
262 NCRemainingMemory *memory = inst->bytes.memory;
263 NCStubOutMem(state, memory->mpc, memory->read_length);
266 /* Does a printf using the error reporter of the state if defined.
267 * Uses NaClLogGetGio() if undefined.
269 static INLINE void NaClPrintVMessage(NaClValidatorState* vstate,
273 vstate->error_reporter->printf_v(vstate->error_reporter, format, ap);
275 gvprintf(NaClLogGetGio(), format, ap);
279 /* Forward declaration to define printf arguments. */
280 static void NaClPrintMessage(NaClValidatorState* vstate,
282 ...) ATTRIBUTE_FORMAT_PRINTF(2, 3);
284 /* Does a printf using the error reporter of the state if defined.
285 * Uses NaClLogGetGio() if undefined.
287 static INLINE void NaClPrintMessage(NaClValidatorState* vstate,
291 va_start(ap, format);
292 NaClPrintVMessage(vstate, format, ap);
296 /* Print out a predefined prefix for messages, along with the serverity
299 static void NaClPrintValidatorPrefix(int level,
300 NaClValidatorState* vstate,
301 Bool visible_level) {
302 NaClPrintMessage(vstate, "VALIDATOR: ");
303 if (visible_level) NaClPrintMessage(vstate, "%s", NaClLogLevelLabel(level));
306 /* Prints out an instruction on behalf of the validator. */
307 static void NaClValidatorPrintInst(int level,
308 NaClValidatorState *vstate,
309 NaClInstState *inst) {
310 NaClPrintValidatorPrefix(level, vstate, FALSE);
312 vstate->error_reporter->print_inst(vstate->error_reporter, (void*) inst);
314 NaClInstStateInstPrint(NaClLogGetGio(), inst);
318 void NaClValidatorMessage(int level,
319 NaClValidatorState *vstate,
322 level = NaClRecordIfValidatorError(vstate, level);
323 if (NaClPrintValidatorMessages(vstate, level)) {
325 NaClPrintValidatorPrefix(level, vstate, TRUE);
326 va_start(ap, format);
327 NaClPrintVMessage(vstate, format, ap);
329 NaClRecordErrorReported(vstate, level);
333 void NaClValidatorVarargMessage(int level,
334 NaClValidatorState *vstate,
337 level = NaClRecordIfValidatorError(vstate, level);
338 if (NaClPrintValidatorMessages(vstate, level)) {
339 NaClPrintValidatorPrefix(level, vstate, TRUE);
340 NaClPrintVMessage(vstate, format, ap);
341 NaClRecordErrorReported(vstate, level);
345 static void NaClValidatorPcAddressMess(
347 NaClValidatorState *vstate,
351 level = NaClRecordIfValidatorError(vstate, level);
352 if (NaClPrintValidatorMessages(vstate, level)) {
353 NaClPrintValidatorPrefix(level, vstate, !NACL_FLAGS_ncval_annotate);
354 NaClPrintMessage(vstate, "%"NACL_PRIxNaClPcAddress ": ", addr);
355 NaClPrintVMessage(vstate, format, ap);
356 NaClRecordErrorReported(vstate, level);
360 void NaClValidatorPcAddressMessage(int level,
361 NaClValidatorState *vstate,
366 va_start(ap, format);
367 NaClValidatorPcAddressMess(level, vstate, vstate->vbase + addr, format, ap);
371 void NaClValidatorInstMessage(int level,
372 NaClValidatorState *vstate,
376 if (NACL_FLAGS_ncval_annotate) {
378 va_start(ap, format);
379 NaClValidatorPcAddressMess(level, vstate,
380 NaClInstStatePrintableAddress(inst),
384 level = NaClRecordIfValidatorError(vstate, level);
385 if (NaClPrintValidatorMessages(vstate, level)) {
387 NaClValidatorPrintInst(level, vstate, inst);
388 NaClPrintValidatorPrefix(level, vstate, TRUE);
389 va_start(ap, format);
390 NaClPrintVMessage(vstate, format, ap);
392 NaClRecordErrorReported(vstate, level);
395 if (vstate->do_stub_out && (level <= LOG_ERROR)) {
396 NaClStubOutInst(vstate, inst);
400 void NaClValidatorTwoInstMessage(int level,
401 NaClValidatorState *vstate,
402 NaClInstState *inst1,
403 NaClInstState *inst2,
406 level = NaClRecordIfValidatorError(vstate, level);
407 if (NaClPrintValidatorMessages(vstate, level)) {
409 NaClPrintValidatorPrefix(level, vstate, TRUE);
410 va_start(ap, format);
411 NaClPrintVMessage(vstate, format, ap);
413 NaClPrintMessage(vstate, "\n ");
414 NaClValidatorPrintInst(level, vstate, inst1);
415 NaClPrintMessage(vstate, " ");
416 NaClValidatorPrintInst(level, vstate, inst2);
417 NaClRecordErrorReported(vstate, level);
419 if (vstate->do_stub_out && (level <= LOG_ERROR)) {
420 NaClStubOutInst(vstate, inst2);
424 Bool NaClValidatorQuit(NaClValidatorState *vstate) {
425 return !vstate->validates_ok && (vstate->quit_after_error_count == 0);
428 Bool NaClValidatorDidStubOut(NaClValidatorState *vstate) {
429 return vstate->did_stub_out;
432 static void NaClNullErrorPrintInst(NaClErrorReporter* self,
433 struct NaClInstState* inst) {}
435 NaClErrorReporter kNaClNullErrorReporter = {
436 NaClNullErrorReporter,
438 NaClNullErrorPrintfV,
439 (NaClPrintInst) NaClNullErrorPrintInst
442 /* Update caches associated the current instruction state associated with
443 * the iterator of the validator state. This routine should be called everytime
444 * the iterator (of the validator state) is advanced.
446 static INLINE void NaClUpdateCaches(NaClValidatorState *vstate) {
448 /* Initialize the pre/post conditions to the empty condition. */
449 strcpy(&vstate->precond[0], "");
450 strcpy(&vstate->postcond[0], "");
452 vstate->cur_inst_state = NaClInstIterGetStateInline(vstate->cur_iter);
453 vstate->cur_inst = NaClInstStateInst(vstate->cur_inst_state);
454 vstate->cur_inst_vector = NaClInstStateExpVector(vstate->cur_inst_state);
457 /* Returns true if the current position of the instruction iterator (for
458 * the validator state) points to an instruction (i.e. not at the end of
461 static INLINE Bool NaClValidatorStateIterHasNextInline(
462 NaClValidatorState *vstate) {
464 if (NULL == vstate->cur_iter) return FALSE;
465 result = NaClInstIterHasNextInline(vstate->cur_iter);
466 if (result && NULL == vstate->cur_inst_state) {
467 /* If reached, this is the first query to check if there is
468 * a next instruction. Update the caches to match.
470 NaClUpdateCaches(vstate);
475 Bool NaClValidatorStateIterHasNext(NaClValidatorState *vstate) {
476 return NaClValidatorStateIterHasNextInline(vstate);
479 /* Move past the current instruction defined by the iterator of the
482 static INLINE void NaClValidatorStateIterAdvanceInline(
483 NaClValidatorState *vstate) {
484 NaClInstIterAdvanceInline(vstate->cur_iter);
485 NaClUpdateCaches(vstate);
488 void NaClValidatorStateIterAdvance(NaClValidatorState *vstate) {
489 NaClValidatorStateIterAdvanceInline(vstate);
492 /* Iterator of the validator state is no longer needed, clean up any
493 * caches associated with the iterator.
495 static void NaClValidatorStateIterFinishInline(NaClValidatorState *vstate) {
496 vstate->cur_inst_state = NULL;
497 vstate->cur_inst = NULL;
498 vstate->cur_inst_vector = NULL;
501 void NaClValidatorStateIterFinish(NaClValidatorState *vstate) {
502 NaClValidatorStateIterFinishInline(vstate);
505 NaClValidatorState *NaClValidatorStateCreate(
506 const NaClPcAddress vbase,
507 const NaClMemorySize codesize,
508 const NaClOpKind base_register,
509 const int readonly_text,
510 const NaClCPUFeaturesX86 *features) {
511 NaClValidatorState *vstate;
512 NaClValidatorState *return_value = NULL;
513 const int bundle_size = 32;
514 DEBUG(NaClLog(LOG_INFO,
515 "Validator Create: vbase = %"NACL_PRIxNaClPcAddress", "
516 "sz = %"NACL_PRIxNaClMemorySize", bundle_size = %u\n",
517 vbase, codesize, bundle_size));
518 if (features == NULL)
520 vstate = (NaClValidatorState*) malloc(sizeof(NaClValidatorState));
521 if (vstate != NULL) {
522 return_value = vstate;
523 vstate->decoder_tables = kNaClValDecoderTables;
524 vstate->vbase = vbase;
525 vstate->bundle_size = bundle_size;
526 vstate->codesize = codesize;
527 vstate->bundle_mask = bundle_size - 1;
528 NaClCopyCPUFeaturesX86(&vstate->cpu_features, features);
529 vstate->base_register = base_register;
530 vstate->validates_ok = TRUE;
531 vstate->did_stub_out = FALSE;
532 vstate->quit_after_error_count = NACL_FLAGS_max_reported_errors;
534 vstate->validates_ok_with_conditions = TRUE;
535 vstate->report_conditions_on_all = NACL_FLAGS_report_conditions_on_all;
537 vstate->error_reporter = &kNaClNullErrorReporter;
538 vstate->print_opcode_histogram = NACL_FLAGS_opcode_histogram;
539 vstate->trace_instructions = NACL_FLAGS_validator_trace_instructions;
540 vstate->trace_inst_internals = NACL_FLAGS_validator_trace_inst_internals;
541 vstate->log_verbosity = LOG_INFO;
542 vstate->cur_iter = NULL;
543 NaClValidatorStateIterFinishInline(vstate);
544 vstate->quit = NaClValidatorQuit(return_value);
545 vstate->do_stub_out = FALSE;
546 vstate->readonly_text = readonly_text;
547 vstate->do_detailed = FALSE;
548 NaClOpcodeHistogramInitialize(vstate);
549 NaClCpuCheckMemoryInitialize(vstate);
550 NaClBaseRegisterMemoryInitialize(vstate);
551 if (!NaClJumpValidatorInitialize(vstate)) {
552 NaClValidatorStateDestroy(vstate);
559 Bool NaClValidatorStateIterReset(NaClValidatorState *vstate) {
560 /* Record infromation needed to reset the iterator, based on the
563 size_t lookback_size = lookback_size = vstate->cur_iter->buffer_size;
564 NaClSegment* segment = vstate->cur_iter->segment;
566 if (NULL == vstate->cur_iter) return FALSE;
568 /* Before deleting, be sure to clean up cached information. and
569 * the destroy the current validator. */
570 NaClValidatorStateIterFinishInline(vstate);
571 NaClInstIterDestroy(vstate->cur_iter);
573 /* Now create a new instruction iterator. */
574 vstate->cur_iter = NaClInstIterCreateWithLookback(
575 vstate->decoder_tables, segment, lookback_size);
577 if (NULL == vstate->cur_iter) return FALSE;
582 void NaClPrintConditions(NaClValidatorState *state) {
583 /* To save space, only report on instructions that have non-empty
584 * pre/post conditions.
586 if ((strlen(state->precond) > 0) || (strlen(state->postcond) > 0)) {
587 printf("%"NACL_PRIxNaClPcAddress": ",
588 NaClInstStatePrintableAddress(state->cur_inst_state));
589 if ('\0' != state->precond[0]) {
590 printf("%s", state->precond);
592 if ('\0' != state->postcond[0]) {
593 if ('\0' != state->precond[0]) printf(" ");
594 printf("-> %s", state->postcond);
601 /* Given we are at the instruction defined by the instruction iterator, for
602 * a segment, apply all applicable validator functions.
604 static INLINE void NaClApplyValidators(NaClValidatorState *vstate) {
605 if (vstate->quit) return;
606 DEBUG(NaClLog(LOG_INFO, "iter state:\n");
607 NaClInstStateInstPrint(NaClLogGetGio(),
608 NaClInstIterGetState(vstate->cur_iter)));
609 if (NaClValidatorStateTraceInline(vstate)) {
610 NaClValidatorTrace(vstate);
612 NaClCpuCheck(vstate, vstate->cur_iter);
613 NaClValidateInstructionLegal(vstate);
614 NaClBaseRegisterValidator(vstate);
615 NaClMemoryReferenceValidator(vstate);
616 NaClJumpValidator(vstate);
617 if (vstate->print_opcode_histogram) {
618 NaClOpcodeHistogramRecord(vstate);
621 /* Collect post conditions for instructions that are non-last.
622 * Only print pre/post conditions for valid instructions (ignoring
623 * pre/post conditions).
625 if (NaClValidatesOk(vstate) || vstate->report_conditions_on_all) {
626 NaClAddAssignsRegisterWithZeroExtendsPostconds(vstate);
627 NaClAddLeaSafeAddressPostconds(vstate);
628 NaClPrintConditions(vstate);
630 /* Reset the exit flags, so that errors do not stop
631 * other instructions from firing errors. By reseting these flags,
632 * it allows us to only print pre/post conditions for instructions
633 * that are not marked illegal.
635 if (!vstate->validates_ok) vstate->validates_ok_with_conditions = FALSE;
636 vstate->validates_ok = TRUE;
637 vstate->quit = FALSE;
641 /* Given that we have just iterated through all instructions in a segment,
642 * apply post validators rules (before we collect the iterator).
644 static INLINE void NaClApplyPostValidators(NaClValidatorState *vstate) {
645 DEBUG(NaClLog(LOG_INFO, "applying post validators...\n"));
646 if (vstate->quit || (NULL == vstate->cur_iter)) return;
648 /* Before doing anything else, process remaining (forward) information
649 * stored by the validator, to see if any errors should be reported
650 * about the last instruction processed.
652 NaClBaseRegisterSummarize(vstate);
654 /* Now do the summarizing steps of the validator. */
655 if (vstate->do_detailed) {
656 NaClJumpValidatorSummarizeDetailed(vstate);
658 NaClJumpValidatorSummarize(vstate);
660 if (NaClValidatorStateTrace(vstate)) {
661 (vstate->error_reporter->printf)
662 (vstate->error_reporter, "<- visit\n");
666 /* The maximum lookback for the instruction iterator of the segment.
667 * Note: Allows for two memory patterns (4 instructions for each pattern).
669 static const size_t kLookbackSize = 8;
671 void NaClValidateSegment(uint8_t *mbase, NaClPcAddress vbase,
672 NaClMemorySize size, NaClValidatorState *vstate) {
676 /* TODO(ncbray): remove redundant vbase/size args. */
677 if ((vbase & vstate->bundle_mask) != 0) {
678 NaClValidatorMessage(LOG_ERROR, vstate,
679 "Code segment starts at 0x%"NACL_PRIxNaClPcAddress
680 ", which isn't aligned properly.\n",
684 if (vbase != vstate->vbase) {
685 NaClValidatorMessage(LOG_ERROR, vstate, "Mismatched vbase address\n");
688 if (size != vstate->codesize) {
689 NaClValidatorMessage(LOG_ERROR, vstate, "Mismatched code size\n");
692 if (vbase > vbase + size) {
693 NaClValidatorMessage(LOG_ERROR, vstate, "Text segment too big for given "
694 "vbase (address overflow)\n");
698 size = NCHaltTrimSize(mbase, size, vstate->bundle_size);
699 vstate->codesize = size;
702 NaClValidatorMessage(LOG_ERROR, vstate, "Bad text segment (zero size)\n");
706 NaClSegmentInitialize(mbase, vbase, size, &segment);
708 vstate->cur_iter = NaClInstIterCreateWithLookback(vstate->decoder_tables,
709 &segment, kLookbackSize);
710 if (NULL == vstate->cur_iter) {
711 NaClValidatorMessage(LOG_ERROR, vstate, "Not enough memory\n");
714 for (; NaClValidatorStateIterHasNextInline(vstate);
715 NaClValidatorStateIterAdvanceInline(vstate)) {
716 NaClApplyValidators(vstate);
717 if (vstate->quit) break;
719 NaClValidatorStateIterFinish(vstate);
721 NaClApplyPostValidators(vstate);
722 NaClInstIterDestroy(vstate->cur_iter);
723 vstate->cur_iter = NULL;
724 if (vstate->print_opcode_histogram) {
725 NaClOpcodeHistogramPrintStats(vstate);
728 /* Update failure to catch instructions that may have validated
731 if (vstate->validates_ok)
732 vstate->validates_ok = vstate->validates_ok_with_conditions;
736 void NaClValidateSegmentUsingTables(uint8_t* mbase,
739 NaClValidatorState* vstate,
740 const struct NaClDecodeTables* tables) {
741 vstate->decoder_tables = tables;
742 NaClValidateSegment(mbase, vbase, sz, vstate);
745 Bool NaClValidatesOk(NaClValidatorState *vstate) {
746 return vstate->validates_ok;
749 void NaClValidatorStateDestroy(NaClValidatorState *vstate) {
750 if (NULL != vstate) {
751 NaClJumpValidatorCleanUp(vstate);
757 * Check that iter_new is a valid replacement for iter_old.
758 * If a validation error occurs, vstate->validates_ok will be set to false by
759 * NaClValidatorInstMessage when it is given LOG_ERROR, see the end of this
761 * Return value: TRUE if the instruction was changed, FALSE if it's identical.
763 static Bool NaClValidateInstReplacement(NaClInstIter *iter_old,
764 NaClInstIter *iter_new,
765 struct NaClValidatorState *vstate) {
766 NaClInstState *istate_old, *istate_new;
767 NaClExpVector *exp_old, *exp_new;
769 Bool inst_changed = FALSE;
772 istate_old = NaClInstIterGetStateInline(iter_old);
773 istate_new = NaClInstIterGetStateInline(iter_new);
775 /* Location/length must match. Assumes vbase is the same. */
776 if (istate_new->inst_addr != istate_old->inst_addr ||
777 istate_new->bytes.length != istate_old->bytes.length) {
778 NaClValidatorTwoInstMessage(LOG_ERROR, vstate, istate_old, istate_new,
779 "Code modification: instructions length/addresses do not match");
786 /* fast check if the replacement is identical */
787 if ((istate_old->bytes.memory->read_length ==
788 istate_new->bytes.memory->read_length) &&
789 !memcmp(istate_old->bytes.memory->mpc, istate_new->bytes.memory->mpc,
790 istate_old->bytes.memory->read_length))
795 if (istate_old->num_prefix_bytes != istate_new->num_prefix_bytes)
797 if (istate_old->num_rex_prefixes != istate_new->num_rex_prefixes)
799 if (istate_old->rexprefix != istate_new->rexprefix)
801 if (istate_old->modrm != istate_new->modrm)
803 if (istate_old->has_sib != istate_new->has_sib)
805 if (istate_old->has_sib && istate_old->sib != istate_new->sib)
807 if (istate_old->operand_size != istate_new->operand_size)
809 if (istate_old->address_size != istate_new->address_size)
811 if (istate_old->prefix_mask != istate_new->prefix_mask)
815 * these are pointers, but they reference entries in a static table,
816 * so if the two instructions are the same, then these pointers must
817 * reference the same entry
819 if (istate_old->inst != istate_new->inst)
822 exp_old = NaClInstStateExpVector(istate_old);
823 exp_new = NaClInstStateExpVector(istate_new);
825 /* check if the instruction operands are identical */
826 if (exp_old->number_expr_nodes != exp_new->number_expr_nodes)
829 for (i = 0; i < exp_old->number_expr_nodes; i++) {
830 /* Allow nodes that are identical. */
831 if (exp_old->node[i].kind != exp_new->node[i].kind) goto error_exit;
832 if (exp_old->node[i].flags != exp_new->node[i].flags) goto error_exit;
833 if (exp_old->node[i].value == exp_new->node[i].value) continue;
836 * Only constant values may differ. However it is important not to
837 * allow constant modification of sandboxing instructions. Note neither
838 * of the instructions allowed for modification is used for sandboxing.
840 if (exp_old->node[i].kind != ExprConstant) goto error_exit;
842 switch (istate_old->inst->name) {
845 /* allow different constants in direct calls */
846 if (!NaClHasBit(exp_old->node[i].flags, NACL_EFLAG(ExprJumpTarget)))
848 parent_index = NaClGetExpParentIndex(exp_old, i);
849 if (parent_index < 0) break;
850 if (exp_old->node[parent_index].kind == OperandReference) continue;
854 parent_index = NaClGetExpParentIndex(exp_old, i);
855 if (parent_index < 0) break;
856 switch (exp_old->node[parent_index].kind) {
857 case OperandReference:
859 * allow different constants in operand of mov
860 * e.g. mov $rax, 0xdeadbeef
862 if (NaClHasBit(exp_old->node[i].flags, NACL_EFLAG(ExprUsed)))
867 * allow different displacements in memory reference of mov
868 * instructions e.g. mov $rax, [$r15+$rbx*2+0x7fff]
870 * Note: displacement is the fourth node after ExprMemOffset*
873 if (4 == (i - parent_index)) continue;
883 /* If reached, we found a value that differed, and wasn't one
884 * of the expected constants that can differ.
889 /* This return signifies there is no error in validation. */
894 /* This logging function is the mechanism that sets the validator state
895 * to indicate an error.
897 NaClValidatorTwoInstMessage(LOG_ERROR, vstate, istate_old, istate_new,
898 "Code modification: failed to modify instruction");
903 * Validate a new code block as a replacement for an existing block.
904 * Note: The code location (vbase) must be bundle aligned and the segment size
905 * must also be a multiple of bundle size (checked in
906 * NaClValidateCodeReplacement).This is to ensure all NaCl psuedo-instructions
907 * and guard sequences are properly inspected and maintained.
909 void NaClValidateSegmentPair(uint8_t *mbase_old, uint8_t *mbase_new,
910 NaClPcAddress vbase, size_t size,
911 struct NaClValidatorState *vstate) {
912 NaClSegment segment_old, segment_new;
913 NaClInstIter *iter_old = NULL;
914 NaClInstIter *iter_new = NULL;
916 NaClSegmentInitialize(mbase_old, vbase, size, &segment_old);
917 NaClSegmentInitialize(mbase_new, vbase, size, &segment_new);
919 iter_old = NaClInstIterCreateWithLookback(vstate->decoder_tables,
920 &segment_old, kLookbackSize);
921 if (NULL == iter_old) break;
922 iter_new = NaClInstIterCreateWithLookback(vstate->decoder_tables,
923 &segment_new, kLookbackSize);
924 if (NULL == iter_new) break;
925 vstate->cur_iter = iter_new;
926 while (NaClInstIterHasNextInline(iter_old) &&
927 NaClValidatorStateIterHasNextInline(vstate)) {
928 vstate->cur_inst_state->unchanged =
929 !NaClValidateInstReplacement(iter_old, iter_new, vstate);
930 NaClApplyValidators(vstate);
931 if (vstate->quit) break;
932 NaClInstIterAdvanceInline(iter_old);
933 NaClValidatorStateIterAdvanceInline(vstate);
935 if (NaClInstIterHasNextInline(iter_old) ||
936 NaClInstIterHasNextInline(iter_new)) {
937 NaClValidatorMessage(
939 "Code modification: code segments have different "
940 "number of instructions\n");
943 NaClValidatorStateIterFinish(vstate);
944 NaClApplyPostValidators(vstate);
945 vstate->cur_iter = NULL;
946 NaClInstIterDestroy(iter_old);
947 NaClInstIterDestroy(iter_new);