416545a57b
This is espacially cruicial when it comes to Nix 1.9, where we even have a more restrictive /nix/store. In any event, VirtualBox in hardenend mode doesn't have to check the /nix/store path, because it's read-only on NixOS systems. So this check would not introduce more security but more hurdles, thus I'm removing it (of course _only_ for /nix/store). Signed-off-by: aszlig <aszlig@redmoonstudios.org>
208 lines
9.5 KiB
Diff
208 lines
9.5 KiB
Diff
diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h
|
|
index 70c596a..78972ed 100644
|
|
--- a/include/iprt/mangling.h
|
|
+++ b/include/iprt/mangling.h
|
|
@@ -1068,6 +1068,7 @@
|
|
# define RTPathStripSuffix RT_MANGLER(RTPathStripSuffix)
|
|
# define RTPathStripFilename RT_MANGLER(RTPathStripFilename)
|
|
# define RTPathStripTrailingSlash RT_MANGLER(RTPathStripTrailingSlash)
|
|
+# define RTPathSuidDir RT_MANGLER(RTPathSuidDir)
|
|
# define RTPathTemp RT_MANGLER(RTPathTemp)
|
|
# define RTPathTraverseList RT_MANGLER(RTPathTraverseList)
|
|
# define RTPathUnlink RT_MANGLER(RTPathUnlink)
|
|
@@ -1105,6 +1106,7 @@
|
|
# define RTProcGetAffinityMask RT_MANGLER(RTProcGetAffinityMask)
|
|
# define RTProcGetExecutablePath RT_MANGLER(RTProcGetExecutablePath)
|
|
# define RTProcGetPriority RT_MANGLER(RTProcGetPriority)
|
|
+# define RTProcGetSuidPath RT_MANGLER(RTProcGetSuidPath)
|
|
# define RTProcIsRunningByName RT_MANGLER(RTProcIsRunningByName)
|
|
# define RTProcQueryParent RT_MANGLER(RTProcQueryParent)
|
|
# define RTProcQueryUsername RT_MANGLER(RTProcQueryUsername)
|
|
diff --git a/include/iprt/path.h b/include/iprt/path.h
|
|
index 7e42754..b4de4c8 100644
|
|
--- a/include/iprt/path.h
|
|
+++ b/include/iprt/path.h
|
|
@@ -1049,6 +1049,15 @@ RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
|
|
RTDECL(int) RTPathExecDir(char *pszPath, size_t cchPath);
|
|
|
|
/**
|
|
+ * Gets the path to the NixOS setuid wrappers directory.
|
|
+ *
|
|
+ * @returns iprt status code.
|
|
+ * @param pszPath Buffer where to store the path.
|
|
+ * @param cchPath Buffer size in bytes.
|
|
+ */
|
|
+RTDECL(int) RTPathSuidDir(char *pszPath, size_t cchPath);
|
|
+
|
|
+/**
|
|
* Gets the user home directory.
|
|
*
|
|
* @returns iprt status code.
|
|
diff --git a/include/iprt/process.h b/include/iprt/process.h
|
|
index 2760306..0ce6c92 100644
|
|
--- a/include/iprt/process.h
|
|
+++ b/include/iprt/process.h
|
|
@@ -313,6 +313,16 @@ RTR3DECL(const char *) RTProcShortName(void);
|
|
RTR3DECL(char *) RTProcGetExecutablePath(char *pszExecPath, size_t cbExecPath);
|
|
|
|
/**
|
|
+ * Gets the path to the NixOS setuid wrappers directory.
|
|
+ *
|
|
+ * @returns pszExecPath on success. NULL on buffer overflow or other errors.
|
|
+ *
|
|
+ * @param pszExecPath Where to store the path.
|
|
+ * @param cbExecPath The size of the buffer.
|
|
+ */
|
|
+RTR3DECL(char *) RTProcGetSuidPath(char *pszExecPath, size_t cbExecPath);
|
|
+
|
|
+/**
|
|
* Daemonize the current process, making it a background process.
|
|
*
|
|
* The way this work is that it will spawn a detached / backgrounded /
|
|
diff --git a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
|
|
index c39d2f7..896b352 100644
|
|
--- a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
|
|
+++ b/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp
|
|
@@ -1415,18 +1415,19 @@ static int supR3HardenedVerifyFsObject(PCSUPR3HARDENEDFSOBJSTATE pFsObjState, bo
|
|
NOREF(fRelaxed);
|
|
#else
|
|
NOREF(fRelaxed);
|
|
- bool fBad = true;
|
|
+ bool fBad = !(fDir && pFsObjState->Stat.st_mode & S_ISVTX && !suplibHardenedStrCmp(pszPath, "/nix/store"));
|
|
#endif
|
|
- if (fBad)
|
|
+ if (fBad && suplibHardenedStrCmp(pszPath, "/nix/store"))
|
|
return supR3HardenedSetError3(VERR_SUPLIB_WRITE_NON_SYS_GROUP, pErrInfo,
|
|
"An unknown (and thus untrusted) group has write access to '", pszPath,
|
|
"' and we therefore cannot trust the directory content or that of any subdirectory");
|
|
}
|
|
|
|
/*
|
|
- * World must not have write access. There is no relaxing this rule.
|
|
+ * World must not have write access.
|
|
+ * There is no relaxing this rule, except when it comes to the Nix store.
|
|
*/
|
|
- if (pFsObjState->Stat.st_mode & S_IWOTH)
|
|
+ if (pFsObjState->Stat.st_mode & S_IWOTH && suplibHardenedStrCmp(pszPath, "/nix/store"))
|
|
return supR3HardenedSetError3(VERR_SUPLIB_WORLD_WRITABLE, pErrInfo,
|
|
"World writable: '", pszPath, "'");
|
|
|
|
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
|
|
index 95dc9a7..39170bc 100644
|
|
--- a/src/VBox/Main/src-server/MachineImpl.cpp
|
|
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
|
|
@@ -7326,7 +7326,7 @@ HRESULT Machine::i_launchVMProcess(IInternalSessionControl *aControl,
|
|
|
|
/* get the path to the executable */
|
|
char szPath[RTPATH_MAX];
|
|
- RTPathAppPrivateArch(szPath, sizeof(szPath) - 1);
|
|
+ RTStrCopy(szPath, sizeof(szPath) - 1, "/var/setuid-wrappers");
|
|
size_t cchBufLeft = strlen(szPath);
|
|
szPath[cchBufLeft++] = RTPATH_DELIMITER;
|
|
szPath[cchBufLeft] = 0;
|
|
diff --git a/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp b/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp
|
|
index 090018e..7dcfc7a 100644
|
|
--- a/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp
|
|
+++ b/src/VBox/Main/src-server/NATNetworkServiceRunner.cpp
|
|
@@ -75,7 +75,7 @@ int NATNetworkServiceRunner::start()
|
|
|
|
/* get the path to the executable */
|
|
char exePathBuf[RTPATH_MAX];
|
|
- const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
|
|
+ const char *exePath = RTProcGetSuidPath(exePathBuf, RTPATH_MAX);
|
|
char *substrSl = strrchr(exePathBuf, '/');
|
|
char *substrBs = strrchr(exePathBuf, '\\');
|
|
char *suffix = substrSl ? substrSl : substrBs;
|
|
diff --git a/src/VBox/Main/src-server/NetworkServiceRunner.cpp b/src/VBox/Main/src-server/NetworkServiceRunner.cpp
|
|
index e9e1ba62..4d1c1e1 100644
|
|
--- a/src/VBox/Main/src-server/NetworkServiceRunner.cpp
|
|
+++ b/src/VBox/Main/src-server/NetworkServiceRunner.cpp
|
|
@@ -79,7 +79,7 @@ int NetworkServiceRunner::start()
|
|
|
|
/* get the path to the executable */
|
|
char exePathBuf[RTPATH_MAX];
|
|
- const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
|
|
+ const char *exePath = RTProcGetSuidPath(exePathBuf, RTPATH_MAX);
|
|
char *substrSl = strrchr(exePathBuf, '/');
|
|
char *substrBs = strrchr(exePathBuf, '\\');
|
|
char *suffix = substrSl ? substrSl : substrBs;
|
|
diff --git a/src/VBox/Main/src-server/generic/NetIf-generic.cpp b/src/VBox/Main/src-server/generic/NetIf-generic.cpp
|
|
index 8559d2a..2177f27 100644
|
|
--- a/src/VBox/Main/src-server/generic/NetIf-generic.cpp
|
|
+++ b/src/VBox/Main/src-server/generic/NetIf-generic.cpp
|
|
@@ -47,7 +47,7 @@ static int NetIfAdpCtl(const char * pcszIfName, const char *pszAddr, const char
|
|
const char *args[] = { NULL, pcszIfName, pszAddr, pszOption, pszMask, NULL };
|
|
|
|
char szAdpCtl[RTPATH_MAX];
|
|
- int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME));
|
|
+ int rc = RTPathSuidDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME));
|
|
if (RT_FAILURE(rc))
|
|
{
|
|
LogRel(("NetIfAdpCtl: failed to get program path, rc=%Rrc.\n", rc));
|
|
@@ -90,7 +90,7 @@ static int NetIfAdpCtl(HostNetworkInterface * pIf, const char *pszAddr, const ch
|
|
int NetIfAdpCtlOut(const char * pcszName, const char * pcszCmd, char *pszBuffer, size_t cBufSize)
|
|
{
|
|
char szAdpCtl[RTPATH_MAX];
|
|
- int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " ") - strlen(pcszCmd));
|
|
+ int rc = RTPathSuidDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " ") - strlen(pcszCmd));
|
|
if (RT_FAILURE(rc))
|
|
{
|
|
LogRel(("NetIfAdpCtlOut: Failed to get program path, rc=%Rrc\n", rc));
|
|
@@ -202,7 +202,7 @@ int NetIfCreateHostOnlyNetworkInterface(VirtualBox *pVirtualBox,
|
|
progress.queryInterfaceTo(aProgress);
|
|
|
|
char szAdpCtl[RTPATH_MAX];
|
|
- int rc = RTPathExecDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " add"));
|
|
+ int rc = RTPathSuidDir(szAdpCtl, sizeof(szAdpCtl) - sizeof("/" VBOXNETADPCTL_NAME " add"));
|
|
if (RT_FAILURE(rc))
|
|
{
|
|
progress->i_notifyComplete(E_FAIL,
|
|
diff --git a/src/VBox/Runtime/r3/path.cpp b/src/VBox/Runtime/r3/path.cpp
|
|
index be2ad8f..7ddf105 100644
|
|
--- a/src/VBox/Runtime/r3/path.cpp
|
|
+++ b/src/VBox/Runtime/r3/path.cpp
|
|
@@ -81,6 +81,12 @@ RTDECL(int) RTPathExecDir(char *pszPath, size_t cchPath)
|
|
}
|
|
|
|
|
|
+RTDECL(int) RTPathSuidDir(char *pszPath, size_t cchPath)
|
|
+{
|
|
+ return RTStrCopy(pszPath, cchPath, "/var/setuid-wrappers");
|
|
+}
|
|
+
|
|
+
|
|
RTDECL(int) RTPathAppPrivateNoArch(char *pszPath, size_t cchPath)
|
|
{
|
|
#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
|
|
diff --git a/src/VBox/Runtime/r3/process.cpp b/src/VBox/Runtime/r3/process.cpp
|
|
index 7bde6af..2656cae 100644
|
|
--- a/src/VBox/Runtime/r3/process.cpp
|
|
+++ b/src/VBox/Runtime/r3/process.cpp
|
|
@@ -111,6 +111,26 @@ RTR3DECL(char *) RTProcGetExecutablePath(char *pszExecPath, size_t cbExecPath)
|
|
return NULL;
|
|
}
|
|
|
|
+/*
|
|
+ * Note the / at the end! This is important, because the functions using this
|
|
+ * will cut off everything after the rightmost / as this function is analogous
|
|
+ * to RTProcGetExecutablePath().
|
|
+ */
|
|
+#define SUIDDIR "/var/setuid-wrappers/"
|
|
+
|
|
+RTR3DECL(char *) RTProcGetSuidPath(char *pszExecPath, size_t cbExecPath)
|
|
+{
|
|
+ if (cbExecPath >= sizeof(SUIDDIR))
|
|
+ {
|
|
+ memcpy(pszExecPath, SUIDDIR, sizeof(SUIDDIR));
|
|
+ pszExecPath[sizeof(SUIDDIR)] = '\0';
|
|
+ return pszExecPath;
|
|
+ }
|
|
+
|
|
+ AssertMsgFailed(("Buffer too small (%zu <= %zu)\n", cbExecPath, sizeof(SUIDDIR)));
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
|
|
RTR3DECL(const char *) RTProcShortName(void)
|
|
{
|