Cheats: Fix possible OOB reads in malformed instructions

pull/3782/head
Stenzek 2 months ago
parent 2688a1dfcd
commit e48b3e302f
No known key found for this signature in database

@ -2677,6 +2677,12 @@ void Cheats::GamesharkCheatCode::Apply() const
case InstructionCode::ExtConstantForceRange16:
{
if ((index + 1) >= count) [[unlikely]]
{
ERROR_LOG("Incomplete ExtConstantForceRange16 instruction");
return;
}
const u16 min = Truncate16(inst.value32 & 0x0000FFFFu);
const u16 max = Truncate16((inst.value32 & 0xFFFF0000u) >> 16);
const u16 value = DoMemoryRead<u16>(inst.address);
@ -2708,12 +2714,12 @@ void Cheats::GamesharkCheatCode::Apply() const
case InstructionCode::ExtFindAndReplace:
{
if ((index + 4) >= instructions.size())
if ((index + 4) >= count) [[unlikely]]
{
ERROR_LOG("Incomplete find/replace instruction");
ERROR_LOG("Incomplete ExtFindAndReplace instruction");
return;
}
const Instruction& inst2 = instructions[index + 1];
const Instruction& inst3 = instructions[index + 2];
const Instruction& inst4 = instructions[index + 3];
@ -3132,70 +3138,60 @@ void Cheats::GamesharkCheatCode::Apply() const
{
conditions_check = true;
for (int i = 1; totalConds >= i; index++, i++)
for (int i = 1; totalConds >= i && index < count; index++, i++)
{
switch (instructions[index].code)
const Instruction& nexti = instructions[index];
switch (nexti.code)
{
case InstructionCode::CompareEqual16: // D0
conditions_check &=
(DoMemoryRead<u16>(instructions[index].address) == instructions[index].value16);
conditions_check &= (DoMemoryRead<u16>(nexti.address) == nexti.value16);
break;
case InstructionCode::CompareNotEqual16: // D1
conditions_check &=
(DoMemoryRead<u16>(instructions[index].address) != instructions[index].value16);
conditions_check &= (DoMemoryRead<u16>(nexti.address) != nexti.value16);
break;
case InstructionCode::CompareLess16: // D2
conditions_check &=
(DoMemoryRead<u16>(instructions[index].address) < instructions[index].value16);
conditions_check &= (DoMemoryRead<u16>(nexti.address) < nexti.value16);
break;
case InstructionCode::CompareGreater16: // D3
conditions_check &=
(DoMemoryRead<u16>(instructions[index].address) > instructions[index].value16);
conditions_check &= (DoMemoryRead<u16>(nexti.address) > nexti.value16);
break;
case InstructionCode::CompareEqual8: // E0
conditions_check &= (DoMemoryRead<u8>(instructions[index].address) == instructions[index].value8);
conditions_check &= (DoMemoryRead<u8>(nexti.address) == nexti.value8);
break;
case InstructionCode::CompareNotEqual8: // E1
conditions_check &= (DoMemoryRead<u8>(instructions[index].address) != instructions[index].value8);
conditions_check &= (DoMemoryRead<u8>(nexti.address) != nexti.value8);
break;
case InstructionCode::CompareLess8: // E2
conditions_check &= (DoMemoryRead<u8>(instructions[index].address) < instructions[index].value8);
conditions_check &= (DoMemoryRead<u8>(nexti.address) < nexti.value8);
break;
case InstructionCode::CompareGreater8: // E3
conditions_check &= (DoMemoryRead<u8>(instructions[index].address) > instructions[index].value8);
conditions_check &= (DoMemoryRead<u8>(nexti.address) > nexti.value8);
break;
case InstructionCode::ExtCompareEqual32: // A0
conditions_check &=
(DoMemoryRead<u32>(instructions[index].address) == instructions[index].value32);
conditions_check &= (DoMemoryRead<u32>(nexti.address) == nexti.value32);
break;
case InstructionCode::ExtCompareNotEqual32: // A1
conditions_check &=
(DoMemoryRead<u32>(instructions[index].address) != instructions[index].value32);
conditions_check &= (DoMemoryRead<u32>(nexti.address) != nexti.value32);
break;
case InstructionCode::ExtCompareLess32: // A2
conditions_check &=
(DoMemoryRead<u32>(instructions[index].address) < instructions[index].value32);
conditions_check &= (DoMemoryRead<u32>(nexti.address) < nexti.value32);
break;
case InstructionCode::ExtCompareGreater32: // A3
conditions_check &=
(DoMemoryRead<u32>(instructions[index].address) > instructions[index].value32);
conditions_check &= (DoMemoryRead<u32>(nexti.address) > nexti.value32);
break;
case InstructionCode::ExtCompareBitsSet8: // E4 Internal to F6
conditions_check &=
(instructions[index].value8 ==
(DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8));
conditions_check &= (nexti.value8 == (DoMemoryRead<u8>(nexti.address) & nexti.value8));
break;
case InstructionCode::ExtCompareBitsClear8: // E5 Internal to F6
conditions_check &=
((DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8) == 0);
conditions_check &= ((DoMemoryRead<u8>(nexti.address) & nexti.value8) == 0);
break;
case InstructionCode::ExtBitCompareButtons: // D7
{
const u32 frame_compare_value = instructions[index].address & 0xFFFFu;
const u8 cht_reg_no = Truncate8((instructions[index].value32 & 0xFF000000u) >> 24);
const bool bit_comparison_type = ((instructions[index].address & 0x100000u) >> 20);
const u8 frame_comparison = Truncate8((instructions[index].address & 0xF0000u) >> 16);
const u32 check_value = (instructions[index].value32 & 0xFFFFFFu);
const u32 frame_compare_value = nexti.address & 0xFFFFu;
const u8 cht_reg_no = Truncate8((nexti.value32 & 0xFF000000u) >> 24);
const bool bit_comparison_type = ((nexti.address & 0x100000u) >> 20);
const u8 frame_comparison = Truncate8((nexti.address & 0xF0000u) >> 16);
const u32 check_value = (nexti.value32 & 0xFFFFFFu);
const u32 value1 = GetControllerButtonBits();
const u32 value2 = GetControllerAnalogBits();
u32 value = value1 | value2;
@ -3205,22 +3201,24 @@ void Cheats::GamesharkCheatCode::Apply() const
(bit_comparison_type == true && check_value != (value & check_value))) // Check Bits are clear
{
cht_register[cht_reg_no] += 1;
const u32 cht_register_value = cht_register[cht_reg_no];
switch (frame_comparison)
{
case 0x0: // No comparison on frame count, just do it
conditions_check &= true;
break;
case 0x1: // Check if frame_compare_value == current count
conditions_check &= (cht_register[cht_reg_no] == frame_compare_value);
conditions_check &= (cht_register_value == frame_compare_value);
break;
case 0x2: // Check if frame_compare_value < current count
conditions_check &= (cht_register[cht_reg_no] < frame_compare_value);
conditions_check &= (cht_register_value < frame_compare_value);
break;
case 0x3: // Check if frame_compare_value > current count
conditions_check &= (cht_register[cht_reg_no] > frame_compare_value);
conditions_check &= (cht_register_value > frame_compare_value);
break;
case 0x4: // Check if frame_compare_value != current count
conditions_check &= (cht_register[cht_reg_no] != frame_compare_value);
conditions_check &= (cht_register_value != frame_compare_value);
break;
default:
conditions_check &= false;
@ -3244,70 +3242,60 @@ void Cheats::GamesharkCheatCode::Apply() const
{
conditions_check = false;
for (int i = 1; totalConds >= i; index++, i++)
for (int i = 1; totalConds >= i && index < count; index++, i++)
{
switch (instructions[index].code)
const Instruction& nexti = instructions[index];
switch (nexti.code)
{
case InstructionCode::CompareEqual16: // D0
conditions_check |=
(DoMemoryRead<u16>(instructions[index].address) == instructions[index].value16);
conditions_check |= (DoMemoryRead<u16>(nexti.address) == nexti.value16);
break;
case InstructionCode::CompareNotEqual16: // D1
conditions_check |=
(DoMemoryRead<u16>(instructions[index].address) != instructions[index].value16);
conditions_check |= (DoMemoryRead<u16>(nexti.address) != nexti.value16);
break;
case InstructionCode::CompareLess16: // D2
conditions_check |=
(DoMemoryRead<u16>(instructions[index].address) < instructions[index].value16);
conditions_check |= (DoMemoryRead<u16>(nexti.address) < nexti.value16);
break;
case InstructionCode::CompareGreater16: // D3
conditions_check |=
(DoMemoryRead<u16>(instructions[index].address) > instructions[index].value16);
conditions_check |= (DoMemoryRead<u16>(nexti.address) > nexti.value16);
break;
case InstructionCode::CompareEqual8: // E0
conditions_check |= (DoMemoryRead<u8>(instructions[index].address) == instructions[index].value8);
conditions_check |= (DoMemoryRead<u8>(nexti.address) == nexti.value8);
break;
case InstructionCode::CompareNotEqual8: // E1
conditions_check |= (DoMemoryRead<u8>(instructions[index].address) != instructions[index].value8);
conditions_check |= (DoMemoryRead<u8>(nexti.address) != nexti.value8);
break;
case InstructionCode::CompareLess8: // E2
conditions_check |= (DoMemoryRead<u8>(instructions[index].address) < instructions[index].value8);
conditions_check |= (DoMemoryRead<u8>(nexti.address) < nexti.value8);
break;
case InstructionCode::CompareGreater8: // E3
conditions_check |= (DoMemoryRead<u8>(instructions[index].address) > instructions[index].value8);
conditions_check |= (DoMemoryRead<u8>(nexti.address) > nexti.value8);
break;
case InstructionCode::ExtCompareEqual32: // A0
conditions_check |=
(DoMemoryRead<u32>(instructions[index].address) == instructions[index].value32);
conditions_check |= (DoMemoryRead<u32>(nexti.address) == nexti.value32);
break;
case InstructionCode::ExtCompareNotEqual32: // A1
conditions_check |=
(DoMemoryRead<u32>(instructions[index].address) != instructions[index].value32);
conditions_check |= (DoMemoryRead<u32>(nexti.address) != nexti.value32);
break;
case InstructionCode::ExtCompareLess32: // A2
conditions_check |=
(DoMemoryRead<u32>(instructions[index].address) < instructions[index].value32);
conditions_check |= (DoMemoryRead<u32>(nexti.address) < nexti.value32);
break;
case InstructionCode::ExtCompareGreater32: // A3
conditions_check |=
(DoMemoryRead<u32>(instructions[index].address) > instructions[index].value32);
conditions_check |= (DoMemoryRead<u32>(nexti.address) > nexti.value32);
break;
case InstructionCode::ExtCompareBitsSet8: // E4 Internal to F6
conditions_check |=
(instructions[index].value8 ==
(DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8));
conditions_check |= (nexti.value8 == (DoMemoryRead<u8>(nexti.address) & nexti.value8));
break;
case InstructionCode::ExtCompareBitsClear8: // E5 Internal to F6
conditions_check |=
((DoMemoryRead<u8>(instructions[index].address) & instructions[index].value8) == 0);
conditions_check |= ((DoMemoryRead<u8>(nexti.address) & nexti.value8) == 0);
break;
case InstructionCode::ExtBitCompareButtons: // D7
{
const u32 frame_compare_value = instructions[index].address & 0xFFFFu;
const u8 cht_reg_no = Truncate8((instructions[index].value32 & 0xFF000000u) >> 24);
const bool bit_comparison_type = ((instructions[index].address & 0x100000u) >> 20);
const u8 frame_comparison = Truncate8((instructions[index].address & 0xF0000u) >> 16);
const u32 check_value = (instructions[index].value32 & 0xFFFFFFu);
const u32 frame_compare_value = nexti.address & 0xFFFFu;
const u8 cht_reg_no = Truncate8((nexti.value32 & 0xFF000000u) >> 24);
const bool bit_comparison_type = ((nexti.address & 0x100000u) >> 20);
const u8 frame_comparison = Truncate8((nexti.address & 0xF0000u) >> 16);
const u32 check_value = (nexti.value32 & 0xFFFFFFu);
const u32 value1 = GetControllerButtonBits();
const u32 value2 = GetControllerAnalogBits();
u32 value = value1 | value2;
@ -3317,22 +3305,24 @@ void Cheats::GamesharkCheatCode::Apply() const
(bit_comparison_type == true && check_value != (value & check_value))) // Check Bits are clear
{
cht_register[cht_reg_no] += 1;
const u32 cht_register_value = cht_register[cht_reg_no];
switch (frame_comparison)
{
case 0x0: // No comparison on frame count, just do it
conditions_check |= true;
break;
case 0x1: // Check if frame_compare_value == current count
conditions_check |= (cht_register[cht_reg_no] == frame_compare_value);
conditions_check |= (cht_register_value == frame_compare_value);
break;
case 0x2: // Check if frame_compare_value < current count
conditions_check |= (cht_register[cht_reg_no] < frame_compare_value);
conditions_check |= (cht_register_value < frame_compare_value);
break;
case 0x3: // Check if frame_compare_value > current count
conditions_check |= (cht_register[cht_reg_no] > frame_compare_value);
conditions_check |= (cht_register_value > frame_compare_value);
break;
case 0x4: // Check if frame_compare_value != current count
conditions_check |= (cht_register[cht_reg_no] != frame_compare_value);
conditions_check |= (cht_register_value != frame_compare_value);
break;
default:
conditions_check |= false;
@ -3374,6 +3364,9 @@ void Cheats::GamesharkCheatCode::Apply() const
const u64 bits = instructions[index++].bits;
if (bits == separator_value)
{
if (index >= count) [[unlikely]]
break;
const u64 bits_ahead = instructions[index].bits;
if ((bits_ahead & 0xFFFFFF00u) == elseif_value)
{
@ -3997,9 +3990,9 @@ void Cheats::GamesharkCheatCode::Apply() const
case InstructionCode::Slide:
{
if ((index + 1) >= instructions.size())
if ((index + 1) >= count) [[unlikely]]
{
ERROR_LOG("Incomplete slide instruction");
ERROR_LOG("Incomplete Slide instruction");
return;
}
@ -4049,9 +4042,9 @@ void Cheats::GamesharkCheatCode::Apply() const
case InstructionCode::ExtImprovedSlide:
{
if ((index + 1) >= instructions.size())
if ((index + 1) >= count) [[unlikely]]
{
ERROR_LOG("Incomplete slide instruction");
ERROR_LOG("Incomplete ExtImprovedSlide instruction");
return;
}
@ -4217,9 +4210,9 @@ void Cheats::GamesharkCheatCode::Apply() const
case InstructionCode::MemoryCopy:
{
if ((index + 1) >= instructions.size())
if ((index + 1) >= count)
{
ERROR_LOG("Incomplete memory copy instruction");
ERROR_LOG("Incomplete MemoryCopy instruction");
return;
}

Loading…
Cancel
Save