diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2024-03-10 20:44:46 +0600 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2024-03-11 04:43:46 +0100 |
commit | 99c1bd1a4ef5365d8c26a41c8e858c67e673beb4 (patch) | |
tree | 3c2a337c7c63ae53a25daed92f7ca570e9220c0d | |
parent | 1ac5353bbb25bd9ff0ab0e157b3dbd0da325480a (diff) |
Disallow closing document during generation of preview
Using an external (Java) script that opens a document, and then quickly
closes it, it may happen that the idle that generates a preview is still
active, when the control thread calls XCloseable::close, which destroys
still used document. This leads to use-after-free.
This uses the close listener in SfxObjectShell, to veto closing document
that is still in use by the preview generation code. After completion,
when the caller of close() transferred ownership, then the call to close
is repeated.
Change-Id: I39691f61ad5141d7e8ee54723d5aef87f0bc01dc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164632
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r-- | include/sfx2/objsh.hxx | 9 | ||||
-rw-r--r-- | sfx2/source/doc/objcont.cxx | 1 | ||||
-rw-r--r-- | sfx2/source/doc/objxtor.cxx | 38 | ||||
-rw-r--r-- | sfx2/source/inc/objshimp.hxx | 3 |
4 files changed, 48 insertions, 3 deletions
diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx index c961394db08c..075b3e57f4b9 100644 --- a/include/sfx2/objsh.hxx +++ b/include/sfx2/objsh.hxx @@ -836,6 +836,15 @@ public: } }; +class SfxCloseVetoLock +{ +public: + SfxCloseVetoLock(const SfxObjectShell& rDocShell); + ~SfxCloseVetoLock(); + +private: + const SfxObjectShell& m_rDocShell; +}; typedef rtl::Reference<SfxObjectShell> SfxObjectShellRef; diff --git a/sfx2/source/doc/objcont.cxx b/sfx2/source/doc/objcont.cxx index b762e9d11084..acaeb1047339 100644 --- a/sfx2/source/doc/objcont.cxx +++ b/sfx2/source/doc/objcont.cxx @@ -105,6 +105,7 @@ SfxObjectShell::GetPreviewMetaFile( bool bFullContent ) const BitmapEx SfxObjectShell::GetPreviewBitmap() const { + SfxCloseVetoLock lock(*this); ScopedVclPtrInstance< VirtualDevice > pDevice; pDevice->SetAntialiasing(AntialiasingFlags::Enable | pDevice->GetAntialiasing()); if(!CreatePreview_Impl(/*bFullContent*/false, pDevice, nullptr)) diff --git a/sfx2/source/doc/objxtor.cxx b/sfx2/source/doc/objxtor.cxx index 88c13826e6b1..8a34dc40812f 100644 --- a/sfx2/source/doc/objxtor.cxx +++ b/sfx2/source/doc/objxtor.cxx @@ -28,6 +28,7 @@ #include <com/sun/star/util/XCloseable.hpp> #include <com/sun/star/frame/XComponentLoader.hpp> #include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/util/CloseVetoException.hpp> #include <com/sun/star/util/XCloseListener.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/frame/XTitle.hpp> @@ -137,8 +138,14 @@ public: } // namespace -void SAL_CALL SfxModelListener_Impl::queryClosing( const css::lang::EventObject& , sal_Bool ) +void SAL_CALL SfxModelListener_Impl::queryClosing( const css::lang::EventObject& , sal_Bool bDeliverOwnership) { + if (mpDoc->Get_Impl()->m_nClosingLockLevel) + { + if (bDeliverOwnership) + mpDoc->Get_Impl()->m_bCloseModelScheduled = true; + throw util::CloseVetoException(u"Closing document is blocked"_ustr, getXWeak()); + } } void SAL_CALL SfxModelListener_Impl::notifyClosing( const css::lang::EventObject& ) @@ -305,8 +312,6 @@ SfxObjectShell::~SfxObjectShell() if ( pSfxApp && pSfxApp->GetDdeService() ) pSfxApp->RemoveDdeTopic( this ); - pImpl->pBaseModel.clear(); - // don't call GetStorage() here, in case of Load Failure it's possible that a storage was never assigned! if ( pMedium && pMedium->HasStorage_Impl() && pMedium->GetStorage( false ) == pImpl->m_xDocStorage ) pMedium->CanDisposeStorage_Impl( false ); @@ -341,6 +346,33 @@ SfxObjectShell::~SfxObjectShell() } } +SfxCloseVetoLock::SfxCloseVetoLock(const SfxObjectShell& rDocShell) + : m_rDocShell(rDocShell) +{ + osl_atomic_increment(&m_rDocShell.Get_Impl()->m_nClosingLockLevel); +} + +SfxCloseVetoLock::~SfxCloseVetoLock() +{ + if (osl_atomic_decrement(&m_rDocShell.Get_Impl()->m_nClosingLockLevel) == 0) + { + if (m_rDocShell.Get_Impl()->m_bCloseModelScheduled) + { + m_rDocShell.Get_Impl()->m_bCloseModelScheduled = false; // pass ownership + if (rtl::Reference model = static_cast<SfxBaseModel*>(m_rDocShell.GetBaseModel().get())) + { + try + { + model->close(true); + } + catch (const util::CloseVetoException&) + { + DBG_UNHANDLED_EXCEPTION("sfx.doc"); + } + } + } + } +} void SfxObjectShell::Stamp_SetPrintCancelState(bool bState) { diff --git a/sfx2/source/inc/objshimp.hxx b/sfx2/source/inc/objshimp.hxx index acd85eb0d1a9..87499380e997 100644 --- a/sfx2/source/inc/objshimp.hxx +++ b/sfx2/source/inc/objshimp.hxx @@ -139,6 +139,9 @@ struct SfxObjectShell_Impl final : public ::sfx2::IMacroDocumentAccess // Recent colors used by toolbar buttons std::unordered_map<sal_uInt16, NamedColor> m_aRecentColors; + mutable oslInterlockedCount m_nClosingLockLevel = 0; + mutable bool m_bCloseModelScheduled = false; + SfxObjectShell_Impl( SfxObjectShell& _rDocShell ); virtual ~SfxObjectShell_Impl(); |