[Lldb-commits] [lldb] 825460a - [lldb/gdb-remote] Do not crash on an invalid server response (#131979)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 19 10:51:31 PDT 2025
Author: Igor Kudrin
Date: 2025-03-19T10:51:27-07:00
New Revision: 825460a7728662d0062405e690485b7a1b689484
URL: https://github.com/llvm/llvm-project/commit/825460a7728662d0062405e690485b7a1b689484
DIFF: https://github.com/llvm/llvm-project/commit/825460a7728662d0062405e690485b7a1b689484.diff
LOG: [lldb/gdb-remote] Do not crash on an invalid server response (#131979)
An invalid RLE sequence in the received packet could result in an
out-of-bounds reading that could cause a crash.
Added:
Modified:
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index dad72a176b5fa..77eadfc8c9f6c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -788,9 +788,14 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len,
// Copy the packet from m_bytes to packet_str expanding the run-length
// encoding in the process.
- std ::string packet_str =
+ auto maybe_packet_str =
ExpandRLE(m_bytes.substr(content_start, content_end - content_start));
- packet = StringExtractorGDBRemote(packet_str);
+ if (!maybe_packet_str) {
+ m_bytes.erase(0, total_length);
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Invalid;
+ }
+ packet = StringExtractorGDBRemote(*maybe_packet_str);
if (m_bytes[0] == '$' || m_bytes[0] == '%') {
assert(checksum_idx < m_bytes.size());
@@ -1311,17 +1316,22 @@ void llvm::format_provider<GDBRemoteCommunication::PacketResult>::format(
}
}
-std::string GDBRemoteCommunication::ExpandRLE(std::string packet) {
+std::optional<std::string>
+GDBRemoteCommunication::ExpandRLE(std::string packet) {
// Reserve enough byte for the most common case (no RLE used).
std::string decoded;
decoded.reserve(packet.size());
for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) {
if (*c == '*') {
+ if (decoded.empty())
+ return std::nullopt;
// '*' indicates RLE. Next character will give us the repeat count and
// previous character is what is to be repeated.
char char_to_repeat = decoded.back();
// Number of time the previous character is repeated.
- int repeat_count = *++c + 3 - ' ';
+ if (++c == packet.end())
+ return std::nullopt;
+ int repeat_count = *c + 3 - ' ';
// We have the char_to_repeat and repeat_count. Now push it in the
// packet.
for (int i = 0; i < repeat_count; ++i)
@@ -1329,7 +1339,9 @@ std::string GDBRemoteCommunication::ExpandRLE(std::string packet) {
} else if (*c == 0x7d) {
// 0x7d is the escape character. The next character is to be XOR'd with
// 0x20.
- char escapee = *++c ^ 0x20;
+ if (++c == packet.end())
+ return std::nullopt;
+ char escapee = *c ^ 0x20;
decoded.push_back(escapee);
} else {
decoded.push_back(*c);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
index 754797ba7f504..107c0896c4e61 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -168,7 +168,7 @@ class GDBRemoteCommunication : public Communication {
GDBRemoteCommunication &server);
/// Expand GDB run-length encoding.
- static std::string ExpandRLE(std::string);
+ static std::optional<std::string> ExpandRLE(std::string);
protected:
std::chrono::seconds m_packet_timeout;
diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
index 425f6cfcd5bc9..3da1f0a718fc5 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationTest.cpp
@@ -68,3 +68,26 @@ TEST_F(GDBRemoteCommunicationTest, ReadPacket) {
ASSERT_EQ(PacketResult::Success, server.GetAck());
}
}
+
+// Test that packets with incorrect RLE sequences do not cause a crash and
+// reported as invalid.
+TEST_F(GDBRemoteCommunicationTest, CheckForPacket) {
+ using PacketType = GDBRemoteCommunication::PacketType;
+ struct TestCase {
+ llvm::StringLiteral Packet;
+ PacketType Result;
+ };
+ static constexpr TestCase Tests[] = {
+ {{"$#00"}, PacketType::Standard},
+ {{"$xx*#00"}, PacketType::Invalid}, // '*' without a count
+ {{"$*#00"}, PacketType::Invalid}, // '*' without a preceding character
+ {{"$xx}#00"}, PacketType::Invalid}, // bare escape character '}'
+ {{"%#00"}, PacketType::Notify}, // a correct packet after an invalid
+ };
+ for (const auto &Test : Tests) {
+ SCOPED_TRACE(Test.Packet);
+ StringExtractorGDBRemote response;
+ EXPECT_EQ(Test.Result, client.CheckForPacket(Test.Packet.bytes_begin(),
+ Test.Packet.size(), response));
+ }
+}
More information about the lldb-commits
mailing list