From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Tom Sepez Date: Thu, 14 Oct 2021 18:29:32 +0000 Subject: M94: Use more safe arithmetic in CFX_DIBBase Most of the calculations are "safe" because we know that the DIB has validated sizes before allocating a buffer, and that calculations in terms of bytes won't overflow and will be within the buffer. But calculations in terms of bits might create overflow in temporaries, so use safe arithmetic there instead. Re-arranging the order of operations thus converting to bytes first might be one option, but we want to handle the 1 bpp case. Test would require large images that might not be possible on all platforms. Bug: chromium:1253399 Change-Id: I3c6c5b8b1f1bf3f429c7d377a8a84c5ab53cafd9 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/85510 Reviewed-by: Lei Zhang Commit-Queue: Tom Sepez (cherry picked from commit a8b293732a0160d1bc1d5b0ad5744922f0f820d5) Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/85950 diff --git a/core/fxge/dib/cfx_bitmapcomposer.cpp b/core/fxge/dib/cfx_bitmapcomposer.cpp index 86066ba72dccc78d65dbaaba76ee4d47d18080a2..af7a2480989668d0108b91fe4e60f2d6a12d31dd 100644 --- a/core/fxge/dib/cfx_bitmapcomposer.cpp +++ b/core/fxge/dib/cfx_bitmapcomposer.cpp @@ -6,6 +6,7 @@ #include "core/fxge/dib/cfx_bitmapcomposer.h" +#include "core/fxcrt/fx_safe_types.h" #include "core/fxge/cfx_cliprgn.h" #include "core/fxge/dib/cfx_dibitmap.h" @@ -109,8 +110,17 @@ void CFX_BitmapComposer::ComposeScanline(int line, m_pClipMask->GetPitch() + (m_DestLeft - m_pClipRgn->GetBox().left); } - uint8_t* dest_scan = m_pBitmap->GetWritableScanline(line + m_DestTop) + - m_DestLeft * m_pBitmap->GetBPP() / 8; + uint8_t* dest_scan = m_pBitmap->GetWritableScanline(line + m_DestTop); + if (dest_scan) { + FX_SAFE_UINT32 offset = m_DestLeft; + offset *= m_pBitmap->GetBPP(); + offset /= 8; + if (!offset.IsValid()) + return; + + // Help some compilers perform pointer arithmetic against safe numerics. + dest_scan += static_cast(offset.ValueOrDie()); + } uint8_t* dest_alpha_scan = m_pBitmap->m_pAlphaMask ? m_pBitmap->m_pAlphaMask->GetWritableScanline(line + m_DestTop) + diff --git a/core/fxge/dib/cfx_dibbase.cpp b/core/fxge/dib/cfx_dibbase.cpp index cff1d79f4a8e992c2b3cd110af471bb8c4bcafc3..8ea50919e224973142ceacee24a5bd03560d4f88 100644 --- a/core/fxge/dib/cfx_dibbase.cpp +++ b/core/fxge/dib/cfx_dibbase.cpp @@ -627,15 +627,25 @@ RetainPtr CFX_DIBBase::Clone(const FX_RECT* pClip) const { } } } else { - int copy_len = (pNewBitmap->GetWidth() * pNewBitmap->GetBPP() + 7) / 8; - if (m_Pitch < static_cast(copy_len)) - copy_len = m_Pitch; + FX_SAFE_UINT32 copy_len = pNewBitmap->GetWidth(); + copy_len *= pNewBitmap->GetBPP(); + copy_len += 7; + copy_len /= 8; + if (!copy_len.IsValid()) + return nullptr; + + copy_len = std::min(m_Pitch, copy_len.ValueOrDie()); + + FX_SAFE_UINT32 offset = rect.left; + offset *= GetBppFromFormat(m_Format); + offset /= 8; + if (!offset.IsValid()) + return nullptr; for (int row = rect.top; row < rect.bottom; ++row) { - const uint8_t* src_scan = - GetScanline(row) + rect.left * GetBppFromFormat(m_Format) / 8; + const uint8_t* src_scan = GetScanline(row) + offset.ValueOrDie(); uint8_t* dest_scan = pNewBitmap->GetWritableScanline(row - rect.top); - memcpy(dest_scan, src_scan, copy_len); + memcpy(dest_scan, src_scan, copy_len.ValueOrDie()); } } return pNewBitmap; diff --git a/core/fxge/dib/cfx_dibitmap.cpp b/core/fxge/dib/cfx_dibitmap.cpp index 1052b357de90e49800c405f7c67e0e6ac34f22b9..c84b622662dab067acd4972acf6a68ad4815e258 100644 --- a/core/fxge/dib/cfx_dibitmap.cpp +++ b/core/fxge/dib/cfx_dibitmap.cpp @@ -216,8 +216,14 @@ bool CFX_DIBitmap::TransferWithUnequalFormats( if (GetBppFromFormat(m_Format) == 8) dest_format = FXDIB_Format::k8bppMask; + FX_SAFE_UINT32 offset = dest_left; + offset *= GetBPP(); + offset /= 8; + if (!offset.IsValid()) + return false; + uint8_t* dest_buf = - m_pBuffer.Get() + dest_top * m_Pitch + dest_left * GetBPP() / 8; + m_pBuffer.Get() + dest_top * m_Pitch + offset.ValueOrDie(); std::vector> d_plt; return ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height, pSrcBitmap, src_left, src_top, &d_plt); @@ -497,7 +503,13 @@ uint32_t CFX_DIBitmap::GetPixel(int x, int y) const { if (!m_pBuffer) return 0; - uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8; + FX_SAFE_UINT32 offset = x; + offset *= GetBPP(); + offset /= 8; + if (!offset.IsValid()) + return 0; + + uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + offset.ValueOrDie(); switch (GetFormat()) { case FXDIB_Format::k1bppMask: { if ((*pos) & (1 << (7 - x % 8))) { @@ -536,7 +548,13 @@ void CFX_DIBitmap::SetPixel(int x, int y, uint32_t color) { if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) return; - uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8; + FX_SAFE_UINT32 offset = x; + offset *= GetBPP(); + offset /= 8; + if (!offset.IsValid()) + return; + + uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + offset.ValueOrDie(); switch (GetFormat()) { case FXDIB_Format::k1bppMask: if (color >> 24) {