/* Given a jump statement, add the corresponding (explicit) jump value * to the set of actual jump targets. * Parameters: * vstate - The state of the validator. */ static void NaClAddExprJumpTarget(NaClValidatorState* vstate) { uint32_t i; NaClInstState* inst_state = vstate->cur_inst_state; NaClExpVector* vector = vstate->cur_inst_vector; DEBUG(NaClLog(LOG_INFO, "jump checking: "); NaClInstStateInstPrint(NaClLogGetGio(), inst_state)); for (i = 0; i < vector->number_expr_nodes; ++i) { NaClExp* node = &vector->node[i]; if (!NaClHasBit(node->flags, NACL_EFLAG(ExprJumpTarget))) continue; switch (node->kind) { case ExprRegister: if (64 == NACL_TARGET_SUBARCH) { NaClAddRegisterJumpIndirect64(vstate, node); } else { NaClAddRegisterJumpIndirect32(vstate, node); } break; case ExprConstant: /* Direct jump. */ NaClAddJumpToJumpSets(vstate, inst_state, (NaClPcNumber) NaClGetExprSignedValue(node)); break; default: NaClValidatorInstMessage( LOG_ERROR, vstate, inst_state, "Jump not native client compliant\n"); } } }
/* Print out the given constant expression node to the given file. */ static void NaClPrintDisassembledConst( struct Gio* file, NaClInstState* state, NaClExp* node) { assert(node->kind == ExprConstant); if (node->flags & NACL_EFLAG(ExprJumpTarget)) { NaClPcAddress target = NaClInstStatePrintableAddress(state) + state->bytes.length + (NaClPcNumber) NaClGetExprSignedValue(node); gprintf(file, "0x%"NACL_PRIxNaClPcAddress, target); }else if (node->flags & NACL_EFLAG(ExprUnsignedHex)) { gprintf(file, "0x%"NACL_PRIx64, NaClGetExprUnsignedValue(node)); } else if (node->flags & NACL_EFLAG(ExprSignedHex)) { int64_t val = NaClGetExprSignedValue(node); if (val < 0) { val = -val; gprintf(file, "-0x%"NACL_PRIx64, val); } else { gprintf(file, "0x%"NACL_PRIx64, val); } } else if (node->flags & NACL_EFLAG(ExprUnsignedInt)) { gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node)); } else { /* Assume ExprSignedInt. */ gprintf(file, "%"NACL_PRId64, NaClGetExprSignedValue(node)); } }
Bool NaClIsExpNegativeConstant(NaClExpVector* vector, int index) { NaClExp* node = &vector->node[index]; switch (node->kind) { case ExprConstant: if (node->flags & NACL_EFLAG(ExprUnsignedHex) || node->flags & NACL_EFLAG(ExprUnsignedInt)) { return FALSE; } else { /* Assume signed value. */ return NaClGetExprSignedValue(node) < 0; } break; default: break; } return FALSE; }
/* Print out the given (memory offset) expression node to the given file. * Returns the index of the node following the given (indexed) memory offset. */ static int NaClPrintDisassembledMemOffset(struct Gio* file, NaClInstState *state, int index) { NaClExpVector* vector = NaClInstStateExpVector(state); int r1_index = index + 1; int r2_index = r1_index + NaClExpWidth(vector, r1_index); int scale_index = r2_index + NaClExpWidth(vector, r2_index); int disp_index = scale_index + NaClExpWidth(vector, scale_index); NaClOpKind r1 = NaClGetExpVectorRegister(vector, r1_index); NaClOpKind r2 = NaClGetExpVectorRegister(vector, r2_index); uint64_t scale = NaClGetExprUnsignedValue(&vector->node[scale_index]); int64_t disp = NaClGetExprSignedValue(&vector->node[disp_index]); assert(ExprMemOffset == vector->node[index].kind); gprintf(file,"["); if (r1 != RegUnknown) { NaClPrintDisassembledRegKind(file, r1); } if (r2 != RegUnknown) { if (r1 != RegUnknown) { gprintf(file, "+"); } NaClPrintDisassembledRegKind(file, r2); gprintf(file, "*%d", (uint32_t) scale); } if (disp != 0) { if ((r1 != RegUnknown || r2 != RegUnknown) && !NaClIsExpNegativeConstant(vector, disp_index)) { gprintf(file, "+"); } /* Recurse to handle print using format flags. */ NaClPrintDisassembledExp(file, state, disp_index); } else if (r1 == RegUnknown && r2 == RegUnknown) { /* be sure to generate case: [0x0]. */ NaClPrintDisassembledExp(file, state, disp_index); } gprintf(file, "]"); return disp_index + NaClExpWidth(vector, disp_index); }
static void NaClInstLayoutCheck(NaClValidatorState* vstate) { NaClPcAddress start; NaClPcAddress end; NaClPcAddress i; if (NULL == vstate->cur_inst_state) return; DEBUG(NaClLog(LOG_INFO, "Jump layout check: "); NaClInstStateInstPrint(NaClLogGetGio(), vstate->cur_inst_state)); /* Check basic block boundaries. */ start = vstate->cur_inst_state->inst_addr; /* Check that if first instruction in a basic block, it isn't in the * middle of a pattern. */ if ((0 == (start & vstate->bundle_mask)) && NaClAddressSetContains(vstate->jump_sets.removed_targets, start, vstate)) { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Instruction begins basic block, but in middle of nacl pattern\n"); } /* Check that instruction doesn't cross block boundaries. */ end = (NaClPcAddress) (start + vstate->cur_inst_state->bytes.length); for (i = start + 1; i < end; ++i) { if (0 == (i & vstate->bundle_mask)) { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Instruction crosses basic block alignment\n"); } } /* Check jump targets. */ if (NaClHasBit(vstate->cur_inst_state->inst->flags, NACL_IFLAG(JumpInstruction) | NACL_IFLAG(ConditionalJump))) { uint32_t i; NaClExpVector* vector = NaClInstStateExpVector(vstate->cur_inst_state); for (i = 0; i < vector->number_expr_nodes; ++i) { NaClExp* node = &vector->node[i]; if (NaClHasBit(node->flags, NACL_EFLAG(ExprJumpTarget)) && node->kind == ExprConstant) { /* Explicit jump value. Check if legal! */ NaClPcAddress target = end + (NaClPcNumber) NaClGetExprSignedValue(node); /* Don't report targets that are out of range. They should have * been reported in the first pass! */ if (NaClCheckAddressRange(target, vstate)) { if (NaClAddressSetContains(vstate->jump_sets.possible_targets, target, vstate)) { if (NaClAddressSetContains(vstate->jump_sets.removed_targets, target, vstate)) { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Jumps into middle of nacl pattern\n"); } } else { NaClValidatorInstMessage( LOG_ERROR, vstate, vstate->cur_inst_state, "Doesn't jump to instruction address\n"); } } } } } }