[tor-commits] [torbrowser/maint-2.3] Improve the website fingerprinting defense patch.
mikeperry at torproject.org
mikeperry at torproject.org
Wed Apr 11 23:11:25 UTC 2012
commit 67873541918d9597024d4439b45c9d1cd3ec582d
Author: Mike Perry <mikeperry-git at 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 at 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-fingerprinting
----
- 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 at 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-fingerprinting
+
+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
+
More information about the tor-commits
mailing list