Bug 1484987 - Avoid writing past the logical length of a string in XPCOM. r=froydnj
☠☠ backed out by 14e5c98875ec ☠ ☠
authorHenri Sivonen <hsivonen@hsivonen.fi>
Tue, 28 Aug 2018 14:29:40 +0000
changeset 488795 9216e8942ed6d31b68411623420e45f3ca964adf
parent 488794 8fd8a747cd87423a2b6938c243393157e2b0e6e4
child 488796 14e5c98875ec7b56d847f74f4eb1658683126310
push id9734
push usershindli@mozilla.com
push dateThu, 30 Aug 2018 12:18:07 +0000
treeherdermozilla-beta@71c71ab3afae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1484987
milestone63.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 1484987 - Avoid writing past the logical length of a string in XPCOM. r=froydnj MozReview-Commit-ID: 3qkhOiQduLQ Differential Revision: https://phabricator.services.mozilla.com/D3883
xpcom/io/Base64.cpp
xpcom/io/nsStorageStream.cpp
--- a/xpcom/io/Base64.cpp
+++ b/xpcom/io/Base64.cpp
@@ -386,26 +386,24 @@ Base64EncodeHelper(const T& aBinary, T& 
 
   if (aBinary.IsEmpty()) {
     aBase64.Truncate();
     return NS_OK;
   }
 
   uint32_t base64Len = ((aBinary.Length() + 2) / 3) * 4;
 
-  // Add one byte for null termination.
-  if (!aBase64.SetCapacity(base64Len + 1, fallible)) {
-    return NS_ERROR_OUT_OF_MEMORY;
+  nsresult rv;
+  auto handle = aBase64.BulkWrite(base64Len, 0, false, rv);
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
-  typename T::char_type* base64 = aBase64.BeginWriting();
-  Encode(aBinary.BeginReading(), aBinary.Length(), base64);
-  base64[base64Len] = '\0';
-
-  aBase64.SetLength(base64Len);
+  Encode(aBinary.BeginReading(), aBinary.Length(), handle.Elements());
+  handle.Finish(base64Len, false);
   return NS_OK;
 }
 
 nsresult
 Base64Encode(const nsACString& aBinary, nsACString& aBase64)
 {
   return Base64EncodeHelper(aBinary, aBase64);
 }
@@ -570,30 +568,29 @@ Base64DecodeString(const T& aBase64, T& 
   // Don't decode the empty string
   if (aBase64.IsEmpty()) {
     aBinary.Truncate();
     return NS_OK;
   }
 
   uint32_t binaryLen = ((aBase64.Length() * 3) / 4);
 
-  // Add one byte for null termination.
-  if (!aBinary.SetCapacity(binaryLen + 1, fallible)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  typename T::char_type* binary = aBinary.BeginWriting();
-  nsresult rv = Base64DecodeHelper(aBase64.BeginReading(), aBase64.Length(),
-                                   binary, &binaryLen);
-  if (NS_FAILED(rv)) {
-    aBinary.Truncate();
+  nsresult rv;
+  auto handle = aBinary.BulkWrite(binaryLen, 0, false, rv);
+  if(NS_FAILED(rv)) {
     return rv;
   }
 
-  aBinary.SetLength(binaryLen);
+  rv = Base64DecodeHelper(aBase64.BeginReading(), aBase64.Length(),
+                          handle.Elements(), &binaryLen);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  handle.Finish(binaryLen, true);
   return NS_OK;
 }
 
 nsresult
 Base64Decode(const nsACString& aBase64, nsACString& aBinary)
 {
   return Base64DecodeString(aBase64, aBinary);
 }
--- a/xpcom/io/nsStorageStream.cpp
+++ b/xpcom/io/nsStorageStream.cpp
@@ -580,23 +580,25 @@ nsStorageInputStream::Serialize(InputStr
   int64_t offset;
   mozilla::DebugOnly<nsresult> rv = Tell(&offset);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   uint64_t remaining;
   rv = Available(&remaining);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
-  combined.SetCapacity(remaining);
+  auto handle = combined.BulkWrite(remaining, 0, false, rv);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+
   uint32_t numRead = 0;
 
-  rv = Read(combined.BeginWriting(), remaining, &numRead);
+  rv = Read(handle.Elements(), remaining, &numRead);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   MOZ_ASSERT(numRead == remaining);
-  combined.SetLength(numRead);
+  handle.Finish(numRead, false);
 
   rv = Seek(NS_SEEK_SET, offset);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   StringInputStreamParams params;
   params.data() = combined;
   aParams = params;
 }