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/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) {