Skip to content

Commit f4e42d2

Browse files
Victor DyachenkoGitHub Enterprise
authored andcommitted
BER decoding crash on bogus string length (DRQS 175292043) (#4815)
* Huge strings decoding * More tests
1 parent b662fc9 commit f4e42d2

File tree

2 files changed

+108
-4
lines changed

2 files changed

+108
-4
lines changed

groups/bal/balber/balber_berutil.cpp

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,45 @@ const u::Uint64 BerUtil_64BitFloatingPointMasks::
8484
const u::Uint64 BerUtil_64BitFloatingPointMasks::k_DOUBLE_SIGN_MASK =
8585
0x8000000000000000ULL;
8686

87+
// =====================
88+
// class ReadRestFunctor
89+
// =====================
90+
91+
class ReadRestFunctor {
92+
// A functor for 'string::resize_and_overwrite'. Appends read bytes to the
93+
// buffer.
94+
95+
// DATA
96+
bsl::streambuf *d_streamBuf;
97+
int d_oldSize;
98+
public:
99+
// CREATORS
100+
ReadRestFunctor(bsl::streambuf *streamBuf, int oldSize);
101+
102+
// MODIFIERS
103+
size_t operator()(char *buf, size_t newSize);
104+
};
105+
106+
// ---------------------
107+
// class ReadRestFunctor
108+
// ---------------------
109+
110+
// CREATORS
111+
ReadRestFunctor::ReadRestFunctor(bsl::streambuf *streamBuf, int oldSize)
112+
: d_streamBuf(streamBuf)
113+
, d_oldSize(oldSize)
114+
{
115+
}
116+
117+
// MODIFIERS
118+
size_t ReadRestFunctor::operator()(char *buf, size_t newSize)
119+
{
120+
bsl::streamsize nRead = d_streamBuf->sgetn(
121+
buf + d_oldSize,
122+
static_cast<int>(newSize) - d_oldSize);
123+
return static_cast<size_t>(d_oldSize + nRead);
124+
}
125+
87126
// FREE FUNCTIONS
88127
void warnOnce()
89128
// The first time this is called, issue an explanatory warning.
@@ -1084,14 +1123,31 @@ int BerUtil_StringImpUtil::getStringValue(bsl::string *value,
10841123
return -1; // RETURN
10851124
}
10861125

1087-
value->resize_and_overwrite(
1088-
length,
1089-
bdlf::MemFnUtil::memFn(&bsl::streambuf::sgetn, streamBuf));
1126+
static const int maxInitialAllocation = 16 * 1024 * 1024; // 16 MB
10901127

1091-
if (static_cast<bsl::string::size_type>(length) != value->size()) {
1128+
// 'length' could be corrupt or invalid, so we limit the initial buffer.
1129+
// On success the remaining bytes are read via a second pass.
1130+
int initialLength = length < maxInitialAllocation ? length
1131+
: maxInitialAllocation;
1132+
1133+
// Read no more than 'maxInitialAllocation'
1134+
value->resize_and_overwrite(initialLength,
1135+
bdlf::MemFnUtil::memFn(&bsl::streambuf::sgetn,
1136+
streamBuf));
1137+
if (static_cast<size_t>(initialLength) != value->size()) {
10921138
return -1; // RETURN
10931139
}
10941140

1141+
if (length > initialLength) {
1142+
// 'length' > 'maxInitialAllocation'. Read the rest.
1143+
value->resize_and_overwrite(length,
1144+
u::ReadRestFunctor(streamBuf,
1145+
initialLength));
1146+
if (static_cast<size_t>(length) != value->size()) {
1147+
return -1; // RETURN
1148+
}
1149+
}
1150+
10951151
return 0;
10961152
}
10971153

groups/bal/balber/balber_berutil.t.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16072,6 +16072,54 @@ int main(int argc, char *argv[])
1607216072
LOOP3_ASSERT(LINE, LEN, numBytesConsumed,
1607316073
LEN == numBytesConsumed);
1607416074
}
16075+
16076+
if (verbose) { cout << "\nDecode truncated string" << endl; }
16077+
{
16078+
const int length = 1024; // the claimed length
16079+
bdlsb::MemOutStreamBuf osb;
16080+
ASSERT(SUCCESS == Util::putLength(&osb, length));
16081+
// Write 'length - 10' bytes
16082+
ASSERT(length > 10);
16083+
for (int n = length - 10; n > 0; --n) {
16084+
ASSERT(osb.sputc('X') == 'X');
16085+
}
16086+
16087+
int numBytesConsumed = 0;
16088+
bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length());
16089+
bsl::string val;
16090+
ASSERT(SUCCESS != Util::getValue(&isb, &val, &numBytesConsumed));
16091+
}
16092+
16093+
static const int notHugeStringMax = 16 * 1024 * 1024; // 16 MB
16094+
16095+
if (verbose) { cout << "\nDecode huge string" << endl; }
16096+
{
16097+
const bsl::string hugeStr(notHugeStringMax + 256, 'X');
16098+
bdlsb::MemOutStreamBuf osb;
16099+
ASSERT(0 == Util::putValue(&osb, hugeStr));
16100+
16101+
int numBytesConsumed = 0;
16102+
bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length());
16103+
bsl::string val;
16104+
ASSERT(SUCCESS == Util::getValue(&isb, &val, &numBytesConsumed));
16105+
ASSERT(val.length() == hugeStr.length());
16106+
ASSERT(val == hugeStr);
16107+
}
16108+
16109+
if (verbose) { cout << "\nDecode truncated huge string" << endl; }
16110+
{
16111+
bdlsb::MemOutStreamBuf osb;
16112+
ASSERT(SUCCESS == Util::putLength(&osb, notHugeStringMax + 20));
16113+
// Write 10 bytes less than claimed
16114+
for (int n = notHugeStringMax + 10; n > 0; --n) {
16115+
ASSERT(osb.sputc('X') == 'X');
16116+
}
16117+
16118+
int numBytesConsumed = 0;
16119+
bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length());
16120+
bsl::string val;
16121+
ASSERT(SUCCESS != Util::getValue(&isb, &val, &numBytesConsumed));
16122+
}
1607516123
} break;
1607616124
case 12: {
1607716125
// --------------------------------------------------------------------

0 commit comments

Comments
 (0)