Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Unified Diff: src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.c

Issue 625923004: Delete old x86 validator. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: rebase master Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.c
diff --git a/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.c b/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.c
deleted file mode 100644
index ce76968ac5b339740adba8fa01eab522a18e20c2..0000000000000000000000000000000000000000
--- a/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.c
+++ /dev/null
@@ -1,572 +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.
- */
-
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_memory_protect.h"
-
-#include "native_client/src/include/portability_io.h"
-#include "native_client/src/shared/platform/nacl_log.h"
-#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state.h"
-#include "native_client/src/trusted/validator/x86/decoder/nc_inst_trans.h"
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/ncvalidate_iter.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/ncvalidate_utils.h"
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_jumps.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"
-#include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c"
-
-/*
- * When true, check both uses and sets of memory. When false, only
- * check sets.
- */
-Bool NACL_FLAGS_read_sandbox = TRUE;
-
-/* Type used to measure number of instructions matched using a validator
- * pattern.
- */
-typedef int NaClPatternLength;
-
-/* Constant denoting that pattern match failed. Used by pattern checking
- * functions that return the number of instructions pattern matched.
- */
-static const NaClPatternLength kNaClPatternMatchFailed = -1;
-
-/* Returns the instruction "distance" elements back from the current
- * instruction of the validator state. Returns NULL if no such instruction
- * exists.
- */
-static INLINE NaClInstState* NaClGetValInstStateAt(NaClValidatorState* state,
- size_t distance) {
- if (distance == 0) {
- return state->cur_inst_state;
- } else if (NaClInstIterHasLookbackStateInline(state->cur_iter, distance)) {
- return NaClInstIterGetLookbackStateInline(state->cur_iter, distance);
- } else {
- return NULL;
- }
-}
-
-/* Returns true if the given register is in {%RSP, %RBP, %RIP, %RBASE}.*/
-static INLINE Bool NaClIsValidBaseRegister(NaClValidatorState* state,
- NaClOpKind reg) {
- return reg == state->base_register ||
- reg == RegRSP ||
- reg == RegRBP ||
- reg == RegRIP;
-}
-
-/* Returns true if the node corresponds to an expression set, or an
- * expression use if we are doing read sandboxing.
- */
-static Bool IsPossibleSandboxingNode(NaClExp* node) {
- return ((NACL_FLAGS_read_sandbox && (node->flags & NACL_EFLAG(ExprUsed))) ||
- (node->flags & NACL_EFLAG(ExprSet)));
-}
-
-/* Returns true if the "distance" instruction, from the current instruction
- * of the validator state is a mov of the form:
- * mov %reg, %reg
- * and %reg is a 32-bit register.
- */
-static Bool NaClIsMov32UsingReg(NaClValidatorState* state,
- size_t distance,
- NaClOpKind reg) {
- NaClExpVector* vector;
- NaClInstState* inst_state;
-
-#ifdef NCVAL_TESTING
- /* Assume we match previous instructions when generating pre/post
- * conditions.
- */
- if (distance > 0) return TRUE;
-#endif
-
- /* Get the instruction to be checked. */
- inst_state = NaClGetValInstStateAt(state, distance);
- if (NULL == inst_state) return FALSE;
-
- /* Check that it is a move on the specified register. */
- vector = NaClInstStateExpVector(inst_state);
- if (!NaClIsMovUsingRegisters(inst_state->decoder_tables,
- inst_state->inst,
- vector,
- reg,
- reg)) return FALSE;
-
- /* Check that this is a 32-bit mov.
- * Note: Since the vector contains a list of operand expressions, the
- * first operand reference is always at index zero, and its first child
- * (where the register set is defined) is at index 1.
- */
- return NaClHasBit(vector->node[1].flags, NACL_EFLAG(ExprSize32));
-}
-
-/* Checks if the given node index for the given instruction is
- * a valid (sandboxed) memory offset, based on NACL rules, returning TRUE iff
- * the memory offset is NACL compliant. That is, of one of
- * the following forms:
- * [%base+%r64*n+d32]
- * where the previous instruction is of the form:
- * op %r32, .. ; zero out top half of r32
- * and r32 is the corresponding 32-bit register for the 64-bit register
- * r64
- * [%base+d32]
- * [%base]
- *
- * where rbase is in { RIP, RSP, RBP, RZP }, and d32 must not exceed 32 bits.
- *
- * parameters are:
- * state - The state of the validator,
- * distance - number of instructions to lookback
- * (within the iterator) in order to retrieve the instruction.
- * node_index - The index of the memory offset within the given
- * instruction vector.
- * use_mov_for_zero_ext - True if zero extending op must be of the
- * form "mov %r32, %r32".
- * print_messages - True if this routine is responsable for printing
- * error messages if the memory offset isn't NACL compliant.
- *
- * Returns the number of (additional) instructions were needed to recognize
- * the pattern, or kNaClPatternMatchFailed if the pattern fails.
- */
-static NaClPatternLength NaClMatchValidMemOffset(
- NaClValidatorState* state,
- size_t distance,
- int node_index,
- Bool use_mov_for_zero_ext,
- Bool print_messages) {
- int base_reg_index;
- NaClOpKind base_reg;
- int index_reg_index;
- NaClExp* index_reg_node;
- NaClOpKind index_reg;
- int scale_index;
- int disp_index;
- NaClInstState* inst;
- NaClExpVector* vector;
- NaClExp* node;
- NaClPatternLength pattern_length = 0;
-
-#ifdef NCVAL_TESTING
- /* Assume we match previous instructions when generating pre/post
- * conditions.
- */
- if (distance > 0) return pattern_length;
-#endif
-
- /* Get the instruction to be checked. */
- inst = NaClGetValInstStateAt(state, distance);
- if (NULL == inst) return kNaClPatternMatchFailed;
-
- /* Check that the node_index of the referenced instruction corresponds to
- * a memory offset.
- */
- vector = NaClInstStateExpVector(inst);
- node = &vector->node[node_index];
- if (ExprMemOffset != node->kind) return kNaClPatternMatchFailed;
-
- DEBUG(NaClLog(LOG_INFO,
- "found MemOffset at node %"NACL_PRIu32" %d\n", node_index,
- (int) distance));
-
- /* Only allow memory offset nodes with address size 64. */
- if (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprSize64))) {
- if (print_messages) {
- NaClValidatorInstMessage(LOG_ERROR, state, inst,
- "Assignment to non-64 bit memory address\n");
- }
- return kNaClPatternMatchFailed;
- }
- DEBUG(NaClLog(LOG_INFO, "found 64 bit address for MemOffset\n"));
-
- /* Check that the base register is valid. */
- base_reg_index = node_index + 1;
- base_reg = NaClGetExpVectorRegister(vector, base_reg_index);
- DEBUG(NaClLog(LOG_INFO, "base reg = %s\n", NaClOpKindName(base_reg)));
- if (!NaClIsValidBaseRegister(state, base_reg)) {
- if (print_messages) {
- NaClValidatorInstMessage(
- LOG_ERROR, state, inst,
- (base_reg == RegUnknown
- ? "No base register specified in memory offset\n"
- : "Invalid base register in memory offset\n"));
- }
- return kNaClPatternMatchFailed;
- }
- DEBUG(NaClLog(LOG_INFO, " => base register is valid\n"));
-
- /* Check that the index register is either undefined, or defined
- * with the appropriate assignment. Note: We currently don't allow
- * an index register to be used with RIP. Only "RIP + disp32" is allowed.
- */
- index_reg_index = base_reg_index + NaClExpWidth(vector, base_reg_index);
- index_reg_node = &vector->node[index_reg_index];
- index_reg = NaClGetExpRegisterInline(index_reg_node);
- DEBUG(NaClLog(LOG_INFO, "index reg = %s\n", NaClOpKindName(index_reg)));
- if (RegUnknown != index_reg) {
- Bool index_reg_is_good = FALSE;
- if ((base_reg != RegRIP) &&
- NaClHasBit(index_reg_node->flags, NACL_EFLAG(ExprSize64))) {
- if (use_mov_for_zero_ext) {
- index_reg_is_good =
- NaClIsMov32UsingReg(state, distance + 1,
- NaClGet32For64BitReg(index_reg));
- } else {
- index_reg_is_good =
- NaClAssignsRegisterWithZeroExtends64(state, distance + 1,
- index_reg);
- }
- }
- if (index_reg_is_good) {
- pattern_length++;
- } else {
- if (print_messages) {
- NaClValidatorInstMessage(LOG_ERROR, state, inst,
- "Invalid index register in memory offset\n");
- }
- return kNaClPatternMatchFailed;
- }
- } else if (use_mov_for_zero_ext) {
- /* The index register must be defined in this case. Report as error!. */
- if (print_messages) {
- NaClValidatorInstMessage(LOG_ERROR, state, inst,
- "Invalid index register in memory offset\n");
- return kNaClPatternMatchFailed;
- }
- }
-
- /* Check displacement value is valid (i.e. 32 or less bits).
- * Note: scale need not be
- * checked since it can't exceed 8, and is undefined if the index register
- * is undefined.
- */
- scale_index = index_reg_index + NaClExpWidth(vector, index_reg_index);
- disp_index = scale_index + NaClExpWidth(vector, scale_index);
- DEBUG(NaClLog(LOG_INFO, "disp index = %d\n", disp_index));
- if (ExprConstant != vector->node[disp_index].kind) {
- if (print_messages) {
- NaClValidatorInstMessage(LOG_ERROR, state, inst,
- "Invalid displacement in memory offset\n");
- }
- return kNaClPatternMatchFailed;
- }
-
- /* If reached, we matched the pattern, return number of instructions
- * needed for match.
- */
- DEBUG(NaClLog(LOG_INFO, "Memory Offset pattern length = %d\n",
- pattern_length));
-#ifdef NCVAL_TESTING
- if ((0 == distance) && (RegUnknown != index_reg)) {
- /* Report precondition of test.
- * TODO(karl): This should be lifted out of this test, and
- * only applied when pattern matches.
- */
- char* buffer;
- size_t buffer_size;
- char reg_name[kMaxBufferSize];
- NaClOpRegName(NaClGet32For64BitReg(index_reg), reg_name, kMaxBufferSize);
- NaClConditionAppend(state->precond, &buffer, &buffer_size);
- SNPRINTF(buffer, buffer_size, "ZeroExtends(%s)", reg_name);
- }
-#endif
- return pattern_length;
-}
-
-/* Applies the precondition "SafeAddress(addr_reg)" pattern for
- * segment addresses. Applies the match to the "distance" instruction
- * back from the current instruction. Returns true if the instruction
- * is a pair of instructions of the form:
- *
- * mov %r32, %r32 ; zero out top half of r32
- * lea %r64, [%r15+%r64*1] ; rebase address and put in r64
- *
- * where r32 is the corresponding 32-bit register for the 64-bit register
- * r64. Returns true if the precondition is met.
- */
-static Bool NaClMatchLeaSafeAddress(
- NaClValidatorState* state,
- size_t distance,
- NaClOpKind reg64) {
- NaClExpVector* vector;
- NaClOpKind lea_reg;
- int memoff_index;
- NaClPatternLength pattern_length;
- NaClInstState* inst_state;
- const NaClInst* inst;
-
- DEBUG(NaClLog(LOG_INFO, "reg64 = %s, distance = %d\n",
- NaClOpKindName(reg64), (int) distance));
-
-#ifdef NCVAL_TESTING
- /* Don't match previous instructions when pattern matching. */
- if (distance > 0) return TRUE;
-#endif
-
- /* Get the instruction to be checked. */
- inst_state = NaClGetValInstStateAt(state, distance);
- if (NULL == inst_state) return FALSE;
-
- /* Check that it is an LEA instruction. */
- inst = NaClInstStateInst(inst_state);
- if (InstLea != inst->name) return FALSE;
-
- /* Note that first argument of LEA is always a register,
- * (under an OperandReference), and hence is always at
- * index 1.
- */
- vector = NaClInstStateExpVector(inst_state);
- lea_reg = NaClGetExpVectorRegister(vector, 1);
- DEBUG(NaClLog(LOG_INFO, "lea reg = %s\n", NaClOpKindName(lea_reg)));
- if (lea_reg != reg64) return FALSE;
-
- /* Move to second argument which should be a memory address. */
- memoff_index = NaClGetNthExpKind(vector, OperandReference, 2);
- if (-1 == memoff_index) return FALSE;
- memoff_index = NaClGetExpKidIndex(vector, memoff_index, 0);
- if (memoff_index >= (int) vector->number_expr_nodes) return FALSE;
- DEBUG(NaClLog(LOG_INFO, "check mem offset!\n"));
-
- /* Check that memory offset argument of the lea is valid. */
- pattern_length = NaClMatchValidMemOffset(state,
- distance,
- memoff_index,
- TRUE,
- FALSE);
- if (kNaClPatternMatchFailed == pattern_length) return FALSE;
-
- /* If reached, matched pattern! */
- return TRUE;
-}
-
-void NaClMemoryReferenceValidator(NaClValidatorState* state) {
- /* Note: This code assumes that only DS:RSI and ES:RDI allow
- * multiple memory accesses with a single instruction, as defined
- * by the string instructions Movs and Cmps. In such cases, the
- * ES:RDI must appear before the DS:RSI.
- */
- int i;
- NaClInstState* inst_state = state->cur_inst_state;
- NaClExpVector* vector = state->cur_inst_vector;
-
- /* Holds the number of additional instructions in pattern(s) associated with
- * the current instruction of the validator state.
- */
- int pattern_length = 0;
-
- /* Counts number of memory references in the current instruction. */
- int number_memory_refs = 0;
-
- /* Counts the number of unique segment (memory) references in the current
- * instruction.
- */
- int number_segment_addresses = 0;
-
- /* Records first segment reference register, to allow duplication of it.
- */
- NaClOpKind previous_seg_addr = RegUnknown;
-
- DEBUG_OR_ERASE({
- struct Gio* g = NaClLogGetGio();
- NaClLog(LOG_INFO, "-> Validating store\n");
- NaClInstStateInstPrint(g, inst_state);
- NaClInstPrint(g, state->decoder_tables, state->cur_inst);
- NaClExpVectorPrint(g, inst_state);
- });
-
- /* Look for assignments on a memory offset. */
- for (i = 0; i < (int) vector->number_expr_nodes; ++i) {
- /* Note: continue (within this loop) is used to indicate
- * that the node describes a safe memory address.
- */
- NaClPatternLength memoffset_length;
- NaClExp* node = &vector->node[i];
- DEBUG(NaClLog(LOG_INFO, "pattern length = %d\n", pattern_length);
- NaClLog(LOG_INFO, "processing argument %"NACL_PRIu32"\n", i));
- if (state->quit) break;
-
- if (!IsPossibleSandboxingNode(node)) continue;
- DEBUG(NaClLog(LOG_INFO, "found possible sandboxing reference\n"));
-
- /* Check if the node is a safe memory offset (i.e address). */
- memoffset_length = NaClMatchValidMemOffset(state, 0, i, FALSE, TRUE);
- DEBUG(NaClLog(LOG_INFO, "memoffset inst length = %d\n", memoffset_length));
- if (kNaClPatternMatchFailed != memoffset_length) {
- /* Cases 1, 2, or 3 (see nc_memory_protect.h). */
- number_memory_refs++;
- pattern_length += memoffset_length;
- continue;
- }
-
- if (ExprSegmentAddress == node->kind) {
- /* Note that operations like stosb, stosw, stosd, and stosq use
- * segment notation. In 64 bit mode, the second argument must
- * be a register, and be computed (using lea) so that it matches
- * a valid (sandboxed) memory offset. For example:
- *
- * mov %edi, %edi ; zero out top half of rdi
- * lea %rdi, [%r15+%edi*1] ; calculate address, put in rdi
- * stos %eax ; implicity uses %es:(%rdi)
- *
- * Note: we allow only one zero-extending operation for string
- * instructions: an identity MOV.
- */
- int seg_prefix_reg_index;
- NaClOpKind seg_prefix_reg;
- DEBUG(NaClLog(LOG_INFO,
- "found segment assign at node %"NACL_PRIu32"\n", i));
-
- /* Only allow if 64 bit segment addresses. */
- if (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprSize64))) {
- NaClValidatorInstMessage(
- LOG_ERROR, state, inst_state,
- "Assignment to non-64 bit segment address\n");
- continue;
- }
-
- /* Only allow segment prefix registers that are treated as
- * null prefixes.
- */
- seg_prefix_reg_index = NaClGetExpKidIndex(vector, i, 0);
- seg_prefix_reg = NaClGetExpVectorRegister(vector, seg_prefix_reg_index);
- switch (seg_prefix_reg) {
- /* Note: continue (of the for loop) is used to indicate a good segment
- * address (for node being checked) while break (of the switch) is
- * used to indicate a bad segment address.
- */
- case RegCS:
- case RegDS:
- case RegES:
- case RegSS: {
- NaClOpKind addr_reg;
-
- /* Get the address register of the segment memory address. */
- int addr_reg_index = NaClGetExpKidIndex(vector, i, 1);
- DEBUG(NaClLog(LOG_INFO,
- "matched segment %s, address at index %d\n",
- NaClOpKindName(seg_prefix_reg), addr_reg_index));
- if (-1 == addr_reg_index) break;
- addr_reg =
- NaClGetExpVectorRegister(vector, addr_reg_index);
- if (addr_reg == RegUnknown) break;
-
- /* If addr_reg a previously known register, allow. */
- if (previous_seg_addr == RegUnknown) {
- previous_seg_addr = addr_reg;
- } else if (addr_reg == previous_seg_addr) {
- /* No need to check new pattern, existing pattern
- * should check.
- */
- continue;
- }
-
- /* Check that the address register is an lea address
- * that is safe. */
- if (!NaClMatchLeaSafeAddress(state, pattern_length + 1,
- addr_reg)) break;
-
- /* Case 4 (see nc_memory_protect.h). */
- number_memory_refs++;
- number_segment_addresses++;
- pattern_length += 2;
- DEBUG(NaClLog(LOG_INFO, "updated pattern_length = %d\n",
- pattern_length));
-#ifdef NCVAL_TESTING
- {
- /* Assume that previous instruction is an LEA, since
- * we want to only generate pre/post conditions.
- */
- char* buffer;
- size_t buffer_size;
- char reg_name[kMaxBufferSize];
- NaClOpRegName(addr_reg, reg_name, kMaxBufferSize);
- NaClConditionAppend(state->precond, &buffer, &buffer_size);
- SNPRINTF(buffer, buffer_size, "SafeAddress(%s)", reg_name);
- }
-#endif
- continue;
- }
- default:
- break;
- }
-
- /* If reached, we don't know how to handle the segment address. */
- NaClValidatorInstMessage(LOG_ERROR, state, inst_state,
- "Segment memory reference not allowed\n");
- continue;
- }
-
- /* Don't complain about register set/usage. */
- if (UndefinedExp == node->kind ||
- (ExprRegister == node->kind &&
- RegUnknown == NaClGetExpRegisterInline(node))) {
- /* First rule out case where the index registers of the memory
- * offset may be unknown.
- */
- int parent_index = NaClGetExpParentIndex(vector, i);
- if (parent_index >= 0 &&
- (i == NaClGetExpKidIndex(vector, parent_index, 1))) {
- /* Special case of memory offsets that we allow. That is, memory
- * offsets can optionally define index register. If the index
- * register isn't specified, the value RegUnknown is used as
- * a placeholder (and hence legal).
- */
- } else {
- /* This shouldn't happpen, but if it does, its because either:
- * (1) We couldn't translate the expression, and hence complain; or
- * (2) It is an X87 instruction with a register address, which we
- * don't allow (in case these instructions get generalized in
- * the future).
- */
- NaClValidatorInstMessage(
- LOG_ERROR, state, inst_state,
- "Memory reference not understood, can't verify correctness.\n");
- }
- }
- }
-
- /* Disallow multiple memory references unless pair of special segment refs. */
- if ((number_memory_refs > 1) &&
- (number_segment_addresses != number_memory_refs)) {
- NaClValidatorInstMessage(
- LOG_ERROR, state, inst_state,
- "Multiple memory references not allowed in this context\n");
- }
-
-#ifndef NCVAL_TESTING
- /* Mark all but first instruction of pattern illegal to jump into. */
- if (0 < pattern_length) {
- NaClMarkInstructionsJumpRangeIllegal(state, pattern_length);
- }
-#endif
- DEBUG(NaClLog(LOG_INFO, "<- Validating store\n"));
-}
-
-#ifdef NCVAL_TESTING
-Bool NaClAcceptLeaSafeAddress(struct NaClValidatorState* state) {
- const NaClInst* inst;
-
- /* Check that it is an LEA instruction. */
- inst = NaClInstStateInst(state->cur_inst_state);
- if (InstLea != inst->name) return FALSE;
-
- /* Note that first argument of LEA is always a register,
- * (under an OperandReference), and hence is always at
- * index 1.
- */
- return NaClMatchLeaSafeAddress(
- state, 0,
- NaClGetExpVectorRegister(NaClInstStateExpVector(state->cur_inst_state),
- 1));
-}
-#endif

Powered by Google App Engine
This is Rietveld 408576698