QJsonDocument: Avoid overflow of string lengths
The added test case contains the binary JSON equivalent of ["ž"] with the modification that the string's length has been set to INT_MAX. In Value::usedStorage this length is used through the pointer d like so s = sizeof(int) + sizeof(ushort) * qFromLittleEndian(*(int *)d); Because 2 * INT_MAX is UINT_MAX-1, the expression as a whole evaluates to 2, which is considered a valid storage size. However, when converting this binary JSON into ordinary JSON we will attempt to construct a QString of length INT_MAX. Fixed by using String::isValid instead of Value::usedStorage. This method already takes care to avoid the overflow problem. Additionally, I've tried in this patch to clarify the behavior of Value::isValid a bit by writing it in a style that is hopefully more amenable to structural induction. Finally, the test case added in my previous patch had the wrong file extension and is renamed in this one. Task-number: QTBUG-61969 Change-Id: I45d891f2467a71d8d105822ef7eb1a73c3efa67a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
bff2101994
commit
8e47474baf
@ -326,38 +326,35 @@ int Value::usedStorage(const Base *b) const
|
|||||||
return alignedSize(s);
|
return alignedSize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isValidValueOffset(uint offset, uint tableOffset)
|
||||||
|
{
|
||||||
|
return offset >= sizeof(Base)
|
||||||
|
&& offset + sizeof(uint) <= tableOffset;
|
||||||
|
}
|
||||||
|
|
||||||
bool Value::isValid(const Base *b) const
|
bool Value::isValid(const Base *b) const
|
||||||
{
|
{
|
||||||
int offset = -1;
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case QJsonValue::Double:
|
|
||||||
if (latinOrIntValue)
|
|
||||||
break;
|
|
||||||
Q_FALLTHROUGH();
|
|
||||||
case QJsonValue::String:
|
|
||||||
case QJsonValue::Array:
|
|
||||||
case QJsonValue::Object:
|
|
||||||
offset = value;
|
|
||||||
break;
|
|
||||||
case QJsonValue::Null:
|
case QJsonValue::Null:
|
||||||
case QJsonValue::Bool:
|
case QJsonValue::Bool:
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset == -1)
|
|
||||||
return true;
|
return true;
|
||||||
if (offset + sizeof(uint) > b->tableOffset || offset < (int)sizeof(Base))
|
case QJsonValue::Double:
|
||||||
|
return latinOrIntValue || isValidValueOffset(value, b->tableOffset);
|
||||||
|
case QJsonValue::String:
|
||||||
|
if (!isValidValueOffset(value, b->tableOffset))
|
||||||
|
return false;
|
||||||
|
if (latinOrIntValue)
|
||||||
|
return asLatin1String(b).isValid(b->tableOffset - value);
|
||||||
|
return asString(b).isValid(b->tableOffset - value);
|
||||||
|
case QJsonValue::Array:
|
||||||
|
return isValidValueOffset(value, b->tableOffset)
|
||||||
|
&& static_cast<Array *>(base(b))->isValid(b->tableOffset - value);
|
||||||
|
case QJsonValue::Object:
|
||||||
|
return isValidValueOffset(value, b->tableOffset)
|
||||||
|
&& static_cast<Object *>(base(b))->isValid(b->tableOffset - value);
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
int s = usedStorage(b);
|
|
||||||
if (s < 0 || s > (int)b->tableOffset - offset)
|
|
||||||
return false;
|
|
||||||
if (type == QJsonValue::Array)
|
|
||||||
return static_cast<Array *>(base(b))->isValid(s);
|
|
||||||
if (type == QJsonValue::Object)
|
|
||||||
return static_cast<Object *>(base(b))->isValid(s);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
BIN
tests/auto/corelib/serialization/json/invalidBinaryData/41.bjson
Normal file
BIN
tests/auto/corelib/serialization/json/invalidBinaryData/41.bjson
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user