1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:47:44 +00:00

UserspaceEmulator+LibX86: Start tracking uninitialized memory :^)

This patch introduces the concept of shadow bits. For every byte of
memory there is a corresponding shadow byte that contains metadata
about that memory.

Initially, the only metadata is whether the byte has been initialized
or not. That's represented by the least significant shadow bit.

Shadow bits travel together with regular values throughout the entire
CPU and MMU emulation. There are two main helper classes to facilitate
this: ValueWithShadow and ValueAndShadowReference.

ValueWithShadow<T> is basically a struct { T value; T shadow; } whereas
ValueAndShadowReference<T> is struct { T& value; T& shadow; }.

The latter is used as a wrapper around general-purpose registers, since
they can't use the plain ValueWithShadow memory as we need to be able
to address individual 8-bit and 16-bit subregisters (EAX, AX, AL, AH.)

Whenever a computation is made using uninitialized inputs, the result
is tainted and becomes uninitialized as well. This allows us to track
this state as it propagates throughout memory and registers.

This patch doesn't yet keep track of tainted flags, that will be an
important upcoming improvement to this.

I'm sure I've messed up some things here and there, but it seems to
basically work, so we have a place to start! :^)
This commit is contained in:
Andreas Kling 2020-07-21 02:29:59 +02:00
parent f2d3cc7325
commit be5f42adea
14 changed files with 1088 additions and 752 deletions

View file

@ -26,6 +26,7 @@
#pragma once
#include "ValueWithShadow.h"
#include <LibX86/Instruction.h>
#include <LibX86/Interpreter.h>
@ -77,71 +78,96 @@ public:
};
};
void push32(u32);
u32 pop32();
void push32(ValueWithShadow<u32>);
ValueWithShadow<u32> pop32();
void push16(u16);
u16 pop16();
void push16(ValueWithShadow<u16>);
ValueWithShadow<u16> pop16();
void push_string(const StringView&);
u16 segment(X86::SegmentRegister seg) const { return m_segment[(int)seg]; }
u16& segment(X86::SegmentRegister seg) { return m_segment[(int)seg]; }
u8& gpr8(X86::RegisterIndex8 reg)
ValueAndShadowReference<u8> gpr8(X86::RegisterIndex8 reg)
{
switch (reg) {
case X86::RegisterAL:
return m_gpr[X86::RegisterEAX].low_u8;
return { m_gpr[X86::RegisterEAX].low_u8, m_gpr_shadow[X86::RegisterEAX].low_u8 };
case X86::RegisterAH:
return m_gpr[X86::RegisterEAX].high_u8;
return { m_gpr[X86::RegisterEAX].high_u8, m_gpr_shadow[X86::RegisterEAX].high_u8 };
case X86::RegisterBL:
return m_gpr[X86::RegisterEBX].low_u8;
return { m_gpr[X86::RegisterEBX].low_u8, m_gpr_shadow[X86::RegisterEBX].low_u8 };
case X86::RegisterBH:
return m_gpr[X86::RegisterEBX].high_u8;
return { m_gpr[X86::RegisterEBX].high_u8, m_gpr_shadow[X86::RegisterEBX].high_u8 };
case X86::RegisterCL:
return m_gpr[X86::RegisterECX].low_u8;
return { m_gpr[X86::RegisterECX].low_u8, m_gpr_shadow[X86::RegisterECX].low_u8 };
case X86::RegisterCH:
return m_gpr[X86::RegisterECX].high_u8;
return { m_gpr[X86::RegisterECX].high_u8, m_gpr_shadow[X86::RegisterECX].high_u8 };
case X86::RegisterDL:
return m_gpr[X86::RegisterEDX].low_u8;
return { m_gpr[X86::RegisterEDX].low_u8, m_gpr_shadow[X86::RegisterEDX].low_u8 };
case X86::RegisterDH:
return m_gpr[X86::RegisterEDX].high_u8;
return { m_gpr[X86::RegisterEDX].high_u8, m_gpr_shadow[X86::RegisterEDX].high_u8 };
}
ASSERT_NOT_REACHED();
}
u8 gpr8(X86::RegisterIndex8 reg) const
ValueWithShadow<u8> const_gpr8(X86::RegisterIndex8 reg) const
{
switch (reg) {
case X86::RegisterAL:
return m_gpr[X86::RegisterEAX].low_u8;
return { m_gpr[X86::RegisterEAX].low_u8, m_gpr_shadow[X86::RegisterEAX].low_u8 };
case X86::RegisterAH:
return m_gpr[X86::RegisterEAX].high_u8;
return { m_gpr[X86::RegisterEAX].high_u8, m_gpr_shadow[X86::RegisterEAX].high_u8 };
case X86::RegisterBL:
return m_gpr[X86::RegisterEBX].low_u8;
return { m_gpr[X86::RegisterEBX].low_u8, m_gpr_shadow[X86::RegisterEBX].low_u8 };
case X86::RegisterBH:
return m_gpr[X86::RegisterEBX].high_u8;
return { m_gpr[X86::RegisterEBX].high_u8, m_gpr_shadow[X86::RegisterEBX].high_u8 };
case X86::RegisterCL:
return m_gpr[X86::RegisterECX].low_u8;
return { m_gpr[X86::RegisterECX].low_u8, m_gpr_shadow[X86::RegisterECX].low_u8 };
case X86::RegisterCH:
return m_gpr[X86::RegisterECX].high_u8;
return { m_gpr[X86::RegisterECX].high_u8, m_gpr_shadow[X86::RegisterECX].high_u8 };
case X86::RegisterDL:
return m_gpr[X86::RegisterEDX].low_u8;
return { m_gpr[X86::RegisterEDX].low_u8, m_gpr_shadow[X86::RegisterEDX].low_u8 };
case X86::RegisterDH:
return m_gpr[X86::RegisterEDX].high_u8;
return { m_gpr[X86::RegisterEDX].high_u8, m_gpr_shadow[X86::RegisterEDX].high_u8 };
}
ASSERT_NOT_REACHED();
}
u16 gpr16(X86::RegisterIndex16 reg) const { return m_gpr[reg].low_u16; }
u16& gpr16(X86::RegisterIndex16 reg) { return m_gpr[reg].low_u16; }
ValueWithShadow<u16> const_gpr16(X86::RegisterIndex16 reg) const
{
return { m_gpr[reg].low_u16, m_gpr_shadow[reg].low_u16 };
}
u32 gpr32(X86::RegisterIndex32 reg) const { return m_gpr[reg].full_u32; }
u32& gpr32(X86::RegisterIndex32 reg) { return m_gpr[reg].full_u32; }
ValueAndShadowReference<u16> gpr16(X86::RegisterIndex16 reg)
{
return { m_gpr[reg].low_u16, m_gpr_shadow[reg].low_u16 };
}
ValueWithShadow<u32> const_gpr32(X86::RegisterIndex32 reg) const
{
return { m_gpr[reg].full_u32, m_gpr_shadow[reg].full_u32 };
}
ValueAndShadowReference<u32> gpr32(X86::RegisterIndex32 reg)
{
return { m_gpr[reg].full_u32, m_gpr_shadow[reg].full_u32 };
}
template<typename T>
T gpr(unsigned register_index) const
ValueWithShadow<T> const_gpr(unsigned register_index) const
{
if constexpr (sizeof(T) == 1)
return const_gpr8((X86::RegisterIndex8)register_index);
if constexpr (sizeof(T) == 2)
return const_gpr16((X86::RegisterIndex16)register_index);
if constexpr (sizeof(T) == 4)
return const_gpr32((X86::RegisterIndex32)register_index);
}
template<typename T>
ValueAndShadowReference<T> gpr(unsigned register_index)
{
if constexpr (sizeof(T) == 1)
return gpr8((X86::RegisterIndex8)register_index);
@ -151,60 +177,49 @@ public:
return gpr32((X86::RegisterIndex32)register_index);
}
template<typename T>
T& gpr(unsigned register_index)
{
if constexpr (sizeof(T) == 1)
return gpr8((X86::RegisterIndex8)register_index);
if constexpr (sizeof(T) == 2)
return gpr16((X86::RegisterIndex16)register_index);
if constexpr (sizeof(T) == 4)
return gpr32((X86::RegisterIndex32)register_index);
}
u32 source_index(bool a32) const
ValueWithShadow<u32> source_index(bool a32) const
{
if (a32)
return esi();
return si();
return { si().value(), (u32)si().shadow() & 0xffff };
}
u32 destination_index(bool a32) const
ValueWithShadow<u32> destination_index(bool a32) const
{
if (a32)
return edi();
return di();
return { di().value(), (u32)di().shadow() & 0xffff };
}
u32 loop_index(bool a32) const
ValueWithShadow<u32> loop_index(bool a32) const
{
if (a32)
return ecx();
return cx();
return { cx().value(), (u32)cx().shadow() & 0xffff };
}
bool decrement_loop_index(bool a32)
{
if (a32) {
set_ecx(ecx() - 1);
return ecx() == 0;
set_ecx({ ecx().value() - 1, ecx().shadow() });
return ecx().value() == 0;
}
set_cx(cx() - 1);
return cx() == 0;
set_cx(ValueWithShadow<u16>(cx().value() - 1, cx().shadow()));
return cx().value() == 0;
}
ALWAYS_INLINE void step_source_index(bool a32, u32 step)
{
if (a32) {
if (df())
set_esi(esi() - step);
set_esi({ esi().value() - step, esi().shadow() });
else
set_esi(esi() + step);
set_esi({ esi().value() + step, esi().shadow() });
} else {
if (df())
set_si(si() - step);
set_si(ValueWithShadow<u16>(si().value() - step, si().shadow()));
else
set_si(si() + step);
set_si(ValueWithShadow<u16>(si().value() + step, si().shadow()));
}
}
@ -212,71 +227,70 @@ public:
{
if (a32) {
if (df())
set_edi(edi() - step);
set_edi({ edi().value() - step, edi().shadow() });
else
set_edi(edi() + step);
set_edi({ edi().value() + step, edi().shadow() });
} else {
if (df())
set_di(di() - step);
set_di(ValueWithShadow<u16>(di().value() - step, di().shadow()));
else
set_di(di() + step);
set_di(ValueWithShadow<u16>(di().value() + step, di().shadow()));
}
}
ValueWithShadow<u32> eax() const { return const_gpr32(X86::RegisterEAX); }
ValueWithShadow<u32> ebx() const { return const_gpr32(X86::RegisterEBX); }
ValueWithShadow<u32> ecx() const { return const_gpr32(X86::RegisterECX); }
ValueWithShadow<u32> edx() const { return const_gpr32(X86::RegisterEDX); }
ValueWithShadow<u32> esp() const { return const_gpr32(X86::RegisterESP); }
ValueWithShadow<u32> ebp() const { return const_gpr32(X86::RegisterEBP); }
ValueWithShadow<u32> esi() const { return const_gpr32(X86::RegisterESI); }
ValueWithShadow<u32> edi() const { return const_gpr32(X86::RegisterEDI); }
u32 eax() const { return gpr32(X86::RegisterEAX); }
u32 ebx() const { return gpr32(X86::RegisterEBX); }
u32 ecx() const { return gpr32(X86::RegisterECX); }
u32 edx() const { return gpr32(X86::RegisterEDX); }
u32 esp() const { return gpr32(X86::RegisterESP); }
u32 ebp() const { return gpr32(X86::RegisterEBP); }
u32 esi() const { return gpr32(X86::RegisterESI); }
u32 edi() const { return gpr32(X86::RegisterEDI); }
ValueWithShadow<u16> ax() const { return const_gpr16(X86::RegisterAX); }
ValueWithShadow<u16> bx() const { return const_gpr16(X86::RegisterBX); }
ValueWithShadow<u16> cx() const { return const_gpr16(X86::RegisterCX); }
ValueWithShadow<u16> dx() const { return const_gpr16(X86::RegisterDX); }
ValueWithShadow<u16> sp() const { return const_gpr16(X86::RegisterSP); }
ValueWithShadow<u16> bp() const { return const_gpr16(X86::RegisterBP); }
ValueWithShadow<u16> si() const { return const_gpr16(X86::RegisterSI); }
ValueWithShadow<u16> di() const { return const_gpr16(X86::RegisterDI); }
u16 ax() const { return gpr16(X86::RegisterAX); }
u16 bx() const { return gpr16(X86::RegisterBX); }
u16 cx() const { return gpr16(X86::RegisterCX); }
u16 dx() const { return gpr16(X86::RegisterDX); }
u16 sp() const { return gpr16(X86::RegisterSP); }
u16 bp() const { return gpr16(X86::RegisterBP); }
u16 si() const { return gpr16(X86::RegisterSI); }
u16 di() const { return gpr16(X86::RegisterDI); }
ValueWithShadow<u8> al() const { return const_gpr8(X86::RegisterAL); }
ValueWithShadow<u8> ah() const { return const_gpr8(X86::RegisterAH); }
ValueWithShadow<u8> bl() const { return const_gpr8(X86::RegisterBL); }
ValueWithShadow<u8> bh() const { return const_gpr8(X86::RegisterBH); }
ValueWithShadow<u8> cl() const { return const_gpr8(X86::RegisterCL); }
ValueWithShadow<u8> ch() const { return const_gpr8(X86::RegisterCH); }
ValueWithShadow<u8> dl() const { return const_gpr8(X86::RegisterDL); }
ValueWithShadow<u8> dh() const { return const_gpr8(X86::RegisterDH); }
u8 al() const { return gpr8(X86::RegisterAL); }
u8 ah() const { return gpr8(X86::RegisterAH); }
u8 bl() const { return gpr8(X86::RegisterBL); }
u8 bh() const { return gpr8(X86::RegisterBH); }
u8 cl() const { return gpr8(X86::RegisterCL); }
u8 ch() const { return gpr8(X86::RegisterCH); }
u8 dl() const { return gpr8(X86::RegisterDL); }
u8 dh() const { return gpr8(X86::RegisterDH); }
void set_eax(ValueWithShadow<u32> value) { gpr32(X86::RegisterEAX) = value; }
void set_ebx(ValueWithShadow<u32> value) { gpr32(X86::RegisterEBX) = value; }
void set_ecx(ValueWithShadow<u32> value) { gpr32(X86::RegisterECX) = value; }
void set_edx(ValueWithShadow<u32> value) { gpr32(X86::RegisterEDX) = value; }
void set_esp(ValueWithShadow<u32> value) { gpr32(X86::RegisterESP) = value; }
void set_ebp(ValueWithShadow<u32> value) { gpr32(X86::RegisterEBP) = value; }
void set_esi(ValueWithShadow<u32> value) { gpr32(X86::RegisterESI) = value; }
void set_edi(ValueWithShadow<u32> value) { gpr32(X86::RegisterEDI) = value; }
void set_eax(u32 value) { gpr32(X86::RegisterEAX) = value; }
void set_ebx(u32 value) { gpr32(X86::RegisterEBX) = value; }
void set_ecx(u32 value) { gpr32(X86::RegisterECX) = value; }
void set_edx(u32 value) { gpr32(X86::RegisterEDX) = value; }
void set_esp(u32 value) { gpr32(X86::RegisterESP) = value; }
void set_ebp(u32 value) { gpr32(X86::RegisterEBP) = value; }
void set_esi(u32 value) { gpr32(X86::RegisterESI) = value; }
void set_edi(u32 value) { gpr32(X86::RegisterEDI) = value; }
void set_ax(ValueWithShadow<u16> value) { gpr16(X86::RegisterAX) = value; }
void set_bx(ValueWithShadow<u16> value) { gpr16(X86::RegisterBX) = value; }
void set_cx(ValueWithShadow<u16> value) { gpr16(X86::RegisterCX) = value; }
void set_dx(ValueWithShadow<u16> value) { gpr16(X86::RegisterDX) = value; }
void set_sp(ValueWithShadow<u16> value) { gpr16(X86::RegisterSP) = value; }
void set_bp(ValueWithShadow<u16> value) { gpr16(X86::RegisterBP) = value; }
void set_si(ValueWithShadow<u16> value) { gpr16(X86::RegisterSI) = value; }
void set_di(ValueWithShadow<u16> value) { gpr16(X86::RegisterDI) = value; }
void set_ax(u16 value) { gpr16(X86::RegisterAX) = value; }
void set_bx(u16 value) { gpr16(X86::RegisterBX) = value; }
void set_cx(u16 value) { gpr16(X86::RegisterCX) = value; }
void set_dx(u16 value) { gpr16(X86::RegisterDX) = value; }
void set_sp(u16 value) { gpr16(X86::RegisterSP) = value; }
void set_bp(u16 value) { gpr16(X86::RegisterBP) = value; }
void set_si(u16 value) { gpr16(X86::RegisterSI) = value; }
void set_di(u16 value) { gpr16(X86::RegisterDI) = value; }
void set_al(u8 value) { gpr8(X86::RegisterAL) = value; }
void set_ah(u8 value) { gpr8(X86::RegisterAH) = value; }
void set_bl(u8 value) { gpr8(X86::RegisterBL) = value; }
void set_bh(u8 value) { gpr8(X86::RegisterBH) = value; }
void set_cl(u8 value) { gpr8(X86::RegisterCL) = value; }
void set_ch(u8 value) { gpr8(X86::RegisterCH) = value; }
void set_dl(u8 value) { gpr8(X86::RegisterDL) = value; }
void set_dh(u8 value) { gpr8(X86::RegisterDH) = value; }
void set_al(ValueWithShadow<u8> value) { gpr8(X86::RegisterAL) = value; }
void set_ah(ValueWithShadow<u8> value) { gpr8(X86::RegisterAH) = value; }
void set_bl(ValueWithShadow<u8> value) { gpr8(X86::RegisterBL) = value; }
void set_bh(ValueWithShadow<u8> value) { gpr8(X86::RegisterBH) = value; }
void set_cl(ValueWithShadow<u8> value) { gpr8(X86::RegisterCL) = value; }
void set_ch(ValueWithShadow<u8> value) { gpr8(X86::RegisterCH) = value; }
void set_dl(ValueWithShadow<u8> value) { gpr8(X86::RegisterDL) = value; }
void set_dh(ValueWithShadow<u8> value) { gpr8(X86::RegisterDH) = value; }
bool of() const { return m_eflags & Flags::OF; }
bool sf() const { return m_eflags & Flags::SF; }
@ -333,12 +347,12 @@ public:
u16 es() const { return m_segment[(int)X86::SegmentRegister::ES]; }
u16 ss() const { return m_segment[(int)X86::SegmentRegister::SS]; }
u8 read_memory8(X86::LogicalAddress);
u16 read_memory16(X86::LogicalAddress);
u32 read_memory32(X86::LogicalAddress);
ValueWithShadow<u8> read_memory8(X86::LogicalAddress);
ValueWithShadow<u16> read_memory16(X86::LogicalAddress);
ValueWithShadow<u32> read_memory32(X86::LogicalAddress);
template<typename T>
T read_memory(X86::LogicalAddress address)
ValueWithShadow<T> read_memory(X86::LogicalAddress address)
{
if constexpr (sizeof(T) == 1)
return read_memory8(address);
@ -348,12 +362,12 @@ public:
return read_memory32(address);
}
void write_memory8(X86::LogicalAddress, u8);
void write_memory16(X86::LogicalAddress, u16);
void write_memory32(X86::LogicalAddress, u32);
void write_memory8(X86::LogicalAddress, ValueWithShadow<u8>);
void write_memory16(X86::LogicalAddress, ValueWithShadow<u16>);
void write_memory32(X86::LogicalAddress, ValueWithShadow<u32>);
template<typename T>
void write_memory(X86::LogicalAddress address, T data)
void write_memory(X86::LogicalAddress address, ValueWithShadow<T> data)
{
if constexpr (sizeof(T) == 1)
return write_memory8(address, data);
@ -896,12 +910,16 @@ private:
template<bool update_dest, typename Op>
void generic_RM16_imm8(Op, const X86::Instruction&);
template<bool update_dest, typename Op>
void generic_RM16_unsigned_imm8(Op, const X86::Instruction&);
template<bool update_dest, typename Op>
void generic_RM16_reg16(Op, const X86::Instruction&);
template<bool update_dest, typename Op>
void generic_RM32_imm32(Op, const X86::Instruction&);
template<bool update_dest, typename Op>
void generic_RM32_imm8(Op, const X86::Instruction&);
template<bool update_dest, typename Op>
void generic_RM32_unsigned_imm8(Op, const X86::Instruction&);
template<bool update_dest, typename Op>
void generic_RM32_reg32(Op, const X86::Instruction&);
template<bool update_dest, typename Op>
void generic_RM8_imm8(Op, const X86::Instruction&);
@ -935,6 +953,8 @@ private:
Emulator& m_emulator;
PartAddressableRegister m_gpr[8];
PartAddressableRegister m_gpr_shadow[8];
u16 m_segment[8] { 0 };
u32 m_eflags { 0 };