summaryrefslogtreecommitdiff
path: root/sal
diff options
context:
space:
mode:
authorSzymon Kłos <szymon.klos@collabora.com>2023-11-29 14:00:32 +0100
committerSzymon Kłos <szymon.klos@collabora.com>2023-11-30 20:08:06 +0100
commitc3bdba781e8c9d61ca9e2a3d8d2eaca435b9aaad (patch)
treeee26d8df778c1380ba7bc0ff9c5c01a19e903296 /sal
parentde6b66f2d9572480bce038b2a03e9ca5b1730b9f (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.cxx46
-rw-r--r--sal/qa/osl/file/osl_File.cxx25
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()