| 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);
|
| -}
|
|
|