/* 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"); }
/* 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); } }
char* NaClInstStateInstructionToString(struct NaClInstState* state) { /* Print to a memory buffer, and then duplicate. */ struct GioMemoryFile filemem; struct Gio *file = (struct Gio*) &filemem; char buffer[MAX_INST_TEXT_SIZE]; char* result; /* Note: Be sure to leave an extra byte to add the null character to * the end of the string. */ GioMemoryFileCtor(&filemem, buffer, MAX_INST_TEXT_SIZE - 1); NaClInstStateInstPrint(file, state); buffer[filemem.curpos < MAX_INST_TEXT_SIZE ? filemem.curpos : MAX_INST_TEXT_SIZE] ='\0'; result = strdup(buffer); GioMemoryFileDtor(file); return result; }
/* 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"); }