Example #1
0
size_t NaClOpRegName(NaClOpKind reg, char* buffer, size_t buffer_size) {
  const char* name = NaClOpKindName(reg);
  char* str;
  size_t index;

  /* Fail if no room to put register name. */
  if (buffer_size == 0) return 0;
  buffer[0] = '\0';  /* To be safe, in case we exit prematurely. */

  /* Get name for register. */
  name = NaClOpKindName(reg);
  if (NULL == name) return 0;

  /* Strip off 'Reg' prefix from register name, if it exists. */
  str = strstr(name, NACLOP_REG_PREFIX);
  if (str != name) return 0;
  str += strlen(NACLOP_REG_PREFIX);

  /* Copy the name, converting characters to lower case. */
  for (index = 0; (index + 1) < buffer_size; ++index) {
    char ch = tolower(str[index]);
    if ('\0' == ch) break;
    buffer[index] = tolower(str[index]);
  }

  /* Be sure to add null character at end. */
  buffer[index] = '\0';
  return index;
}
/* Print out the opcode operand in a simplified (i.e. more human readable)
 * form.
 */
void NaClOpPrint(struct Gio* f, const NaClOp* operand) {
  gprintf(f, "%s", NaClOpKindName(operand->kind));
  if (operand->flags) {
    size_t i;
    for (i = strlen(NaClOpKindName(operand->kind)); i < 24; ++i) {
      gprintf(f, " ");
    }
    NaClOpFlagsPrint(f, operand->flags);
  }
  gprintf(f, "\n");
}
Example #3
0
/* Appends the given kind of register onto the vector of expression nodes.
 * Returns the appended register.
 */
static INLINE NaClExp* NaClAppendReg(NaClOpKind r, NaClExpVector* vector) {
  NaClExp* node;
  DEBUG(NaClLog(LOG_INFO, "append register %s\n", NaClOpKindName(r)));
  node = NaClAppendExp(ExprRegister, r, NaClGetRegSize(r), vector);
  DEBUG(NaClExpVectorPrint(NaClLogGetGio(), vector));
  return node;
}
Example #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");
}
Example #5
0
/* Returns the 32-bit register for instructions of the form
 *
 *    and %reg32, MASK
 *
 * where 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.
 *
 * Returns RegUnknown if the instruction doesn't match the form listed above.
 */
static NaClOpKind NaClGetAndMaskReg32(NaClValidatorState* vstate,
                                      size_t distance) {
  NaClInstState* state;
  const NaClInst* inst;
  int op_1, op_2;
  NaClExpVector* nodes;
  NaClExp* node;
  uint8_t mask;
  NaClOpKind reg32;
  NaClInstIter* iter = vstate->cur_iter;

  /* Get the corresponding and instruction. */
  if (!NaClInstIterHasLookbackStateInline(iter, distance)) return RegUnknown;
  state = NaClInstIterGetLookbackStateInline(iter, distance);
  inst = NaClInstStateInst(state);
  if ((InstAnd != inst->name) ||
      (state->num_opcode_bytes == 0) ||
      (0x83 != state->bytes.byte[state->num_prefix_bytes])) return RegUnknown;
  DEBUG(NaClLog(LOG_INFO, "inst(%d): and mask: ", (int) distance);
        NaClInstStateInstPrint(NaClLogGetGio(), state));

  /* Extract the values of the two operands for the and. */
  if (!NaClExtractBinaryOperandIndices(state, &op_1, &op_2)) return RegUnknown;

  /* Extract the destination register of the and. */
  nodes = NaClInstStateExpVector(state);
  node = &nodes->node[op_1];
  if (ExprRegister != node->kind) return RegUnknown;

  reg32 = NaClGetExpRegisterInline(node);
  DEBUG(NaClLog(LOG_INFO, "and mask reg = %s\n", NaClOpKindName(reg32)));

  /* Check that the mask is ok. */
  mask = NaClGetJumpMask(vstate);
  DEBUG(NaClLog(LOG_INFO, "mask = %"NACL_PRIx8"\n", mask));

  assert(0xf0 == mask || 0xe0 == mask); /* alignment must be either 16 or 32. */
  node = &nodes->node[op_2];
  /* Technically the operand is a signed value, but "mask" has not been sign
   * extended, so treat the value as an unsigned byte.
   */
  if (ExprConstant != node->kind || mask != NaClGetExprUnsignedValue(node))
    return RegUnknown;
  DEBUG(NaClLog(LOG_INFO, "is mask constant\n"));

  return reg32;
}
Example #6
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");
}