Skip to content

Commit 413b823

Browse files
authored
fix: ASAN stack-buffer-overflow in NFTHelpersTest_NFTDataFromLedgerObject (#2306)
1 parent e664f0b commit 413b823

File tree

3 files changed

+25
-12
lines changed

3 files changed

+25
-12
lines changed

src/etl/NFTHelpers.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//==============================================================================
1919

2020
#include "data/DBHelpers.hpp"
21+
#include "util/Assert.hpp"
2122

2223
#include <fmt/format.h>
2324
#include <xrpl/basics/base_uint.h>
@@ -359,14 +360,18 @@ getNFTDataFromTx(ripple::TxMeta const& txMeta, ripple::STTx const& sttx)
359360
std::vector<NFTsData>
360361
getNFTDataFromObj(std::uint32_t const seq, std::string const& key, std::string const& blob)
361362
{
362-
std::vector<NFTsData> nfts;
363-
ripple::STLedgerEntry const sle =
363+
// https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0020-non-fungible-tokens#tokenpage-id-format
364+
ASSERT(key.size() == ripple::uint256::size(), "The size of the key (token) is expected to fit uint256 exactly");
365+
366+
auto const sle =
364367
ripple::STLedgerEntry(ripple::SerialIter{blob.data(), blob.size()}, ripple::uint256::fromVoid(key.data()));
365368

366369
if (sle.getFieldU16(ripple::sfLedgerEntryType) != ripple::ltNFTOKEN_PAGE)
367-
return nfts;
370+
return {};
368371

369372
auto const owner = ripple::AccountID::fromVoid(key.data());
373+
std::vector<NFTsData> nfts;
374+
370375
for (ripple::STObject const& node : sle.getFieldArray(ripple::sfNFTokens))
371376
nfts.emplace_back(node.getFieldH256(ripple::sfNFTokenID), seq, owner, node.getFieldVL(ripple::sfURI));
372377

tests/common/util/BinaryTestObject.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,16 @@ createObjectWithTwoNFTs()
148148

149149
auto const nftPage = createNftTokenPage({{kNFT_ID, url1}, {kNFT_ID2, url2}}, std::nullopt);
150150
auto const serializerNftPage = nftPage.getSerializer();
151-
152151
auto const account = getAccountIdWithString(kACCOUNT);
152+
153+
// key is a token made up from owner's account ID followed by unused (in Clio) value described here:
154+
// https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0020-non-fungible-tokens#tokenpage-id-format
155+
auto constexpr kEXTRA_BYTES = "000000000000";
156+
auto const key = std::string(std::begin(account), std::end(account)) + kEXTRA_BYTES;
157+
153158
return {
154159
.key = {},
155-
.keyRaw = std::string(reinterpret_cast<char const*>(account.data()), ripple::AccountID::size()),
160+
.keyRaw = key,
156161
.data = {},
157162
.dataRaw =
158163
std::string(static_cast<char const*>(serializerNftPage.getDataPtr()), serializerNftPage.getDataLength()),

tests/unit/etl/NFTHelpersTests.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <xrpl/basics/Blob.h>
2727
#include <xrpl/basics/Slice.h>
2828
#include <xrpl/basics/base_uint.h>
29+
#include <xrpl/basics/strHex.h>
2930
#include <xrpl/protocol/AccountID.h>
3031
#include <xrpl/protocol/SField.h>
3132
#include <xrpl/protocol/STObject.h>
@@ -471,17 +472,19 @@ TEST_F(NFTHelpersTest, NFTDataFromLedgerObject)
471472
ripple::Blob const uri1Blob(url1.begin(), url1.end());
472473
ripple::Blob const uri2Blob(url2.begin(), url2.end());
473474

475+
auto const account = getAccountIdWithString(kACCOUNT);
474476
auto const nftPage = createNftTokenPage({{kNFT_ID, url1}, {kNFT_ID2, url2}}, std::nullopt);
475477
auto const serializerNftPage = nftPage.getSerializer();
478+
auto const blob =
479+
std::string(static_cast<char const*>(serializerNftPage.getDataPtr()), serializerNftPage.getDataLength());
476480

477-
int constexpr kSEQ{5};
478-
auto const account = getAccountIdWithString(kACCOUNT);
481+
// key is a token made up from owner's account ID followed by unused (in Clio) value described here:
482+
// https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0020-non-fungible-tokens#tokenpage-id-format
483+
auto constexpr kEXTRA_BYTES = "000000000000";
484+
auto const key = std::string(std::begin(account), std::end(account)) + kEXTRA_BYTES;
479485

480-
auto const nftDatas = etl::getNFTDataFromObj(
481-
kSEQ,
482-
std::string(reinterpret_cast<char const*>(account.data()), ripple::AccountID::size()),
483-
std::string(static_cast<char const*>(serializerNftPage.getDataPtr()), serializerNftPage.getDataLength())
484-
);
486+
uint32_t constexpr kSEQ{5};
487+
auto const nftDatas = etl::getNFTDataFromObj(kSEQ, key, blob);
485488

486489
EXPECT_EQ(nftDatas.size(), 2);
487490
EXPECT_EQ(nftDatas[0].tokenID, ripple::uint256(kNFT_ID));

0 commit comments

Comments
 (0)