Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/adapters/corelliumadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ std::vector<DebugThread> CorelliumAdapter::GetThreadList()
reply.AsString().substr(1);
const auto tids = RspConnector::Split(shortened_string, ",");
for ( const auto& tid : tids )
threads.emplace_back(std::stoi(tid, nullptr, 16));
threads.emplace_back(RspConnector::ParseInt<int>(tid));

reply = this->m_rspConnector->TransmitAndReceive(RspData("qsThreadInfo"));
}
Expand Down Expand Up @@ -827,7 +827,7 @@ DebugStopReason CorelliumAdapter::ResponseHandler()
if (replyString.length() >= 3)
{
std::string signalString = replyString.substr(1, 2);
uint64_t signal = std::stoull(signalString, nullptr, 16);
uint64_t signal = RspConnector::ParseInt(signalString);

m_isTargetRunning = false;

Expand Down Expand Up @@ -993,7 +993,7 @@ static std::string HexToAscii(const std::string& hex)
{
// Convert the two hex characters to a byte (using a stringstream)
std::string byte_string = hex.substr(i, 2);
unsigned char byte = static_cast<unsigned char>(std::stoi(byte_string, nullptr, 16)); // Convert to byte
unsigned char byte = static_cast<unsigned char>(RspConnector::ParseInt<int>(byte_string)); // Convert to byte

// Append the byte (ASCII char) to the resulting string
ascii.push_back(byte);
Expand Down
8 changes: 4 additions & 4 deletions core/adapters/gdbadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ std::vector<DebugThread> GdbAdapter::GetThreadList()
reply.AsString().substr(1);
const auto tids = RspConnector::Split(shortened_string, ",");
for ( const auto& tid : tids )
threads.emplace_back(std::stoi(tid, nullptr, 16));
threads.emplace_back(RspConnector::ParseInt<int>(tid));

reply = this->m_rspConnector->TransmitAndReceive(RspData("qsThreadInfo"));
}
Expand Down Expand Up @@ -1000,8 +1000,8 @@ DebugStopReason GdbAdapter::ResponseHandler(bool notifyStopped)
if (replyString.length() >= 3)
{
std::string signalString = replyString.substr(1, 2);
uint64_t signal = std::stoull(signalString, nullptr, 16);
uint64_t signal = RspConnector::ParseInt(signalString);

m_isTargetRunning = false;
CheckApplyPendingBreakpoints();

Expand Down Expand Up @@ -1457,7 +1457,7 @@ static std::string HexToAscii(const std::string& hex)
{
// Convert the two hex characters to a byte (using a stringstream)
std::string byte_string = hex.substr(i, 2);
unsigned char byte = static_cast<unsigned char>(std::stoi(byte_string, nullptr, 16)); // Convert to byte
unsigned char byte = static_cast<unsigned char>(RspConnector::ParseInt<int>(byte_string)); // Convert to byte

// Append the byte (ASCII char) to the resulting string
ascii.push_back(byte);
Expand Down
12 changes: 11 additions & 1 deletion core/adapters/gdbmiadapter.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "gdbmiadapter.h"
#include <sstream>
#include <charconv>
#include <cinttypes>
#include "../debuggercontroller.h"
#include "../../cli/log.h"
Expand Down Expand Up @@ -953,7 +954,16 @@ DataBuffer GdbMiAdapter::ReadMemory(std::uintptr_t address, size_t size) {
std::string hex_contents = value["memory"][0]["contents"].GetString();
DataBuffer buffer(hex_contents.length() / 2);
for(size_t i = 0; i < buffer.GetLength(); i++) {
buffer[i] = std::stoul(hex_contents.substr(i*2, 2), nullptr, 16);
// Parse with the non-throwing std::from_chars, since std::stoul throws on
// malformed data coming from the gdb process
unsigned int byte = 0;
const char* first = hex_contents.data() + i * 2;
if (std::from_chars(first, first + 2, byte, 16).ec != std::errc())
{
LogDebug("Malformed hex contents in memory read reply");
return zero;
}
buffer[i] = byte;
}
return buffer;
}
Expand Down
30 changes: 18 additions & 12 deletions core/adapters/rspconnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,12 @@ RspData RspConnector::DecodeRLE(const RspData& data)
std::unordered_map<std::string, std::uint64_t> RspConnector::PacketToUnorderedMap(const RspData& data)
{
std::unordered_map<std::string, std::uint64_t> packet_map{};
packet_map["signal"] = std::stoull(data.AsString().substr(1, 2), nullptr, 16);

const auto data_string = data.AsString();
if (data_string.length() < 3)
return packet_map;

packet_map["signal"] = ParseInt(data_string.substr(1, 2));

const auto after_signal = data_string.substr(3);

for ( const auto& entries : RspConnector::Split(after_signal, ";")) {
Expand All @@ -117,15 +120,16 @@ std::unordered_map<std::string, std::uint64_t> RspConnector::PacketToUnorderedMa
if (key == "thread") {
if (value[0] == 'p' && value.find('.') != std::string::npos) {
auto core_id_and_thread_id = RspConnector::Split(value.substr(1), ".");
packet_map["thread"] = std::stoull(core_id_and_thread_id[1], nullptr, 16);
if (core_id_and_thread_id.size() >= 2)
packet_map["thread"] = ParseInt(core_id_and_thread_id[1]);
} else {
packet_map["thread"] = std::stoull(value, nullptr, 16);
packet_map["thread"] = ParseInt(value);
}
} else if (std::regex_search(key, std::regex("^[0-9a-fA-F]+$"))) {
packet_map[fmt::format("r{}", std::stoi(key, nullptr, 16))] =
static_cast<std::int64_t>( RspConnector::SwapEndianness(std::stoull(value, nullptr, 16)));
packet_map[fmt::format("r{}", ParseInt<int>(key))] =
static_cast<std::int64_t>( RspConnector::SwapEndianness(ParseInt(value)));
} else {
packet_map[key] = std::stoull(value, nullptr, 16);
packet_map[key] = ParseInt(value);
}
}
else
Expand Down Expand Up @@ -204,8 +208,8 @@ void RspConnector::NegotiateCapabilities(const std::vector <std::string>& capabi
{
if ( reply_token.find("PacketSize=") != std::string::npos )
{
if (auto packet_tokens = RspConnector::Split(reply_token, "="); !packet_tokens.empty())
this->m_maxPacketLength = std::stoi(packet_tokens[1], nullptr, 16);
if (auto packet_tokens = RspConnector::Split(reply_token, "="); packet_tokens.size() >= 2)
this->m_maxPacketLength = ParseInt<int>(packet_tokens[1], 16, this->m_maxPacketLength);
continue;
}

Expand Down Expand Up @@ -413,11 +417,13 @@ int32_t RspConnector::HostFileIO(const RspData& data, RspData& output, int32_t&
if (resultErrno.find(',') != std::string::npos) {
const auto split = RspConnector::Split(resultErrno, ",");
if ((split.size() >= 2) && (split[1] != ""))
error = std::stol(split[1].c_str(), nullptr, 16);
error = ParseInt<int32_t>(split[1]);

return std::stol(split[0].c_str(), nullptr, 16);
if (split.empty())
return -1;
return ParseInt<int32_t>(split[0], 16, -1);
}
return std::stol(resultErrno.c_str(), nullptr, 16);
return ParseInt<int32_t>(resultErrno, 16, -1);
}


Expand Down
13 changes: 13 additions & 0 deletions core/adapters/rspconnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ limitations under the License.
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <charconv>
#include <regex>
#include <array>
#include "binaryninjaapi.h"
Expand Down Expand Up @@ -153,6 +154,18 @@ namespace BinaryNinjaDebugger
static std::unordered_map<std::string, std::uint64_t> PacketToUnorderedMap(const RspData& data);
static std::vector<std::string> Split(const std::string& string, const std::string& regex);

// Parse an integer from remote protocol data without throwing. std::stoi and friends
// raise std::invalid_argument/std::out_of_range on malformed input, which crashes the
// process when the string comes from an untrusted remote stub.
template <typename Ty = uint64_t>
static Ty ParseInt(const std::string& str, int base = 16, Ty fallback = 0)
{
Ty value = fallback;
if (std::from_chars(str.data(), str.data() + str.size(), value, base).ec != std::errc())
return fallback;
return value;
}

static uint64_t SwapEndianness(uint64_t value, size_t len)
{
switch (len)
Expand Down