Bug 1344461 - Keep track of line length to not read beyond eol. r=valentin a=gchang
authorDaniel Stenberg <daniel@haxx.se>
Mon, 20 Mar 2017 18:23:18 -0400
changeset 379140 1171236daacc7fb79e5400c2ac00c881f93042f0
parent 379139 4153103b32cc4e617f9c61d2e569b1566e974311
child 379141 e85944a3d58f1219869582dd117282c63cf520a3
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvalentin, gchang
bugs1344461
milestone53.0
Bug 1344461 - Keep track of line length to not read beyond eol. r=valentin a=gchang
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[];