Improve the validation algorithm for binary JSON
Add better boundary checks and catch (hopefully all) cases where invalid binary JSON could cause crashes. Change-Id: I206510b7c5e3ba953802a5f46645878e65704ecc Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
3c2cb87de2
commit
bfaa8925d5
@ -129,10 +129,12 @@ bool Data::valid() const
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool res = false;
|
bool res = false;
|
||||||
if (header->root()->is_object)
|
Base *root = header->root();
|
||||||
res = static_cast<Object *>(header->root())->isValid();
|
int maxSize = alloc - sizeof(Header);
|
||||||
|
if (root->is_object)
|
||||||
|
res = static_cast<Object *>(root)->isValid(maxSize);
|
||||||
else
|
else
|
||||||
res = static_cast<Array *>(header->root())->isValid();
|
res = static_cast<Array *>(root)->isValid(maxSize);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -195,9 +197,9 @@ int Object::indexOf(const QString &key, bool *exists)
|
|||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Object::isValid() const
|
bool Object::isValid(int maxSize) const
|
||||||
{
|
{
|
||||||
if (tableOffset + length*sizeof(offset) > size)
|
if (size > (uint)maxSize || tableOffset + length*sizeof(offset) > size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QString lastKey;
|
QString lastKey;
|
||||||
@ -206,8 +208,7 @@ bool Object::isValid() const
|
|||||||
if (entryOffset + sizeof(Entry) >= tableOffset)
|
if (entryOffset + sizeof(Entry) >= tableOffset)
|
||||||
return false;
|
return false;
|
||||||
Entry *e = entryAt(i);
|
Entry *e = entryAt(i);
|
||||||
int s = e->size();
|
if (!e->isValid(tableOffset - table()[i]))
|
||||||
if (table()[i] + s > tableOffset)
|
|
||||||
return false;
|
return false;
|
||||||
QString key = e->key();
|
QString key = e->key();
|
||||||
if (key < lastKey)
|
if (key < lastKey)
|
||||||
@ -221,9 +222,9 @@ bool Object::isValid() const
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Array::isValid() const
|
bool Array::isValid(int maxSize) const
|
||||||
{
|
{
|
||||||
if (tableOffset + length*sizeof(offset) > size)
|
if (size > (uint)maxSize || tableOffset + length*sizeof(offset) > size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uint i = 0; i < length; ++i) {
|
for (uint i = 0; i < length; ++i) {
|
||||||
@ -323,12 +324,12 @@ bool Value::isValid(const Base *b) const
|
|||||||
int s = usedStorage(b);
|
int s = usedStorage(b);
|
||||||
if (!s)
|
if (!s)
|
||||||
return true;
|
return true;
|
||||||
if (s < 0 || offset + s > (int)b->tableOffset)
|
if (s < 0 || s > (int)b->tableOffset - offset)
|
||||||
return false;
|
return false;
|
||||||
if (type == QJsonValue::Array)
|
if (type == QJsonValue::Array)
|
||||||
return static_cast<Array *>(base(b))->isValid();
|
return static_cast<Array *>(base(b))->isValid(s);
|
||||||
if (type == QJsonValue::Object)
|
if (type == QJsonValue::Object)
|
||||||
return static_cast<Object *>(base(b))->isValid();
|
return static_cast<Object *>(base(b))->isValid(s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,12 +302,19 @@ public:
|
|||||||
String(const char *data) { d = (Data *)data; }
|
String(const char *data) { d = (Data *)data; }
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
qle_int length;
|
qle_uint length;
|
||||||
qle_ushort utf16[1];
|
qle_ushort utf16[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
Data *d;
|
Data *d;
|
||||||
|
|
||||||
|
int byteSize() const { return sizeof(uint) + sizeof(ushort) * d->length; }
|
||||||
|
bool isValid(int maxSize) const {
|
||||||
|
// Check byteSize() <= maxSize, avoiding integer overflow
|
||||||
|
maxSize -= sizeof(uint);
|
||||||
|
return maxSize >= 0 && uint(d->length) <= maxSize / sizeof(ushort);
|
||||||
|
}
|
||||||
|
|
||||||
inline String &operator=(const QString &str)
|
inline String &operator=(const QString &str)
|
||||||
{
|
{
|
||||||
d->length = str.length();
|
d->length = str.length();
|
||||||
@ -376,11 +383,16 @@ public:
|
|||||||
Latin1String(const char *data) { d = (Data *)data; }
|
Latin1String(const char *data) { d = (Data *)data; }
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
qle_short length;
|
qle_ushort length;
|
||||||
char latin1[1];
|
char latin1[1];
|
||||||
};
|
};
|
||||||
Data *d;
|
Data *d;
|
||||||
|
|
||||||
|
int byteSize() const { return sizeof(ushort) + sizeof(char)*(d->length); }
|
||||||
|
bool isValid(int maxSize) const {
|
||||||
|
return byteSize() <= maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
inline Latin1String &operator=(const QString &str)
|
inline Latin1String &operator=(const QString &str)
|
||||||
{
|
{
|
||||||
int len = d->length = str.length();
|
int len = d->length = str.length();
|
||||||
@ -567,7 +579,7 @@ public:
|
|||||||
}
|
}
|
||||||
int indexOf(const QString &key, bool *exists);
|
int indexOf(const QString &key, bool *exists);
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid(int maxSize) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -577,7 +589,7 @@ public:
|
|||||||
inline Value at(int i) const;
|
inline Value at(int i) const;
|
||||||
inline Value &operator [](int i);
|
inline Value &operator [](int i);
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid(int maxSize) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -631,12 +643,12 @@ public:
|
|||||||
// key
|
// key
|
||||||
// value data follows key
|
// value data follows key
|
||||||
|
|
||||||
int size() const {
|
uint size() const {
|
||||||
int s = sizeof(Entry);
|
int s = sizeof(Entry);
|
||||||
if (value.latinKey)
|
if (value.latinKey)
|
||||||
s += sizeof(ushort) + qFromLittleEndian(*(ushort *) ((const char *)this + sizeof(Entry)));
|
s += shallowLatin1Key().byteSize();
|
||||||
else
|
else
|
||||||
s += sizeof(uint) + sizeof(ushort)*qFromLittleEndian(*(int *) ((const char *)this + sizeof(Entry)));
|
s += shallowKey().byteSize();
|
||||||
return alignedSize(s);
|
return alignedSize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,6 +674,15 @@ public:
|
|||||||
return shallowKey().toString();
|
return shallowKey().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValid(int maxSize) const {
|
||||||
|
if (maxSize < (int)sizeof(Entry))
|
||||||
|
return false;
|
||||||
|
maxSize -= sizeof(Entry);
|
||||||
|
if (value.latinKey)
|
||||||
|
return shallowLatin1Key().isValid(maxSize);
|
||||||
|
return shallowKey().isValid(maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator ==(const QString &key) const;
|
bool operator ==(const QString &key) const;
|
||||||
inline bool operator !=(const QString &key) const { return !operator ==(key); }
|
inline bool operator !=(const QString &key) const { return !operator ==(key); }
|
||||||
inline bool operator >=(const QString &key) const;
|
inline bool operator >=(const QString &key) const;
|
||||||
|
BIN
tests/auto/corelib/json/invalidBinaryData/10.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/10.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/11.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/11.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/12.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/12.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/13.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/13.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/14.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/14.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/15.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/15.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/16.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/16.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/17.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/17.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/18.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/18.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/19.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/19.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/20.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/20.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/21.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/21.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/22.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/22.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/23.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/23.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/24.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/24.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/25.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/25.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/26.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/26.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/27.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/27.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/28.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/28.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/29.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/29.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/30.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/30.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/31.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/31.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/32.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/32.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/33.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/33.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/34.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/34.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/35.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/35.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/36.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/36.bjson
Normal file
Binary file not shown.
BIN
tests/auto/corelib/json/invalidBinaryData/37.bjson
Normal file
BIN
tests/auto/corelib/json/invalidBinaryData/37.bjson
Normal file
Binary file not shown.
@ -103,6 +103,7 @@ private Q_SLOTS:
|
|||||||
void fromBinary();
|
void fromBinary();
|
||||||
void toAndFromBinary_data();
|
void toAndFromBinary_data();
|
||||||
void toAndFromBinary();
|
void toAndFromBinary();
|
||||||
|
void invalidBinaryData();
|
||||||
void parseNumbers();
|
void parseNumbers();
|
||||||
void parseStrings();
|
void parseStrings();
|
||||||
void parseDuplicateKeys();
|
void parseDuplicateKeys();
|
||||||
@ -1779,6 +1780,21 @@ void tst_QtJson::toAndFromBinary()
|
|||||||
QVERIFY(doc == outdoc);
|
QVERIFY(doc == outdoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QtJson::invalidBinaryData()
|
||||||
|
{
|
||||||
|
QDir dir(testDataDir + "/invalidBinaryData");
|
||||||
|
QFileInfoList files = dir.entryInfoList();
|
||||||
|
for (int i = 0; i < files.size(); ++i) {
|
||||||
|
if (!files.at(i).isFile())
|
||||||
|
continue;
|
||||||
|
QFile file(files.at(i).filePath());
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
QByteArray bytes = file.readAll();
|
||||||
|
QJsonDocument document = QJsonDocument::fromRawData(bytes.constData(), bytes.size());
|
||||||
|
QVERIFY(document.isNull());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QtJson::parseNumbers()
|
void tst_QtJson::parseNumbers()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user