summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2024-03-10 20:44:46 +0600
committerMike Kaganski <mike.kaganski@collabora.com>2024-03-11 04:43:46 +0100
commit99c1bd1a4ef5365d8c26a41c8e858c67e673beb4 (patch)
tree3c2a337c7c63ae53a25daed92f7ca570e9220c0d
parent1ac5353bbb25bd9ff0ab0e157b3dbd0da325480a (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.hxx9
-rw-r--r--sfx2/source/doc/objcont.cxx1
-rw-r--r--sfx2/source/doc/objxtor.cxx38
-rw-r--r--sfx2/source/inc/objshimp.hxx3
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();