diff options
author | Szymon Kłos <szymon.klos@collabora.com> | 2023-11-29 14:00:32 +0100 |
---|---|---|
committer | Szymon Kłos <szymon.klos@collabora.com> | 2023-11-30 20:08:06 +0100 |
commit | c3bdba781e8c9d61ca9e2a3d8d2eaca435b9aaad (patch) | |
tree | ee26d8df778c1380ba7bc0ff9c5c01a19e903296 /sal | |
parent | de6b66f2d9572480bce038b2a03e9ca5b1730b9f (diff) |
sal: osl::File allow to create files in 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>
Diffstat (limited to 'sal')
-rw-r--r-- | sal/osl/unx/file.cxx | 46 | ||||
-rw-r--r-- | sal/qa/osl/file/osl_File.cxx | 25 |
2 files changed, 62 insertions, 9 deletions
diff --git a/sal/osl/unx/file.cxx b/sal/osl/unx/file.cxx index 0556be7fc97a..d5b76a09a47a 100644 --- a/sal/osl/unx/file.cxx +++ b/sal/osl/unx/file.cxx @@ -788,6 +788,18 @@ static std::vector<OString> allowedPathsRead; static std::vector<OString> allowedPathsReadWrite; static std::vector<OString> allowedPathsExecute; +static OString getParentFolder(const OString &rFilePath) +{ + sal_Int32 n = rFilePath.lastIndexOf('/'); + OString folderPath; + if (n < 1) + folderPath = "."; + else + folderPath = rFilePath.copy(0, n); + + return folderPath; +} + SAL_DLLPUBLIC void osl_setAllowedPaths( rtl_uString *pustrFilePaths ) @@ -818,9 +830,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') @@ -850,13 +878,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 0703e89493b9..cdd72d45fa72 100644 --- a/sal/qa/osl/file/osl_File.cxx +++ b/sal/qa/osl/file/osl_File.cxx @@ -1352,6 +1352,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", @@ -1376,6 +1389,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() |