diff --git a/CVE-2019-9850_1_2.patch b/CVE-2019-9850_1_2.patch new file mode 100644 index 0000000..8cf5750 --- /dev/null +++ b/CVE-2019-9850_1_2.patch @@ -0,0 +1,206 @@ +Description: - expand LibreLogo check to global events + - decode url escape codes and check each path segment + - keep name percent-encoded + - expand pyuno path separators + - construct final url from parsed output +Authors: - Caolán McNamara + - Stephan Bergmann + +diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx +index b51498905..35b3091e4 100644 +--- a/include/sfx2/objsh.hxx ++++ b/include/sfx2/objsh.hxx +@@ -397,6 +397,8 @@ public: + */ + bool AdjustMacroMode(); + ++ static bool UnTrustedScript(const OUString& rScriptURL); ++ + SvKeyValueIterator* GetHeaderAttributes(); + void ClearHeaderAttributesForSourceViewHack(); + void SetHeaderAttributesForSourceViewHack(); +diff --git a/scripting/source/protocolhandler/scripthandler.cxx b/scripting/source/protocolhandler/scripthandler.cxx +index 150ffa052..751099d92 100644 +--- a/scripting/source/protocolhandler/scripthandler.cxx ++++ b/scripting/source/protocolhandler/scripthandler.cxx +@@ -47,6 +47,7 @@ + + #include + #include ++#include + #include + + #include +@@ -133,8 +134,12 @@ void SAL_CALL ScriptProtocolHandler::dispatchWithNotification( + { + try + { +- bool bIsDocumentScript = ( aURL.Complete.indexOf( "document" ) !=-1 ); +- // TODO: isn't this somewhat strange? This should be a test for a location=document parameter, shouldn't it? ++ css::uno::Reference urifac( ++ css::uri::UriReferenceFactory::create(m_xContext)); ++ css::uno::Reference uri( ++ urifac->parse(aURL.Complete), css::uno::UNO_QUERY_THROW); ++ auto const loc = uri->getParameter("location"); ++ bool bIsDocumentScript = loc == "document"; + + if ( bIsDocumentScript ) + { +diff --git a/scripting/source/pyprov/pythonscript.py b/scripting/source/pyprov/pythonscript.py +index f5aa21733..316c5012c 100644 +--- a/scripting/source/pyprov/pythonscript.py ++++ b/scripting/source/pyprov/pythonscript.py +@@ -219,10 +219,18 @@ class MyUriHelper: + + # path to the .py file + "$functionname, arguments, etc + xStorageUri = self.m_uriRefFac.parse(scriptURI) +- sStorageUri = xStorageUri.getName().replace( "|", "/" ); ++ # getName will apply url-decoding to the name, so encode back ++ sStorageUri = xStorageUri.getName().replace("%", "%25") ++ sStorageUri = sStorageUri.replace( "|", "/" ) + + # path to the .py file, relative to the base +- sFileUri = sStorageUri[0:sStorageUri.find("$")] ++ funcNameStart = sStorageUri.find("$") ++ if funcNameStart != -1: ++ sFileUri = sStorageUri[0:funcNameStart] ++ sFuncName = sStorageUri[funcNameStart+1:] ++ else: ++ sFileUri = sStorageUri ++ + xFileUri = self.m_uriRefFac.parse(sFileUri) + if not xFileUri: + message = "pythonscript: invalid relative uri '" + sFileUri+ "'" +@@ -239,7 +247,9 @@ class MyUriHelper: + log.debug( message ) + raise RuntimeException( message ) + +- ret = sBaseUri + sStorageUri ++ ret = sAbsScriptUri ++ if funcNameStart != -1: ++ ret = ret + "$" + sFuncName + log.debug( "converting scriptURI="+scriptURI + " to storageURI=" + ret ) + return ret + except UnoException as e: +diff --git a/sfx2/source/doc/objmisc.cxx b/sfx2/source/doc/objmisc.cxx +index 02d79c356..a508aea86 100644 +--- a/sfx2/source/doc/objmisc.cxx ++++ b/sfx2/source/doc/objmisc.cxx +@@ -41,6 +41,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -1347,14 +1349,36 @@ namespace + } + } + +-namespace { +- + // don't allow LibreLogo to be used with our mouseover/etc dom-alike events +-bool UnTrustedScript(const OUString& rScriptURL) ++bool SfxObjectShell::UnTrustedScript(const OUString& rScriptURL) + { +- return rScriptURL.startsWithIgnoreAsciiCase("vnd.sun.star.script:LibreLogo"); +-} ++ if (!rScriptURL.startsWith("vnd.sun.star.script:")) ++ return false; ++ ++ // ensure URL Escape Codes are decoded ++ css::uno::Reference uri( ++ css::uri::UriReferenceFactory::create(comphelper::getProcessComponentContext())->parse(rScriptURL)); ++ css::uno::Reference sfUri(uri, css::uno::UNO_QUERY); ++ ++ if (!sfUri.is()) ++ return false; ++ ++ // pyuno encodes path separator as | ++ OUString sScript = sfUri->getName().replace('|', '/'); + ++ // check if any path portion matches LibreLogo and ban it if it does ++ sal_Int32 nIndex = 0; ++ do ++ { ++ OUString aToken = sScript.getToken(0, '/', nIndex); ++ if (aToken.startsWithIgnoreAsciiCase("LibreLogo")) ++ { ++ return true; ++ } ++ } ++ while (nIndex >= 0); ++ ++ return false; + } + + ErrCode SfxObjectShell::CallXScript( const Reference< XInterface >& _rxScriptContext, const OUString& _rScriptURL, +@@ -1363,19 +1387,22 @@ ErrCode SfxObjectShell::CallXScript( const Reference< XInterface >& _rxScriptCon + SAL_INFO("sfx", "in CallXScript" ); + ErrCode nErr = ERRCODE_NONE; + +- bool bIsDocumentScript = ( _rScriptURL.indexOf( "location=document" ) >= 0 ); +- // TODO: we should parse the URL, and check whether there is a parameter with this name. +- // Otherwise, we might find too much. +- if ( bIsDocumentScript && !lcl_isScriptAccessAllowed_nothrow( _rxScriptContext ) ) +- return ERRCODE_IO_ACCESSDENIED; +- +- if ( UnTrustedScript(_rScriptURL) ) +- return ERRCODE_IO_ACCESSDENIED; +- + bool bCaughtException = false; + Any aException; + try + { ++ css::uno::Reference urifac( ++ css::uri::UriReferenceFactory::create(comphelper::getProcessComponentContext())); ++ css::uno::Reference uri( ++ urifac->parse(_rScriptURL), css::uno::UNO_QUERY_THROW); ++ auto const loc = uri->getParameter("location"); ++ bool bIsDocumentScript = loc == "document"; ++ if ( bIsDocumentScript && !lcl_isScriptAccessAllowed_nothrow( _rxScriptContext ) ) ++ return ERRCODE_IO_ACCESSDENIED; ++ ++ if ( UnTrustedScript(_rScriptURL) ) ++ return ERRCODE_IO_ACCESSDENIED; ++ + // obtain/create a script provider + Reference< provider::XScriptProvider > xScriptProvider; + Reference< provider::XScriptProviderSupplier > xSPS( _rxScriptContext, UNO_QUERY ); +diff --git a/sfx2/source/notify/eventsupplier.cxx b/sfx2/source/notify/eventsupplier.cxx +index 69076ad01..d18724d74 100644 +--- a/sfx2/source/notify/eventsupplier.cxx ++++ b/sfx2/source/notify/eventsupplier.cxx +@@ -209,18 +209,24 @@ void SfxEvents_Impl::Execute( uno::Any const & aEventData, const document::Docum + else if (aType == "Service" || + aType == "Script") + { +- if ( !aScript.isEmpty() ) ++ bool bAllowed = false; ++ util::URL aURL; ++ if (!aScript.isEmpty()) + { +- SfxViewFrame* pView = pDoc ? +- SfxViewFrame::GetFirst( pDoc ) : +- SfxViewFrame::Current(); +- + uno::Reference < util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) ); + +- util::URL aURL; + aURL.Complete = aScript; + xTrans->parseStrict( aURL ); + ++ bAllowed = !SfxObjectShell::UnTrustedScript(aURL.Complete); ++ } ++ ++ if (bAllowed) ++ { ++ SfxViewFrame* pView = pDoc ? ++ SfxViewFrame::GetFirst( pDoc ) : ++ SfxViewFrame::Current(); ++ + uno::Reference + < frame::XDispatchProvider > xProv; + diff --git a/libreoffice.spec b/libreoffice.spec index e44dfc5..625bf11 100644 --- a/libreoffice.spec +++ b/libreoffice.spec @@ -42,7 +42,7 @@ Summary: Office suite Name: libreoffice Epoch: 1 Version: 6.0.7 -Release: 5 +Release: 6 License: (MPLv1.1 or LGPLv3+) and LGPLv3 and LGPLv2+ and BSD and (MPLv1.1 or GPLv2 or LGPLv2 or Netscape) and Public Domain and ASL 2.0 and Artistic Group: Office Url: http://www.libreoffice.org @@ -100,6 +100,7 @@ Patch105: libreoffice-5.4.3.1-breeze-fallback-theme.patch Patch110: CVE-2019-9848.patch Patch111: CVE-2019-9849.patch +Patch112: CVE-2019-9850_1_2.patch BuildRequires: bison BuildRequires: bsh