Exemplo n.º 1
0
/* 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");
    }
  }
}
Exemplo n.º 2
0
/* Given the number of bytes for a literal constant, return the corresponding
 * expr node flags that represent the value of the parsed bytes.
 */
static NaClExpFlags NaClGetExprSizeFlagForBytes(uint8_t num_bytes) {
  switch (num_bytes) {
    case 1:
      return NACL_EFLAG(ExprSize8);
      break;
    case 2:
      return NACL_EFLAG(ExprSize16);
      break;
    case 4:
      return NACL_EFLAG(ExprSize32);
    case 8:
      return NACL_EFLAG(ExprSize64);
    default:
      return 0;
  }
}
Exemplo n.º 3
0
/* Checks if an indirect jump (in 32-bit mode) is native client compliant.
 *
 * Expects pattern:
 *    and %REG, MASK
 *    jmp %REG
 *
 * where the MASK is all 1's except for the alignment mask bits, which must
 * be zero.
 *
 * It is assumed that opcode 0x83 is used for the AND operation, and hence, the
 * mask is a single byte.
 *
 * Note: applies to all kinds of jumps and calls.
 *
 * Parameters:
 *   state - The state of the validator.
 *   reg - The register used in the jump instruction.
 */
static void NaClAddRegisterJumpIndirect32(NaClValidatorState* vstate,
                                          NaClExp* reg) {
  NaClOpKind jump_reg, and_reg;

  /* Do the following block exactly once. Use loop so that "break" can
   * be used for premature exit of block.
   */
  do {
    /* Check that jump register is 32-bit. */
    if (!NaClHasBit(reg->flags, NACL_EFLAG(ExprSize32))) break;
    jump_reg = NaClGetExpRegisterInline(reg);
    if (RegUnknown == jump_reg) break;
    DEBUG(NaClLog(LOG_INFO, "checking indirect jump: ");
          NaClInstStateInstPrint(NaClLogGetGio(), vstate->cur_inst_state);
          gprintf(NaClLogGetGio(), "jump_reg = %s\n",
                  NaClOpKindName(jump_reg)));

    /* Check that sequence begins with an appropriate and instruction. */
    and_reg = NaClGetAndMaskReg32(vstate, 1);
    if (jump_reg != and_reg) break;

    /* If reached, indirect jump is properly masked. */
    DEBUG(NaClLog(LOG_INFO, "Protect register jump indirect\n"));
    NaClMarkInstructionJumpIllegal(vstate, vstate->cur_inst_state);
    return;
  } while(0);

  /* If reached, mask was not found. */
  NaClValidatorInstMessage(LOG_ERROR, vstate, vstate->cur_inst_state,
                           "Invalid indirect jump\n");
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
/* Append the given constant onto the given vector of expression
 * nodes. Returns the appended expression node.
 */
static INLINE NaClExp* NaClAppendConst(uint64_t value, NaClExpFlags flags,
                                       NaClExpVector* vector) {
  uint32_t val1;
  uint32_t val2;
  DEBUG(
      NaClLog(LOG_INFO, "Append constant %"NACL_PRIx64" : ", value);
      NaClPrintExpFlags(NaClLogGetGio(), flags);
      gprintf(NaClLogGetGio(), "\n"));
  NaClSplitExpConstant(value, &val1, &val2);
  if (val2 == 0) {
    return NaClAppendExp(ExprConstant, val1, flags, vector);
  } else {
    NaClExp* root = NaClAppendExp(ExprConstant64, 0, flags, vector);
    NaClAppendExp(ExprConstant, val1, NACL_EFLAG(ExprUnsignedHex), vector);
    NaClAppendExp(ExprConstant, val2, NACL_EFLAG(ExprUnsignedHex), vector);
    return root;
  }
}
Exemplo n.º 6
0
/* Retrurns true if the segment register of the index segment address is ES,
 * and ES has been marked (by the instruction) as the default register
 * for the segment address.
 */
static Bool IsSegmentAddressEsRegPair(NaClInstState* state,
                                      int index) {
  NaClExpVector* vector = NaClInstStateExpVector(state);
  NaClExp* segment_address = &vector->node[index];
  NaClExp* segment_register =
      &vector->node[NaClGetExpKidIndex(vector, index, 0)];
  return NaClHasBit(segment_address->flags, NACL_EFLAG(ExprESrCase)) &&
      (segment_register->kind == ExprRegister) &&
      (RegES == NaClGetExpRegisterInline(segment_register));
}
Exemplo n.º 7
0
/* Returns true if there is a segment override in the segment address
 * node defined by vector[seg_addr_index].
 *
 * Parameters:
 *   vector - The node expression tree associated with the instruction.
 *   seg_addr_index - The index to the segment address node to check.
 *   seg_eflag - The expr flag that must be associated with the
 *      segment address node to be considered for an override.
 *   seg_reg - The expected (i.e. default) segment register
 *      to be associated with the segment address.
 */
static Bool NaClHasSegmentOverride(NaClExpVector* vector,
                                   int seg_addr_index,
                                   NaClExpFlag seg_eflag,
                                   NaClOpKind seg_reg) {
  NaClExp* seg_node = &vector->node[seg_addr_index];
  if (seg_node->flags & NACL_EFLAG(seg_eflag)) {
    int seg_index = seg_addr_index + 1;
    NaClExp* node = &vector->node[seg_index];
    if ((ExprRegister == node->kind) &&
        (seg_reg != NaClGetExpRegisterInline(node))) {
      return TRUE;
    }
  }
  return FALSE;
}
Exemplo n.º 8
0
/* 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));
  }
}
Exemplo n.º 9
0
void NaClPrintExpFlags(struct Gio* file, NaClExpFlags flags) {
  if (flags == 0) {
    gprintf(file, "0");
  } else {
    NaClExpFlag f;
    Bool is_first = TRUE;
    for (f = 0; f < NaClExpFlagEnumSize; f++) {
      if (flags & NACL_EFLAG(f)) {
        if (is_first) {
          is_first = FALSE;
        } else {
          gprintf(file, " | ");
        }
        gprintf(file, "%s", NaClExpFlagName(f));
      }
    }
  }
}
Exemplo n.º 10
0
/* Checks if an indirect jump (in 64-bit mode) is native client compliant.
 *
 * Expects pattern:
 *
 *    and %REG32, MASK
 *    add %REG64, %RBASE
 *    jmp %REG64
 *
 * where MASK is all 1/s except for the alignment mask bits, which must be zero.
 *
 * REG32 is the corresponding 32-bit register that whose value will get zero
 * extended by the AND operation into the corresponding 64-bit register REG64.
 *
 * It is assumed that opcode 0x83 is used for the AND operation, and hence, the
 * mask is a single byte.
 *
 * Note: applies to all kinds of jumps and calls.
 *
 * Parameters:
 *   vstate - The state of the validator.
 *   reg - The register used in the jump instruction.
 */
static void NaClAddRegisterJumpIndirect64(NaClValidatorState* vstate,
                                          NaClExp* reg) {
  NaClOpKind jump_reg, and_reg32, and_reg64;

  /* Do the following block exactly once. Use loop so that "break" can
   * be used for premature exit of block.
   */
  do {
    /* Check that jump register is 64-bit. */
    if (!NaClHasBit(reg->flags, NACL_EFLAG(ExprSize64))) break;
    jump_reg = NaClGetExpRegisterInline(reg);
    if (RegUnknown == jump_reg) break;
    DEBUG(NaClLog(LOG_INFO, "checking indirect jump: ");
          NaClInstStateInstPrint(NaClLogGetGio(), vstate->cur_inst_state);
          gprintf(NaClLogGetGio(), "jump_reg = %s\n",
                  NaClOpKindName(jump_reg)));

    /* Check that sequence begins with an appropriate and instruction. */
    and_reg32 = NaClGetAndMaskReg32(vstate, 2);
    if (RegUnknown == and_reg32) break;

    /* Get corresponding 64-bit register for 32-bit result of 'and',
     * and make sure it matches the jump register.
     */
    and_reg64 = NaClGet64For32BitReg(and_reg32);
    if (and_reg64 != jump_reg) break;

    /* Check that the middle instruction is an appropriate add instruction. */
    if (!NaClIsAddRbaseToReg64(vstate, 1, and_reg64)) break;

    /* If reached, indirect jump is properly masked. */
    DEBUG(NaClLog(LOG_INFO, "Protect indirect jump instructions\n"));
    NaClMarkInstructionJumpIllegal(
        vstate, NaClInstIterGetLookbackStateInline(vstate->cur_iter, 1));
    NaClMarkInstructionJumpIllegal(vstate, vstate->cur_inst_state);
    return;
  } while(0);

  /* If reached, mask was not found. */
  NaClValidatorInstMessage(LOG_ERROR, vstate, vstate->cur_inst_state,
                           "Invalid indirect jump\n");
}
Exemplo n.º 11
0
/* Returns the (NaClExpFlag) size of the given register. */
static NaClExpFlags NaClGetRegSize(NaClOpKind register_name) {
  switch (register_name) {
  case RegAL:
  case RegBL:
  case RegCL:
  case RegDL:
  case RegAH:
  case RegBH:
  case RegCH:
  case RegDH:
  case RegDIL:
  case RegSIL:
  case RegBPL:
  case RegSPL:
  case RegR8B:
  case RegR9B:
  case RegR10B:
  case RegR11B:
  case RegR12B:
  case RegR13B:
  case RegR14B:
  case RegR15B:
    return NACL_EFLAG(ExprSize8);
  case RegAX:
  case RegBX:
  case RegCX:
  case RegDX:
  case RegSI:
  case RegDI:
  case RegBP:
  case RegSP:
  case RegR8W:
  case RegR9W:
  case RegR10W:
  case RegR11W:
  case RegR12W:
  case RegR13W:
  case RegR14W:
  case RegR15W:
    return NACL_EFLAG(ExprSize16);
  case RegEAX:
  case RegEBX:
  case RegECX:
  case RegEDX:
  case RegESI:
  case RegEDI:
  case RegEBP:
  case RegESP:
  case RegR8D:
  case RegR9D:
  case RegR10D:
  case RegR11D:
  case RegR12D:
  case RegR13D:
  case RegR14D:
  case RegR15D:
    return NACL_EFLAG(ExprSize32);
  case RegCS:
  case RegDS:
  case RegSS:
  case RegES:
  case RegFS:
  case RegGS:
    return NACL_EFLAG(ExprSize16);
  case RegEIP:
    return NACL_EFLAG(ExprSize32);
  case RegRIP:
    return NACL_EFLAG(ExprSize64);
  case RegRAX:
  case RegRBX:
  case RegRCX:
  case RegRDX:
  case RegRSI:
  case RegRDI:
  case RegRBP:
  case RegRSP:
  case RegR8:
  case RegR9:
  case RegR10:
  case RegR11:
  case RegR12:
  case RegR13:
  case RegR14:
  case RegR15:
    return NACL_EFLAG(ExprSize64);
  default:
    return 0;
  }
}
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");
          }
        }
      }
    }
  }
}
Exemplo n.º 13
0
/* Print the given instruction opcode of the give state, to the
 * given file.
 */
static void NaClPrintDisassembled(struct Gio* file,
                                  NaClInstState* state,
                                  const NaClInst* inst) {
  uint32_t tree_index = 0;
  Bool is_first = TRUE;
  Bool not_printed_prefix_segment = TRUE;
  NaClExp* node;
  NaClExpVector* vector = NaClInstStateExpVector(state);

  /* Print the name of the instruction. */
  if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction))) {
    /* Instruction has been simplified. Print out corresponding
     * hints to the reader, so that they know that the instruction
     * has been simplified.
     */
    gprintf(file, "[P] ");
    NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
    if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) {
      gprintf(file, "(illegal)");
    }
  } else {
    NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
  }

  /* Use the generated expression tree to print out (non-implicit) operands
   * of the instruction.
   */
  while (tree_index < vector->number_expr_nodes) {
    node = &vector->node[tree_index];
    if (node->kind != OperandReference ||
        (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprImplicit)))) {
      if (is_first) {
        gprintf(file, " ");
        is_first = FALSE;
      } else {
        gprintf(file, ", ");
      }
      NaClPrintDisassembledExp(file, state, tree_index);

      /* If this is a partial instruction, add set/use information
       * so that that it is more clear what was matched.
       */
      if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction)) &&
          node->kind == OperandReference) {
        const NaClOp* op =
            NaClGetInstOperandInline(state->decoder_tables,
                                     inst,
                                     (uint8_t) NaClGetExprUnsignedValue(node));
        if (NaClHasBit(op->flags, (NACL_OPFLAG(OpSet) |
                                   NACL_OPFLAG(OpUse) |
                                   NACL_OPFLAG(OperandZeroExtends_v)))) {
          gprintf(file, " (");
          NaClPrintAddOperandFlag(file, op, OpSet, "s");
          NaClPrintAddOperandFlag(file, op, OpUse, "u");
          NaClPrintAddOperandFlag(file, op, OperandZeroExtends_v, "z");
          gprintf(file, ")");
        }
      }
    } else if (not_printed_prefix_segment &&
               (OperandReference == node->kind) &&
               (node->flags & NACL_EFLAG(ExprImplicit))) {
      /* Print out segment override of implicit segment address, if
       * applicable.
       */
      if (OperandReference == node->kind) {
        int seg_addr_index = tree_index + 1;
        if (ExprSegmentAddress == vector->node[seg_addr_index].kind) {
          if (NaClHasSegmentOverride(vector, seg_addr_index,
                                     ExprDSrCase, RegDS)) {
            NaClPrintSegmentOverride(file, &is_first, state, vector,
                                     seg_addr_index);
          } else if (NaClHasSegmentOverride(vector, seg_addr_index,
                                            ExprESrCase, RegES)) {
            NaClPrintSegmentOverride(file, &is_first, state, vector,
                                     seg_addr_index);
          }
        }
      }
    }
    /* Skip over expression to next expresssion. */
    tree_index += NaClExpWidth(vector, tree_index);
  }
}