Exemplo n.º 1
0
void NaClDisassembleSegment(uint8_t* mbase, NaClPcAddress vbase,
                            NaClMemorySize size, NaClDisassembleFlags flags) {
  if (NaClHasBit(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleFull))) {
    if (NaClHasBit(flags,
                   NACL_DISASSEMBLE_FLAG(NaClDisassembleValidatorDecoder))) {
      gprintf(NaClLogGetGio(),
              "Error: can't specify both full and validator disassembly,\n"
              "       assuming full disassembly.\n");
    }
    NaClDisassembleSegmentUsingTables(mbase, vbase, size, flags,
                                      kNaClDecoderTables);
  } else if (NaClHasBit
             (flags,
              NACL_DISASSEMBLE_FLAG(NaClDisassembleValidatorDecoder))) {
    if (64 == NACL_TARGET_SUBARCH) {
      NaClDisassembleSegmentUsingTables(mbase, vbase, size, flags,
                                        kNaClValDecoderTables);
    } else {
      NCDecodeSegment(mbase, vbase, size);
    }
  } else {
    gprintf(NaClLogGetGio(),
            "Error: No decoder tables specified, can't disassemble\n");
  }
}
/* Print out the register (from the list of register names),
 * that is referenced by the decoded instruction in the
 * decoder state. If is_gp_regs is true, the register names
 * correspond to general purpose register names. Otherwise,
 * they are some other set, such as MMX or XMM.
 */
static void RegMemPrint(const NCDecoderInst *dinst,
                        const char* reg_names[],
                        const uint8_t is_gp_regs,
                        struct Gio* fp) {
  DEBUG( printf(
             "reg mem print: sib_offset = %d, "
             "disp_offset = %d, mrm.mod = %02x\n",
             NCSibOffset(dinst), (int) NCDispOffset(dinst),
             modrm_modInline(dinst->inst.mrm)) );
  switch (modrm_modInline(dinst->inst.mrm)) {
    case 0:
      SegPrefixPrint(dinst, fp);
      if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) {
        NaClIllegalOp(fp);
      } else {
        if (4 == modrm_rmInline(dinst->inst.mrm)) {
          SibPrint(dinst, fp);
        } else if (5 == modrm_rmInline(dinst->inst.mrm)) {
          gprintf(fp, "[0x%x]", DispValue32(dinst));
        } else {
          gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]);
        }
      }
      break;
    case 1:
      SegPrefixPrint(dinst, fp);
      if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) {
        NaClIllegalOp(fp);
      } else {
        gprintf(fp, "0x%x", DispValue32(dinst));
        if (4 == modrm_rmInline(dinst->inst.mrm)) {
          SibPrint(dinst, fp);
        } else {
          gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]);
        }
      }
      break;
    case 2:
      SegPrefixPrint(dinst, fp);
      if (NaClHasBit(dinst->inst.prefixmask, kPrefixADDR16)) {
        NaClIllegalOp(fp);
      } else {
        gprintf(fp, "0x%x", DispValue32(dinst));
        if (4 == modrm_rmInline(dinst->inst.mrm)) {
          SibPrint(dinst, fp);
        } else {
          gprintf(fp, "[%s]", gp_regs[modrm_rmInline(dinst->inst.mrm)]);
        }
      }
      break;
    case 3:
      if (is_gp_regs) {
        gprintf(fp, "%s", reg_names[state_modrm_reg(dinst)]);
      } else {
        gprintf(fp, "%s", reg_names[modrm_rmInline(dinst->inst.mrm)]);
      }
      break;
  }
}
Exemplo n.º 3
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.º 4
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.º 5
0
/* Disassemble the code segment, using the given decoder tables.
 * Note: The decoder tables specified in the flags argument will
 * be ignored.
 *
 * Parameters:
 *    mbase - Memory region containing code segment.
 *    vbase - PC address associated with first byte of memory region.
 *    size - Number of bytes in memory region.
 *    flags - Flags to use when decoding.
 */
static void NaClDisassembleSegmentUsingTables(
    uint8_t* mbase, NaClPcAddress vbase,
    NaClMemorySize size, NaClDisassembleFlags flags,
    const struct NaClDecodeTables* decoder_tables)  {
  NaClSegment segment;
  NaClInstIter* iter;
  struct Gio* gout = NaClLogGetGio();
  Bool print_internals =
      NaClHasBit(flags, NACL_DISASSEMBLE_FLAG(NaClDisassembleAddInternals));
  NaClSegmentInitialize(mbase, vbase, size, &segment);
  iter = NaClInstIterCreate(decoder_tables, &segment);
  if (NULL == iter) {
    gprintf(gout, "Error: not enough memory\n");
  } else {
    for (; NaClInstIterHasNext(iter); NaClInstIterAdvance(iter)) {
      NaClInstState* state = NaClInstIterGetState(iter);
      NaClInstStateInstPrint(gout, state);
      if (print_internals) {
        NaClInstPrintOpcodeSeq(gout, state);
        NaClInstPrint(gout, state->decoder_tables, NaClInstStateInst(state));
        NaClExpVectorPrint(gout, state);
      }
    }
    NaClInstIterDestroy(iter);
  }
}
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
/* 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");
}
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.º 9
0
/* Returns true if the disassemble flag is in the given flag set. */
Bool NaClContainsDisasembleFlag(NaClDisassembleFlags flags,
                                NaClDisassembleFlag flag) {
  return NaClHasBit(flags, NACL_DISASSEMBLE_FLAG(flag)) ? TRUE : FALSE;
}
Exemplo n.º 10
0
uint8_t NaClRexB(uint8_t prefix) {
  return NaClHasBit(prefix, NaClRexBMask);
}
Exemplo n.º 11
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);
  }
}