commit 67873541918d9597024d4439b45c9d1cd3ec582d Author: Mike Perry mikeperry-git@fscked.org Date: Wed Apr 11 15:47:11 2012 -0700
Improve the website fingerprinting defense patch. --- ...6-Randomize-HTTP-pipeline-order-and-depth.patch | 151 ------------- ...ize-HTTP-request-order-and-pipeline-depth.patch | 234 ++++++++++++++++++++ 2 files changed, 234 insertions(+), 151 deletions(-)
diff --git a/src/current-patches/firefox/0006-Randomize-HTTP-pipeline-order-and-depth.patch b/src/current-patches/firefox/0006-Randomize-HTTP-pipeline-order-and-depth.patch deleted file mode 100644 index 04a34ea..0000000 --- a/src/current-patches/firefox/0006-Randomize-HTTP-pipeline-order-and-depth.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 39a9dab25c4ed3acc95009c0f44f4f6f2f1c5086 Mon Sep 17 00:00:00 2001 -From: Mike Perry mikeperry-git@torproject.org -Date: Thu, 15 Mar 2012 20:05:07 -0700 -Subject: [PATCH 06/13] Randomize HTTP pipeline order and depth. - -This is an experimental defense against -http://lorre.uni.lu/~andriy/papers/acmccs-wpes11-fingerprinting.pdf - -See also: -https://blog.torproject.org/blog/experimental-defense-website-traffic-finger... ---- - netwerk/protocol/http/nsHttpConnectionMgr.cpp | 79 ++++++++++++++++++++++++- - netwerk/protocol/http/nsHttpConnectionMgr.h | 4 + - 2 files changed, 82 insertions(+), 1 deletions(-) - -diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp -index 17d897f..3200638 100644 ---- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp -+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp -@@ -99,6 +99,12 @@ nsHttpConnectionMgr::nsHttpConnectionMgr() - LOG(("Creating nsHttpConnectionMgr @%x\n", this)); - mCT.Init(); - mAlternateProtocolHash.Init(16); -+ -+ nsresult rv; -+ mRandomGenerator = do_GetService("@mozilla.org/security/random-generator;1", &rv); -+ if (NS_FAILED(rv)) { -+ mRandomGenerator = nsnull; -+ } - } - - nsHttpConnectionMgr::~nsHttpConnectionMgr() -@@ -1227,7 +1233,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent, - - if (conn->SupportsPipelining() && (caps & NS_HTTP_ALLOW_PIPELINING)) { - LOG((" looking to build pipeline...\n")); -- if (BuildPipeline(ent, trans, &pipeline)) -+ if (BuildRandomizedPipeline(ent, trans, &pipeline)) - trans = pipeline; - } - -@@ -1300,6 +1306,77 @@ nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry *ent, - return true; - } - -+bool -+nsHttpConnectionMgr::BuildRandomizedPipeline(nsConnectionEntry *ent, -+ nsAHttpTransaction *firstTrans, -+ nsHttpPipeline **result) -+{ -+ if (mRandomGenerator == nsnull) -+ return BuildPipeline(ent, firstTrans, result); -+ if (mMaxPipelinedRequests < 2) -+ return PR_FALSE; -+ -+ nsresult rv; -+ PRUint8 *bytes = nsnull; -+ -+ nsHttpPipeline *pipeline = nsnull; -+ nsHttpTransaction *trans; -+ -+ PRUint32 i = 0, numAdded = 0, numAllowed = 0; -+ PRUint32 max = 0; -+ -+ while (i < ent->mPendingQ.Length()) { -+ if (ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING) -+ numAllowed++; -+ i++; -+ } -+ -+ rv = mRandomGenerator->GenerateRandomBytes(1, &bytes); -+ NS_ENSURE_SUCCESS(rv, rv); -+ // 4...12 -+ max = 4 + (bytes[0] % (mMaxPipelinedRequests + 1)); -+ NS_Free(bytes); -+ -+ while (numAllowed > 0) { -+ rv = mRandomGenerator->GenerateRandomBytes(1, &bytes); -+ NS_ENSURE_SUCCESS(rv, rv); -+ i = bytes[0] % ent->mPendingQ.Length(); -+ NS_Free(bytes); -+ -+ trans = ent->mPendingQ[i]; -+ -+ if (!(ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING)) -+ continue; -+ -+ if (numAdded == 0) { -+ pipeline = new nsHttpPipeline; -+ if (!pipeline) -+ return PR_FALSE; -+ pipeline->AddTransaction(firstTrans); -+ numAdded = 1; -+ } -+ pipeline->AddTransaction(trans); -+ -+ // remove transaction from pending queue -+ ent->mPendingQ.RemoveElementAt(i); -+ NS_RELEASE(trans); -+ -+ numAllowed--; -+ -+ if (++numAdded == max) -+ break; -+ } -+ -+ //fprintf(stderr, "Yay!!! pipelined %u/%u transactions\n", numAdded, max); -+ LOG((" pipelined %u/%u transactions\n", numAdded, max)); -+ -+ if (numAdded == 0) -+ return PR_FALSE; -+ -+ NS_ADDREF(*result = pipeline); -+ return PR_TRUE; -+} -+ - nsresult - nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans) - { -diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h -index bb605a1..47d01f6 100644 ---- a/netwerk/protocol/http/nsHttpConnectionMgr.h -+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h -@@ -54,6 +54,7 @@ - #include "nsIObserver.h" - #include "nsITimer.h" - #include "nsIX509Cert3.h" -+#include "nsIRandomGenerator.h" - - class nsHttpPipeline; - -@@ -312,6 +313,7 @@ private: - nsresult DispatchTransaction(nsConnectionEntry *, nsHttpTransaction *, - PRUint8 caps, nsHttpConnection *); - bool BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **); -+ bool BuildRandomizedPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **); - nsresult ProcessNewTransaction(nsHttpTransaction *); - nsresult EnsureSocketThreadTargetIfOnline(); - void ClosePersistentConnections(nsConnectionEntry *ent); -@@ -405,6 +407,8 @@ private: - PRUint64 mTimeOfNextWakeUp; - // Timer for next pruning of dead connections. - nsCOMPtr<nsITimer> mTimer; -+ // Random number generator for reordering HTTP pipeline -+ nsCOMPtr<nsIRandomGenerator> mRandomGenerator; - - // - // the connection table --- -1.7.5.4 - diff --git a/src/current-patches/firefox/0006-Randomize-HTTP-request-order-and-pipeline-depth.patch b/src/current-patches/firefox/0006-Randomize-HTTP-request-order-and-pipeline-depth.patch new file mode 100644 index 0000000..9687737 --- /dev/null +++ b/src/current-patches/firefox/0006-Randomize-HTTP-request-order-and-pipeline-depth.patch @@ -0,0 +1,234 @@ +From 8e8833ea22369c7597f5844139de37212deb1cd7 Mon Sep 17 00:00:00 2001 +From: Mike Perry mikeperry-git@torproject.org +Date: Thu, 15 Mar 2012 20:05:07 -0700 +Subject: [PATCH 12/12] Randomize HTTP request order and pipeline depth. + +This is an experimental defense against +http://lorre.uni.lu/~andriy/papers/acmccs-wpes11-fingerprinting.pdf + +See: +https://blog.torproject.org/blog/experimental-defense-website-traffic-finger... + +This defense has been improved since that blog post to additionally randomize +the order and concurrency of non-pipelined HTTP requests. +--- + netwerk/protocol/http/nsHttpConnectionMgr.cpp | 133 ++++++++++++++++++++++++- + netwerk/protocol/http/nsHttpConnectionMgr.h | 5 + + 2 files changed, 133 insertions(+), 5 deletions(-) + +diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp +index 17d897f..8f50bf6 100644 +--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp ++++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp +@@ -99,6 +99,12 @@ nsHttpConnectionMgr::nsHttpConnectionMgr() + LOG(("Creating nsHttpConnectionMgr @%x\n", this)); + mCT.Init(); + mAlternateProtocolHash.Init(16); ++ ++ nsresult rv; ++ mRandomGenerator = do_GetService("@mozilla.org/security/random-generator;1", &rv); ++ if (NS_FAILED(rv)) { ++ mRandomGenerator = nsnull; ++ } + } + + nsHttpConnectionMgr::~nsHttpConnectionMgr() +@@ -353,8 +359,12 @@ nsHttpConnectionMgr::AddTransactionToPipeline(nsHttpPipeline *pipeline) + nsConnectionEntry *ent = mCT.Get(ci->HashKey()); + if (ent) { + // search for another request to pipeline... +- PRInt32 i, count = ent->mPendingQ.Length(); +- for (i=0; i<count; ++i) { ++ PRInt32 i, h, count = ent->mPendingQ.Length(); ++ PRInt32 ind[count]; ++ ShuffleRequestOrder((PRUint32*)ind, (PRUint32)count); ++ ++ for (h=0; h<count; ++h) { ++ i = ind[h]; // random request sequence + nsHttpTransaction *trans = ent->mPendingQ[i]; + if (trans->Caps() & NS_HTTP_ALLOW_PIPELINING) { + pipeline->AddTransaction(trans); +@@ -895,12 +905,17 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent) + if (gHttpHandler->IsSpdyEnabled()) + ProcessSpdyPendingQ(ent); + +- PRUint32 i, count = ent->mPendingQ.Length(); ++ PRUint32 h, i = 0, count = ent->mPendingQ.Length(); + if (count > 0) { + LOG((" pending-count=%u\n", count)); + nsHttpTransaction *trans = nsnull; + nsHttpConnection *conn = nsnull; +- for (i = 0; i < count; ++i) { ++ ++ PRUint32 ind[count]; ++ ShuffleRequestOrder(ind, count); ++ ++ for (h=0; h<count; ++h) { ++ i = ind[h]; // random request sequence + trans = ent->mPendingQ[i]; + + // When this transaction has already established a half-open +@@ -1011,6 +1026,19 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, PRUint8 cap + maxPersistConns = mMaxPersistConnsPerHost; + } + ++ // Fuzz maxConns for website fingerprinting attack ++ // We create a range of maxConns/5 up to 6*maxConns/5 ++ // because this function is called repeatedly, and we'll ++ // end up converging on a the high side of concurrent connections ++ // after a short while. ++ PRUint8 *bytes = nsnull; ++ nsresult rv = mRandomGenerator->GenerateRandomBytes(1, &bytes); ++ NS_ENSURE_SUCCESS(rv, rv); ++ ++ bytes[0] = bytes[0] % (maxConns + 1); ++ maxConns = (maxConns/5) + bytes[0]; ++ NS_Free(bytes); ++ + // use >= just to be safe + return (totalCount >= maxConns) || ( (caps & NS_HTTP_ALLOW_KEEPALIVE) && + (persistCount >= maxPersistConns) ); +@@ -1227,7 +1255,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent, + + if (conn->SupportsPipelining() && (caps & NS_HTTP_ALLOW_PIPELINING)) { + LOG((" looking to build pipeline...\n")); +- if (BuildPipeline(ent, trans, &pipeline)) ++ if (BuildRandomizedPipeline(ent, trans, &pipeline)) + trans = pipeline; + } + +@@ -1300,6 +1328,101 @@ nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry *ent, + return true; + } + ++ ++// Generate a shuffled request ordering sequence ++void ++nsHttpConnectionMgr::ShuffleRequestOrder(PRUint32 *ind, PRUint32 count) ++{ ++ PRUint32 i; ++ PRUint32 *rints; ++ ++ for (i=0; i<count; ++i) { ++ ind[i] = i; ++ } ++ nsresult rv = mRandomGenerator->GenerateRandomBytes(sizeof(PRUint32)*count, ++ (PRUint8**)&rints); ++ if (NS_FAILED(rv)) ++ return; // Leave unshuffled if error ++ ++ for (i=0; i < count; ++i) { ++ PRInt32 temp = ind[i]; ++ ind[i] = ind[rints[i]%count]; ++ ind[rints[i]%count] = temp; ++ } ++ NS_Free(rints); ++} ++ ++bool ++nsHttpConnectionMgr::BuildRandomizedPipeline(nsConnectionEntry *ent, ++ nsAHttpTransaction *firstTrans, ++ nsHttpPipeline **result) ++{ ++ if (mRandomGenerator == nsnull) ++ return BuildPipeline(ent, firstTrans, result); ++ if (mMaxPipelinedRequests < 2) ++ return PR_FALSE; ++ ++ nsresult rv; ++ PRUint8 *bytes = nsnull; ++ ++ nsHttpPipeline *pipeline = nsnull; ++ nsHttpTransaction *trans; ++ ++ PRUint32 i = 0, numAdded = 0, numAllowed = 0; ++ PRUint32 max = 0; ++ ++ while (i < ent->mPendingQ.Length()) { ++ if (ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING) ++ numAllowed++; ++ i++; ++ } ++ ++ rv = mRandomGenerator->GenerateRandomBytes(1, &bytes); ++ NS_ENSURE_SUCCESS(rv, rv); ++ // 4...12 ++ max = 4 + (bytes[0] % (mMaxPipelinedRequests + 1)); ++ NS_Free(bytes); ++ ++ while (numAllowed > 0) { ++ rv = mRandomGenerator->GenerateRandomBytes(1, &bytes); ++ NS_ENSURE_SUCCESS(rv, rv); ++ i = bytes[0] % ent->mPendingQ.Length(); ++ NS_Free(bytes); ++ ++ trans = ent->mPendingQ[i]; ++ ++ if (!(ent->mPendingQ[i]->Caps() & NS_HTTP_ALLOW_PIPELINING)) ++ continue; ++ ++ if (numAdded == 0) { ++ pipeline = new nsHttpPipeline; ++ if (!pipeline) ++ return PR_FALSE; ++ pipeline->AddTransaction(firstTrans); ++ numAdded = 1; ++ } ++ pipeline->AddTransaction(trans); ++ ++ // remove transaction from pending queue ++ ent->mPendingQ.RemoveElementAt(i); ++ NS_RELEASE(trans); ++ ++ numAllowed--; ++ ++ if (++numAdded == max) ++ break; ++ } ++ ++ //fprintf(stderr, "Yay!!! pipelined %u/%u transactions\n", numAdded, max); ++ LOG((" pipelined %u/%u transactions\n", numAdded, max)); ++ ++ if (numAdded == 0) ++ return PR_FALSE; ++ ++ NS_ADDREF(*result = pipeline); ++ return PR_TRUE; ++} ++ + nsresult + nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans) + { +diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h +index bb605a1..e372096 100644 +--- a/netwerk/protocol/http/nsHttpConnectionMgr.h ++++ b/netwerk/protocol/http/nsHttpConnectionMgr.h +@@ -54,6 +54,7 @@ + #include "nsIObserver.h" + #include "nsITimer.h" + #include "nsIX509Cert3.h" ++#include "nsIRandomGenerator.h" + + class nsHttpPipeline; + +@@ -312,6 +313,8 @@ private: + nsresult DispatchTransaction(nsConnectionEntry *, nsHttpTransaction *, + PRUint8 caps, nsHttpConnection *); + bool BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **); ++ bool BuildRandomizedPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **); ++ void ShuffleRequestOrder(PRUint32 *, PRUint32); + nsresult ProcessNewTransaction(nsHttpTransaction *); + nsresult EnsureSocketThreadTargetIfOnline(); + void ClosePersistentConnections(nsConnectionEntry *ent); +@@ -405,6 +408,8 @@ private: + PRUint64 mTimeOfNextWakeUp; + // Timer for next pruning of dead connections. + nsCOMPtr<nsITimer> mTimer; ++ // Random number generator for reordering HTTP pipeline ++ nsCOMPtr<nsIRandomGenerator> mRandomGenerator; + + // + // the connection table +-- +1.7.5.4 +
tor-commits@lists.torproject.org