summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/tools
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <dangelog@gmail.com>2012-03-24 08:50:02 +0000
committerQt by Nokia <qt-info@nokia.com>2012-04-04 13:02:58 +0200
commit9a77171ccc2838c2fd7b666ed9ee9c7ba8ebd488 (patch)
treec2b090636b77d3019b3da9389c596d3753b526f7 /tests/auto/corelib/tools
parentfb20f9c2da369b07fc50857a90b596ae63f943da (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.cpp97
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"