diff options
author | Giuseppe D'Angelo <dangelog@gmail.com> | 2012-03-24 08:50:02 +0000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-04-04 13:02:58 +0200 |
commit | 9a77171ccc2838c2fd7b666ed9ee9c7ba8ebd488 (patch) | |
tree | c2b090636b77d3019b3da9389c596d3753b526f7 /tests/auto/corelib/tools | |
parent | fb20f9c2da369b07fc50857a90b596ae63f943da (diff) |
QHash security fix (1.5/2): qHash two arguments overload support
Algorithmic complexity attacks against hash tables have been known
since 2003 (cf. [1, 2]), and they have been left unpatched for years
until the 2011 attacks [3] against many libraries /
(reference) implementations of programming languages.
This patch adds a qHash overload taking two arguments: the value to
be hashed, and a uint to be used as a seed for the hash function
itself (support the global QHash seed was added in a previous patch).
The seed itself is not used just yet; instead, 0 is passed.
Compatibility with the one-argument qHash(T) implementation is kept
through a catch-all template.
[1] http://www.cs.rice.edu/~scrosby/hash/CrosbyWallach_UsenixSec2003.pdf
[2] http://perldoc.perl.org/perlsec.html#Algorithmic-Complexity-Attacks
[3] http://www.ocert.org/advisories/ocert-2011-003.html
Task-number: QTBUG-23529
Change-Id: I1d0a84899476d134db455418c8043a349a7e5317
Reviewed-by: João Abecasis <joao.abecasis@nokia.com>
Diffstat (limited to 'tests/auto/corelib/tools')
-rw-r--r-- | tests/auto/corelib/tools/qhash/tst_qhash.cpp | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index 3b5d15dbfc..9d18c7a34e 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -73,6 +73,7 @@ private slots: void noNeedlessRehashes(); void const_shared_null(); + void twoArguments_qHash(); }; struct Foo { @@ -1203,5 +1204,101 @@ void tst_QHash::const_shared_null() QVERIFY(!hash2.isDetached()); } +// This gets set to != 0 in wrong qHash overloads +static int wrongqHashOverload = 0; + +struct OneArgumentQHashStruct1 {}; +bool operator==(const OneArgumentQHashStruct1 &, const OneArgumentQHashStruct1 &) { return false; } +uint qHash(OneArgumentQHashStruct1) { return 0; } + +struct OneArgumentQHashStruct2 {}; +bool operator==(const OneArgumentQHashStruct2 &, const OneArgumentQHashStruct2 &) { return false; } +uint qHash(const OneArgumentQHashStruct2 &) { return 0; } + +struct OneArgumentQHashStruct3 {}; +bool operator==(const OneArgumentQHashStruct3 &, const OneArgumentQHashStruct3 &) { return false; } +uint qHash(OneArgumentQHashStruct3) { return 0; } +uint qHash(OneArgumentQHashStruct3 &, uint) { wrongqHashOverload = 1; return 0; } + +struct OneArgumentQHashStruct4 {}; +bool operator==(const OneArgumentQHashStruct4 &, const OneArgumentQHashStruct4 &) { return false; } +uint qHash(const OneArgumentQHashStruct4 &) { return 0; } +uint qHash(OneArgumentQHashStruct4 &, uint) { wrongqHashOverload = 1; return 0; } + + +struct TwoArgumentsQHashStruct1 {}; +bool operator==(const TwoArgumentsQHashStruct1 &, const TwoArgumentsQHashStruct1 &) { return false; } +uint qHash(const TwoArgumentsQHashStruct1 &) { wrongqHashOverload = 1; return 0; } +uint qHash(const TwoArgumentsQHashStruct1 &, uint) { return 0; } + +struct TwoArgumentsQHashStruct2 {}; +bool operator==(const TwoArgumentsQHashStruct2 &, const TwoArgumentsQHashStruct2 &) { return false; } +uint qHash(TwoArgumentsQHashStruct2) { wrongqHashOverload = 1; return 0; } +uint qHash(const TwoArgumentsQHashStruct2 &, uint) { return 0; } + +struct TwoArgumentsQHashStruct3 {}; +bool operator==(const TwoArgumentsQHashStruct3 &, const TwoArgumentsQHashStruct3 &) { return false; } +uint qHash(const TwoArgumentsQHashStruct3 &) { wrongqHashOverload = 1; return 0; } +uint qHash(TwoArgumentsQHashStruct3, uint) { return 0; } + +struct TwoArgumentsQHashStruct4 {}; +bool operator==(const TwoArgumentsQHashStruct4 &, const TwoArgumentsQHashStruct4 &) { return false; } +uint qHash(TwoArgumentsQHashStruct4) { wrongqHashOverload = 1; return 0; } +uint qHash(TwoArgumentsQHashStruct4, uint) { return 0; } + +/*! + \internal + + Check that QHash picks up the right overload. + The best one, for a type T, is the two-args version of qHash: + either uint qHash(T, uint) or uint qHash(const T &, uint). + + If neither of these exists, then one between + uint qHash(T) or uint qHash(const T &) must exist + (and it gets selected instead). +*/ +void tst_QHash::twoArguments_qHash() +{ + QHash<OneArgumentQHashStruct1, int> oneArgHash1; + OneArgumentQHashStruct1 oneArgObject1; + oneArgHash1[oneArgObject1] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<OneArgumentQHashStruct2, int> oneArgHash2; + OneArgumentQHashStruct2 oneArgObject2; + oneArgHash2[oneArgObject2] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<OneArgumentQHashStruct3, int> oneArgHash3; + OneArgumentQHashStruct3 oneArgObject3; + oneArgHash3[oneArgObject3] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<OneArgumentQHashStruct4, int> oneArgHash4; + OneArgumentQHashStruct4 oneArgObject4; + oneArgHash4[oneArgObject4] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct1, int> twoArgsHash1; + TwoArgumentsQHashStruct1 twoArgsObject1; + twoArgsHash1[twoArgsObject1] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct2, int> twoArgsHash2; + TwoArgumentsQHashStruct2 twoArgsObject2; + twoArgsHash2[twoArgsObject2] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct3, int> twoArgsHash3; + TwoArgumentsQHashStruct3 twoArgsObject3; + twoArgsHash3[twoArgsObject3] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct4, int> twoArgsHash4; + TwoArgumentsQHashStruct4 twoArgsObject4; + twoArgsHash4[twoArgsObject4] = 1; + QCOMPARE(wrongqHashOverload, 0); +} + QTEST_APPLESS_MAIN(tst_QHash) #include "tst_qhash.moc" |