Bug 702217 - Add very basic sanity checking to PrefixSet construction. Handle corrupted update errors. r=dcamp
authorGian-Carlo Pascutto <gpascutto@mozilla.com>
Fri, 02 Dec 2011 10:45:56 +0100
changeset 81956 636ea2bf3366ecabe3832080e4fb5e7e75f49306
parent 81955 7319edc477a342754f8d05ba6c890540135cfb46
child 81957 cddc8b0ba0b64339f82d4eb39bfaa6776389850b
push idunknown
push userunknown
push dateunknown
reviewersdcamp
bugs702217
milestone11.0a1
Bug 702217 - Add very basic sanity checking to PrefixSet construction. Handle corrupted update errors. r=dcamp
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -3073,18 +3073,23 @@ nsUrlClassifierDBServiceWorker::FinishSt
            mServerMAC.get(), clientMAC.get()));
       mUpdateStatus = NS_ERROR_FAILURE;
     }
     PRIntervalTime updateTime = PR_IntervalNow() - mUpdateStartTime;
     if (PR_IntervalToSeconds(updateTime) >=
         static_cast<PRUint32>(gWorkingTimeThreshold)) {
       // We've spent long enough working that we should commit what we
       // have and hold off for a bit.
-      ApplyUpdate();
-
+      nsresult rv = ApplyUpdate();
+      if (NS_FAILED(rv)) {
+        if (rv == NS_ERROR_FILE_CORRUPTED) {
+          ResetDatabase();
+        }
+        return rv;
+      }
       nextStreamDelay = gDelayTime * 1000;
     }
   }
 
   mUpdateObserver->StreamFinished(mUpdateStatus,
                                   static_cast<PRUint32>(nextStreamDelay));
 
   ResetStream();
@@ -3186,17 +3191,23 @@ nsUrlClassifierDBServiceWorker::FinishUp
   NS_ENSURE_STATE(mUpdateObserver);
 
   // We need to get the error code before ApplyUpdate, because it might
   // close/open the connection.
   PRInt32 errcode = SQLITE_OK;
   if (mConnection)
     mConnection->GetLastError(&errcode);
 
-  ApplyUpdate();
+  nsresult rv = ApplyUpdate();
+  if (NS_FAILED(rv)) {
+    if (rv == NS_ERROR_FILE_CORRUPTED) {
+      ResetDatabase();
+    }
+    return rv;
+  }
 
   if (NS_SUCCEEDED(mUpdateStatus)) {
     mUpdateObserver->UpdateSuccess(mUpdateWait);
   } else {
     mUpdateObserver->UpdateError(mUpdateStatus);
   }
 
   // It's important that we only reset the database on an update
@@ -3448,17 +3459,22 @@ nsUrlClassifierDBServiceWorker::OpenDb()
 
   mConnection = connection;
 
   mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   LOG(("loading Prefix Set\n"));
   rv = LoadPrefixSet(mPSFile);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    if (rv == NS_ERROR_FILE_CORRUPTED) {
+      ResetDatabase();
+    }
+    return rv;
+  }
 
   return NS_OK;
 }
 
 // We have both a prefix and a domain. Drop the domain, but
 // hash the domain, the prefix and a random value together,
 // ensuring any collisions happens at a different points for
 // different users.
@@ -3556,16 +3572,21 @@ nsresult nsUrlClassifierStore::ReadPrefi
     }
 
     PRUint32 keyedVal;
     nsresult rv = KeyedHash(prefixval, domainval, aKey, &keyedVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     array.AppendElement(keyedVal);
     pcnt++;
+    // Normal DB size is about 500k entries. If we are getting 10x
+    // as much, the database must be corrupted.
+    if (pcnt > 5000000) {
+      return NS_ERROR_FILE_CORRUPTED;
+    }
   }
 
   LOG(("SB prefixes: %d fulldomain: %d\n", pcnt, fcnt));
 
 #if defined(PR_LOGGING)
   if (LOG_ENABLED()) {
     PRIntervalTime clockEnd = PR_IntervalNow();
     LOG(("Gathering took %dms\n",
@@ -3643,17 +3664,18 @@ nsUrlClassifierDBServiceWorker::LoadPref
 
   if (exists) {
     Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_PS_FILELOAD_TIME> timer;
     LOG(("stored PrefixSet exists, loading from disk"));
     rv = mPrefixSet->LoadFromFile(aFile);
   }
   if (!exists || NS_FAILED(rv)) {
     LOG(("no (usable) stored PrefixSet found, constructing from store"));
-    ConstructPrefixSet();
+    rv = ConstructPrefixSet();
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
 #ifdef DEBUG
   PRUint32 size = 0;
   rv = mPrefixSet->SizeOfIncludingThis(&size);
   LOG(("SB tree done, size = %d bytes\n", size));
   NS_ENSURE_SUCCESS(rv, rv);
 #endif