summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2022-04-18 04:13:25 +0200
committerAdmiral H. Curtiss <pikachu025@gmail.com>2022-04-18 23:48:00 +0200
commitef760ee012a1a7a9d8997fecce4f0c9a7122e1bd (patch)
tree1e97fada9f3c2a759a5d6b78353fee2ad051385b /Source/Core
parent853cf4f8181dd0162e81ebcd61331d8765d089ca (diff)
Common/PointerWrap: Prevent reads/writes past the end of the buffer.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/ChunkFile.h34
-rw-r--r--Source/Core/Core/State.cpp28
-rw-r--r--Source/Core/UICommon/GameFileCache.cpp10
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.cpp6
4 files changed, 51 insertions, 27 deletions
diff --git a/Source/Core/Common/ChunkFile.h b/Source/Core/Common/ChunkFile.h
index e7791839db..9fd785459e 100644
--- a/Source/Core/Common/ChunkFile.h
+++ b/Source/Core/Common/ChunkFile.h
@@ -47,11 +47,16 @@ public:
};
private:
- u8** ptr;
+ u8** m_ptr_current;
+ u8* m_ptr_end;
Mode mode;
public:
- PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {}
+ PointerWrap(u8** ptr, size_t size, Mode mode_)
+ : m_ptr_current(ptr), m_ptr_end(*ptr + size), mode(mode_)
+ {
+ }
+
void SetMode(Mode mode_) { mode = mode_; }
Mode GetMode() const { return mode; }
template <typename K, class V>
@@ -209,8 +214,13 @@ public:
[[nodiscard]] u8* DoExternal(u32& count)
{
Do(count);
- u8* current = *ptr;
- *ptr += count;
+ u8* current = *m_ptr_current;
+ *m_ptr_current += count;
+ if (mode != MODE_MEASURE && *m_ptr_current > m_ptr_end)
+ {
+ // trying to read/write past the end of the buffer, prevent this
+ mode = MODE_MEASURE;
+ }
return current;
}
@@ -320,26 +330,32 @@ private:
DOLPHIN_FORCE_INLINE void DoVoid(void* data, u32 size)
{
+ if (mode != MODE_MEASURE && (*m_ptr_current + size) > m_ptr_end)
+ {
+ // trying to read/write past the end of the buffer, prevent this
+ mode = MODE_MEASURE;
+ }
+
switch (mode)
{
case MODE_READ:
- memcpy(data, *ptr, size);
+ memcpy(data, *m_ptr_current, size);
break;
case MODE_WRITE:
- memcpy(*ptr, data, size);
+ memcpy(*m_ptr_current, data, size);
break;
case MODE_MEASURE:
break;
case MODE_VERIFY:
- DEBUG_ASSERT_MSG(COMMON, !memcmp(data, *ptr, size),
+ DEBUG_ASSERT_MSG(COMMON, !memcmp(data, *m_ptr_current, size),
"Savestate verification failure: buf {} != {} (size {}).\n", fmt::ptr(data),
- fmt::ptr(*ptr), size);
+ fmt::ptr(*m_ptr_current), size);
break;
}
- *ptr += size;
+ *m_ptr_current += size;
}
};
diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp
index b1a3c70910..71e8642f06 100644
--- a/Source/Core/Core/State.cpp
+++ b/Source/Core/Core/State.cpp
@@ -225,8 +225,8 @@ void LoadFromBuffer(std::vector<u8>& buffer)
Core::RunOnCPUThread(
[&] {
- u8* ptr = &buffer[0];
- PointerWrap p(&ptr, PointerWrap::MODE_READ);
+ u8* ptr = buffer.data();
+ PointerWrap p(&ptr, buffer.size(), PointerWrap::MODE_READ);
DoState(p);
},
true);
@@ -237,14 +237,14 @@ void SaveToBuffer(std::vector<u8>& buffer)
Core::RunOnCPUThread(
[&] {
u8* ptr = nullptr;
- PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
+ PointerWrap p_measure(&ptr, 0, PointerWrap::MODE_MEASURE);
- DoState(p);
+ DoState(p_measure);
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
buffer.resize(buffer_size);
- ptr = &buffer[0];
- p.SetMode(PointerWrap::MODE_WRITE);
+ ptr = buffer.data();
+ PointerWrap p(&ptr, buffer_size, PointerWrap::MODE_WRITE);
DoState(p);
},
true);
@@ -412,20 +412,22 @@ void SaveAs(const std::string& filename, bool wait)
[&] {
// Measure the size of the buffer.
u8* ptr = nullptr;
- PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
- DoState(p);
+ PointerWrap p_measure(&ptr, 0, PointerWrap::MODE_MEASURE);
+ DoState(p_measure);
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
// Then actually do the write.
+ PointerWrap::Mode p_mode;
{
std::lock_guard lk(g_cs_current_buffer);
g_current_buffer.resize(buffer_size);
- ptr = &g_current_buffer[0];
- p.SetMode(PointerWrap::MODE_WRITE);
+ ptr = g_current_buffer.data();
+ PointerWrap p(&ptr, buffer_size, PointerWrap::MODE_WRITE);
DoState(p);
+ p_mode = p.GetMode();
}
- if (p.GetMode() == PointerWrap::MODE_WRITE)
+ if (p_mode == PointerWrap::MODE_WRITE)
{
Core::DisplayMessage("Saving State...", 1000);
@@ -588,8 +590,8 @@ void LoadAs(const std::string& filename)
if (!buffer.empty())
{
- u8* ptr = &buffer[0];
- PointerWrap p(&ptr, PointerWrap::MODE_READ);
+ u8* ptr = buffer.data();
+ PointerWrap p(&ptr, buffer.size(), PointerWrap::MODE_READ);
DoState(p);
loaded = true;
loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ);
diff --git a/Source/Core/UICommon/GameFileCache.cpp b/Source/Core/UICommon/GameFileCache.cpp
index 1040c24b2f..a41c07553c 100644
--- a/Source/Core/UICommon/GameFileCache.cpp
+++ b/Source/Core/UICommon/GameFileCache.cpp
@@ -230,14 +230,14 @@ bool GameFileCache::SyncCacheFile(bool save)
{
// Measure the size of the buffer.
u8* ptr = nullptr;
- PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
- DoState(&p);
+ PointerWrap p_measure(&ptr, 0, PointerWrap::MODE_MEASURE);
+ DoState(&p_measure);
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
// Then actually do the write.
std::vector<u8> buffer(buffer_size);
- ptr = &buffer[0];
- p.SetMode(PointerWrap::MODE_WRITE);
+ ptr = buffer.data();
+ PointerWrap p(&ptr, buffer_size, PointerWrap::MODE_WRITE);
DoState(&p, buffer_size);
if (f.WriteBytes(buffer.data(), buffer.size()))
success = true;
@@ -248,7 +248,7 @@ bool GameFileCache::SyncCacheFile(bool save)
if (!buffer.empty() && f.ReadBytes(buffer.data(), buffer.size()))
{
u8* ptr = buffer.data();
- PointerWrap p(&ptr, PointerWrap::MODE_READ);
+ PointerWrap p(&ptr, buffer.size(), PointerWrap::MODE_READ);
DoState(&p, buffer.size());
if (p.GetMode() == PointerWrap::MODE_READ)
success = true;
diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp
index 078abf10b1..b1c9ead97a 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/TextureCacheBase.cpp
@@ -459,6 +459,12 @@ void TextureCacheBase::SerializeTexture(AbstractTexture* tex, const TextureConfi
// needing to allocate/free an extra buffer.
u8* texture_data = p.DoExternal(total_size);
+ if (p.GetMode() == PointerWrap::MODE_MEASURE)
+ {
+ ERROR_LOG_FMT(VIDEO, "Couldn't acquire {} bytes for serializing texture.", total_size);
+ return;
+ }
+
if (!skip_readback)
{
// Save out each layer of the texture to the pointer.