Bug 1344461 - Keep track of line length to not read beyond eol. r=valentin
authorDaniel Stenberg <daniel@haxx.se>
Mon, 20 Mar 2017 18:23:18 -0400
changeset 348532 5ef67e15fd88a16025632e31ec1bb6519d2f4441
parent 348531 b4e95d147909540f65d41a921e57c510bdc22bc5
child 348533 514a06ddb08ca52e552124f6d23d2f053c4f7e13
push id31526
push userkwierso@gmail.com
push dateTue, 21 Mar 2017 01:20:02 +0000
treeherdermozilla-central@5fe5dcf1c10a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin
bugs1344461
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1344461 - Keep track of line length to not read beyond eol. r=valentin
netwerk/streamconv/converters/nsDirIndexParser.cpp
netwerk/streamconv/converters/nsDirIndexParser.h
--- a/netwerk/streamconv/converters/nsDirIndexParser.cpp
+++ b/netwerk/streamconv/converters/nsDirIndexParser.cpp
@@ -149,16 +149,17 @@ nsDirIndexParser::ParseFormat(const char
   } while (*pos);
 
   delete[] mFormat;
   mFormat = new int[num+1];
   // Prevent nullptr Deref - Bug 443299 
   if (mFormat == nullptr)
     return NS_ERROR_OUT_OF_MEMORY;
   mFormat[num] = -1;
+  mFormat[0] = -1; // to detect zero header fields
   
   int formatNum=0;
   do {
     while (*aFormatStr && nsCRT::IsAsciiSpace(char16_t(*aFormatStr)))
       ++aFormatStr;
     
     if (! *aFormatStr)
       break;
@@ -187,57 +188,83 @@ nsDirIndexParser::ParseFormat(const char
     }
 
   } while (*aFormatStr);
   
   return NS_OK;
 }
 
 nsresult
-nsDirIndexParser::ParseData(nsIDirIndex *aIdx, char* aDataStr) {
+nsDirIndexParser::ParseData(nsIDirIndex *aIdx, char* aDataStr, int32_t aLineLen)
+{
   // Parse a "201" data line, using the field ordering specified in
   // mFormat.
 
   if (!mFormat) {
     // Ignore if we haven't seen a format yet.
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
+  nsAutoCString filename;
+  int32_t lineLen = aLineLen;
 
-  nsAutoCString filename;
+  if (mFormat[0] == -1) {
+    // no known header fields is an error
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
 
   for (int32_t i = 0; mFormat[i] != -1; ++i) {
-    // If we've exhausted the data before we run out of fields, just
-    // bail.
-    if (! *aDataStr)
-      break;
+    // If we've exhausted the data before we run out of fields, just bail.
+    if (!*aDataStr || (lineLen < 1)) {
+      return NS_ERROR_ILLEGAL_VALUE;
+    }
 
-    while (*aDataStr && nsCRT::IsAsciiSpace(*aDataStr))
+    while ((lineLen > 0) && nsCRT::IsAsciiSpace(*aDataStr)) {
       ++aDataStr;
+      --lineLen;
+    }
+
+    if (lineLen < 1) {
+      // invalid format, bail
+      return NS_ERROR_ILLEGAL_VALUE;
+    }
 
     char    *value = aDataStr;
-
     if (*aDataStr == '"' || *aDataStr == '\'') {
       // it's a quoted string. snarf everything up to the next quote character
       const char quotechar = *(aDataStr++);
+      lineLen--;
       ++value;
-      while (*aDataStr && *aDataStr != quotechar)
+      while ((lineLen > 0) && *aDataStr != quotechar) {
         ++aDataStr;
-      *aDataStr++ = '\0';
+        --lineLen;
+      }
+      if (lineLen > 0) {
+        *aDataStr++ = '\0';
+        --lineLen;
+      }
 
-      if (! aDataStr) {
-        NS_WARNING("quoted value not terminated");
+      if (!lineLen) {
+        // invalid format, bail
+        return NS_ERROR_ILLEGAL_VALUE;
       }
     } else {
       // it's unquoted. snarf until we see whitespace.
       value = aDataStr;
-      while (*aDataStr && (!nsCRT::IsAsciiSpace(*aDataStr)))
+      while ((lineLen > 0) && (!nsCRT::IsAsciiSpace(*aDataStr))) {
         ++aDataStr;
-      *aDataStr++ = '\0';
+        --lineLen;
+      }
+      if (lineLen > 0) {
+        *aDataStr++ = '\0';
+        --lineLen;
+      }
+      // even if we ran out of line length here, there's still a trailing zero
+      // byte afterwards
     }
 
     fieldType t = fieldType(mFormat[i]);
     switch (t) {
     case FIELD_FILENAME: {
       // don't unescape at this point, so that UnEscapeAndConvert() can
       filename = value;
       
@@ -399,17 +426,17 @@ nsDirIndexParser::ProcessData(nsIRequest
               return rv;
             }
           } else if (buf[2] == '1' && buf[3] == ':') {
             // 201. Field data
             nsCOMPtr<nsIDirIndex> idx = do_CreateInstance("@mozilla.org/dirIndex;1",&rv);
             if (NS_FAILED(rv))
               return rv;
             
-            rv = ParseData(idx, ((char *)buf) + 4);
+            rv = ParseData(idx, ((char *)buf) + 4, lineLen - 4);
             if (NS_FAILED(rv)) {
               return rv;
             }
 
             mListener->OnIndexAvailable(aRequest, aCtxt, idx);
           }
         }
       } else if (buf[0] == '3') {
--- a/netwerk/streamconv/converters/nsDirIndexParser.h
+++ b/netwerk/streamconv/converters/nsDirIndexParser.h
@@ -46,17 +46,17 @@ protected:
     nsCString    mComment;
     nsCString    mBuf;
     int32_t      mLineStart;
     bool         mHasDescription;
     int*         mFormat;
 
     nsresult ProcessData(nsIRequest *aRequest, nsISupports *aCtxt);
     nsresult ParseFormat(const char* buf);
-    nsresult ParseData(nsIDirIndex* aIdx, char* aDataStr);
+    nsresult ParseData(nsIDirIndex* aIdx, char* aDataStr, int32_t lineLen);
 
     struct Field {
         const char *mName;
         fieldType mType;
     };
 
     static Field gFieldTable[];