mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-10-11 22:49:50 +00:00
VideoCommon: validate restored FIFO pointers
Save states restored video FIFO pointers from unchecked offsets. A crafted offset could place a pointer outside its backing allocation and turn the next gather-pipe copy into an out-of-bounds native write. Require pointer offsets to stay within their backing array and reject a state when either offset is invalid or the read pointer follows the write pointer.
This commit is contained in:
@@ -288,7 +288,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DoPointer(T*& x, T* const base)
|
||||
bool DoPointer(T*& x, T* const base, size_t count)
|
||||
{
|
||||
// pointers can be more than 2^31 apart, but you're using this function wrong if you need that
|
||||
// much range
|
||||
@@ -296,15 +296,23 @@ public:
|
||||
Do(offset);
|
||||
if (IsReadMode())
|
||||
{
|
||||
if (offset < 0 || static_cast<size_t>(offset) > count)
|
||||
{
|
||||
SetMeasureMode();
|
||||
return false;
|
||||
}
|
||||
x = base + offset;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DoPointer(void*& x, void* const base)
|
||||
bool DoPointer(void*& x, void* const base, size_t count)
|
||||
{
|
||||
auto* ptr = static_cast<u8*>(x);
|
||||
DoPointer(ptr, static_cast<u8*>(base));
|
||||
if (!DoPointer(ptr, static_cast<u8*>(base), count))
|
||||
return false;
|
||||
x = ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DoMarker(const std::string& prevName, u32 arbitraryNumber = 0x42)
|
||||
|
||||
@@ -54,9 +54,16 @@ void FifoManager::DoState(PointerWrap& p)
|
||||
{
|
||||
p.DoArray(m_video_buffer, FIFO_SIZE);
|
||||
u8* write_ptr = m_video_buffer_write_ptr;
|
||||
p.DoPointer(write_ptr, m_video_buffer);
|
||||
if (!p.DoPointer(write_ptr, m_video_buffer, FIFO_SIZE))
|
||||
return;
|
||||
m_video_buffer_write_ptr = write_ptr;
|
||||
p.DoPointer(m_video_buffer_read_ptr, m_video_buffer);
|
||||
if (!p.DoPointer(m_video_buffer_read_ptr, m_video_buffer, FIFO_SIZE))
|
||||
return;
|
||||
if (p.IsReadMode() && m_video_buffer_read_ptr > write_ptr)
|
||||
{
|
||||
p.SetMeasureMode();
|
||||
return;
|
||||
}
|
||||
if (p.IsReadMode() && m_use_deterministic_gpu_thread)
|
||||
{
|
||||
// We're good and paused, right?
|
||||
|
||||
Reference in New Issue
Block a user