desktop/source/lib/init.cxx | 12 - include/osl/file.h | 48 ------ include/osl/file.hxx | 52 ------ include/rtl/alloc.h | 8 - sal/CppunitTest_sal_osl_file_details.mk | 43 +++++ sal/Library_sal.mk | 1 sal/Module_sal.mk | 1 sal/inc/setallowedpaths.hxx | 39 ++++ sal/osl/unx/file.cxx | 19 -- sal/osl/unx/file_impl.hxx | 17 ++ sal/qa/osl/file/forbidden.cxx | 254 ++++++++++++++++++++++++++++++++ sal/qa/osl/file/osl_File.cxx | 144 ------------------ sal/qa/rtl/alloc/rtl_alloc.cxx | 4 sal/rtl/preinit.cxx | 51 ++++++ sal/rtl/strimp.cxx | 2 sal/rtl/strimp.hxx | 2 sal/util/sal.map | 6 solenv/clang-format/excludelist | 1 18 files changed, 425 insertions(+), 279 deletions(-)
New commits: commit 242ccc31d5a2c8be900828523de145e173900514 Author: Stephan Bergmann <stephan.bergm...@collabora.com> AuthorDate: Wed Jul 2 16:31:28 2025 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Thu Jul 3 21:15:04 2025 +0200 Avoid extending the sal UNO API ...with osl_setAllowedPaths and osl_isForbiddenPath from 34f1a750a128e02aa3191e36a2c0b28371e96287 "sal: initial osl::File sand-boxing commit for Unix." Instead: * For osl_setAllowedPaths, rather extend (in an ABI-compatible way, even) the already existing rtl_alloc_preInit, which took a sal_Bool (i.e., unsigned char) to take a sal_uInt8 (i.e., unsigned char) and let an argument "2" mean "call the (now sal-internal) setAllowedPaths with the value of the SAL_ALLOWED_PATHS env var". (And SAL_ALLOWED_PATHS and SAL_ABORT_ON_FORBIDDEN remain undocumented internal env vars, whose semantics can be changed freely anytime.) * And osl_isForbiddenPath wasn't called from outside sal (other than in a CppunitTest, see next), anyway. The test code that had been added to CppunitTest_sal_osl (and which required access to osl_setAllowedPaths and osl_isForbiddenPath) is broken out into its own CppunitTest_sal_osl_file_details, which uses gb_CppunitTest_use_library_objects to access the (now sal-internal) setAllowedPaths and isForbidden. Change-Id: I6b48dce51cbb4acc8a44f0ee9d79d4f0d37cfa58 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187286 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 124289e9a2cd..5408a92bb24a 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -8271,12 +8271,8 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char } #ifdef LINUX - { - const char *pAllowedPaths = getenv("SAL_ALLOWED_PATHS"); - if (pAllowedPaths) - osl_setAllowedPaths( - OUString(pAllowedPaths, strlen(pAllowedPaths), RTL_TEXTENCODING_UTF8).pData); - } + // Enforce SAL_ALLOWED_PATHS: + rtl_alloc_preInit(2); #endif char* pAllowlist = ::getenv("LOK_HOST_ALLOWLIST"); @@ -8316,7 +8312,7 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char if (eStage == PRE_INIT) { - rtl_alloc_preInit(true); + rtl_alloc_preInit(1); // Set the default timezone to the TZ envar, if set. const char* tz = ::getenv("TZ"); @@ -8623,7 +8619,7 @@ static int lo_initialize(LibreOfficeKit* pThis, const char* pAppPath, const char // staticize all strings. if (eStage == PRE_INIT) - rtl_alloc_preInit(false); + rtl_alloc_preInit(0); return bInitialized; } diff --git a/include/osl/file.h b/include/osl/file.h index 98ad568550b9..07d2beb2ae1f 100644 --- a/include/osl/file.h +++ b/include/osl/file.h @@ -960,54 +960,6 @@ SAL_DLLPUBLIC oslFileError SAL_CALL osl_readFile( SAL_DLLPUBLIC oslFileError SAL_CALL osl_isEndOfFile( oslFileHandle Handle, sal_Bool *pIsEOF ); -/** Resets the list of paths and associated permissions for osl - - @param[in] pustrFileURLs - Contains a ':' delimited list of control strings and paths. - Control segments are a short path that refers to the following - segments and contain either: - - r: read-only paths follow (the default) - w: read & write paths follow - x: executable paths follow - - Any real paths (ie. having resolved all symlinks) - accessed outside of these paths will cause an - osl_File_E_ACCESS error in the relevant method calls. - - This method is Unix specific. - - @see osl_isForbiddenPath - - @since LibreOffice 7.7 -*/ -SAL_DLLPUBLIC void SAL_CALL osl_setAllowedPaths( - rtl_uString *pustrFileURLs - ); - -/** - Determine if the passed in path is not contained inside - the allowed paths, or if no allowed paths are set it - will not forbid any access. - - @param[in] pustrFileURL - A URL (or path) that we want to check if it is forbidden - to access. - - @param[in] nFlags - Flags to determine what type of access is requested, - osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'. - - This method is Unix specific. - - @see osl_setAllowedPaths - - @since LibreOffice 7.7 - */ -SAL_DLLPUBLIC sal_Bool SAL_CALL osl_isForbiddenPath( - rtl_uString *pustrFileURL, int nFlags - ); - /** Write a number of bytes to a file. Writes a number of bytes to a file. diff --git a/include/osl/file.hxx b/include/osl/file.hxx index 787da4f98f31..1f1121d547e2 100644 --- a/include/osl/file.hxx +++ b/include/osl/file.hxx @@ -312,58 +312,6 @@ public: return static_cast< RC >( osl_createTempFile(pustr_dir_url, pHandle, ppustr_tmp_file_url) ); } - - - /** Resets the list of paths and associated permissions for osl - - @param[in] rPaths - Contains a ':' delimited list of control strings and paths. - Control segments are a short path that refers to the following - segments and contain either: - - r: read-only paths follow (the default) - w: read & write paths follow - x: executable paths follow - - Any real paths (ie. having resolved all symlinks) - accessed outside of these paths will cause an - osl_File_E_ACCESS error in the relevant method calls. - - This method is Unix specific. - - @see osl_isForbiddenPath - - @since LibreOffice 7.7 - */ - - static void setAllowedPaths(const ::rtl::OUString& rPaths) - { - osl_setAllowedPaths(rPaths.pData); - } - - /** - Determine if the passed in path is not contained inside - the allowed paths, or if no allowed paths are set it - will not forbid any access. - - @param[in] pustrFileURL - A URL (or path) that we want to check if it is forbidden - to access. - - @param[in] nFlags - Flags to determine what type of access is requested, - osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'. - - This method is Unix specific. - - @see osl_setAllowedPaths - - @since LibreOffice 7.7 - */ - static bool isForbidden(const ::rtl::OUString& rPath, int nFlags) - { - return osl_isForbiddenPath(rPath.pData, nFlags); - } }; diff --git a/include/rtl/alloc.h b/include/rtl/alloc.h index 1dc9cefacb0d..bfcc9a02b186 100644 --- a/include/rtl/alloc.h +++ b/include/rtl/alloc.h @@ -298,8 +298,8 @@ SAL_DLLPUBLIC void SAL_CALL rtl_cache_free ( * at the end of LibreOfficeKit pre-initialization to enable * various optimizations. * - * Its function is to annotate a section @start = true - * to end (@start = false) via. two calls. Inside this + * Its function is to annotate a section @mode = 1 + * to end (@mode = 0) via. two calls. Inside this * section string allocators are replaced with ones which cause the * strings to be staticized at the end of the section. * @@ -313,6 +313,8 @@ SAL_DLLPUBLIC void SAL_CALL rtl_cache_free ( * This method is not thread-safe, nor intended for use in * a threaded context, cf. previous constraints. * + * Further @mode values may have further meanings, which may change at any time. + * * It is almost certainly not the method that you want, * use with extraordinary care referring to the * implementation. @@ -320,7 +322,7 @@ SAL_DLLPUBLIC void SAL_CALL rtl_cache_free ( * @since LibreOffice 6.1 */ SAL_DLLPUBLIC void SAL_CALL rtl_alloc_preInit ( - sal_Bool start + sal_uInt8 mode ) SAL_THROW_EXTERN_C(); /** @endcond */ diff --git a/sal/CppunitTest_sal_osl_file_details.mk b/sal/CppunitTest_sal_osl_file_details.mk new file mode 100644 index 000000000000..acfed31c0135 --- /dev/null +++ b/sal/CppunitTest_sal_osl_file_details.mk @@ -0,0 +1,43 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,sal_osl_file_details)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sal_osl_file_details, \ + sal/qa/osl/file/forbidden \ +)) + +$(eval $(call gb_CppunitTest_add_libs,sal_osl_file_details, \ + $(if $(filter LINUX,$(OS)), \ + -ldl \ + -lrt \ + ) \ + $(if $(filter SOLARIS,$(OS)), \ + -lnsl \ + -lsocket \ + ) \ + $(if $(filter HAIKU,$(OS)), \ + -lnetwork \ + ) \ + $(BACKTRACE_LIBS) \ +)) + +$(eval $(call gb_CppunitTest_set_include,sal_osl_file_details, \ + $$(INCLUDE) \ + -I$(SRCDIR)/sal/inc \ +)) + +$(eval $(call gb_CppunitTest_use_externals,sal_osl_file_details, \ + dtoa \ + zlib \ +)) + +$(eval $(call gb_CppunitTest_use_library_objects,sal_osl_file_details,sal)) + +# vim: set noet sw=4 ts=4: diff --git a/sal/Library_sal.mk b/sal/Library_sal.mk index a7026e8327d8..94e7fe10c5ca 100644 --- a/sal/Library_sal.mk +++ b/sal/Library_sal.mk @@ -109,6 +109,7 @@ $(eval $(call gb_Library_add_exception_objects,sal,\ sal/rtl/hash \ sal/rtl/locale \ sal/rtl/math \ + sal/rtl/preinit \ sal/rtl/random \ sal/rtl/rtl_process \ sal/rtl/strbuf \ diff --git a/sal/Module_sal.mk b/sal/Module_sal.mk index 854d46a8e6d4..242dc3297c31 100644 --- a/sal/Module_sal.mk +++ b/sal/Module_sal.mk @@ -31,6 +31,7 @@ $(eval $(call gb_Module_add_check_targets,sal,\ $(if $(filter WNT,$(OS)),CppunitTest_sal_retry_if_failed) \ CppunitTest_sal_osl_security \ CppunitTest_sal_osl \ + CppunitTest_sal_osl_file_details \ CppunitTest_sal_rtl \ CppunitTest_sal_types \ $(if $(COM_IS_CLANG),$(if $(COMPILER_EXTERNAL_TOOL)$(COMPILER_PLUGIN_TOOL),, \ diff --git a/sal/inc/setallowedpaths.hxx b/sal/inc/setallowedpaths.hxx new file mode 100644 index 000000000000..110b7cc1a46d --- /dev/null +++ b/sal/inc/setallowedpaths.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#if defined UNX +/** Resets the list of paths and associated permissions for osl + + @param[in] aPaths + Contains a ':' delimited list of control strings and paths. + Control segments are a short path that refers to the following + segments and contain either: + + r: read-only paths follow (the default) + w: read & write paths follow + x: executable paths follow + + Any real paths (ie. having resolved all symlinks) + accessed outside of these paths will cause an + osl_File_E_ACCESS error in the relevant method calls. + + This method is Unix specific. + + @see isForbidden in sal/osl/unx/file_impl.hxx +*/ +void setAllowedPaths(std::u16string_view aPaths); +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx index 96f4633e42b0..45adb8b8be42 100644 --- a/sal/osl/unx/file.cxx +++ b/sal/osl/unx/file.cxx @@ -26,6 +26,8 @@ #include <rtl/string.hxx> #include <o3tl/string_view.hxx> +#include <setallowedpaths.hxx> + #include "system.hxx" #include "createfilehandlefromfd.hxx" #include "file_error_transl.hxx" @@ -844,20 +846,16 @@ static OString getParentFolder(std::string_view rFilePath) return folderPath; } -SAL_DLLPUBLIC void osl_setAllowedPaths( - rtl_uString *pustrFilePaths +void setAllowedPaths( + std::u16string_view aPaths ) { allowedPathsRead.clear(); allowedPathsReadWrite.clear(); allowedPathsExecute.clear(); - if (!pustrFilePaths) - return; - char eType = 'r'; sal_Int32 nIndex = 0; - OUString aPaths(pustrFilePaths); do { OString aPath = rtl::OUStringToOString( @@ -965,15 +963,6 @@ bool isForbidden(const OString &filePath, int nFlags) return !allowed; } -SAL_DLLPUBLIC sal_Bool SAL_CALL osl_isForbiddenPath( - rtl_uString *pustrFileURL, int nFlags - ) -{ - return isForbidden( - rtl::OUStringToOString(OUString(pustrFileURL), - RTL_TEXTENCODING_UTF8), nFlags); -} - #ifdef HAVE_O_EXLOCK #define OPEN_WRITE_FLAGS ( O_RDWR | O_EXLOCK | O_NONBLOCK ) #define OPEN_CREATE_FLAGS ( O_CREAT | O_RDWR | O_EXLOCK | O_NONBLOCK ) diff --git a/sal/osl/unx/file_impl.hxx b/sal/osl/unx/file_impl.hxx index 64504296955d..f0aec40c59cd 100644 --- a/sal/osl/unx/file_impl.hxx +++ b/sal/osl/unx/file_impl.hxx @@ -40,6 +40,23 @@ struct DirectoryItem_Impl oslFileType getFileType() const; }; +/** + Determine if the passed in path is not contained inside + the allowed paths, or if no allowed paths are set it + will not forbid any access. + + @param[in] filePath + A URL (or path) that we want to check if it is forbidden + to access. + + @param[in] nFlags + Flags to determine what type of access is requested, + osl_File_OpenFlag_Read | Write, or 0x80 for 'execute'. + + This method is Unix specific. + + @see setAllowedPaths in sal/inc/setallowedpaths.hxx +*/ bool isForbidden(const OString &filePath, int nFlags); oslFileError openFile( diff --git a/sal/qa/osl/file/forbidden.cxx b/sal/qa/osl/file/forbidden.cxx new file mode 100644 index 000000000000..d474fbbc39db --- /dev/null +++ b/sal/qa/osl/file/forbidden.cxx @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include <cppunit/plugin/TestPlugIn.h> + +#if (defined UNX) + +#include <stdio.h> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <osl/file.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +#include <setallowedpaths.hxx> + +#include "../../../osl/unx/file_impl.hxx" + +using namespace osl; + +namespace osl::qa { + +static bool isForbidden(OUString const & path, sal_uInt32 flags) { + OString utf8; + auto const ok = path.convertToString(&utf8, RTL_TEXTENCODING_UTF8, RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR); + CPPUNIT_ASSERT(ok); + return ::isForbidden(utf8, flags); +} + +} + +namespace osl_Forbidden +{ + + class Forbidden : public CppUnit::TestFixture + { + OUString maScratchBad; + OUString maScratchGood; + public: + void setUp() override + { + // create a directory to play in + createTestDirectory(aTmpName3); + OUString aBadURL = aTmpName3 + "/bad"; + OUString aGoodURL = aTmpName3 + "/good"; + createTestDirectory(aBadURL); + createTestDirectory(aGoodURL); + File::getSystemPathFromFileURL(aBadURL, maScratchBad); + File::getSystemPathFromFileURL(aGoodURL, maScratchGood); + } + + void tearDown() override + { + setAllowedPaths(u""); + OUString aBadURL = aTmpName3 + "/bad"; + OUString aGoodURL = aTmpName3 + "/good"; + deleteTestDirectory(aBadURL); + deleteTestDirectory(aGoodURL); + deleteTestDirectory(aTmpName3); + } + + void forbidden() + { + setAllowedPaths(maScratchGood); + + // check some corner cases first + CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", + true, osl::qa::isForbidden(".", osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", + true, osl::qa::isForbidden("", osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", + true, osl::qa::isForbidden("a", osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", + true, osl::qa::isForbidden("/", osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("read from non-existent should be allowed", + false, osl::qa::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Read)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", + true, osl::qa::isForbidden(maScratchBad, osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed", + false, osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be forbidden", + true, osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Write)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("create in good should be forbidden", + true, osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Create)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden", + true, osl::qa::isForbidden(maScratchGood, 0x80)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be forbidden", + true, osl::qa::isForbidden(maScratchBad + "/notthere", osl_File_OpenFlag_Write)); + + setAllowedPaths(Concat2View("w:" + maScratchGood + ":x:" + maScratchBad)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", + true, osl::qa::isForbidden(maScratchBad, osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed", // w implies 'r' + false, osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Read)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be allowed", + false, osl::qa::isForbidden(maScratchGood, osl_File_OpenFlag_Write)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden", + true, osl::qa::isForbidden(maScratchGood, 0x80)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from bad should be allowed", + false, osl::qa::isForbidden(maScratchBad, 0x80)); + + setAllowedPaths(Concat2View(":r:" + maScratchBad)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be forbidden", + true, osl::qa::isForbidden(maScratchGood + "/notthere", osl_File_OpenFlag_Write)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be forbidden 2", + true, osl::qa::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Write)); + + setAllowedPaths(Concat2View(":r:" + maScratchBad + ":w:" + maScratchGood + "/notthere")); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be allowed", + false, osl::qa::isForbidden(maScratchGood + "/notthere", osl_File_OpenFlag_Write)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be allowed 2", + false, osl::qa::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Write)); + } + +/* + void open() + { + setAllowedPaths(maScratchGood); + File testFile(maScratchBad + "/open"); + auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); + CPPUNIT_ASSERT_EQUAL_MESSAGE("disabled path allowed", osl::FileBase::E_ACCES, nError1); + deleteTestFile(testFile.getURL()); + } + + void copy() + { + setAllowedPaths("w:" + maScratchGood); + File testGood(maScratchGood + "/good"); + File testGoodTo(maScratchGood + "/good_to"); + File testBad(maScratchBad + "/bad"); + + auto nError1 = testGood.open(osl_File_OpenFlag_Create); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); + + auto nErrorCopy = File::copy(maScratchGood + "/good", maScratchGood + "/good_to"); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nErrorCopy); + + auto nErrorCopyBad = File::copy(maScratchGood + "/good_to", maScratchBad + "/bad"); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_ACCES, nErrorCopyBad); + + deleteTestFile(maScratchGood + "/good_to"); + deleteTestFile(maScratchGood + "/good"); + } + + void nextTests() + { + // more entry points to test +#if 0 + auto nError1 = File::move(aTmpName4, aCanURL1); + auto nError2 = File::remove(aTmpName4); + auto nError3 = File::setAttributes(aTmpName6, osl_File_Attribute_ReadOnly); + bool bOk = osl_getSystemTime(pTV_current); + CPPUNIT_ASSERT(bOk); + auto nError4 = File::setTime(aTmpName6, *pTV_current, *pTV_current, *pTV_current); + CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError2).getStr(), osl::FileBase::E_None, nError2); +#endif + } +*/ + CPPUNIT_TEST_SUITE(Forbidden); + CPPUNIT_TEST(forbidden); +// CPPUNIT_TEST(open); +// CPPUNIT_TEST(copy); +// CPPUNIT_TEST(nextTests); + CPPUNIT_TEST_SUITE_END(); + + //TODO: The following parts are mainly copied from sal/qa/osl/file/osl_File.cxx and + // sal/qa/osl/file/osl_File_Const.h (but the latter cannot be included directly, as its use of + // static C++ objects would cause issues with the use of gb_CppunitTest_use_library_objects in + // this test's sal/CppunitTest_sal_osl_file_details.mk): + private: + static OUString getTempDirectoryURL_() + { + OUString aDir; + CPPUNIT_ASSERT_EQUAL_MESSAGE("couldn't get system temp URL", + osl::FileBase::E_None, osl::FileBase::getTempDirURL(aDir)); + // This resolves symlinks in the temp path if any + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, + osl::FileBase::getAbsoluteFileURL(aDir, aDir, aDir)); + return aDir; + } + + OUString aTempDirectoryURL; + + OUString aTmpName3; + + /** simple version to judge if a file name or directory name is a URL or a system path, just to see if it + is start with "file:///";. + */ + static bool isURL(const OUString& pathname) + { + return pathname.startsWith(u"file:///"); + } + + /** create a temp test directory using OUString name of full qualified URL or system path. + */ + static void createTestDirectory(const OUString& dirname) + { + OUString aPathURL = dirname.copy(0); + osl::FileBase::RC nError; + + if (!isURL(dirname)) + osl::FileBase::getFileURLFromSystemPath(dirname, aPathURL); // convert if not full qualified URL + nError = Directory::create(aPathURL); + if ((nError != osl::FileBase::E_None) && (nError != osl::FileBase::E_EXIST)) + printf("createTestDirectory failed: %d! ", int(nError)); + } + + /** delete a temp test directory using OUString name of full qualified URL or system path. + */ + static void deleteTestDirectory(const OUString& dirname) + { + OUString aPathURL = dirname.copy(0); + if (!isURL(dirname)) + osl::FileBase::getFileURLFromSystemPath(dirname, aPathURL); // convert if not full qualified URL + + Directory testDir(aPathURL); + if (testDir.isOpen()) + testDir.close(); // close if still open. + + osl::FileBase::RC nError = Directory::remove(aPathURL); + + OString strError = "In deleteTestDirectory function: remove Directory " + + OUStringToOString(aPathURL, RTL_TEXTENCODING_ASCII_US) + " -> result: " + OString::number(nError); + CPPUNIT_ASSERT_MESSAGE(strError.getStr(), (osl::FileBase::E_None == nError) || (nError == osl::FileBase::E_NOENT)); + } + + public: + Forbidden(): + aTempDirectoryURL(getTempDirectoryURL_()), + aTmpName3( aTempDirectoryURL + "/tmpdir" ) + {} + }; + + CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Forbidden::Forbidden, "osl_Forbidden"); + + CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_Forbidden"); +} +#endif + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sal/qa/osl/file/osl_File.cxx b/sal/qa/osl/file/osl_File.cxx index d768c151ddaf..159f32ad7410 100644 --- a/sal/qa/osl/file/osl_File.cxx +++ b/sal/qa/osl/file/osl_File.cxx @@ -1313,150 +1313,6 @@ namespace osl_FileBase CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_osl::FileBase"); } -#if (defined UNX) - -namespace osl_Forbidden -{ - - class Forbidden : public CppUnit::TestFixture - { - OUString maScratchBad; - OUString maScratchGood; - public: - void setUp() override - { - // create a directory to play in - createTestDirectory(aTmpName3); - OUString aBadURL = aTmpName3 + "/bad"; - OUString aGoodURL = aTmpName3 + "/good"; - createTestDirectory(aBadURL); - createTestDirectory(aGoodURL); - File::getSystemPathFromFileURL(aBadURL, maScratchBad); - File::getSystemPathFromFileURL(aGoodURL, maScratchGood); - } - - void tearDown() override - { - osl_setAllowedPaths(nullptr); - OUString aBadURL = aTmpName3 + "/bad"; - OUString aGoodURL = aTmpName3 + "/good"; - deleteTestDirectory(aBadURL); - deleteTestDirectory(aGoodURL); - deleteTestDirectory(aTmpName3); - } - - void forbidden() - { - File::setAllowedPaths(maScratchGood); - - // check some corner cases first - CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", - true, File::isForbidden(".", osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", - true, File::isForbidden("", osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", - true, File::isForbidden("a", osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", - true, File::isForbidden("/", osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("read from non-existent should be allowed", - false, File::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Read)); - - CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", - true, File::isForbidden(maScratchBad, osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed", - false, File::isForbidden(maScratchGood, osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be forbidden", - true, File::isForbidden(maScratchGood, osl_File_OpenFlag_Write)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("create in good should be forbidden", - true, File::isForbidden(maScratchGood, osl_File_OpenFlag_Create)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden", - true, File::isForbidden(maScratchGood, 0x80)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be forbidden", - true, File::isForbidden(maScratchBad + "/notthere", osl_File_OpenFlag_Write)); - - File::setAllowedPaths("w:" + maScratchGood + ":x:" + maScratchBad); - CPPUNIT_ASSERT_EQUAL_MESSAGE("read bad should be forbidden", - true, File::isForbidden(maScratchBad, osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("read from good should be allowed", // w implies 'r' - false, File::isForbidden(maScratchGood, osl_File_OpenFlag_Read)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("write to good should be allowed", - false, File::isForbidden(maScratchGood, osl_File_OpenFlag_Write)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from good should be forbidden", - true, File::isForbidden(maScratchGood, 0x80)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("exec from bad should be allowed", - false, File::isForbidden(maScratchBad, 0x80)); - - File::setAllowedPaths(":r:" + maScratchBad); - CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be forbidden", - true, File::isForbidden(maScratchGood + "/notthere", osl_File_OpenFlag_Write)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be forbidden 2", - true, File::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Write)); - - File::setAllowedPaths(":r:" + maScratchBad + ":w:" + maScratchGood + "/notthere"); - CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be allowed", - false, File::isForbidden(maScratchGood + "/notthere", osl_File_OpenFlag_Write)); - CPPUNIT_ASSERT_EQUAL_MESSAGE("write to non-existent should be allowed 2", - false, File::isForbidden(maScratchGood + "/notthere/file", osl_File_OpenFlag_Write)); - } - -/* - void open() - { - File::setAllowedPaths(maScratchGood); - File testFile(maScratchBad + "/open"); - auto nError1 = testFile.open(osl_File_OpenFlag_Read | osl_File_OpenFlag_Write); - CPPUNIT_ASSERT_EQUAL_MESSAGE("disabled path allowed", osl::FileBase::E_ACCES, nError1); - deleteTestFile(testFile.getURL()); - } - - void copy() - { - File::setAllowedPaths("w:" + maScratchGood); - File testGood(maScratchGood + "/good"); - File testGoodTo(maScratchGood + "/good_to"); - File testBad(maScratchBad + "/bad"); - - auto nError1 = testGood.open(osl_File_OpenFlag_Create); - CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nError1); - - auto nErrorCopy = File::copy(maScratchGood + "/good", maScratchGood + "/good_to"); - CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, nErrorCopy); - - auto nErrorCopyBad = File::copy(maScratchGood + "/good_to", maScratchBad + "/bad"); - CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_ACCES, nErrorCopyBad); - - deleteTestFile(maScratchGood + "/good_to"); - deleteTestFile(maScratchGood + "/good"); - } - - void nextTests() - { - // more entry points to test -#if 0 - auto nError1 = File::move(aTmpName4, aCanURL1); - auto nError2 = File::remove(aTmpName4); - auto nError3 = File::setAttributes(aTmpName6, osl_File_Attribute_ReadOnly); - bool bOk = osl_getSystemTime(pTV_current); - CPPUNIT_ASSERT(bOk); - auto nError4 = File::setTime(aTmpName6, *pTV_current, *pTV_current, *pTV_current); - CPPUNIT_ASSERT_EQUAL_MESSAGE(errorToStr(nError2).getStr(), osl::FileBase::E_None, nError2); -#endif - } -*/ - CPPUNIT_TEST_SUITE(Forbidden); - CPPUNIT_TEST(forbidden); -// CPPUNIT_TEST(open); -// CPPUNIT_TEST(copy); -// CPPUNIT_TEST(nextTests); - CPPUNIT_TEST_SUITE_END(); - }; - - CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(osl_Forbidden::Forbidden, "osl_Forbidden"); - - CPPUNIT_REGISTRY_ADD_TO_DEFAULT("osl_Forbidden"); -} -#endif - namespace osl_FileStatus { // testing the method diff --git a/sal/qa/rtl/alloc/rtl_alloc.cxx b/sal/qa/rtl/alloc/rtl_alloc.cxx index 0e743cae3c11..f63d3f1275aa 100644 --- a/sal/qa/rtl/alloc/rtl_alloc.cxx +++ b/sal/qa/rtl/alloc/rtl_alloc.cxx @@ -157,7 +157,7 @@ public: const char sample[] = "Hello World"; std::vector<OUString> aStrings; - rtl_alloc_preInit(true); + rtl_alloc_preInit(1); OUString aFoo(o3tl::nonStaticString(u"foo")); @@ -182,7 +182,7 @@ public: } // should static-ize all the strings. - rtl_alloc_preInit(false); + rtl_alloc_preInit(0); for (size_t i = 0; i < aStrings.size(); ++i) CPPUNIT_ASSERT_MESSAGE( "static after.", (aStrings[i].pData->refCount & SAL_STRING_STATIC_FLAG) ); diff --git a/sal/rtl/preinit.cxx b/sal/rtl/preinit.cxx new file mode 100644 index 000000000000..d1c6c1478d5a --- /dev/null +++ b/sal/rtl/preinit.cxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include <stdlib.h> +#include <string.h> + +#include <rtl/alloc.h> +#include <rtl/textenc.h> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <sal/types.h> + +#include <setallowedpaths.hxx> + +#include "strimp.hxx" + +void SAL_CALL rtl_alloc_preInit(sal_uInt8 mode) SAL_THROW_EXTERN_C() +{ + switch (mode) + { + case 0: + alloc_preInit(false); + break; + case 1: + alloc_preInit(true); + break; +#if defined UNX + case 2: + { + const char* pAllowedPaths = getenv("SAL_ALLOWED_PATHS"); + if (pAllowedPaths) + setAllowedPaths( + OUString(pAllowedPaths, strlen(pAllowedPaths), RTL_TEXTENCODING_UTF8)); + break; + } +#endif + default: + SAL_WARN("sal.rtl", "Unknown rtl_alloc_preInit mode " << unsigned(mode)); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sal/rtl/strimp.cxx b/sal/rtl/strimp.cxx index 678bbb69c406..fac73cecf7b4 100644 --- a/sal/rtl/strimp.cxx +++ b/sal/rtl/strimp.cxx @@ -65,7 +65,7 @@ static void mark_static(void *addr, sal_Size /* size */) str->refCount |= SAL_STRING_STATIC_FLAG; } -void SAL_CALL rtl_alloc_preInit (sal_Bool start) noexcept +void alloc_preInit (bool start) noexcept { if (start) { diff --git a/sal/rtl/strimp.hxx b/sal/rtl/strimp.hxx index 5fd759313ed3..6691296aa3b8 100644 --- a/sal/rtl/strimp.hxx +++ b/sal/rtl/strimp.hxx @@ -60,6 +60,8 @@ typedef void (*rtl_freeStringFn)(void *); extern rtl_allocateStringFn rtl_allocateString; extern rtl_freeStringFn rtl_freeString; +void alloc_preInit(bool start) noexcept; + // string lifetime instrumentation / diagnostics #if USE_SDT_PROBES # define PROBE_SNAME(n,b) n ## _ ## b diff --git a/sal/util/sal.map b/sal/util/sal.map index 586a41ee997d..c5c3e4d55641 100644 --- a/sal/util/sal.map +++ b/sal/util/sal.map @@ -761,12 +761,6 @@ PRIVATE_1.8 { # LibreOffice 7.3 rtl_uString_newReplaceStrAtUtf16L; } PRIVATE_1.7; -PRIVATE_1.9 { # LibreOffice 7.7 - global: - osl_setAllowedPaths; - osl_isForbiddenPath; -} PRIVATE_1.8; - PRIVATE_textenc.1 { # LibreOffice 3.6 global: _ZN3sal6detail7textenc20convertCharToUnicode*; diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index 554233aad13e..1111f5117fc9 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -7530,6 +7530,7 @@ sal/qa/OStringBuffer/rtl_OStringBuffer.cxx sal/qa/OStringBuffer/rtl_String_Const.h sal/qa/inc/valueequal.hxx sal/qa/osl/condition/osl_Condition.cxx +sal/qa/osl/file/forbidden.cxx sal/qa/osl/file/osl_File.cxx sal/qa/osl/file/osl_File_Const.h sal/qa/osl/file/osl_old_test_file.cxx