diff options
author | Szymon Kłos <szymon.klos@collabora.com> | 2023-11-29 14:00:32 +0100 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2023-12-02 21:15:23 +0000 |
commit | 16306492b8b584fc5f5ec835b6a91dd11259c59c (patch) | |
tree | 853d954c1e303d5d4fda31e80649084a89eea2f4 | |
parent | lok: import Work path from LOK_WORKDIR (diff) | |
download | core-private/mmeeks/sandbox.tar.gz core-private/mmeeks/sandbox.zip |
sal: osl::File allow to create files in sandbox
private/mmeeks/sandbox
"realpath" returns NULL for path which doesn't exist.
Allow usage of non-existing paths if parent is allowed.
This allows to successfully start the sandboxed kit.
osl_setAllowedPaths will allow now to use:
/foo/bar/nonexisting - previously it was ignored, is needed for LOK
but /foo/bar/nonexisting/newlevel - still cannot be used
isForbidden now checks parents of non-existing dir and assumes
the same permissions, if parent doesn't exist - it tries with
parent of parent, etc ...
Change-Id: I1052747ca284d2f81dfd5c5fbf893936e7426220
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160111
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
-rw-r--r-- | sal/osl/unx/file.cxx | 56 | ||||
-rw-r--r-- | sal/qa/osl/file/osl_File.cxx | 25 |
2 files changed, 68 insertions, 13 deletions
diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx index aaf0f704fead..7c2d0ac54798 100644 --- a/sal/osl/unx/file.cxx +++ b/sal/osl/unx/file.cxx @@ -19,6 +19,7 @@ #include <config_features.h> #include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> #include <o3tl/typed_flags_set.hxx> #include <sal/log.hxx> #include <osl/detail/file.h> @@ -790,6 +791,20 @@ static std::vector<OString> allowedPathsRead; static std::vector<OString> allowedPathsReadWrite; static std::vector<OString> allowedPathsExecute; +static OString getParentFolder(const std::string_view &rHappyPlugin) +{ + OString aFilePath(rHappyPlugin); + sal_Int32 n = aFilePath.lastIndexOf('/'); + OString folderPath; + static constexpr OStringLiteral dot("."); + if (n < 1) + folderPath = dot; + else + folderPath = aFilePath.copy(0, n); + + return folderPath; +} + SAL_DLLPUBLIC void osl_setAllowedPaths( rtl_uString *pustrFilePaths ) @@ -803,12 +818,11 @@ SAL_DLLPUBLIC void osl_setAllowedPaths( char eType = 'r'; sal_Int32 nIndex = 0; - OUString aPaths(pustrFilePaths); + OString aPaths = rtl::OUStringToOString( + OUString(pustrFilePaths), RTL_TEXTENCODING_UTF8); do { - OString aPath = rtl::OUStringToOString( - aPaths.getToken(0, ':', nIndex), - RTL_TEXTENCODING_UTF8); + OString aPath(o3tl::getToken(aPaths, ':', nIndex)); if (aPath.getLength() == 0) continue; @@ -820,9 +834,25 @@ SAL_DLLPUBLIC void osl_setAllowedPaths( } char resolvedPath[PATH_MAX]; - if (realpath(aPath.getStr(), resolvedPath)) + bool isResolved = !!realpath(aPath.getStr(), resolvedPath); + bool notExists = !isResolved && errno == ENOENT; + + if (notExists) { - OString aPushPath = OString(resolvedPath, strlen(resolvedPath)); + sal_Int32 n = aPath.lastIndexOf('/'); + OString folderPath = getParentFolder(aPath); + isResolved = !!realpath(folderPath.getStr(), resolvedPath); + notExists = !isResolved && errno == ENOENT; + + if (notExists || !isResolved || strlen(resolvedPath) + aPath.getLength() - n + 1 >= PATH_MAX) + return; // too bad + else + strcat(resolvedPath, aPath.getStr() + n); + } + + if (isResolved) + { + OString aPushPath(resolvedPath, strlen(resolvedPath)); if (eType == 'r') allowedPathsRead.push_back(aPushPath); else if (eType == 'w') @@ -852,13 +882,13 @@ bool isForbidden(const OString &filePath, int nFlags) // fail to resolve. Thankfully our I/O APIs don't allow // symlink creation to race here. sal_Int32 n = filePath.lastIndexOf('/'); - OString folderPath; - if (n < 1) - folderPath = "."; - else - folderPath = filePath.copy(0, n); - if (!realpath(folderPath.getStr(), resolvedPath) || - strlen(resolvedPath) + filePath.getLength() - n + 1 >= PATH_MAX) + OString folderPath = getParentFolder(filePath); + + bool isResolved = !!realpath(folderPath.getStr(), resolvedPath); + bool notExists = !isResolved && errno == ENOENT; + if (notExists) // folder doesn't exist, check parent, in the end of chain checks "." + return isForbidden(folderPath, nFlags); + else if (!isResolved || strlen(resolvedPath) + filePath.getLength() - n + 1 >= PATH_MAX) return true; // too bad else strcat(resolvedPath, filePath.getStr() + n); diff --git a/sal/qa/osl/file/osl_File.cxx b/sal/qa/osl/file/osl_File.cxx index 0de87eeb14a9..df59f33e6070 100644 --- a/sal/qa/osl/file/osl_File.cxx +++ b/sal/qa/osl/file/osl_File.cxx @@ -1348,6 +1348,19 @@ namespace osl_Forbidden 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", @@ -1372,6 +1385,18 @@ namespace osl_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() |