Bug 1473161 - Add missing bound check in nsContentUtils::DataTransferItemToImage. r=nika a=RyanVM
authorAnny Gakhokidze <agakhokidze@mozilla.com>
Tue, 17 Jul 2018 19:02:51 -0400
changeset 478020 a85b6c7cc4181d314cedcc865bb228ff44fab99e
parent 478019 83e495b4c9335e11c2cce23a30c01c821087c1c1
child 478021 6fffc0b497a3b306d929f7ed8221ac648748f5c0
push id9500
push userarchaeopteryx@coole-files.de
push dateThu, 19 Jul 2018 07:13:35 +0000
treeherdermozilla-beta@9573e5a35f1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika, RyanVM
bugs1473161
milestone62.0
Bug 1473161 - Add missing bound check in nsContentUtils::DataTransferItemToImage. r=nika a=RyanVM MozReview-Commit-ID: 3dq5yWZwJiG
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7918,30 +7918,62 @@ nsContentUtils::IsFileImage(nsIFile* aFi
   if (NS_FAILED(rv)) {
     return false;
   }
 
   return StringBeginsWith(aType, NS_LITERAL_CSTRING("image/"));
 }
 
 nsresult
+nsContentUtils::CalculateBufferSizeForImage(const uint32_t& aStride,
+                                            const IntSize& aImageSize,
+                                            const SurfaceFormat& aFormat,
+                                            size_t* aMaxBufferSize,
+                                            size_t* aUsedBufferSize)
+{
+  CheckedInt32 requiredBytes =
+    CheckedInt32(aStride) * CheckedInt32(aImageSize.height);
+  if (!requiredBytes.isValid()) {
+    return NS_ERROR_FAILURE;
+  }
+  *aMaxBufferSize = requiredBytes.value();
+  *aUsedBufferSize = *aMaxBufferSize - aStride + (aImageSize.width * BytesPerPixel(aFormat));
+  return NS_OK;
+}
+
+nsresult
 nsContentUtils::DataTransferItemToImage(const IPCDataTransferItem& aItem,
                                         imgIContainer** aContainer)
 {
   MOZ_ASSERT(aItem.data().type() == IPCDataTransferData::TShmem);
   MOZ_ASSERT(IsFlavorImage(aItem.flavor()));
 
   const IPCDataTransferImage& imageDetails = aItem.imageDetails();
   const IntSize size(imageDetails.width(), imageDetails.height());
   if (!size.width || !size.height) {
     return NS_ERROR_FAILURE;
   }
 
   Shmem data = aItem.data().get_Shmem();
 
+  // Validate shared memory buffer size
+  size_t imageBufLen = 0;
+  size_t maxBufLen = 0;
+  nsresult rv = CalculateBufferSizeForImage(imageDetails.stride(),
+                                            size,
+                                            imageDetails.format(),
+                                            &maxBufLen,
+                                            &imageBufLen);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (imageBufLen > data.Size<uint8_t>()) {
+    return NS_ERROR_FAILURE;
+  }
+
   RefPtr<DataSourceSurface> image =
       CreateDataSourceSurfaceFromData(size,
                                       imageDetails.format(),
                                       data.get<uint8_t>(),
                                       imageDetails.stride());
 
   RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, size);
   nsCOMPtr<imgIContainer> imageContainer =
@@ -8282,31 +8314,28 @@ GetSurfaceDataImpl(mozilla::gfx::DataSou
                    size_t* aLength, int32_t* aStride,
                    GetSurfaceDataContext aContext = GetSurfaceDataContext())
 {
   mozilla::gfx::DataSourceSurface::MappedSurface map;
   if (!aSurface->Map(mozilla::gfx::DataSourceSurface::MapType::READ, &map)) {
     return GetSurfaceDataContext::NullValue();
   }
 
-  mozilla::gfx::IntSize size = aSurface->GetSize();
-  mozilla::CheckedInt32 requiredBytes =
-    mozilla::CheckedInt32(map.mStride) * mozilla::CheckedInt32(size.height);
-  if (!requiredBytes.isValid()) {
+  size_t bufLen = 0;
+  size_t maxBufLen = 0;
+  nsresult rv = nsContentUtils::CalculateBufferSizeForImage(map.mStride,
+                                                            aSurface->GetSize(),
+                                                            aSurface->GetFormat(),
+                                                            &maxBufLen,
+                                                            &bufLen);
+  if (NS_FAILED(rv)) {
     aSurface->Unmap();
     return GetSurfaceDataContext::NullValue();
   }
 
-  size_t maxBufLen = requiredBytes.value();
-  mozilla::gfx::SurfaceFormat format = aSurface->GetFormat();
-
-  // Surface data handling is totally nuts. This is the magic one needs to
-  // know to access the data.
-  size_t bufLen = maxBufLen - map.mStride + (size.width * BytesPerPixel(format));
-
   // nsDependentCString wants null-terminated string.
   typename GetSurfaceDataContext::ReturnType surfaceData = aContext.Allocate(maxBufLen + 1);
   if (GetSurfaceDataContext::GetBuffer(surfaceData)) {
     memcpy(GetSurfaceDataContext::GetBuffer(surfaceData),
            reinterpret_cast<char*>(map.mData),
            bufLen);
     memset(GetSurfaceDataContext::GetBuffer(surfaceData) + bufLen,
            0,
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1162,21 +1162,27 @@ public:
                      uint32_t *aColumnOut, nsString& aMessageOut);
 
   /**
    * Helper function to tell if user ever enabled DevTools explicitely.
    * Allows making DevTools related API no-op until user do so.
    */
   static bool DevToolsEnabled(JSContext* aCx);
 
+  static nsresult CalculateBufferSizeForImage(const uint32_t& aStride,
+                                            const mozilla::gfx::IntSize& aImageSize,
+                                            const mozilla::gfx::SurfaceFormat& aFormat,
+                                            size_t* aMaxBufferSize,
+                                            size_t* aUsedBufferSize);
+
+private:
   /**
    * Fill (with the parameters given) the localized string named |aKey| in
    * properties file |aFile|.
    */
-private:
   static nsresult FormatLocalizedString(PropertiesFile aFile,
                                         const char* aKey,
                                         const char16_t** aParams,
                                         uint32_t aParamsLength,
                                         nsAString& aResult);
 
 public:
   template<uint32_t N>