コード例 #1
0
/*
 * Validate that two nacljmps are byte-for-byte identical.  Note that
 * one of the individual jumps must be validated in isolation with
 * ValidateIndirect5() before this is called.
 */
void ValidateIndirect5Replacement(const struct NCDecoderState *mstate_old,
                                  const struct NCDecoderState *mstate_new) {
  do {
    /* check that the and-guard is 3 bytes and bit-for-bit identical */
    struct NCDecoderState *andinst_old = PreviousInst(mstate_old, -1);
    struct NCDecoderState *andinst_new = PreviousInst(mstate_new, -1);
    if (andinst_old->inst.length != 3) break;
    if (andinst_new->inst.length != 3) break;
    if (memcmp(andinst_old->inst.maddr, andinst_new->inst.maddr, 3) != 0) break;

    /* check that the indirect-jmp is 2 bytes and bit-for-bit identical */
    if (mstate_old->inst.length != 2) break;
    if (mstate_new->inst.length != 2) break;
    if (memcmp(mstate_old->inst.maddr, mstate_new->inst.maddr, 2) != 0) break;

    return;
  } while (0);
  BadInstructionError(mstate_new,
                      "Replacement indirect jump must match original");
  Stats_UnsafeIndirect(mstate_new->vstate);
}
コード例 #2
0
/*
 * The NaCl five-byte safe indirect calling sequence looks like this:
 *   83 e0 e0                 and  $0xe0,%eax
 *   ff d0                    call *%eax
 * The call may be replaced with a ff e0 jmp. Any register may
 * be used, not just eax. The validator requires exactly this
 * sequence.
 * Note: The code above assumes 32-bit alignment. Change e0 as appropriate
 * if a different alignment is used.
 */
static void ValidateIndirect5(const NCDecoderInst *dinst) {
  NCInstBytesPtr jmpopcode;
  NCInstBytesPtr andopcode;
  uint8_t               mrm;
  uint8_t               targetreg;
  const uint8_t         kReg_ESP = 4;
  NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate);

  struct NCDecoderInst *andinst = PreviousInst(dinst, 1);
  if ((andinst == NULL) || (andinst->inst.bytes.length != 3)) {
    NCBadInstructionError(dinst, "Unsafe indirect jump");
    NCStatsUnsafeIndirect(vstate);
    return;
  }
  /* note: no prefixbytes allowed */
  NCInstBytesPtrInitInc(&jmpopcode, &dinst->inst_bytes, 0);
  /* note: no prefixbytes allowed */
  NCInstBytesPtrInitInc(&andopcode, &andinst->inst_bytes, 0);
  mrm = NCInstBytesByteInline(&jmpopcode, 1);
  /* Note that the modrm_rm field holds the
   * target addr the modrm_reg is the opcode.
   */
  targetreg = modrm_rmInline(mrm);
  NCStatsCheckTarget(vstate);
  NCStatsTargetIndirect(vstate);
  do {
    /* no prefix bytes allowed */
    if (dinst->inst.prefixbytes != 0) break;
    if (dinst->inst.prefixbytes != 0) break;
    /* Check all the opcodes. */
    /* In GROUP5, 2 => call, 4 => jmp */
    if (NCInstBytesByteInline(&jmpopcode, 0) != 0xff) break;
    if ((modrm_regInline(mrm) != 2) && (modrm_regInline(mrm) != 4)) break;
    /* Issue 32: disallow unsafe call/jump indirection */
    /* example:    ff 12     call (*edx)               */
    /* Reported by defend.the.world on 11 Dec 2008     */
    if (modrm_modInline(mrm) != 3) break;
    if (targetreg == kReg_ESP) break;
    if (NCInstBytesByteInline(&andopcode, 0) != 0x83) break;
    /* check modrm bytes of or and and instructions */
    if (NCInstBytesByteInline(&andopcode, 1) != (0xe0 | targetreg)) break;
    /* check mask */
    if (NCInstBytesByteInline(&andopcode, 2) !=
        (0x0ff & ~vstate->bundle_mask)) break;
    /* All checks look good. Make the sequence 'atomic.' */
    ForgetInstructionBoundary(dinst, vstate);
    /* as a courtesy, check call alignment correctness */
    if (modrm_regInline(mrm) == 2) ValidateCallAlignment(dinst);
    return;
  } while (0);
  NCBadInstructionError(dinst, "Unsafe indirect jump");
  NCStatsUnsafeIndirect(vstate);
}
コード例 #3
0
/*
 * Validate that two nacljmps are byte-for-byte identical.  Note that
 * one of the individual jumps must be validated in isolation with
 * ValidateIndirect5() before this is called.
 */
static void ValidateIndirect5Replacement(NCDecoderInst *dinst_old,
                                         NCDecoderInst *dinst_new) {
  do {
    /* check that the and-guard is 3 bytes and bit-for-bit identical */
    NCDecoderInst *andinst_old = PreviousInst(dinst_old, 1);
    NCDecoderInst *andinst_new = PreviousInst(dinst_new, 1);
    if ((andinst_old == NULL) || (andinst_old->inst.bytes.length != 3)) break;
    if ((andinst_new == NULL) || (andinst_new->inst.bytes.length != 3)) break;
    if (memcmp(andinst_old->inst.bytes.byte,
               andinst_new->inst.bytes.byte, 3) != 0) break;

    /* check that the indirect-jmp is 2 bytes and bit-for-bit identical */
    if (dinst_old->inst.bytes.length != 2) break;
    if (dinst_new->inst.bytes.length != 2) break;
    if (memcmp(dinst_old->inst.bytes.byte,
               dinst_new->inst.bytes.byte, 2) != 0) break;

    return;
  } while (0);
  NCBadInstructionError(dinst_new,
                        "Replacement indirect jump must match original");
  NCStatsUnsafeIndirect(NCVALIDATOR_STATE_DOWNCAST(dinst_new->dstate));
}
コード例 #4
0
/*
 * The NaCl five-byte safe indirect calling sequence looks like this:
 *   83 e0 f0                 and  $0xfffffff0,%eax
 *   ff d0                    call *%eax
 * The call may be replaced with a ff e0 jmp. Any register may
 * be used, not just eax. The validator requires exactly this
 * sequence.
 * TODO(brad): validate or write the masks.
 */
static void ValidateIndirect5(const struct NCDecoderState *mstate) {
  uint8_t               *jmpopcode;
  uint8_t               *andopcode;
  uint8_t               mrm;
  uint8_t               targetreg;
  const uint8_t         kReg_ESP = 4;

  struct NCDecoderState *andinst = PreviousInst(mstate, -1);
  assert(andinst != NULL);
  if (andinst->inst.length == 0) {
    BadInstructionError(mstate, "Unsafe indirect jump");
    Stats_UnsafeIndirect(mstate->vstate);
    return;
  }
  jmpopcode = mstate->inst.maddr;   /* note: no prefixbytes allowed */
  andopcode = andinst->inst.maddr;  /* note: no prefixbytes allowed */
  mrm = jmpopcode[1];
  targetreg = modrm_rm(mrm);  /* Note that the modrm_rm field holds the   */
                              /* target addr the modrm_reg is the opcode. */

  Stats_CheckTarget(mstate->vstate);
  Stats_TargetIndirect(mstate->vstate);
  do {
    /* no prefix bytes allowed */
    if (mstate->inst.prefixbytes != 0) break;
    if (andinst->inst.prefixbytes != 0) break;
    /* Check all the opcodes. */
    /* In GROUP5, 2 => call, 4 => jmp */
    if (jmpopcode[0] != 0xff) break;
    if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
    /* Issue 32: disallow unsafe call/jump indirection */
    /* example:    ff 12     call (*edx)               */
    /* Reported by defend.the.world on 11 Dec 2008     */
    if (modrm_mod(mrm) != 3) break;
    if (targetreg == kReg_ESP) break;
    if (andopcode[0] != 0x83) break;
    /* check modrm bytes of or and and instructions */
    if (andopcode[1] != (0xe0 | targetreg)) break;
    /* check mask */
    if (andopcode[2] != (0x0ff & ~mstate->vstate->alignmask)) break;
    /* All checks look good. Make the sequence 'atomic.' */
    ForgetIP(mstate->inst.vaddr, mstate->vstate);
    /* as a courtesy, check call alignment correctness */
    if (modrm_reg(mrm) == 2) ValidateCallAlignment(mstate);
    return;
  } while (0);
  BadInstructionError(mstate, "Unsafe indirect jump");
  Stats_UnsafeIndirect(mstate->vstate);
}