[Lldb-commits] [lldb] [lldb] Bounds check minidump location descriptors (PR #223911)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Tue Sep 15 22:16:28 PDT 2026
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/223911
MinidumpParser::GetModuleUUID sliced the file with the RVA and DataSize taken straight from a module's CvRecord. ArrayRef::slice asserts, but a build without assertions still reads out of bounds.
Route both through MinidumpFile::getRawData, which range checks in 64 bits, and log the error rather than returning a slice that looks valid.
rdar://186889966
>From e8ec435c32babb3f85390d1270ade9e34ef44606 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 15 Sep 2026 22:14:45 -0700
Subject: [PATCH] [lldb] Bounds check minidump location descriptors
MinidumpParser::GetModuleUUID sliced the file with the RVA and DataSize
taken straight from a module's CvRecord. ArrayRef::slice asserts, but a
build without assertions still reads out of bounds.
Route both through MinidumpFile::getRawData, which range checks in 64
bits, and log the error rather than returning a slice that looks valid.
rdar://186889966
---
.../Process/minidump/MinidumpParser.cpp | 20 ++++--
.../Process/minidump/MinidumpParserTest.cpp | 68 +++++++++++++++++++
2 files changed, 84 insertions(+), 4 deletions(-)
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
index 1334f69dad6dc..f15e837cc006c 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -55,8 +55,14 @@ MinidumpParser::GetRawStream(StreamType stream_type) {
}
UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {
- auto cv_record =
- GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize);
+ llvm::Expected<llvm::ArrayRef<uint8_t>> expected_cv_record =
+ GetMinidumpFile().getRawData(module->CvRecord);
+ if (!expected_cv_record) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Modules), expected_cv_record.takeError(),
+ "Failed to read the CodeView record: {0}");
+ return UUID();
+ }
+ llvm::ArrayRef<uint8_t> cv_record = *expected_cv_record;
// Read the CV record signature
const llvm::support::ulittle32_t *signature = nullptr;
@@ -96,9 +102,15 @@ llvm::ArrayRef<minidump::Thread> MinidumpParser::GetThreads() {
llvm::ArrayRef<uint8_t>
MinidumpParser::GetThreadContext(const LocationDescriptor &location) {
- if (location.RVA + location.DataSize > GetData().size())
+ // Use getRawData to widen the two 32-bit fields and check for overflow.
+ llvm::Expected<llvm::ArrayRef<uint8_t>> expected_context =
+ GetMinidumpFile().getRawData(location);
+ if (!expected_context) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), expected_context.takeError(),
+ "Failed to read the thread context: {0}");
return {};
- return GetData().slice(location.RVA, location.DataSize);
+ }
+ return *expected_context;
}
llvm::ArrayRef<uint8_t>
diff --git a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
index a5986eafda83e..2121e3b7f9f97 100644
--- a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
+++ b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -36,6 +36,28 @@
using namespace lldb_private;
using namespace minidump;
+/// Wrap raw stream contents in a single-stream minidump. Unlike yaml2obj, this
+/// leaves the location descriptors inside the stream untouched, so they can
+/// point anywhere.
+static std::string MakeMinidump(StreamType type, llvm::StringRef contents) {
+ Header header = {};
+ header.Signature = Header::MagicSignature;
+ header.Version = Header::MagicVersion;
+ header.NumberOfStreams = 1;
+ header.StreamDirectoryRVA = sizeof(Header);
+
+ Directory directory = {};
+ directory.Type = type;
+ directory.Location.RVA = sizeof(Header) + sizeof(Directory);
+ directory.Location.DataSize = contents.size();
+
+ std::string data;
+ data.append(reinterpret_cast<const char *>(&header), sizeof(header));
+ data.append(reinterpret_cast<const char *>(&directory), sizeof(directory));
+ data.append(contents);
+ return data;
+}
+
class MinidumpParserTest : public testing::Test {
public:
SubsystemRAII<FileSystem> subsystems;
@@ -59,6 +81,10 @@ class MinidumpParserTest : public testing::Test {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"convertYAML() failed");
+ return SetUpFromData(data);
+ }
+
+ llvm::Error SetUpFromData(llvm::StringRef data) {
auto data_buffer_sp =
std::make_shared<DataBufferHeap>(data.data(), data.size());
auto expected_parser = MinidumpParser::Create(std::move(data_buffer_sp));
@@ -911,3 +937,45 @@ TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA),
llvm::HasValue("/tmp/b"));
}
+
+TEST_F(MinidumpParserTest, GetModuleUUIDOutOfRangeCvRecord) {
+ minidump::Module module = {};
+ module.BaseOfImage = 0x1000;
+ module.SizeOfImage = 0x1000;
+ module.CvRecord.RVA = 0xf0000000;
+ module.CvRecord.DataSize = sizeof(llvm::support::ulittle32_t);
+
+ std::string stream;
+ llvm::support::ulittle32_t module_count(1);
+ stream.append(reinterpret_cast<const char *>(&module_count),
+ sizeof(module_count));
+ stream.append(reinterpret_cast<const char *>(&module), sizeof(module));
+
+ ASSERT_THAT_ERROR(SetUpFromData(MakeMinidump(StreamType::ModuleList, stream)),
+ llvm::Succeeded());
+
+ llvm::ArrayRef<minidump::Module> modules = parser->GetModuleList();
+ ASSERT_EQ(1u, modules.size());
+ EXPECT_FALSE(parser->GetModuleUUID(&modules[0]).IsValid());
+}
+
+TEST_F(MinidumpParserTest, GetThreadContextOutOfRange) {
+ minidump::Thread thread = {};
+ thread.ThreadId = 0x3e81;
+ // The sum of the two fields wraps around in 32 bits.
+ thread.Context.RVA = 0xfffffff0;
+ thread.Context.DataSize = 0x20;
+
+ std::string stream;
+ llvm::support::ulittle32_t thread_count(1);
+ stream.append(reinterpret_cast<const char *>(&thread_count),
+ sizeof(thread_count));
+ stream.append(reinterpret_cast<const char *>(&thread), sizeof(thread));
+
+ ASSERT_THAT_ERROR(SetUpFromData(MakeMinidump(StreamType::ThreadList, stream)),
+ llvm::Succeeded());
+
+ llvm::ArrayRef<minidump::Thread> threads = parser->GetThreads();
+ ASSERT_EQ(1u, threads.size());
+ EXPECT_TRUE(parser->GetThreadContext(threads[0]).empty());
+}
More information about the lldb-commits
mailing list