Index: src/trusted/validator/x86/ncval_reg_sfi/nc_protect_base.c |
diff --git a/src/trusted/validator/x86/ncval_reg_sfi/nc_protect_base.c b/src/trusted/validator/x86/ncval_reg_sfi/nc_protect_base.c |
deleted file mode 100644 |
index e33cd54f1780de2d1bd2351b853c660673e175f6..0000000000000000000000000000000000000000 |
--- a/src/trusted/validator/x86/ncval_reg_sfi/nc_protect_base.c |
+++ /dev/null |
@@ -1,512 +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. |
- */ |
- |
-/* nc_protect_base.h - For 64-bit mode, verifies that no instruction |
- * changes the value of the base register, that the invariant between |
- * RSP and RBP is maintained, and that segment registers are not set. |
- */ |
-#include <assert.h> |
-#include <string.h> |
- |
-#include "native_client/src/trusted/validator/x86/ncval_reg_sfi/nc_protect_base.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/ncop_exps.h" |
-#include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal.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/ncopcode_desc_inl.c" |
-#include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c" |
-#include "native_client/src/trusted/validator/x86/decoder/nc_inst_iter_inl.c" |
- |
-static void NaClReportIllegalChangeToRsp(NaClValidatorState* state, |
- NaClInstState* inst) { |
- NaClValidatorInstMessage(LOG_ERROR, state, inst, |
- "Illegal assignment to RSP\n"); |
-} |
- |
-/* Checks flags in the possible set base registers, and reports any |
- * previous instructions that were marked as bad. |
- * |
- * Parameters: |
- * state - The state of the validator. |
- */ |
-static INLINE void NaClMaybeReportPreviousBad(NaClValidatorState* state) { |
- NaClInstState* prev_esp_set_inst = |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].esp_set_inst; |
- NaClInstState* prev_ebp_set_inst = |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].ebp_set_inst; |
- |
- /* First check if previous register references are not followed |
- * by acceptable instructions. |
- */ |
- if (NULL != prev_esp_set_inst) { |
- NaClValidatorInstMessage(LOG_ERROR, |
- state, |
- prev_esp_set_inst, |
- "Illegal assignment to ESP\n"); |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].esp_set_inst = NULL; |
- } |
- if (NULL != prev_ebp_set_inst) { |
- NaClValidatorInstMessage(LOG_ERROR, |
- state, |
- prev_ebp_set_inst, |
- "Illegal assignment to EBP\n"); |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].ebp_set_inst = NULL; |
- } |
- |
- /* Now advance the register recording by one instruction. */ |
- state->set_base_registers.previous_index = |
- state->set_base_registers.current_index; |
- state->set_base_registers.current_index = |
- ((state->set_base_registers.current_index + 1) |
- % NACL_REGISTER_LOCALS_BUFFER_SIZE); |
-} |
- |
-void NaClBaseRegisterMemoryInitialize(NaClValidatorState* state) { |
- int i; |
- for (i = 0; i < NACL_REGISTER_LOCALS_BUFFER_SIZE; ++i) { |
- state->set_base_registers.buffer[i].esp_set_inst = NULL; |
- state->set_base_registers.buffer[i].ebp_set_inst = NULL; |
- } |
- state->set_base_registers.previous_index = 0; |
- state->set_base_registers.current_index = 1; |
-} |
- |
-/* Returns true iff the instruction of form "lea _, [%reg+%rbase*1]" */ |
-static Bool NaClIsLeaAddressRegPlusRbase(NaClValidatorState* state, |
- NaClInstState* inst_state, |
- NaClOpKind reg) { |
- const NaClInst* inst = NaClInstStateInst(inst_state); |
- Bool result = FALSE; |
- DEBUG(NaClLog(LOG_INFO, "-> LeaAddressRegPlusRbase(%s)\n", |
- NaClOpKindName(reg))); |
- if (InstLea == inst->name && |
- 2 == NaClGetInstNumberOperandsInline(inst)) { |
- NaClExpVector* vector = NaClInstStateExpVector(inst_state); |
- int op2_index = |
- NaClGetExpKidIndex(vector, |
- NaClGetNthExpKind(vector, OperandReference, 2), |
- 0); |
- NaClExp* op2 = &(vector->node[op2_index]); |
- /* Only allow memory offset nodes with address size 64. */ |
- if (ExprMemOffset == op2->kind && |
- NACL_EMPTY_EFLAGS != (op2->flags & NACL_EFLAG(ExprSize64))) { |
- int base_reg_index = op2_index + 1; |
- NaClOpKind base_reg = NaClGetExpVectorRegister(vector, base_reg_index); |
- DEBUG(NaClLog(LOG_INFO, " base_reg = %s\n", NaClOpKindName(base_reg))); |
- if (base_reg == reg) { |
- int index_reg_index = |
- base_reg_index + NaClExpWidth(vector, base_reg_index); |
- NaClOpKind index_reg = |
- NaClGetExpVectorRegister(vector, index_reg_index); |
- DEBUG(NaClLog(LOG_INFO, |
- " index_reg = %s\n", NaClOpKindName(index_reg))); |
- if (index_reg == state->base_register) { |
- int scale_index = |
- index_reg_index + NaClExpWidth(vector, index_reg_index); |
- DEBUG(NaClLog(LOG_INFO, " scale_index = %d\n", scale_index)); |
- if (ExprConstant == vector->node[scale_index].kind) { |
- if ((uint64_t)1 == |
- NaClGetExprUnsignedValue(&vector->node[scale_index])) { |
- int 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 ((uint64_t)0 == |
- NaClGetExprSignedValue(&vector->node[disp_index])) { |
- result = TRUE; |
- } else { |
- DEBUG(NaClLog(LOG_INFO, " disp not zero!\n")); |
- } |
- } |
- } else { |
- DEBUG(NaClLog(LOG_INFO, " scale not 1!\n")); |
- } |
- } |
- } |
- } |
- } |
- } |
- /* If reached, did not match. */ |
- DEBUG(NaClLog(LOG_INFO, "<-LeaAddressRegPlusRbase = %d\n", result)); |
- return result; |
-} |
- |
-Bool NaClAcceptLeaWithMoveLea32To64(struct NaClValidatorState* state, |
- NaClOpKind reg) { |
- NaClInstState* inst_state = state->cur_inst_state; |
- Bool result = NaClOperandOneIsRegisterSet(inst_state, reg) && |
- NaClIsLeaAddressRegPlusRbase(state, inst_state, reg) && |
- NaClAssignsRegisterWithZeroExtends64(state, 1, reg); |
- if (result) { |
- DEBUG({ |
- const char* reg_name = NaClOpKindName(reg); |
- printf("nc protect base for 'lea %s. [%s, rbase]'\n", |
- reg_name, reg_name); |
- }); |
- result = TRUE; |
- } |
- return result; |
-} |
- |
-/* Check if assignments to stack register RSP is legal. |
- * |
- * Parameters are: |
- * state - The state of the validator. |
- * i - The index of the node (in the expression tree) that |
- * assigns the RSP register. |
- */ |
-static void NaClCheckRspAssignments(struct NaClValidatorState* state, |
- uint32_t i) { |
- /* |
- * Only allow one of: |
- * (1) mov %rsp, %rbp |
- * |
- * Note: maintains RSP/RBP invariant, since RBP was already |
- * meeting the invariant. |
- * (2) %esp = zero extend 32-bit value |
- * OP %rsp, %rbase |
- * |
- * where OP in { or , add }. |
- * (3) An instruction that updates the stack a (small) bounded amount, |
- * and then does a memory access. This includes Push, Pop, Call, |
- * |
- * Note that entering a function corresponds to the pattern: |
- * push %rpb |
- * mov %rbp, %rsp |
- * (4) Allow stack updates of the form: |
- * OP %esp, C |
- * add %rsp, %rbase |
- * where OP is a operator in { add , sub }, |
- * and C is a 32-bit constant. |
- * Note: Since add/sub are zero-extending operations for operand |
- * size 32, this doesn't have to be treated as a special case! |
- * (5) Allow "and $rsp, 0xXX" where 0xXX is an immediate 8 bit |
- * value that is negative. Used to realign the stack pointer. |
- * (6) %esp = zero extend 32-bit value. |
- * lea %rsp, [%rsp+%rbase*1] |
- * |
- * Same as (6), except that we use instructions prior to the |
- * pattern to do the add/subtract. Then let the result be |
- * (zero-extended) moved into ESP, and use the lea to fill |
- * in the top 32 bits of %rsp. |
- * |
- * Note: We require the scale to be 1, and rbase be in |
- * the index position. |
- * |
- * Note: Cases 2, 4, 5, and 6 are maintaining the invariant that |
- * the top half of RSP is the same as RBASE, and the lower half |
- * of RBASE is zero. Case (2) does this by seting the bottom 32 |
- * bits with the first instruction (zeroing out the top 32 bits), |
- * and then copies (via or or add) the top 32 bits of RBASE into RSP |
- * (since the bottom 32 bits of RBASE are zero). |
- * Case (4) maintains this by first clearing the top half |
- * of RSP, and then setting the top half to match RBASE. Case (5) |
- * maintains the variant because the constant is small |
- * (-1 to -128) to that the invariant for $RSP (top half |
- * is unchanged). Case 6 uses the addition in the address calculation |
- * of lea to fill in the top 32 bits. |
- */ |
- NaClInstState* inst_state = state->cur_inst_state; |
- const NaClInst* inst = state->cur_inst; |
- NaClMnemonic inst_name = inst->name; |
- NaClExpVector* vector = state->cur_inst_vector; |
-#ifdef NCVAL_TESTING |
- char* buffer; |
- size_t buffer_size; |
-#endif |
- |
- switch (inst_name) { |
- case InstPush: |
- case InstPop: |
- /* Legal if index corresponds to the first (stack) argument. |
- * Note: Since the vector contains a list of operand exrpessions, |
- * the first operand reference is always at index zero, and its |
- * first child (where the stack register is defined) is at index 1. |
- */ |
- if (i == 1) return; |
- break; |
- case InstCall: |
- /* Legal if index corresponds to the second (stack) argument. |
- * Note: The first operand is an operand reference to the instruction |
- * register. It consists of an operand reference at index zero, |
- * and its first child (where the instruction registers is defined) |
- * is at index 1. The node at index 2 is the operand reference to |
- * the stack register, and its first child (where the stack register is |
- * defined) is at index 3; |
- */ |
- if (i == 3) return; |
- break; |
- case InstOr: |
- case InstAdd: |
- /* case 2/4 (depending on instruction name) */ |
- if (NaClIsBinarySetUsingRegisters( |
- state->decoder_tables, |
- inst, inst_name, vector, RegRSP, |
- state->base_register) && |
- NaClAssignsRegisterWithZeroExtends32(state, 1, RegESP)) { |
-#ifdef NCVAL_TESTING |
- /* Report precondition of test. */ |
- NaClConditionAppend(state->precond, &buffer, &buffer_size); |
- SNPRINTF(buffer, buffer_size, "ZeroExtends(esp)"); |
-#endif |
- NaClMarkInstructionJumpIllegal(state, state->cur_inst_state); |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].esp_set_inst = NULL; |
- return; |
- } |
- break; |
- case InstLea: |
- if (NaClAcceptLeaWithMoveLea32To64(state, RegRSP)) { |
- /* case 6. Found that the assignment to ESP in the previous |
- * instruction is legal, so long as the two instructions |
- * are atomic. |
- */ |
-#ifdef NCVAL_TESTING |
- /* Report precondition of test. */ |
- NaClConditionAppend(state->precond, &buffer, &buffer_size); |
- SNPRINTF(buffer, buffer_size, "ZeroExtends(esp)"); |
-#endif |
- NaClMarkInstructionJumpIllegal(state, state->cur_inst_state); |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].esp_set_inst = NULL; |
- return; |
- } |
- break; |
- case InstAnd: |
- /* See if case 5: and $rsp, 0xXX */ |
- if (NaClInstStateLength(inst_state) == 4 && |
- NaClInstStateByte(inst_state, 0) == 0x48 && |
- NaClInstStateByte(inst_state, 1) == 0x83 && |
- NaClInstStateByte(inst_state, 2) == 0xe4 && |
- /* negative byte test: check if leftmost bit set. */ |
- (NaClInstStateByte(inst_state, 3) & 0x80)) { |
- return; |
- } |
- /* Intentionally fall to the next case. */ |
- default: |
- if (NaClIsMovUsingRegisters(state->decoder_tables, |
- inst, vector, RegRSP, RegRBP)) { |
- /* case (1) -- see above, matching |
- * mov %rsp, %rbp |
- */ |
- return; |
- } |
- break; |
- } |
- /* If reached, assume that not a special case. */ |
- NaClReportIllegalChangeToRsp(state, inst_state); |
-} |
- |
-/* Check if assignments to rbp resister is legal. |
- * |
- * Parameters are: |
- * state - The state of the validator. |
- * i - The index of the node (in the expression tree) that |
- * assigns the RSP register. |
- */ |
-static void NaClCheckRbpAssignments(struct NaClValidatorState* state, |
- uint32_t i) { |
- /* (1) mov %rbp, %rsp |
- * |
- * Note: maintains RSP/RBP invariant, since RSP was already |
- * meeting the invariant. |
- * |
- * (2) %ebp = zero extend 32-bit value. |
- * add %rbp, %rbase |
- * |
- * Typical use in the exit from a function, restoring RBP. |
- * The ... in the MOV is gotten from a stack pop in such |
- * cases. However, for long jumps etc., the value may |
- * be gotten from memory, or even a register. |
- * |
- * (3) %ebp = zero extend 32-bit value. |
- * lea %rbp, [%rbp+%rbase*1] |
- * |
- * Same as (2), except that we use instructions prior to the |
- * pattern to do the add/subtract. Then let the result be |
- * (zero-extended) moved into EBP, and use the lea to fill |
- * in the top 32 bits of %RSP. |
- * |
- * Note: We require the scale to be 1, and rbase be in |
- * the index position. |
- */ |
- NaClInstState* inst_state = state->cur_inst_state; |
- const NaClInst* inst = state->cur_inst; |
- NaClMnemonic inst_name = inst->name; |
- NaClExpVector* vector = state->cur_inst_vector; |
-#ifdef NCVAL_TESTING |
- char* buffer; |
- size_t buffer_size; |
-#endif |
- |
- switch (inst_name) { |
- case InstAdd: |
- /* case 2. */ |
- if (NaClIsBinarySetUsingRegisters( |
- state->decoder_tables, |
- inst, InstAdd, vector, |
- RegRBP, state->base_register) && |
- NaClAssignsRegisterWithZeroExtends32(state, 1, RegEBP)) { |
-#ifdef NCVAL_TESTING |
- /* Report precondition of test. */ |
- NaClConditionAppend(state->precond, &buffer, &buffer_size); |
- SNPRINTF(buffer, buffer_size, "ZeroExtends(ebp)"); |
-#endif |
- NaClMarkInstructionJumpIllegal(state, state->cur_inst_state); |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].ebp_set_inst = NULL; |
- return; |
- } |
- break; |
- case InstLea: |
- /* case 3 */ |
- if (NaClAcceptLeaWithMoveLea32To64(state, RegRBP)) { |
-#ifdef NCVAL_TESTING |
- /* Report precondition of test. */ |
- NaClConditionAppend(state->precond, &buffer, &buffer_size); |
- SNPRINTF(buffer, buffer_size, "ZeroExtends(ebp)"); |
-#endif |
- NaClMarkInstructionJumpIllegal(state, state->cur_inst_state); |
- state->set_base_registers.buffer[ |
- state->set_base_registers.previous_index].ebp_set_inst = NULL; |
- return; |
- } |
- break; |
- default: |
- if (NaClIsMovUsingRegisters(inst_state->decoder_tables, |
- inst, vector, RegRBP, RegRSP)) { |
- /* case 1 */ |
- return; |
- } |
- break; |
- } |
- /* If reached, not valid. */ |
- NaClValidatorInstMessage(LOG_ERROR, state, inst_state, |
- "Illegal change to register RBP\n"); |
-} |
- |
-/* Reports error if the register name is a subregister of Rsp/Rbp/base register, |
- * under assumption that it is illegal to change the value of such registers. |
- */ |
-static void NaClCheckSubregChangeOfRspRbpOrBase( |
- struct NaClValidatorState* state, |
- NaClOpKind reg_name) { |
- NaClInstState* inst_state = state->cur_inst_state; |
- if (NaClIs64Subreg(inst_state, reg_name, state->base_register)) { |
- NaClValidatorInstMessage( |
- LOG_ERROR, state, inst_state, |
- "Changing %s changes the value of %s\n", |
- NaClOpKindName(reg_name), |
- NaClOpKindName(state->base_register)); |
- } else if (NaClIs64Subreg(inst_state, reg_name, RegRSP)) { |
- NaClValidatorInstMessage( |
- LOG_ERROR, state, inst_state, |
- "Changing %s changes the value of %s\n", |
- NaClOpKindName(reg_name), |
- NaClOpKindName(RegRSP)); |
- } else if (NaClIs64Subreg(inst_state, reg_name, RegRBP)) { |
- NaClValidatorInstMessage( |
- LOG_ERROR, state, inst_state, |
- "Changing %s changes the value of %s\n", |
- NaClOpKindName(reg_name), |
- NaClOpKindName(RegRBP)); |
- } |
-} |
- |
-void NaClBaseRegisterValidator(struct NaClValidatorState* state) { |
- uint32_t i; |
- NaClInstState* inst_state = state->cur_inst_state; |
- NaClExpVector* vector = state->cur_inst_vector; |
- |
- DEBUG(NaClValidatorInstMessage( |
- LOG_INFO, state, inst_state, "Checking base registers...\n")); |
- |
- /* Look for assignments to registers. */ |
- for (i = 0; i < vector->number_expr_nodes; ++i) { |
- NaClExp* node = &vector->node[i]; |
- if (ExprRegister == node->kind) { |
- if (node->flags & NACL_EFLAG(ExprSet)) { |
- NaClOpKind reg_name = NaClGetExpRegisterInline(node); |
- |
- /* If reached, found an assignment to a register. |
- * Check if its one that we care about (i.e. |
- * the base register (RBASE), RSP, RBP, or segment register). |
- */ |
- if (reg_name == state->base_register) { |
- NaClValidatorInstMessage( |
- LOG_ERROR, state, inst_state, |
- "Illegal to change the value of register %s\n", |
- NaClOpKindName(state->base_register)); |
- } else { |
- switch (reg_name) { |
- case RegRSP: |
- NaClCheckRspAssignments(state, i); |
- break; |
- case RegRBP: |
- NaClCheckRbpAssignments(state, i); |
- break; |
- case RegESP: |
- /* Record that we must recheck this after we have |
- * moved to the next instruction. |
- */ |
- state->set_base_registers.buffer[ |
- state->set_base_registers.current_index |
- ].esp_set_inst = inst_state; |
- break; |
- case RegEBP: |
- /* Record that we must recheck this after we have |
- * moved to the next instruction. |
- */ |
- state->set_base_registers.buffer[ |
- state->set_base_registers.current_index |
- ].ebp_set_inst = inst_state; |
- break; |
- case RegCS: |
- case RegDS: |
- case RegSS: |
- case RegES: |
- case RegFS: |
- case RegGS: |
- NaClValidatorInstMessage( |
- LOG_ERROR, state, inst_state, |
- "Illegal assignment to segment register %s\n", |
- NaClOpKindName(reg_name)); |
- break; |
- default: |
- NaClCheckSubregChangeOfRspRbpOrBase(state, reg_name); |
- break; |
- } |
- } |
- } |
- } |
- } |
- /* Before moving to the next instruction, see if we need to report |
- * problems with the previous instruction. |
- */ |
- NaClMaybeReportPreviousBad(state); |
-} |
- |
-void NaClBaseRegisterSummarize(struct NaClValidatorState* state) { |
- /* Check if problems in last instruction of segment. */ |
- NaClMaybeReportPreviousBad(state); |
-} |