Add checks in cryptonote serialization routine

(cherry picked from commit 2143283872c9b9e83dc04a571d9b8cd46548c3f7)
This commit is contained in:
Lee *!* Clagett
2026-10-04 18:51:04 -04:00
committed by such-gitea
parent 84fd02ea1d
commit cf393346bc
4 changed files with 47 additions and 24 deletions
+2 -2
View File
@@ -363,7 +363,7 @@ namespace cryptonote
ar.tag("signatures");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures, 0);
bool signatures_not_expected = signatures.empty();
if (!signatures_not_expected && vin.size() != signatures.size())
return false;
@@ -379,7 +379,7 @@ namespace cryptonote
return false;
}
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i], sizeof(crypto::signature));
if (signature_size != signatures[i].size())
return false;
+27 -14
View File
@@ -350,7 +350,7 @@ namespace rct {
{
ar.tag("pseudoOuts");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts, sizeof(key));
if (pseudoOuts.size() != inputs)
return false;
for (size_t i = 0; i < inputs; ++i)
@@ -364,12 +364,18 @@ namespace rct {
ar.tag("ecdhInfo");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, ecdhInfo);
const bool compressed_ecdh =
(type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit);
const std::size_t min_size = compressed_ecdh ? sizeof(crypto::hash8) : sizeof(key) * 2;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, ecdhInfo, min_size);
if (ecdhInfo.size() != outputs)
return false;
for (size_t i = 0; i < outputs; ++i)
{
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit)
if (compressed_ecdh)
{
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
// first 8 bytes of ecdhInfo[i].amount
@@ -395,7 +401,7 @@ namespace rct {
ar.tag("outPk");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk, sizeof(key));
if (outPk.size() != outputs)
return false;
for (size_t i = 0; i < outputs; ++i)
@@ -444,7 +450,8 @@ namespace rct {
{
ar.tag("bp");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, bulletproofs);
// Wownero legacy per-output bulletproofs: same minimum wire size as a Bulletproof below.
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, bulletproofs, sizeof(key) * 9);
if (bulletproofs.size() != outputs)
return false;
for (size_t i = 0; i < outputs; ++i)
@@ -463,7 +470,7 @@ namespace rct {
ar.begin_array();
if (nbp > outputs)
return false;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs_plus);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs_plus, sizeof(key) * 6);
for (size_t i = 0; i < nbp; ++i)
{
FIELDS(bulletproofs_plus[i])
@@ -485,7 +492,7 @@ namespace rct {
ar.begin_array();
if (nbp > outputs)
return false;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs, sizeof(key) * 9);
for (size_t i = 0; i < nbp; ++i)
{
FIELDS(bulletproofs[i])
@@ -500,7 +507,7 @@ namespace rct {
{
ar.tag("rangeSigs");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs, sizeof(key) * 193);
if (rangeSigs.size() != outputs)
return false;
for (size_t i = 0; i < outputs; ++i)
@@ -516,7 +523,7 @@ namespace rct {
{
ar.tag("CLSAGs");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, CLSAGs);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, CLSAGs, sizeof(key) * 3);
if (CLSAGs.size() != inputs)
return false;
for (size_t i = 0; i < inputs; ++i)
@@ -527,7 +534,7 @@ namespace rct {
ar.begin_object();
ar.tag("s");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, CLSAGs[i].s);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, CLSAGs[i].s, sizeof(key));
if (CLSAGs[i].s.size() != mixin + 1)
return false;
for (size_t j = 0; j <= mixin; ++j)
@@ -559,9 +566,12 @@ namespace rct {
// we keep a byte for size of MGs, because we don't know whether this is
// a simple or full rct signature, and it's starting to annoy the hell out of me
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeSimpleBulletproof) ? inputs : 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
// Each MGs has `cc` (`key`) AND at least 1 MGs[i].ss which has at least 1 `key`
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs, sizeof(key) * 2);
if (MGs.size() != mg_elements)
return false;
for (size_t i = 0; i < mg_elements; ++i)
{
// we save the MGs contents directly, because we want it to save its
@@ -570,14 +580,17 @@ namespace rct {
ar.begin_object();
ar.tag("ss");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, MGs[i].ss);
// each MGs[i].ss has at least one `key`
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1,MGs[i].ss, sizeof(key));
if (MGs[i].ss.size() != mixin + 1)
return false;
for (size_t j = 0; j < mixin + 1; ++j)
{
ar.begin_array();
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeSimpleBulletproof) ? 1 : inputs) + 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j], sizeof(key));
if (MGs[i].ss[j].size() != mg_ss2_elements)
return false;
for (size_t k = 0; k < mg_ss2_elements; ++k)
@@ -607,7 +620,7 @@ namespace rct {
{
ar.tag("pseudoOuts");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts, sizeof(key));
if (pseudoOuts.size() != inputs)
return false;
for (size_t i = 0; i < inputs; ++i)
+1 -1
View File
@@ -46,7 +46,7 @@ bool do_serialize(Archive<false> &ar, std::vector<crypto::signature> &v)
v.clear();
// very basic sanity check
if (ar.remaining_bytes() < cnt*sizeof(crypto::signature)) {
if (ar.remaining_bytes() / sizeof(crypto::signature) < cnt) {
ar.set_fail();
return false;
}
+17 -7
View File
@@ -139,10 +139,15 @@ inline bool do_serialize(Archive &ar, bool &v)
template <bool W, template <bool> class Archive> \
bool do_serialize_object(Archive<W> &ar){
/*! \macro PREPARE_CUSTOM_VECTOR_SERIALIZATION
/*! \macro RESERVE_VECTOR_SERIALIZATION. `min_wire` must be the minimum bytes
* each element takes on the wire.
*/
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \
::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving())
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec, min_wire) \
do \
{ \
if (!::serialization::detail::prepare_custom_vector_serialization(size, vec, min_wire, ar)) \
return false; \
} while (0);
/*! \macro END_SERIALIZE
* \brief self-explanatory
@@ -237,6 +242,7 @@ inline bool do_serialize(Archive &ar, bool &v)
} while(0);
namespace serialization {
/*! \namespace detail
*
* \brief declaration and default definition for the functions used the API
@@ -248,15 +254,19 @@ namespace serialization {
*
* prepares the vector /vec for serialization
*/
template <typename T>
void prepare_custom_vector_serialization(size_t size, std::vector<T>& vec, const boost::mpl::bool_<true>& /*is_saving*/)
template <typename T, template<bool> class A>
constexpr bool prepare_custom_vector_serialization(size_t, const std::vector<T>& vec, size_t, const A<true>&) noexcept
{
return true;
}
template <typename T>
void prepare_custom_vector_serialization(size_t size, std::vector<T>& vec, const boost::mpl::bool_<false>& /*is_saving*/)
template <typename T, template<bool> class A>
bool prepare_custom_vector_serialization(const size_t size, std::vector<T>& vec, const size_t min_size, const A<false>& ar)
{
if (size && ar.remaining_bytes() / size < min_size)
return false;
vec.resize(size);
return true;
}
/*! \fn do_check_stream_state