Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package podofo for openSUSE:Factory checked in at 2024-09-25 21:51:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/podofo (Old) and /work/SRC/openSUSE:Factory/.podofo.new.29891 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "podofo" Wed Sep 25 21:51:41 2024 rev:39 rq:1203389 version:0.10.4 Changes: -------- --- /work/SRC/openSUSE:Factory/podofo/podofo.changes 2024-08-20 16:13:15.081807566 +0200 +++ /work/SRC/openSUSE:Factory/.podofo.new.29891/podofo.changes 2024-09-25 21:51:46.696504218 +0200 @@ -1,0 +2,21 @@ +Sun Sep 8 07:50:21 UTC 2024 - Cliff Zhao <qz...@suse.com> + +- Add podofo-CVE-2019-20093.patch: + Backport from upstream proposed fix, Fix denial of service + (NULL pointer dereference) in PoDoFo::PdfVariant::DelayedLoad + function in PdfVariant.h. + https://sourceforge.net/p/podofo/tickets/75/ + (CVE-2019-20093, bsc#1159921) + +------------------------------------------------------------------- +Sat Sep 7 17:53:18 UTC 2024 - Cliff Zhao <qz...@suse.com> + +- update to 0.10.4: + * StandardStreamDevice: Fixed seek() in case of iostream/fstream + * PdfWriter: Fixed computing the doc identifier with a wrong buffer + * PdfPainter: Fix SetCurrentMatrix() to really update CTM + * Fixed compilation in mingw < 12 + * PdfCIDToGIDMap: Fixed map reading + * PdfPainter: Fixed offset on multiline text if text is not left aligned + +------------------------------------------------------------------- @@ -28,0 +50,3 @@ + (bsc#1213720) + - PdfEncrypt: Validate more encrypt dictionary parameters + (bsc#1213720) Old: ---- podofo-0.10.3.tar.gz New: ---- podofo-0.10.4.tar.gz podofo-CVE-2019-20093.patch BETA DEBUG BEGIN: New: - Add podofo-CVE-2019-20093.patch: Backport from upstream proposed fix, Fix denial of service BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ podofo.spec ++++++ --- /var/tmp/diff_new_pack.nJpZP1/_old 2024-09-25 21:51:47.184524546 +0200 +++ /var/tmp/diff_new_pack.nJpZP1/_new 2024-09-25 21:51:47.184524546 +0200 @@ -19,7 +19,7 @@ %define libver 2 %bcond_with tools Name: podofo -Version: 0.10.3 +Version: 0.10.4 Release: 0 Summary: Tools to work with PDF files License: GPL-2.0-or-later @@ -28,6 +28,7 @@ Source0: https://github.com/podofo/podofo/archive/%{version}/%{name}-%{version}.tar.gz # PATCH-FIX-OPENSUSE: manuals does not build Patch0: podofo-tools_man.patch +Patch1: podofo-CVE-2019-20093.patch BuildRequires: cmake >= 2.6 BuildRequires: doxygen BuildRequires: fdupes ++++++ podofo-0.10.3.tar.gz -> podofo-0.10.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/.github/workflows/build-mac.yml new/podofo-0.10.4/.github/workflows/build-mac.yml --- old/podofo-0.10.3/.github/workflows/build-mac.yml 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/.github/workflows/build-mac.yml 2024-09-12 21:14:33.000000000 +0200 @@ -10,12 +10,15 @@ ctestArgs: description: 'CTest arguments' +# NOTE: Don't update other tools with broken linkage with +# HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK. See https://docs.brew.sh/Manpage#install-options-formulacask- env: BUILD_TYPE: Release + HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 jobs: build: - runs-on: macos-11 + runs-on: macos-12 steps: - uses: actions/checkout@v2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/CHANGELOG.md new/podofo-0.10.4/CHANGELOG.md --- old/podofo-0.10.3/CHANGELOG.md 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/CHANGELOG.md 2024-09-12 21:14:33.000000000 +0200 @@ -1,3 +1,6 @@ +# Version 0.10.4 +- Fixed seek() in case of iostream/fstream used with StandardStreamDevice + # Version 0.10.3 - Fixed big performance regression introduced in 0.10, see #108 - Fixed data loss with encrypted documents, see #99 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/CMakeLists.txt new/podofo-0.10.4/CMakeLists.txt --- old/podofo-0.10.3/CMakeLists.txt 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/CMakeLists.txt 2024-09-12 21:14:33.000000000 +0200 @@ -20,7 +20,7 @@ set(PODOFO_VERSION_MAJOR "0" CACHE STRING "Major part of podofo version number") set(PODOFO_VERSION_MINOR "10" CACHE STRING "Minor part of podofo version number") -set(PODOFO_VERSION_PATCH "3" CACHE STRING "Patchlevel part of podofo version number") +set(PODOFO_VERSION_PATCH "4" CACHE STRING "Patchlevel part of podofo version number") set(PODOFO_VERSION "${PODOFO_VERSION_MAJOR}.${PODOFO_VERSION_MINOR}.${PODOFO_VERSION_PATCH}") set(PODOFO_SOVERSION "2") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/auxiliary/StreamDevice.cpp new/podofo-0.10.4/src/podofo/auxiliary/StreamDevice.cpp --- old/podofo-0.10.3/src/podofo/auxiliary/StreamDevice.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/auxiliary/StreamDevice.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -65,22 +65,20 @@ template <typename TStream> void seek(TStream& stream, ssize_t pos, SeekDirection direction) { - ios_base::seekdir seekdir; switch (direction) { case SeekDirection::Begin: - seekdir = ios_base::beg; + (void)utls::stream_helper<TStream>::seek(stream, (std::streampos)pos, ios_base::beg); break; case SeekDirection::Current: - seekdir = ios_base::cur; + (void)utls::stream_helper<TStream>::seek(stream, (std::streampos)pos, ios_base::cur); break; case SeekDirection::End: - seekdir = ios_base::end; + (void)utls::stream_helper<TStream>::seek(stream, (std::streampos)pos, ios_base::end); break; default: PODOFO_RAISE_ERROR(PdfErrorCode::InvalidEnumValue); } - (void)utls::stream_helper<TStream>::seek(stream, (std::streampos)pos, seekdir); } StreamDevice::StreamDevice(DeviceAccess access) @@ -190,13 +188,13 @@ switch (GetAccess()) { case DeviceAccess::Read: + case DeviceAccess::ReadWrite: // We just take the input stream as the reference { PODOFO_INVARIANT(m_istream != nullptr); ret = getLength(*m_istream); break; } case DeviceAccess::Write: - case DeviceAccess::ReadWrite: { PODOFO_INVARIANT(m_ostream != nullptr); ret = getLength(*m_ostream); @@ -218,13 +216,13 @@ switch (GetAccess()) { case DeviceAccess::Read: + case DeviceAccess::ReadWrite: // We just take the input stream as the reference { PODOFO_INVARIANT(m_istream != nullptr); ret = getPosition(*m_istream); break; } case DeviceAccess::Write: - case DeviceAccess::ReadWrite: { PODOFO_INVARIANT(m_ostream != nullptr); ret = getPosition(*m_ostream); @@ -252,10 +250,42 @@ void StandardStreamDevice::writeBuffer(const char* buffer, size_t size) { - PODOFO_INVARIANT(m_ostream != nullptr); - m_ostream->write(buffer, size); - if (m_ostream->fail()) - PODOFO_RAISE_ERROR_INFO(PdfErrorCode::InvalidDeviceOperation, "Failed to write the given buffer"); + switch (GetAccess()) + { + case DeviceAccess::Write: + { + PODOFO_INVARIANT(m_ostream != nullptr); + m_ostream->write(buffer, size); + if (m_ostream->fail()) + PODOFO_RAISE_ERROR_INFO(PdfErrorCode::InvalidDeviceOperation, "Failed to write the given buffer"); + break; + } + case DeviceAccess::ReadWrite: + { + PODOFO_INVARIANT(m_ostream != nullptr && m_istream != nullptr); + // Since some iostreams such as std::stringstream have different position + // indicators for input and output sequences. Synchronize the ostream + // position indicator with the istream (the reference one) before writing + // NOTE: Some c++ libraries don't reset eofbit prior seeking + auto pos = getPosition(*m_istream); + m_Stream->clear(m_Stream->rdstate() & ~ios_base::eofbit); + ::seek(*m_ostream, (ssize_t)pos, SeekDirection::Begin); + m_ostream->write(buffer, size); + if (m_ostream->fail()) + goto Fail; + + // After writing, finally synchronize the istream position indicator + ::seek(*m_istream, (ssize_t)(pos + size), SeekDirection::Begin); + if (m_istream->fail()) + goto Fail; + + break; + + Fail: + PODOFO_RAISE_ERROR_INFO(PdfErrorCode::InvalidDeviceOperation, "Failed to write the given buffer"); + break; + } + } } void StandardStreamDevice::flush() @@ -319,20 +349,30 @@ { // NOTE: Some c++ libraries don't reset eofbit prior seeking m_Stream->clear(m_Stream->rdstate() & ~ios_base::eofbit); - if ((GetAccess() & DeviceAccess::Read) != DeviceAccess{ }) - { - PODOFO_INVARIANT(m_istream != nullptr); - ::seek(*m_istream, offset, direction); - } - - if ((GetAccess() & DeviceAccess::Write) != DeviceAccess{ }) + switch (GetAccess()) { - PODOFO_INVARIANT(m_ostream != nullptr); - ::seek(*m_ostream, offset, direction); + case DeviceAccess::Read: + case DeviceAccess::ReadWrite: + { + PODOFO_INVARIANT(m_istream != nullptr); + ::seek(*m_istream, offset, direction); + break; + } + case DeviceAccess::Write: + { + PODOFO_INVARIANT(m_ostream != nullptr); + ::seek(*m_ostream, offset, direction); + break; + } } if (m_Stream->fail()) - PODOFO_RAISE_ERROR_INFO(PdfErrorCode::InvalidDeviceOperation, "Failed to seek to given position in the stream"); + goto Fail; + + return; + +Fail: + PODOFO_RAISE_ERROR_INFO(PdfErrorCode::InvalidDeviceOperation, "Failed to seek to given position in the stream"); } FileStreamDevice::FileStreamDevice(const string_view& filepath) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/auxiliary/StreamDevice.h new/podofo-0.10.4/src/podofo/auxiliary/StreamDevice.h --- old/podofo-0.10.3/src/podofo/auxiliary/StreamDevice.h 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/auxiliary/StreamDevice.h 2024-09-12 21:14:33.000000000 +0200 @@ -135,9 +135,15 @@ m_container(&container), m_Position(ate ? container.size() : 0) { } + /** + * \remarks by default it set the current position at the begin of the container + */ ContainerStreamDevice(const TContainer& container) : ContainerStreamDevice(const_cast<TContainer&>(container), DeviceAccess::Read, false) { } + /** + * \remarks by default it set the current position at the end of the container + */ ContainerStreamDevice(TContainer& container) : ContainerStreamDevice(container, DeviceAccess::ReadWrite, true) { } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/auxiliary/span.hpp new/podofo-0.10.4/src/podofo/auxiliary/span.hpp --- old/podofo-0.10.3/src/podofo/auxiliary/span.hpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/auxiliary/span.hpp 2024-09-12 21:14:33.000000000 +0200 @@ -27,6 +27,7 @@ #ifndef TCB_SPAN_NO_EXCEPTIONS #include <cstdio> #include <stdexcept> +#include <exception> #endif // Various feature test macros @@ -339,23 +340,23 @@ constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N) {} - template <std::size_t N, std::size_t E = Extent, + template <typename T, std::size_t N, std::size_t E = Extent, typename std::enable_if< (E == dynamic_extent || N == E) && detail::is_container_element_type_compatible< - std::array<value_type, N>&, ElementType>::value, + std::array<T, N>&, ElementType>::value, int>::type = 0> - TCB_SPAN_ARRAY_CONSTEXPR span(std::array<value_type, N>& arr) noexcept + TCB_SPAN_ARRAY_CONSTEXPR span(std::array<T, N>& arr) noexcept : storage_(arr.data(), N) {} - template <std::size_t N, std::size_t E = Extent, + template <typename T, std::size_t N, std::size_t E = Extent, typename std::enable_if< (E == dynamic_extent || N == E) && detail::is_container_element_type_compatible< - const std::array<value_type, N>&, ElementType>::value, + const std::array<T, N>&, ElementType>::value, int>::type = 0> - TCB_SPAN_ARRAY_CONSTEXPR span(const std::array<value_type, N>& arr) noexcept + TCB_SPAN_ARRAY_CONSTEXPR span(const std::array<T, N>& arr) noexcept : storage_(arr.data(), N) {} @@ -385,7 +386,8 @@ template <typename OtherElementType, std::size_t OtherExtent, typename std::enable_if< - (Extent == OtherExtent || Extent == dynamic_extent) && + (Extent == dynamic_extent || OtherExtent == dynamic_extent || + Extent == OtherExtent) && std::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value, int>::type = 0> @@ -518,7 +520,8 @@ span(const std::array<T, N>&)->span<const T, N>; template <class Container> -span(Container&)->span<typename Container::value_type>; +span(Container&)->span<typename std::remove_reference< + decltype(*detail::data(std::declval<Container&>()))>::type>; template <class Container> span(const Container&)->span<const typename Container::value_type>; @@ -552,7 +555,9 @@ } template <typename Container> -constexpr span<typename Container::value_type> make_span(Container& cont) +constexpr span<typename std::remove_reference< + decltype(*detail::data(std::declval<Container&>()))>::type> +make_span(Container& cont) { return {cont}; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfCIDToGIDMap.cpp new/podofo-0.10.4/src/podofo/main/PdfCIDToGIDMap.cpp --- old/podofo-0.10.3/src/podofo/main/PdfCIDToGIDMap.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfCIDToGIDMap.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -25,7 +25,7 @@ auto buffer = cidToGidMapObj.MustGetStream().GetCopy(); for (unsigned i = 0, count = (unsigned)buffer.size() / 2; i < count; i++) { - unsigned gid = (unsigned)buffer[i * 2 + 0] << 8 | (unsigned)buffer[i * 2 + 1]; + unsigned gid = (unsigned)((uint8_t)buffer[i * 2 + 0] << 8 | (uint8_t)buffer[i * 2 + 1]); map[i] = gid; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfCommon.cpp new/podofo-0.10.4/src/podofo/main/PdfCommon.cpp --- old/podofo-0.10.3/src/podofo/main/PdfCommon.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfCommon.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -11,6 +11,21 @@ using namespace std; using namespace PoDoFo; +// Default stack sizes +// Windows: 1MB on x32, x64, ARM https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-160 +// Windows IIS: 512 KB for 64-bit worker processes, 256 KB for 32-bit worker processes +// macOS: 8MB on main thread, 512KB on secondary threads https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html +// iOS: 1MB on main thread, 512KB on secondary threads +// Modern Linux distros: usually 8MB on main and secondary threads (but setting ulimit RLIMIT_STACK to unlimited *reduces* the secondary stack size on most architectures: see https://man7.org/linux/man-pages/man3/pthread_create.3.html#NOTES ) +// the amount allocated on stack for local variables and function parameters varies between x86 and x64 +// in x86 pointers are 32-bit but all function parameters are on stack +// in x64 pointers are 64-bit but first 4 function params are passed in registers +// the biggest difference is between debug and non-debug stacks: a debug stack frame can be around 3x larger +// due to instrumentation like ASAN which put guard bytes around stack variables to detect buffer overflows +constexpr unsigned MaxRecursionDepthDefault = 450; + +PODOFO_EXPORT unsigned s_MaxRecursionDepth = MaxRecursionDepthDefault; + #ifdef DEBUG PODOFO_EXPORT PdfLogSeverity s_MaxLogSeverity = PdfLogSeverity::Debug; #else @@ -43,3 +58,13 @@ { return logSeverity <= s_MaxLogSeverity; } + +void PdfCommon::SetMaxRecursionDepth(unsigned maxRecursionDepth) +{ + s_MaxRecursionDepth = maxRecursionDepth; +} + +unsigned PdfCommon::GetMaxRecursionDepth() +{ + return s_MaxRecursionDepth; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfCommon.h new/podofo-0.10.4/src/podofo/main/PdfCommon.h --- old/podofo-0.10.3/src/podofo/main/PdfCommon.h 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfCommon.h 2024-09-12 21:14:33.000000000 +0200 @@ -33,6 +33,11 @@ */ static PdfLogSeverity GetMaxLoggingSeverity(); + // set maximum recursion depth (set to 0 to disable recursion check) + static void SetMaxRecursionDepth(unsigned maxRecursionDepth); + + static unsigned GetMaxRecursionDepth(); + /** The if the given logging severity enabled or not */ static bool IsLoggingSeverityEnabled(PdfLogSeverity logSeverity); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfImage.cpp new/podofo-0.10.4/src/podofo/main/PdfImage.cpp --- old/podofo-0.10.3/src/podofo/main/PdfImage.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfImage.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -385,7 +385,7 @@ GetObject().GetOrCreateStream().SetData(stream, info.Filters, true); } -void PdfImage::Load(const string_view& filepath) +void PdfImage::Load(const string_view& filepath, unsigned imageIndex) { if (filepath.length() > 3) { @@ -395,7 +395,7 @@ #ifdef PODOFO_HAVE_TIFF_LIB if (extension == ".tif" || extension == ".tiff") { - loadFromTiff(filepath); + loadFromTiff(filepath, imageIndex); return; } #endif @@ -420,7 +420,7 @@ PODOFO_RAISE_ERROR_INFO(PdfErrorCode::UnsupportedImageFormat, filepath); } -void PdfImage::LoadFromBuffer(const bufferview& buffer) +void PdfImage::LoadFromBuffer(const bufferview& buffer, unsigned imageIndex) { if (buffer.size() <= 4) return; @@ -438,7 +438,7 @@ magic[2] == 0x2A && magic[3] == 0x00)) { - loadFromTiffData((const unsigned char*)buffer.data(), buffer.size()); + loadFromTiffData((const unsigned char*)buffer.data(), buffer.size(), imageIndex); return; } #endif @@ -651,7 +651,7 @@ // Do nothing } -void PdfImage::loadFromTiffHandle(void* handle) +void PdfImage::loadFromTiffHandle(void* handle, unsigned imageIndex) { TIFF* hInTiffHandle = (TIFF*)handle; @@ -662,6 +662,9 @@ uint16_t planarConfig, photoMetric, orientation; int32_t resolutionUnit; + // Set the page/image index in the tiff context + TIFFSetDirectory(hInTiffHandle, (uint16)imageIndex); + TIFFGetField(hInTiffHandle, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(hInTiffHandle, TIFFTAG_IMAGELENGTH, &height); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); @@ -684,22 +687,10 @@ // TODO: implement special cases if (TIFFIsTiled(hInTiffHandle)) - { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); - } if (planarConfig != PLANARCONFIG_CONTIG && colorChannels != 1) - { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); - } - - if (orientation != ORIENTATION_TOPLEFT) - { - TIFFClose(hInTiffHandle); - PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); - } PdfImageInfo info; info.Width = width; @@ -715,6 +706,7 @@ decode.insert(decode.end(), PdfObject(static_cast<int64_t>(0))); decode.insert(decode.end(), PdfObject(static_cast<int64_t>(1))); info.Decode = std::move(decode); + info.ColorSpace = PdfColorSpace::DeviceGray; } else if (bitsPixel == 8 || bitsPixel == 16) { @@ -722,7 +714,6 @@ } else { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); } break; @@ -735,6 +726,7 @@ decode.insert(decode.end(), PdfObject(static_cast<int64_t>(1))); decode.insert(decode.end(), PdfObject(static_cast<int64_t>(0))); info.Decode = std::move(decode); + info.ColorSpace = PdfColorSpace::DeviceGray; } else if (bitsPixel == 8 || bitsPixel == 16) { @@ -742,7 +734,6 @@ } else { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); } break; @@ -750,20 +741,16 @@ case PHOTOMETRIC_RGB: { if (bitsPixel != 24) - { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); - } + info.ColorSpace = PdfColorSpace::DeviceRGB; break; } case PHOTOMETRIC_SEPARATED: { if (bitsPixel != 32) - { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); - } + info.ColorSpace = PdfColorSpace::DeviceCMYK; break; } @@ -806,7 +793,6 @@ default: { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); break; } @@ -821,7 +807,6 @@ &buffer[row * scanlineSize], row) == (-1)) { - TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR(PdfErrorCode::UnsupportedImageFormat); } } @@ -830,7 +815,7 @@ SetDataRaw(input, info); } -void PdfImage::loadFromTiff(const string_view& filename) +void PdfImage::loadFromTiff(const string_view& filename, unsigned imageIndex) { TIFFSetErrorHandler(TIFFErrorWarningHandler); TIFFSetWarningHandler(TIFFErrorWarningHandler); @@ -850,7 +835,7 @@ try { - loadFromTiffHandle(hInfile); + loadFromTiffHandle(hInfile, imageIndex); } catch (...) { @@ -968,7 +953,7 @@ { return; }; -void PdfImage::loadFromTiffData(const unsigned char* data, size_t len) +void PdfImage::loadFromTiffData(const unsigned char* data, size_t len, unsigned imageIndex) { TIFFSetErrorHandler(TIFFErrorWarningHandler); TIFFSetWarningHandler(TIFFErrorWarningHandler); @@ -983,7 +968,17 @@ if (hInHandle == nullptr) PODOFO_RAISE_ERROR(PdfErrorCode::InvalidHandle); - loadFromTiffHandle(hInHandle); + try + { + loadFromTiffHandle(hInHandle, imageIndex); + } + catch (...) + { + TIFFClose(hInHandle); + throw; + } + + TIFFClose(hInHandle); } #endif // PODOFO_HAVE_TIFF_LIB diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfImage.h new/podofo-0.10.4/src/podofo/main/PdfImage.h --- old/podofo-0.10.3/src/podofo/main/PdfImage.h 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfImage.h 2024-09-12 21:14:33.000000000 +0200 @@ -131,13 +131,17 @@ */ void SetDataRaw(InputStream& stream, const PdfImageInfo& info); - /** Load the image data from a file + /** Load the image data from bytes + * \param imageIndex image index to be fed to multi image/page + * formats (eg. TIFF). Ignored by the other formats */ - void Load(const std::string_view& filepath); + void Load(const std::string_view& filepath, unsigned imageIndex = 0); /** Load the image data from bytes + * \param imageIndex image index to be fed to multi image/page + * formats (eg. TIFF). Ignored by the other formats */ - void LoadFromBuffer(const bufferview& buffer); + void LoadFromBuffer(const bufferview& buffer, unsigned imageIndex = 0); void ExportTo(charbuff& buff, PdfExportFormat format, PdfArray args = {}) const; @@ -188,17 +192,17 @@ #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_TIFF_LIB - void loadFromTiffHandle(void* handle); + void loadFromTiffHandle(void* handle, unsigned imageIndex); /** Load the image data from a TIFF file * \param filename */ - void loadFromTiff(const std::string_view& filename); + void loadFromTiff(const std::string_view& filename, unsigned imageIndex); /** Load the image data from TIFF bytes * \param data TIFF bytes * \param len number of bytes */ - void loadFromTiffData(const unsigned char* data, size_t len); + void loadFromTiffData(const unsigned char* data, size_t len, unsigned imageIndex); #endif // PODOFO_HAVE_TIFF_LIB #ifdef PODOFO_HAVE_PNG_LIB diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfPainter.cpp new/podofo-0.10.4/src/podofo/main/PdfPainter.cpp --- old/podofo-0.10.3/src/podofo/main/PdfPainter.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfPainter.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -479,6 +479,18 @@ this->drawTextAligned(line, x, y, width, hAlignment, style); x = 0; + switch (hAlignment) + { + default: + case PdfHorizontalAlignment::Left: + break; + case PdfHorizontalAlignment::Center: + x = -(width - textState.Font->GetStringLength(line, textState)) / 2.0; + break; + case PdfHorizontalAlignment::Right: + x = -(width - textState.Font->GetStringLength(line, textState)); + break; + } y = -font.GetLineSpacing(textState); } PoDoFo::WriteOperator_ET(m_stream); @@ -1200,11 +1212,8 @@ void PdfGraphicsStateWrapper::SetCurrentMatrix(const Matrix& matrix) { - if (m_state->CTM == matrix) - return; - - m_state->CTM = matrix; - m_painter->SetTransformationMatrix(m_state->CTM); + m_state->CTM = matrix * m_state->CTM; + m_painter->SetTransformationMatrix(matrix); } void PdfGraphicsStateWrapper::SetLineWidth(double lineWidth) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfParser.cpp new/podofo-0.10.4/src/podofo/main/PdfParser.cpp --- old/podofo-0.10.3/src/podofo/main/PdfParser.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfParser.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -238,11 +238,6 @@ if (trailer->GetDictionary().HasKey("XRefStm")) { - // Whenever we read a XRefStm key, - // we know that the file was updated. - if (!trailer->GetDictionary().HasKey("Prev")) - m_IncrementalUpdateCount++; - try { ReadXRefStreamContents(device, static_cast<size_t>(trailer->GetDictionary().FindKeyAs<int64_t>("XRefStm", 0)), false); @@ -265,19 +260,11 @@ // we know that the file was updated. m_IncrementalUpdateCount++; - try - { - if (m_visitedXRefOffsets.find((size_t)offset) == m_visitedXRefOffsets.end()) - ReadXRefContents(device, (size_t)offset); - else - PoDoFo::LogMessage(PdfLogSeverity::Warning, "XRef contents at offset {} requested twice, skipping the second read", - static_cast<int64_t>(offset)); - } - catch (PdfError& e) - { - PODOFO_PUSH_FRAME_INFO(e, "Unable to load /Prev xref entries"); - throw e; - } + if (m_visitedXRefOffsets.find((size_t)offset) == m_visitedXRefOffsets.end()) + ReadXRefContents(device, (size_t)offset, false); + else + PoDoFo::LogMessage(PdfLogSeverity::Warning, "XRef contents at offset {} requested twice, skipping the second read", + static_cast<int64_t>(offset)); } else { @@ -410,18 +397,7 @@ } } - try - { - readNextTrailer(device); - } - catch (PdfError& e) - { - if (e != PdfErrorCode::NoTrailer) - { - PODOFO_PUSH_FRAME(e); - throw e; - } - } + readNextTrailer(device); } bool CheckEOL(char e1, char e2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/main/PdfWriter.cpp new/podofo-0.10.4/src/podofo/main/PdfWriter.cpp --- old/podofo-0.10.3/src/podofo/main/PdfWriter.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/main/PdfWriter.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -290,7 +290,7 @@ info->Write(length, m_WriteFlags, nullptr, m_buffer); charbuff buffer(length.GetLength()); - StringStreamDevice device(buffer); + StringStreamDevice device(buffer, DeviceAccess::Write, false); info->Write(device, m_WriteFlags, nullptr, m_buffer); // calculate the MD5 Sum diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/private/PdfDeclarationsPrivate.cpp new/podofo-0.10.4/src/podofo/private/PdfDeclarationsPrivate.cpp --- old/podofo-0.10.3/src/podofo/private/PdfDeclarationsPrivate.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/private/PdfDeclarationsPrivate.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -28,25 +28,12 @@ constexpr unsigned BUFFER_SIZE = 4096; -// Default stack sizes -// Windows: 1MB on x32, x64, ARM https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-160 -// Windows IIS: 512 KB for 64-bit worker processes, 256 KB for 32-bit worker processes -// macOS: 8MB on main thread, 512KB on secondary threads https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html -// iOS: 1MB on main thread, 512KB on secondary threads -// Modern Linux distros: usually 8MB on main and secondary threads (but setting ulimit RLIMIT_STACK to unlimited *reduces* the secondary stack size on most architectures: see https://man7.org/linux/man-pages/man3/pthread_create.3.html#NOTES ) -// the amount allocated on stack for local variables and function parameters varies between x86 and x64 -// in x86 pointers are 32-bit but all function parameters are on stack -// in x64 pointers are 64-bit but first 4 function params are passed in registers -// the biggest difference is between debug and non-debug stacks: a debug stack frame can be around 3x larger -// due to instrumentation like ASAN which put guard bytes around stack variables to detect buffer overflows -constexpr unsigned MaxRecursionDepthDefault = 256; - -static unsigned s_MaxRecursionDepth = MaxRecursionDepthDefault; thread_local unsigned s_recursionDepth = 0; static const locale s_cachedLocale("C"); extern PODOFO_IMPORT PdfLogSeverity s_MaxLogSeverity; +extern PODOFO_IMPORT unsigned s_MaxRecursionDepth; extern PODOFO_IMPORT LogMessageCallback s_LogMessageCallback; static char getEscapedCharacter(char ch); @@ -1420,16 +1407,6 @@ Exit(); } -void utls::RecursionGuard::SetMaxRecursionDepth(unsigned maxRecursionDepth) -{ - s_MaxRecursionDepth = maxRecursionDepth; -} - -unsigned utls::RecursionGuard::GetMaxRecursionDepth() -{ - return s_MaxRecursionDepth; -} - void removeTrailingZeroes(string& str) { // Remove trailing zeroes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/private/PdfDeclarationsPrivate.h new/podofo-0.10.4/src/podofo/private/PdfDeclarationsPrivate.h --- old/podofo-0.10.3/src/podofo/private/PdfDeclarationsPrivate.h 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/private/PdfDeclarationsPrivate.h 2024-09-12 21:14:33.000000000 +0200 @@ -216,11 +216,6 @@ RecursionGuard(); ~RecursionGuard(); - // set maximum recursion depth (set to 0 to disable recursion check) - static void SetMaxRecursionDepth(unsigned maxRecursionDepth); - - static unsigned GetMaxRecursionDepth(); - private: void Enter(); void Exit(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/src/podofo/private/charconv_compat.h new/podofo-0.10.4/src/podofo/private/charconv_compat.h --- old/podofo-0.10.3/src/podofo/private/charconv_compat.h 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/src/podofo/private/charconv_compat.h 2024-09-12 21:14:33.000000000 +0200 @@ -7,7 +7,7 @@ #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 10 #define WANT_CHARS_FORMAT #endif -#if (defined(__GNUC__) && __GNUC__ < 11) || defined(__clang__) +#if (defined(__GNUC__) && !defined(__MINGW32__) && __GNUC__ < 11) || (defined(__MINGW32__) && __GNUC__ < 12) || defined(__clang__) #define WANT_FROM_CHARS #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/test/unit/ImageTest.cpp new/podofo-0.10.4/test/unit/ImageTest.cpp --- old/podofo-0.10.3/test/unit/ImageTest.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/test/unit/ImageTest.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -38,7 +38,7 @@ PdfMemDocument doc; doc.Load(TestUtils::GetTestInputFilePath("Hierarchies1.pdf")); // Try to extract jpeg image - auto imageObj = doc.GetObjects().GetObject(PdfReference(36, 0)); + auto imageObj = doc.GetObjects().GetObject(PdfReference(156, 0)); charbuff buffer; // Unpacking directly the stream shall throw since it has jpeg content @@ -99,7 +99,7 @@ painter.SetCanvas(page); auto img = doc.CreateImage(); img->Load(TestUtils::GetTestInputFilePath("ReferenceImage.png")); - painter.DrawImage(*img.get(), 50.0, 50.0); + painter.DrawImage(*img, 50.0, 50.0); painter.FinishDrawing(); doc.Save(outputFile); } @@ -185,3 +185,25 @@ TestUtils::WriteTestOutputFile(TestUtils::GetTestOutputFilePath("YCCK-jpeg.ppm"), ppmbuffer); } } + +TEST_CASE("TestImage7") +{ + auto outputFile = TestUtils::GetTestOutputFilePath("TestImage7.pdf"); + { + PdfMemDocument doc; + PdfPainter painter; + auto& page = doc.GetPages().CreatePage(PdfPage::CreateStandardPageSize(PdfPageSize::A4)); + painter.SetCanvas(page); + + auto img1 = doc.CreateImage(); + img1->Load(TestUtils::GetTestInputFilePath("MultipleFormats.tif")); + painter.DrawImage(*img1, 50, 700, 0.5, 0.5); + + auto img2 = doc.CreateImage(); + img2->Load(TestUtils::GetTestInputFilePath("MultipleFormats.tif"), 8); + painter.DrawImage(*img2, 50, 600, 0.5, 0.5); + + painter.FinishDrawing(); + doc.Save(outputFile); + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/podofo-0.10.3/test/unit/ParserTest.cpp new/podofo-0.10.4/test/unit/ParserTest.cpp --- old/podofo-0.10.3/test/unit/ParserTest.cpp 2023-11-28 10:23:37.000000000 +0100 +++ new/podofo-0.10.4/test/unit/ParserTest.cpp 2024-09-12 21:14:33.000000000 +0200 @@ -166,7 +166,7 @@ } catch (PdfError& error) { - REQUIRE(error.GetCode() == PdfErrorCode::InvalidXRef); + REQUIRE(error.GetCode() == PdfErrorCode::NoTrailer); } catch (exception&) { @@ -204,7 +204,7 @@ } catch (PdfError& error) { - REQUIRE(error.GetCode() == PdfErrorCode::InvalidXRef); + REQUIRE(error.GetCode() == PdfErrorCode::NoTrailer); } catch (exception&) { @@ -2707,6 +2707,21 @@ } } +TEST_CASE("TestManyTrailer") +{ + try + { + PdfCommon::SetMaxRecursionDepth(256); + PdfMemDocument doc; + doc.Load(TestUtils::GetTestInputFilePath("Empty160trailer.pdf")); + } + catch (PdfError&) + { + return; + } + FAIL("Should fail with stack overflow"); +} + string generateXRefEntries(size_t count) { string strXRefEntries; ++++++ podofo-CVE-2019-20093.patch ++++++ >From the upstream bug report proposed fix From: Sandro Mani Date: Fri, 17 Jan 2020 Subject: podofo: denial of service (NULL pointer dereference) in PoDoFo::PdfVariant::DelayedLoad function in PdfVariant.h References: https://bugzilla.opensuse.org/1223437 References: https://sourceforge.net/p/podofo/tickets/75/ References: CVE-2019-20093 --- podofo-0.10.4/tools/podofoimgextract/ImageExtractor.cpp +++ podofo-0.10.4_new/tools/podofoimgextract/ImageExtractor.cpp @@ -88,6 +88,11 @@ //long lBitsPerComponent = pObject->GetDictionary().GetKey( PdfName("BitsPerComponent" ) )->GetNumber(); // TODO: Handle colorspaces + if ( !pObject->GetDictionary().HasKey( PdfName("Width" ) ) || !pObject->GetDictionary().HasKey( PdfName("Height" ) ) ) + { + PODOFO_RAISE_ERROR( ePdfError_BrokenFile ); + } + // Create a ppm image const char* ppmHeader = "P6\n# Image extracted by PoDoFo\n%u %u\n%li\n"; 2020-01-17