diff --git a/nixos/modules/programs/virtualbox-host.nix b/nixos/modules/programs/virtualbox-host.nix index c6abc9ddf89..504ef36d44b 100644 --- a/nixos/modules/programs/virtualbox-host.nix +++ b/nixos/modules/programs/virtualbox-host.nix @@ -62,15 +62,20 @@ in )); security.setuidOwners = let - mkVboxStub = program: { + mkSuid = program: { inherit program; + source = "${virtualbox}/libexec/virtualbox/${program}"; owner = "root"; group = "vboxusers"; setuid = true; }; - in mkIf cfg.enableHardening (map mkVboxStub [ + in mkIf cfg.enableHardening (map mkSuid [ "VBoxHeadless" + "VBoxNetAdpCtl" + "VBoxNetDHCP" + "VBoxNetNAT" "VBoxSDL" + "VBoxVolInfo" "VirtualBox" ]); diff --git a/pkgs/applications/virtualization/virtualbox/hardened.patch b/pkgs/applications/virtualization/virtualbox/hardened.patch index a0184b68f07..aad9171b68e 100644 --- a/pkgs/applications/virtualization/virtualbox/hardened.patch +++ b/pkgs/applications/virtualization/virtualbox/hardened.patch @@ -1,3 +1,64 @@ +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..cd19186 100644 --- a/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp @@ -37,3 +98,108 @@ index 95dc9a7..39170bc 100644 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) + {