8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 21:23:04 +01:00

Fixed CORE-6432: Possible buffer overflow in client library in Attachment::getInfo() call

This commit is contained in:
AlexPeshkoff 2020-10-28 20:46:27 +03:00
parent ca77a37910
commit f88c95acb6
3 changed files with 62 additions and 32 deletions

View File

@ -86,7 +86,8 @@ void ClumpletReader::dump() const
try {
ClumpletDump d(kind, getBuffer(), getBufferLength());
int t = (kind == SpbStart || kind == UnTagged || kind == WideUnTagged || kind == SpbResponse) ? -1 : d.getBufferTag();
int t = (kind == SpbStart || kind == UnTagged || kind == WideUnTagged || kind == SpbResponse || kind == InfoResponse) ?
-1 : d.getBufferTag();
gds__log("Tag=%d Offset=%d Length=%d Eof=%d\n", t, getCurOffset(), getBufferLength(), isEof());
for (d.rewind(); !(d.isEof()); d.moveNext())
{
@ -240,6 +241,7 @@ UCHAR ClumpletReader::getBufferTag() const
case SpbSendItems:
case SpbReceiveItems:
case SpbResponse:
case InfoResponse:
usage_mistake("buffer is not tagged");
return 0;
case SpbAttach:
@ -535,6 +537,16 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const
}
invalid_structure("unrecognized service response tag", tag);
break;
case InfoResponse:
switch (tag)
{
case isc_info_end:
case isc_info_truncated:
case isc_info_data_not_ready:
case isc_info_flag_end:
return SingleTpb;
}
return StringSpb;
}
invalid_structure("unknown clumplet kind", kind);
return SingleTpb;
@ -688,6 +700,7 @@ void ClumpletReader::rewind()
case SpbSendItems:
case SpbReceiveItems:
case SpbResponse:
case InfoResponse:
cur_offset = 0;
break;
default:

View File

@ -57,7 +57,8 @@ public:
WideUnTagged,
SpbSendItems,
SpbReceiveItems,
SpbResponse
SpbResponse,
InfoResponse
};
struct KindList
@ -130,7 +131,8 @@ public:
FB_SIZE_T rc = getBufferEnd() - getBuffer();
if (rc == 1 && kind != UnTagged && kind != SpbStart &&
kind != WideUnTagged && kind != SpbSendItems &&
kind != SpbReceiveItems && kind != SpbResponse)
kind != SpbReceiveItems && kind != SpbResponse &&
kind != InfoResponse)
{
rc = 0;
}

View File

@ -37,12 +37,12 @@ inline void PUT_WORD(UCHAR*& ptr, USHORT value)
#define PUT(ptr, value) *(ptr)++ = value;
static ISC_STATUS merge_setup(const UCHAR**, UCHAR**, const UCHAR* const, USHORT);
static ISC_STATUS merge_setup(const Firebird::ClumpletReader&, UCHAR**, const UCHAR* const, FB_SIZE_T);
USHORT MERGE_database_info(const UCHAR* in,
USHORT MERGE_database_info(const UCHAR* const in,
UCHAR* out,
USHORT out_length,
USHORT buf_length,
USHORT impl,
USHORT class_,
USHORT base_level,
@ -65,22 +65,37 @@ USHORT MERGE_database_info(const UCHAR* in,
const UCHAR* p;
UCHAR* start = out;
const UCHAR* const end = out + out_length;
const UCHAR* const end = out + buf_length;
UCHAR mergeLevel = 0;
for (const UCHAR* getMergeLevel = in;
*getMergeLevel != isc_info_end && *getMergeLevel != isc_info_truncated;
getMergeLevel += (3 + gds__vax_integer(getMergeLevel + 1, 2)))
Firebird::ClumpletReader input(Firebird::ClumpletReader::InfoResponse, in, buf_length);
while (!input.isEof())
{
if (*getMergeLevel == isc_info_implementation)
bool flStop = true;
switch(input.getClumpTag())
{
mergeLevel = getMergeLevel[3];
case isc_info_implementation:
mergeLevel = input.getBytes()[0];
break;
case isc_info_end:
case isc_info_truncated:
break;
default:
flStop = false;
break;
}
if (flStop)
break;
input.moveNext();
}
for (;;)
switch (*out++ = *in++)
for (input.rewind(); !input.isEof(); input.moveNext())
{
*out++ = input.getClumpTag();
switch (input.getClumpTag())
{
case isc_info_end:
case isc_info_truncated:
@ -90,7 +105,7 @@ USHORT MERGE_database_info(const UCHAR* in,
l = static_cast<SSHORT>(strlen((char *) (p = version)));
if (l > MAX_UCHAR)
l = MAX_UCHAR;
if (merge_setup(&in, &out, end, l + 1))
if (merge_setup(input, &out, end, l + 1))
return 0;
for (*out++ = (UCHAR) l; l; --l)
*out++ = *p++;
@ -100,21 +115,21 @@ USHORT MERGE_database_info(const UCHAR* in,
l = static_cast<SSHORT>(strlen((SCHAR *) (p = id)));
if (l > MAX_UCHAR)
l = MAX_UCHAR;
if (merge_setup(&in, &out, end, l + 1))
if (merge_setup(input, &out, end, l + 1))
return 0;
for (*out++ = (UCHAR) l; l; --l)
*out++ = *p++;
break;
case isc_info_implementation:
if (merge_setup(&in, &out, end, 2))
if (merge_setup(input, &out, end, 2))
return 0;
PUT(out, (UCHAR) impl);
PUT(out, (UCHAR) class_);
break;
case fb_info_implementation:
if (merge_setup(&in, &out, end, 6))
if (merge_setup(input, &out, end, 6))
return 0;
Firebird::DbImplementation::current.stuff(&out);
PUT(out, (UCHAR) class_);
@ -122,30 +137,32 @@ USHORT MERGE_database_info(const UCHAR* in,
break;
case isc_info_base_level:
if (merge_setup(&in, &out, end, 1))
if (merge_setup(input, &out, end, 1))
return 0;
PUT(out, (UCHAR) base_level);
break;
default:
{
USHORT length = (USHORT) gds__vax_integer(in, 2);
in += 2;
USHORT length = input.getClumpLength();
if (out + length + 2 >= end)
{
out[-1] = isc_info_truncated;
return 0;
}
PUT_WORD(out, length);
while (length--)
*out++ = *in++;
memcpy(out, input.getBytes(), length);
out += length;
}
break;
}
}
return 0; // error - missing isc_info_end item
}
static ISC_STATUS merge_setup(const UCHAR** in, UCHAR** out, const UCHAR* const end,
USHORT delta_length)
static ISC_STATUS merge_setup(const Firebird::ClumpletReader& input, UCHAR** out, const UCHAR* const end,
FB_SIZE_T delta_length)
{
/**************************************
*
@ -159,17 +176,16 @@ static ISC_STATUS merge_setup(const UCHAR** in, UCHAR** out, const UCHAR* const
* already there.
*
**************************************/
USHORT length = (USHORT) gds__vax_integer(*in, 2);
const USHORT new_length = length + delta_length;
FB_SIZE_T length = input.getClumpLength();
const FB_SIZE_T new_length = length + delta_length;
if (*out + new_length + 2 >= end)
if (new_length > MAX_USHORT || *out + new_length + 2 >= end)
{
(*out)[-1] = isc_info_truncated;
return FB_FAILURE;
}
*in += 2;
const USHORT count = 1 + *(*in)++;
const USHORT count = 1 + *(input.getBytes());
PUT_WORD(*out, new_length);
PUT(*out, (UCHAR) count);
@ -177,9 +193,8 @@ static ISC_STATUS merge_setup(const UCHAR** in, UCHAR** out, const UCHAR* const
if (--length)
{
memcpy(*out, *in, length);
memcpy(*out, input.getBytes() + 1, length);
*out += length;
*in += length;
}
return FB_SUCCESS;