Bug 1473161 - Add missing bound check in nsContentUtils::DataTransferItemToImage. r=nika
authorAnny Gakhokidze <agakhokidze@mozilla.com>
Tue, 17 Jul 2018 19:02:51 -0400
changeset 427010 a9f3535ee3fd0d5834490478f3f72e7e197d6bdf
parent 427009 8ed2557771a8cab161267b48ad662da0e4284597
child 427011 7692346c4515d94e12966f22f2278a9c2b7946b9
push id66487
push userryanvm@gmail.com
push dateTue, 17 Jul 2018 23:03:09 +0000
treeherderautoland@a9f3535ee3fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1473161
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 1473161 - Add missing bound check in nsContentUtils::DataTransferItemToImage. r=nika MozReview-Commit-ID: 3dq5yWZwJiG
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7864,30 +7864,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 =
@@ -8228,31 +8260,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
@@ -1155,21 +1155,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>