summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSzymon Kłos <szymon.klos@collabora.com>2023-11-29 14:00:32 +0100
committerMichael Meeks <michael.meeks@collabora.com>2023-12-02 21:15:23 +0000
commit16306492b8b584fc5f5ec835b6a91dd11259c59c (patch)
tree853d954c1e303d5d4fda31e80649084a89eea2f4
parentlok: import Work path from LOK_WORKDIR (diff)
downloadcore-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.cxx56
-rw-r--r--sal/qa/osl/file/osl_File.cxx25
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()