Index: src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.c |
diff --git a/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.c b/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.c |
deleted file mode 100644 |
index 4d16b1dfe0ed58e1dc0f7a7c14b1581a35a5f558..0000000000000000000000000000000000000000 |
--- a/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.c |
+++ /dev/null |
@@ -1,948 +0,0 @@ |
-/* |
- * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
- |
-/* |
- * ncvalidate_iter.c |
- * Validate x86 instructions for Native Client |
- * |
- */ |
- |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.h" |
- |
-#include <assert.h> |
-#include <string.h> |
- |
-#include "native_client/src/include/portability_io.h" |
-#include "native_client/src/shared/platform/nacl_check.h" |
-#include "native_client/src/shared/platform/nacl_log.h" |
-#include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h" |
-#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.h" |
-#include "native_client/src/trusted/validator/x86/halt_trim.h" |
-#include "native_client/src/trusted/validator/x86/nc_segment.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter_internal.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncval_decode_tables.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_illegal.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps_detailed.h" |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.h" |
-#ifdef NCVAL_TESTING |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_postconds.h" |
-#endif |
-#include "native_client/src/trusted/validator_x86/ncdis_decode_tables.h" |
- |
-/* To turn on debugging of instruction decoding, change value of |
- * DEBUGGING to 1. |
- */ |
-#define DEBUGGING 0 |
- |
-#include "native_client/src/shared/utils/debugging.h" |
- |
-#include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter_inl.c" |
- |
-/* When >= 0, only print that many errors before quiting. When |
- * < 0, print all errors. |
- */ |
-int NACL_FLAGS_max_reported_errors = |
-#ifdef NCVAL_TESTING |
- /* Turn off error reporting when generating pre/post conditions. |
- * Note: conditional code for NCVAL_TESTING will reset the |
- * quit flag after each instruction. Hence, by using 0, we |
- * effectively turn off printing of errors as the default. However, |
- * one can override this on the command line to force errors to |
- * be printed as well. |
- */ |
- 0 |
-#else |
- 100 |
-#endif |
- ; |
- |
-Bool NACL_FLAGS_validator_trace_instructions = FALSE; |
- |
-Bool NACL_FLAGS_validator_trace_inst_internals = FALSE; |
- |
-Bool NACL_FLAGS_ncval_annotate = TRUE; |
- |
-Bool NACL_FLAGS_unsafe_single_inst_mode = FALSE; |
- |
-#ifdef NCVAL_TESTING |
-Bool NACL_FLAGS_report_conditions_on_all = FALSE; |
- |
-void NaClConditionAppend(char* condition, |
- char** buffer, |
- size_t* remaining_buffer_size) { |
- size_t bsize = strlen(condition); |
- *buffer = condition + bsize; |
- if (bsize > 0) { |
- /* Add that we are adding an alternative. */ |
- SNPRINTF(*buffer, NCVAL_CONDITION_SIZE - bsize, |
- "&"); |
- bsize = strlen(condition); |
- *buffer = condition + bsize; |
- } |
- *remaining_buffer_size = NCVAL_CONDITION_SIZE - bsize; |
-} |
-#endif |
- |
-/* Define the stop instruction. */ |
-const uint8_t kNaClFullStop = 0xf4; /* x86 HALT opcode */ |
- |
-void NaClValidatorFlagsSetTraceVerbose(void) { |
- NACL_FLAGS_validator_trace_instructions = TRUE; |
- NACL_FLAGS_validator_trace_inst_internals = TRUE; |
-} |
- |
-int NaClValidatorStateGetMaxReportedErrors(NaClValidatorState *vstate) { |
- return vstate->quit_after_error_count; |
-} |
- |
-void NaClValidatorStateSetMaxReportedErrors(NaClValidatorState *vstate, |
- int new_value) { |
- vstate->quit_after_error_count = new_value; |
- vstate->quit = NaClValidatorQuit(vstate); |
-} |
- |
-Bool NaClValidatorStateGetTraceInstructions(NaClValidatorState *vstate) { |
- return vstate->trace_instructions; |
-} |
- |
-void NaClValidatorStateSetTraceInstructions(NaClValidatorState *vstate, |
- Bool new_value) { |
- vstate->trace_instructions = new_value; |
-} |
- |
-Bool NaClValidatorStateGetTraceInstInternals(NaClValidatorState *vstate) { |
- return vstate->trace_inst_internals; |
-} |
- |
-void NaClValidatorStateSetTraceInstInternals(NaClValidatorState *vstate, |
- Bool new_value) { |
- vstate->trace_inst_internals = new_value; |
-} |
- |
-static INLINE Bool NaClValidatorStateTraceInline(NaClValidatorState *vstate) { |
- return vstate->trace_instructions || vstate->trace_inst_internals; |
-} |
- |
- |
-Bool NaClValidatorStateTrace(NaClValidatorState *vstate) { |
- return NaClValidatorStateTraceInline(vstate); |
-} |
- |
-void NaClValidatorStateSetTraceVerbose(NaClValidatorState *vstate) { |
- vstate->trace_instructions = TRUE; |
- vstate->trace_inst_internals = TRUE; |
-} |
- |
-int NaClValidatorStateGetLogVerbosity(NaClValidatorState *vstate) { |
- return vstate->log_verbosity; |
-} |
- |
-void NaClValidatorStateSetLogVerbosity(NaClValidatorState *vstate, |
- Bool new_value) { |
- vstate->log_verbosity = new_value; |
-} |
- |
-Bool NaClValidatorStateGetDoStubOut(NaClValidatorState *vstate) { |
- return vstate->do_stub_out; |
-} |
- |
-void NaClValidatorStateSetDoStubOut(NaClValidatorState *vstate, |
- Bool new_value) { |
- vstate->do_stub_out = new_value; |
- /* We also turn off error diagnostics, under the assumption |
- * you don't want them. (Note: if the user wants them, |
- * you can run ncval to get them). |
- */ |
- if (new_value) { |
- NaClValidatorStateSetMaxReportedErrors(vstate, 0); |
- } |
-} |
- |
-static void NaClValidatorTrace(NaClValidatorState* vstate) { |
- struct Gio* g = NaClLogGetGio(); |
- NaClInstState* inst_state = NaClInstIterGetStateInline(vstate->cur_iter); |
- (*vstate->error_reporter->printf) |
- (vstate->error_reporter, "-> visit: "); |
- if (NaClValidatorStateGetTraceInstructions(vstate)) { |
- (*vstate->error_reporter->print_inst)(vstate->error_reporter, |
- (void*) NaClInstStateInst(inst_state)); |
- } |
- if (NaClValidatorStateGetTraceInstInternals(vstate)) { |
- NaClExpVectorPrint(g, inst_state); |
- } |
-} |
- |
-/* TODO(karl) Move the print routines to a separate module. */ |
- |
-/* Returns true if an error message should be printed for the given level, in |
- * the current validator state. |
- * Parameters: |
- * vstate - The validator state (may be NULL). |
- * level - The log level of the validator message. |
- */ |
-static INLINE Bool NaClPrintValidatorMessages( |
- NaClValidatorState *vstate, int level) { |
- if (NULL == vstate) { |
- /* Validator not defined yet, only used log verbosity to decide if message |
- * should be printed. |
- */ |
- return level <= NaClLogGetVerbosity(); |
- } else { |
- return (vstate->quit_after_error_count != 0) && |
- (level <= vstate->log_verbosity) && |
- (level <= NaClLogGetVerbosity()); |
- } |
-} |
- |
-static INLINE const char *NaClLogLevelLabel(int level) { |
- switch (level) { |
- case LOG_WARNING: |
- return "WARNING: "; |
- case LOG_ERROR: |
- return "ERROR: "; |
- case LOG_FATAL: |
- return "FATAL: "; |
- default: |
- return ""; |
- } |
-} |
- |
-/* Records that an error message has just been reported. |
- * Parameters: |
- * vstate - The validator state (may be NULL). |
- * level - The log level of the validator message. |
- */ |
-static void NaClRecordErrorReported(NaClValidatorState *vstate, int level) { |
- if ((vstate != NULL) && ((level == LOG_ERROR) || (level == LOG_FATAL)) && |
- (vstate->quit_after_error_count > 0) && |
- !vstate->do_stub_out) { |
- --(vstate->quit_after_error_count); |
- vstate->quit = NaClValidatorQuit(vstate); |
- if (vstate->quit_after_error_count == 0) { |
- (*vstate->error_reporter->printf)( |
- vstate->error_reporter, |
- "%sError limit reached. Validator quitting!\n", |
- NaClLogLevelLabel(LOG_INFO)); |
- } |
- } |
-} |
- |
-/* Records the number of error validator messages generated for the state. |
- * Parameters: |
- * vstate - The validator state (may be NULL). |
- * level - The log level of the validator message. |
- * Returns - Updated error level, based on state. |
- */ |
-static INLINE int NaClRecordIfValidatorError(NaClValidatorState *vstate, |
- int level) { |
- /* Note: don't quit if stubbing out, so all problems are fixed. */ |
- if (((level == LOG_ERROR) || (level == LOG_FATAL)) && |
- (NULL != vstate) && !vstate->do_stub_out) { |
- vstate->validates_ok = FALSE; |
- vstate->quit = NaClValidatorQuit(vstate); |
- } |
- return level; |
-} |
- |
-/* The low-level implementation for stubbing out an instruction. Always use |
- * this function to (ultimately) stub out instructions. This makes it possible |
- * to detect when the validator modifies the code. |
- */ |
-void NCStubOutMem(NaClValidatorState *state, void *ptr, size_t num) { |
- state->did_stub_out = TRUE; |
- memset(ptr, kNaClFullStop, num); |
-} |
- |
-/* Does stub out of instruction in validator state. */ |
-static void NaClStubOutInst(NaClValidatorState *state, NaClInstState* inst) { |
- NCRemainingMemory *memory = inst->bytes.memory; |
- NCStubOutMem(state, memory->mpc, memory->read_length); |
-} |
- |
-/* Does a printf using the error reporter of the state if defined. |
- * Uses NaClLogGetGio() if undefined. |
- */ |
-static INLINE void NaClPrintVMessage(NaClValidatorState* vstate, |
- const char* format, |
- va_list ap) { |
- if (vstate) { |
- vstate->error_reporter->printf_v(vstate->error_reporter, format, ap); |
- } else { |
- gvprintf(NaClLogGetGio(), format, ap); |
- } |
-} |
- |
-/* Forward declaration to define printf arguments. */ |
-static void NaClPrintMessage(NaClValidatorState* vstate, |
- const char* format, |
- ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); |
- |
-/* Does a printf using the error reporter of the state if defined. |
- * Uses NaClLogGetGio() if undefined. |
- */ |
-static INLINE void NaClPrintMessage(NaClValidatorState* vstate, |
- const char* format, |
- ...) { |
- va_list ap; |
- va_start(ap, format); |
- NaClPrintVMessage(vstate, format, ap); |
- va_end(ap); |
-} |
- |
-/* Print out a predefined prefix for messages, along with the serverity |
- * of the message. |
- */ |
-static void NaClPrintValidatorPrefix(int level, |
- NaClValidatorState* vstate, |
- Bool visible_level) { |
- NaClPrintMessage(vstate, "VALIDATOR: "); |
- if (visible_level) NaClPrintMessage(vstate, "%s", NaClLogLevelLabel(level)); |
-} |
- |
-/* Prints out an instruction on behalf of the validator. */ |
-static void NaClValidatorPrintInst(int level, |
- NaClValidatorState *vstate, |
- NaClInstState *inst) { |
- NaClPrintValidatorPrefix(level, vstate, FALSE); |
- if (vstate) { |
- vstate->error_reporter->print_inst(vstate->error_reporter, (void*) inst); |
- } else { |
- NaClInstStateInstPrint(NaClLogGetGio(), inst); |
- } |
-} |
- |
-void NaClValidatorMessage(int level, |
- NaClValidatorState *vstate, |
- const char *format, |
- ...) { |
- level = NaClRecordIfValidatorError(vstate, level); |
- if (NaClPrintValidatorMessages(vstate, level)) { |
- va_list ap; |
- NaClPrintValidatorPrefix(level, vstate, TRUE); |
- va_start(ap, format); |
- NaClPrintVMessage(vstate, format, ap); |
- va_end(ap); |
- NaClRecordErrorReported(vstate, level); |
- } |
-} |
- |
-void NaClValidatorVarargMessage(int level, |
- NaClValidatorState *vstate, |
- const char *format, |
- va_list ap) { |
- level = NaClRecordIfValidatorError(vstate, level); |
- if (NaClPrintValidatorMessages(vstate, level)) { |
- NaClPrintValidatorPrefix(level, vstate, TRUE); |
- NaClPrintVMessage(vstate, format, ap); |
- NaClRecordErrorReported(vstate, level); |
- } |
-} |
- |
-static void NaClValidatorPcAddressMess( |
- int level, |
- NaClValidatorState *vstate, |
- NaClPcAddress addr, |
- const char *format, |
- va_list ap) { |
- level = NaClRecordIfValidatorError(vstate, level); |
- if (NaClPrintValidatorMessages(vstate, level)) { |
- NaClPrintValidatorPrefix(level, vstate, !NACL_FLAGS_ncval_annotate); |
- NaClPrintMessage(vstate, "%"NACL_PRIxNaClPcAddress ": ", addr); |
- NaClPrintVMessage(vstate, format, ap); |
- NaClRecordErrorReported(vstate, level); |
- } |
-} |
- |
-void NaClValidatorPcAddressMessage(int level, |
- NaClValidatorState *vstate, |
- NaClPcAddress addr, |
- const char *format, |
- ...) { |
- va_list ap; |
- va_start(ap, format); |
- NaClValidatorPcAddressMess(level, vstate, vstate->vbase + addr, format, ap); |
- va_end(ap); |
-} |
- |
-void NaClValidatorInstMessage(int level, |
- NaClValidatorState *vstate, |
- NaClInstState *inst, |
- const char *format, |
- ...) { |
- if (NACL_FLAGS_ncval_annotate) { |
- va_list ap; |
- va_start(ap, format); |
- NaClValidatorPcAddressMess(level, vstate, |
- NaClInstStatePrintableAddress(inst), |
- format, ap); |
- va_end(ap); |
- } else { |
- level = NaClRecordIfValidatorError(vstate, level); |
- if (NaClPrintValidatorMessages(vstate, level)) { |
- va_list ap; |
- NaClValidatorPrintInst(level, vstate, inst); |
- NaClPrintValidatorPrefix(level, vstate, TRUE); |
- va_start(ap, format); |
- NaClPrintVMessage(vstate, format, ap); |
- va_end(ap); |
- NaClRecordErrorReported(vstate, level); |
- } |
- } |
- if (vstate->do_stub_out && (level <= LOG_ERROR)) { |
- NaClStubOutInst(vstate, inst); |
- } |
-} |
- |
-void NaClValidatorTwoInstMessage(int level, |
- NaClValidatorState *vstate, |
- NaClInstState *inst1, |
- NaClInstState *inst2, |
- const char *format, |
- ...) { |
- level = NaClRecordIfValidatorError(vstate, level); |
- if (NaClPrintValidatorMessages(vstate, level)) { |
- va_list ap; |
- NaClPrintValidatorPrefix(level, vstate, TRUE); |
- va_start(ap, format); |
- NaClPrintVMessage(vstate, format, ap); |
- va_end(ap); |
- NaClPrintMessage(vstate, "\n "); |
- NaClValidatorPrintInst(level, vstate, inst1); |
- NaClPrintMessage(vstate, " "); |
- NaClValidatorPrintInst(level, vstate, inst2); |
- NaClRecordErrorReported(vstate, level); |
- } |
- if (vstate->do_stub_out && (level <= LOG_ERROR)) { |
- NaClStubOutInst(vstate, inst2); |
- } |
-} |
- |
-Bool NaClValidatorQuit(NaClValidatorState *vstate) { |
- return !vstate->validates_ok && (vstate->quit_after_error_count == 0); |
-} |
- |
-Bool NaClValidatorDidStubOut(NaClValidatorState *vstate) { |
- return vstate->did_stub_out; |
-} |
- |
-static void NaClNullErrorPrintInst(NaClErrorReporter* self, |
- struct NaClInstState* inst) {} |
- |
-NaClErrorReporter kNaClNullErrorReporter = { |
- NaClNullErrorReporter, |
- NaClNullErrorPrintf, |
- NaClNullErrorPrintfV, |
- (NaClPrintInst) NaClNullErrorPrintInst |
-}; |
- |
-/* Update caches associated the current instruction state associated with |
- * the iterator of the validator state. This routine should be called everytime |
- * the iterator (of the validator state) is advanced. |
- */ |
-static INLINE void NaClUpdateCaches(NaClValidatorState *vstate) { |
-#ifdef NCVAL_TESTING |
- /* Initialize the pre/post conditions to the empty condition. */ |
- strcpy(&vstate->precond[0], ""); |
- strcpy(&vstate->postcond[0], ""); |
-#endif |
- vstate->cur_inst_state = NaClInstIterGetStateInline(vstate->cur_iter); |
- vstate->cur_inst = NaClInstStateInst(vstate->cur_inst_state); |
- vstate->cur_inst_vector = NaClInstStateExpVector(vstate->cur_inst_state); |
-} |
- |
-/* Returns true if the current position of the instruction iterator (for |
- * the validator state) points to an instruction (i.e. not at the end of |
- * the segment). |
- */ |
-static INLINE Bool NaClValidatorStateIterHasNextInline( |
- NaClValidatorState *vstate) { |
- Bool result; |
- if (NULL == vstate->cur_iter) return FALSE; |
- result = NaClInstIterHasNextInline(vstate->cur_iter); |
- if (result && NULL == vstate->cur_inst_state) { |
- /* If reached, this is the first query to check if there is |
- * a next instruction. Update the caches to match. |
- */ |
- NaClUpdateCaches(vstate); |
- } |
- return result; |
-} |
- |
-Bool NaClValidatorStateIterHasNext(NaClValidatorState *vstate) { |
- return NaClValidatorStateIterHasNextInline(vstate); |
-} |
- |
-/* Move past the current instruction defined by the iterator of the |
- * validator state. |
- */ |
-static INLINE void NaClValidatorStateIterAdvanceInline( |
- NaClValidatorState *vstate) { |
- NaClInstIterAdvanceInline(vstate->cur_iter); |
- NaClUpdateCaches(vstate); |
-} |
- |
-void NaClValidatorStateIterAdvance(NaClValidatorState *vstate) { |
- NaClValidatorStateIterAdvanceInline(vstate); |
-} |
- |
-/* Iterator of the validator state is no longer needed, clean up any |
- * caches associated with the iterator. |
- */ |
-static void NaClValidatorStateIterFinishInline(NaClValidatorState *vstate) { |
- vstate->cur_inst_state = NULL; |
- vstate->cur_inst = NULL; |
- vstate->cur_inst_vector = NULL; |
-} |
- |
-void NaClValidatorStateIterFinish(NaClValidatorState *vstate) { |
- NaClValidatorStateIterFinishInline(vstate); |
-} |
- |
-NaClValidatorState *NaClValidatorStateCreate( |
- const NaClPcAddress vbase, |
- const NaClMemorySize codesize, |
- const NaClOpKind base_register, |
- const int readonly_text, |
- const NaClCPUFeaturesX86 *features) { |
- NaClValidatorState *vstate; |
- NaClValidatorState *return_value = NULL; |
- const int bundle_size = 32; |
- DEBUG(NaClLog(LOG_INFO, |
- "Validator Create: vbase = %"NACL_PRIxNaClPcAddress", " |
- "sz = %"NACL_PRIxNaClMemorySize", bundle_size = %u\n", |
- vbase, codesize, bundle_size)); |
- if (features == NULL) |
- return NULL; |
- vstate = (NaClValidatorState*) malloc(sizeof(NaClValidatorState)); |
- if (vstate != NULL) { |
- return_value = vstate; |
- vstate->decoder_tables = kNaClValDecoderTables; |
- vstate->vbase = vbase; |
- vstate->bundle_size = bundle_size; |
- vstate->codesize = codesize; |
- vstate->bundle_mask = bundle_size - 1; |
- NaClCopyCPUFeaturesX86(&vstate->cpu_features, features); |
- vstate->base_register = base_register; |
- vstate->validates_ok = TRUE; |
- vstate->did_stub_out = FALSE; |
- vstate->quit_after_error_count = NACL_FLAGS_max_reported_errors; |
-#ifdef NCVAL_TESTING |
- vstate->validates_ok_with_conditions = TRUE; |
- vstate->report_conditions_on_all = NACL_FLAGS_report_conditions_on_all; |
-#endif |
- vstate->error_reporter = &kNaClNullErrorReporter; |
- vstate->print_opcode_histogram = NACL_FLAGS_opcode_histogram; |
- vstate->trace_instructions = NACL_FLAGS_validator_trace_instructions; |
- vstate->trace_inst_internals = NACL_FLAGS_validator_trace_inst_internals; |
- vstate->log_verbosity = LOG_INFO; |
- vstate->cur_iter = NULL; |
- NaClValidatorStateIterFinishInline(vstate); |
- vstate->quit = NaClValidatorQuit(return_value); |
- vstate->do_stub_out = FALSE; |
- vstate->readonly_text = readonly_text; |
- vstate->do_detailed = FALSE; |
- NaClOpcodeHistogramInitialize(vstate); |
- NaClCpuCheckMemoryInitialize(vstate); |
- NaClBaseRegisterMemoryInitialize(vstate); |
- if (!NaClJumpValidatorInitialize(vstate)) { |
- NaClValidatorStateDestroy(vstate); |
- return_value = NULL; |
- } |
- } |
- return return_value; |
-} |
- |
-Bool NaClValidatorStateIterReset(NaClValidatorState *vstate) { |
- /* Record infromation needed to reset the iterator, based on the |
- * current iterator |
- */ |
- size_t lookback_size = lookback_size = vstate->cur_iter->buffer_size; |
- NaClSegment* segment = vstate->cur_iter->segment; |
- |
- if (NULL == vstate->cur_iter) return FALSE; |
- |
- /* Before deleting, be sure to clean up cached information. and |
- * the destroy the current validator. */ |
- NaClValidatorStateIterFinishInline(vstate); |
- NaClInstIterDestroy(vstate->cur_iter); |
- |
- /* Now create a new instruction iterator. */ |
- vstate->cur_iter = NaClInstIterCreateWithLookback( |
- vstate->decoder_tables, segment, lookback_size); |
- |
- if (NULL == vstate->cur_iter) return FALSE; |
- return TRUE; |
-} |
- |
-#ifdef NCVAL_TESTING |
-void NaClPrintConditions(NaClValidatorState *state) { |
- /* To save space, only report on instructions that have non-empty |
- * pre/post conditions. |
- */ |
- if ((strlen(state->precond) > 0) || (strlen(state->postcond) > 0)) { |
- printf("%"NACL_PRIxNaClPcAddress": ", |
- NaClInstStatePrintableAddress(state->cur_inst_state)); |
- if ('\0' != state->precond[0]) { |
- printf("%s", state->precond); |
- } |
- if ('\0' != state->postcond[0]) { |
- if ('\0' != state->precond[0]) printf(" "); |
- printf("-> %s", state->postcond); |
- } |
- printf("\n"); |
- } |
-} |
-#endif |
- |
-/* Given we are at the instruction defined by the instruction iterator, for |
- * a segment, apply all applicable validator functions. |
- */ |
-static INLINE void NaClApplyValidators(NaClValidatorState *vstate) { |
- if (vstate->quit) return; |
- DEBUG(NaClLog(LOG_INFO, "iter state:\n"); |
- NaClInstStateInstPrint(NaClLogGetGio(), |
- NaClInstIterGetState(vstate->cur_iter))); |
- if (NaClValidatorStateTraceInline(vstate)) { |
- NaClValidatorTrace(vstate); |
- } |
- NaClCpuCheck(vstate, vstate->cur_iter); |
- NaClValidateInstructionLegal(vstate); |
- NaClBaseRegisterValidator(vstate); |
- NaClMemoryReferenceValidator(vstate); |
- NaClJumpValidator(vstate); |
- if (vstate->print_opcode_histogram) { |
- NaClOpcodeHistogramRecord(vstate); |
- } |
-#ifdef NCVAL_TESTING |
- /* Collect post conditions for instructions that are non-last. |
- * Only print pre/post conditions for valid instructions (ignoring |
- * pre/post conditions). |
- */ |
- if (NaClValidatesOk(vstate) || vstate->report_conditions_on_all) { |
- NaClAddAssignsRegisterWithZeroExtendsPostconds(vstate); |
- NaClAddLeaSafeAddressPostconds(vstate); |
- NaClPrintConditions(vstate); |
- } |
- /* Reset the exit flags, so that errors do not stop |
- * other instructions from firing errors. By reseting these flags, |
- * it allows us to only print pre/post conditions for instructions |
- * that are not marked illegal. |
- */ |
- if (!vstate->validates_ok) vstate->validates_ok_with_conditions = FALSE; |
- vstate->validates_ok = TRUE; |
- vstate->quit = FALSE; |
-#endif |
-} |
- |
-/* Given that we have just iterated through all instructions in a segment, |
- * apply post validators rules (before we collect the iterator). |
- */ |
-static INLINE void NaClApplyPostValidators(NaClValidatorState *vstate) { |
- DEBUG(NaClLog(LOG_INFO, "applying post validators...\n")); |
- if (vstate->quit || (NULL == vstate->cur_iter)) return; |
- |
- /* Before doing anything else, process remaining (forward) information |
- * stored by the validator, to see if any errors should be reported |
- * about the last instruction processed. |
- */ |
- NaClBaseRegisterSummarize(vstate); |
- |
- /* Now do the summarizing steps of the validator. */ |
- if (vstate->do_detailed) { |
- NaClJumpValidatorSummarizeDetailed(vstate); |
- } else { |
- NaClJumpValidatorSummarize(vstate); |
- } |
- if (NaClValidatorStateTrace(vstate)) { |
- (vstate->error_reporter->printf) |
- (vstate->error_reporter, "<- visit\n"); |
- } |
-} |
- |
-/* The maximum lookback for the instruction iterator of the segment. |
- * Note: Allows for two memory patterns (4 instructions for each pattern). |
- */ |
-static const size_t kLookbackSize = 8; |
- |
-void NaClValidateSegment(uint8_t *mbase, NaClPcAddress vbase, |
- NaClMemorySize size, NaClValidatorState *vstate) { |
- NaClSegment segment; |
- do { |
- /* Sanity checks */ |
- /* TODO(ncbray): remove redundant vbase/size args. */ |
- if ((vbase & vstate->bundle_mask) != 0) { |
- NaClValidatorMessage(LOG_ERROR, vstate, |
- "Code segment starts at 0x%"NACL_PRIxNaClPcAddress |
- ", which isn't aligned properly.\n", |
- vbase); |
- break; |
- } |
- if (vbase != vstate->vbase) { |
- NaClValidatorMessage(LOG_ERROR, vstate, "Mismatched vbase address\n"); |
- break; |
- } |
- if (size != vstate->codesize) { |
- NaClValidatorMessage(LOG_ERROR, vstate, "Mismatched code size\n"); |
- break; |
- } |
- if (vbase > vbase + size) { |
- NaClValidatorMessage(LOG_ERROR, vstate, "Text segment too big for given " |
- "vbase (address overflow)\n"); |
- break; |
- } |
- |
- size = NCHaltTrimSize(mbase, size, vstate->bundle_size); |
- vstate->codesize = size; |
- |
- if (size == 0) { |
- NaClValidatorMessage(LOG_ERROR, vstate, "Bad text segment (zero size)\n"); |
- break; |
- } |
- |
- NaClSegmentInitialize(mbase, vbase, size, &segment); |
- |
- vstate->cur_iter = NaClInstIterCreateWithLookback(vstate->decoder_tables, |
- &segment, kLookbackSize); |
- if (NULL == vstate->cur_iter) { |
- NaClValidatorMessage(LOG_ERROR, vstate, "Not enough memory\n"); |
- break; |
- } |
- for (; NaClValidatorStateIterHasNextInline(vstate); |
- NaClValidatorStateIterAdvanceInline(vstate)) { |
- NaClApplyValidators(vstate); |
- if (vstate->quit) break; |
- } |
- NaClValidatorStateIterFinish(vstate); |
- } while (0); |
- NaClApplyPostValidators(vstate); |
- NaClInstIterDestroy(vstate->cur_iter); |
- vstate->cur_iter = NULL; |
- if (vstate->print_opcode_histogram) { |
- NaClOpcodeHistogramPrintStats(vstate); |
- } |
-#ifdef NCVAL_TESTING |
- /* Update failure to catch instructions that may have validated |
- * incorrectly. |
- */ |
- if (vstate->validates_ok) |
- vstate->validates_ok = vstate->validates_ok_with_conditions; |
-#endif |
-} |
- |
-void NaClValidateSegmentUsingTables(uint8_t* mbase, |
- NaClPcAddress vbase, |
- NaClMemorySize sz, |
- NaClValidatorState* vstate, |
- const struct NaClDecodeTables* tables) { |
- vstate->decoder_tables = tables; |
- NaClValidateSegment(mbase, vbase, sz, vstate); |
-} |
- |
-Bool NaClValidatesOk(NaClValidatorState *vstate) { |
- return vstate->validates_ok; |
-} |
- |
-void NaClValidatorStateDestroy(NaClValidatorState *vstate) { |
- if (NULL != vstate) { |
- NaClJumpValidatorCleanUp(vstate); |
- free(vstate); |
- } |
-} |
- |
-/* |
- * Check that iter_new is a valid replacement for iter_old. |
- * If a validation error occurs, vstate->validates_ok will be set to false by |
- * NaClValidatorInstMessage when it is given LOG_ERROR, see the end of this |
- * function. |
- * Return value: TRUE if the instruction was changed, FALSE if it's identical. |
- */ |
-static Bool NaClValidateInstReplacement(NaClInstIter *iter_old, |
- NaClInstIter *iter_new, |
- struct NaClValidatorState *vstate) { |
- NaClInstState *istate_old, *istate_new; |
- NaClExpVector *exp_old, *exp_new; |
- uint32_t i; |
- Bool inst_changed = FALSE; |
- int parent_index; |
- |
- istate_old = NaClInstIterGetStateInline(iter_old); |
- istate_new = NaClInstIterGetStateInline(iter_new); |
- |
- /* Location/length must match. Assumes vbase is the same. */ |
- if (istate_new->inst_addr != istate_old->inst_addr || |
- istate_new->bytes.length != istate_old->bytes.length) { |
- NaClValidatorTwoInstMessage(LOG_ERROR, vstate, istate_old, istate_new, |
- "Code modification: instructions length/addresses do not match"); |
- inst_changed = TRUE; |
- return inst_changed; |
- } |
- |
- |
- do { |
- /* fast check if the replacement is identical */ |
- if ((istate_old->bytes.memory->read_length == |
- istate_new->bytes.memory->read_length) && |
- !memcmp(istate_old->bytes.memory->mpc, istate_new->bytes.memory->mpc, |
- istate_old->bytes.memory->read_length)) |
- return inst_changed; |
- |
- inst_changed = TRUE; |
- |
- if (istate_old->num_prefix_bytes != istate_new->num_prefix_bytes) |
- break; |
- if (istate_old->num_rex_prefixes != istate_new->num_rex_prefixes) |
- break; |
- if (istate_old->rexprefix != istate_new->rexprefix) |
- break; |
- if (istate_old->modrm != istate_new->modrm) |
- break; |
- if (istate_old->has_sib != istate_new->has_sib) |
- break; |
- if (istate_old->has_sib && istate_old->sib != istate_new->sib) |
- break; |
- if (istate_old->operand_size != istate_new->operand_size) |
- break; |
- if (istate_old->address_size != istate_new->address_size) |
- break; |
- if (istate_old->prefix_mask != istate_new->prefix_mask) |
- break; |
- |
- /* |
- * these are pointers, but they reference entries in a static table, |
- * so if the two instructions are the same, then these pointers must |
- * reference the same entry |
- */ |
- if (istate_old->inst != istate_new->inst) |
- break; |
- |
- exp_old = NaClInstStateExpVector(istate_old); |
- exp_new = NaClInstStateExpVector(istate_new); |
- |
- /* check if the instruction operands are identical */ |
- if (exp_old->number_expr_nodes != exp_new->number_expr_nodes) |
- break; |
- |
- for (i = 0; i < exp_old->number_expr_nodes; i++) { |
- /* Allow nodes that are identical. */ |
- if (exp_old->node[i].kind != exp_new->node[i].kind) goto error_exit; |
- if (exp_old->node[i].flags != exp_new->node[i].flags) goto error_exit; |
- if (exp_old->node[i].value == exp_new->node[i].value) continue; |
- |
- /* |
- * Only constant values may differ. However it is important not to |
- * allow constant modification of sandboxing instructions. Note neither |
- * of the instructions allowed for modification is used for sandboxing. |
- */ |
- if (exp_old->node[i].kind != ExprConstant) goto error_exit; |
- |
- switch (istate_old->inst->name) { |
- |
- case InstCall: |
- /* allow different constants in direct calls */ |
- if (!NaClHasBit(exp_old->node[i].flags, NACL_EFLAG(ExprJumpTarget))) |
- break; |
- parent_index = NaClGetExpParentIndex(exp_old, i); |
- if (parent_index < 0) break; |
- if (exp_old->node[parent_index].kind == OperandReference) continue; |
- break; |
- |
- case InstMov: |
- parent_index = NaClGetExpParentIndex(exp_old, i); |
- if (parent_index < 0) break; |
- switch (exp_old->node[parent_index].kind) { |
- case OperandReference: |
- /* |
- * allow different constants in operand of mov |
- * e.g. mov $rax, 0xdeadbeef |
- */ |
- if (NaClHasBit(exp_old->node[i].flags, NACL_EFLAG(ExprUsed))) |
- continue; |
- break; |
- case ExprMemOffset: |
- /* |
- * allow different displacements in memory reference of mov |
- * instructions e.g. mov $rax, [$r15+$rbx*2+0x7fff] |
- * |
- * Note: displacement is the fourth node after ExprMemOffset* |
- * node |
- */ |
- if (4 == (i - parent_index)) continue; |
- break; |
- default: |
- break; |
- } |
- break; |
- default: |
- break; |
- } |
- |
- /* If reached, we found a value that differed, and wasn't one |
- * of the expected constants that can differ. |
- */ |
- goto error_exit; |
- } |
- |
- /* This return signifies there is no error in validation. */ |
- return inst_changed; |
- } while (0); |
- |
-error_exit: |
- /* This logging function is the mechanism that sets the validator state |
- * to indicate an error. |
- */ |
- NaClValidatorTwoInstMessage(LOG_ERROR, vstate, istate_old, istate_new, |
- "Code modification: failed to modify instruction"); |
- return inst_changed; |
-} |
- |
-/* |
- * Validate a new code block as a replacement for an existing block. |
- * Note: The code location (vbase) must be bundle aligned and the segment size |
- * must also be a multiple of bundle size (checked in |
- * NaClValidateCodeReplacement).This is to ensure all NaCl psuedo-instructions |
- * and guard sequences are properly inspected and maintained. |
- */ |
-void NaClValidateSegmentPair(uint8_t *mbase_old, uint8_t *mbase_new, |
- NaClPcAddress vbase, size_t size, |
- struct NaClValidatorState *vstate) { |
- NaClSegment segment_old, segment_new; |
- NaClInstIter *iter_old = NULL; |
- NaClInstIter *iter_new = NULL; |
- |
- NaClSegmentInitialize(mbase_old, vbase, size, &segment_old); |
- NaClSegmentInitialize(mbase_new, vbase, size, &segment_new); |
- do { |
- iter_old = NaClInstIterCreateWithLookback(vstate->decoder_tables, |
- &segment_old, kLookbackSize); |
- if (NULL == iter_old) break; |
- iter_new = NaClInstIterCreateWithLookback(vstate->decoder_tables, |
- &segment_new, kLookbackSize); |
- if (NULL == iter_new) break; |
- vstate->cur_iter = iter_new; |
- while (NaClInstIterHasNextInline(iter_old) && |
- NaClValidatorStateIterHasNextInline(vstate)) { |
- vstate->cur_inst_state->unchanged = |
- !NaClValidateInstReplacement(iter_old, iter_new, vstate); |
- NaClApplyValidators(vstate); |
- if (vstate->quit) break; |
- NaClInstIterAdvanceInline(iter_old); |
- NaClValidatorStateIterAdvanceInline(vstate); |
- } |
- if (NaClInstIterHasNextInline(iter_old) || |
- NaClInstIterHasNextInline(iter_new)) { |
- NaClValidatorMessage( |
- LOG_ERROR, vstate, |
- "Code modification: code segments have different " |
- "number of instructions\n"); |
- } |
- } while (0); |
- NaClValidatorStateIterFinish(vstate); |
- NaClApplyPostValidators(vstate); |
- vstate->cur_iter = NULL; |
- NaClInstIterDestroy(iter_old); |
- NaClInstIterDestroy(iter_new); |
-} |