SUPR3HardenedMain.cpp revision a3b910b31da2f6dd99e41dc573f051a74e802a68
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox Support Library - Hardened main().
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (C) 2006-2008 Sun Microsystems, Inc.
af062818b47340eef15700d2f0211576ba3506eevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
af062818b47340eef15700d2f0211576ba3506eevboxsync * available from http://www.virtualbox.org. This file is free software;
af062818b47340eef15700d2f0211576ba3506eevboxsync * you can redistribute it and/or modify it under the terms of the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * General Public License (GPL) as published by the Free Software
af062818b47340eef15700d2f0211576ba3506eevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
af062818b47340eef15700d2f0211576ba3506eevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
af062818b47340eef15700d2f0211576ba3506eevboxsync * The contents of this file may alternatively be used under the terms
af062818b47340eef15700d2f0211576ba3506eevboxsync * of the Common Development and Distribution License Version 1.0
af062818b47340eef15700d2f0211576ba3506eevboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox OSE distribution, in which case the provisions of the
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * CDDL are applicable instead of those of the GPL.
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * You may elect to license modified versions of this file under the
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * terms and conditions of either the GPL or the CDDL or both.
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync * additional information or have any questions.
af062818b47340eef15700d2f0211576ba3506eevboxsync/*******************************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync* Header Files *
0658e98c3d1b59361863ce3390e57a356fd42217vboxsync*******************************************************************************/
6cd9e4d9b3398c78dfee8363a3ad75a33304d76cvboxsync#else /* UNIXes */
6cd9e4d9b3398c78dfee8363a3ad75a33304d76cvboxsync# include <iprt/types.h> /* stdint fun on darwin. */
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync/*******************************************************************************
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync* Defined Constants And Macros *
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync*******************************************************************************/
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync/** @def SUP_HARDENED_SUID
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync * Whether we're employing set-user-ID-on-execute in the hardening.
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_L4)
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync/** @def SUP_HARDENED_SYM
d2432596ad0325b8a9b42552ce4fcd251f37fcc3vboxsync * Decorate a symbol that's resolved dynamically.
af062818b47340eef15700d2f0211576ba3506eevboxsync/*******************************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync* Structures and Typedefs *
af062818b47340eef15700d2f0211576ba3506eevboxsync*******************************************************************************/
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @see RTR3InitEx */
af062818b47340eef15700d2f0211576ba3506eevboxsynctypedef DECLCALLBACK(int) FNRTR3INITEX(uint32_t iVersion, const char *pszProgramPath, bool fInitSUPLib);
af062818b47340eef15700d2f0211576ba3506eevboxsync/*******************************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync* Global Variables *
af062818b47340eef15700d2f0211576ba3506eevboxsync*******************************************************************************/
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The pre-init data we pass on to SUPR3 (residing in VBoxRT). */
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The progam executable path. */
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The program directory path. */
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The program name. */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic const char *g_pszSupLibHardenedProgName;
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The real UID at startup. */
d4af5b054ea5e3fa148cfb539e5fb886338f9c41vboxsync/** The real GID at startup. */
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsync/*******************************************************************************
af062818b47340eef15700d2f0211576ba3506eevboxsync* Internal Functions *
af062818b47340eef15700d2f0211576ba3506eevboxsync*******************************************************************************/
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsyncstatic PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName);
af062818b47340eef15700d2f0211576ba3506eevboxsync * @copydoc RTPathStripFilename.
3c5c04d7b0973be0757addef8ba44b9352b38386vboxsyncstatic void suplibHardenedPathStripFilename(char *pszPath)
af062818b47340eef15700d2f0211576ba3506eevboxsync /* handle separators. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* the end */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* will never get here */
af062818b47340eef15700d2f0211576ba3506eevboxsync * @copydoc RTPathFilename
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath)
af062818b47340eef15700d2f0211576ba3506eevboxsync /* handle separators. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* the end */
af062818b47340eef15700d2f0211576ba3506eevboxsync return (char *)(void *)pszLastComp;
af062818b47340eef15700d2f0211576ba3506eevboxsync /* will never get here */
af062818b47340eef15700d2f0211576ba3506eevboxsync * @copydoc RTPathAppPrivateNoArch
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath)
af062818b47340eef15700d2f0211576ba3506eevboxsync#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathAppPrivateNoArch: Buffer overflow, %lu >= %lu\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync (unsigned long)cchPathPrivateNoArch, (unsigned long)cchPath);
af062818b47340eef15700d2f0211576ba3506eevboxsync memcpy(pszPath, pszSrcPath, cchPathPrivateNoArch + 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync * @copydoc RTPathAppPrivateArch
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath)
af062818b47340eef15700d2f0211576ba3506eevboxsync#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE_ARCH)
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathAppPrivateArch: Buffer overflow, %lu >= %lu\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync (unsigned long)cchPathPrivateArch, (unsigned long)cchPath);
af062818b47340eef15700d2f0211576ba3506eevboxsync memcpy(pszPath, pszSrcPath, cchPathPrivateArch + 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync * @copydoc RTPathSharedLibs
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLHIDDEN(int) supR3HardenedPathSharedLibs(char *pszPath, size_t cchPath)
af062818b47340eef15700d2f0211576ba3506eevboxsync#if !defined(RT_OS_WINDOWS) && defined(RTPATH_SHARED_LIBS)
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathSharedLibs: Buffer overflow, %lu >= %lu\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync (unsigned long)cchPathSharedLibs, (unsigned long)cchPath);
af062818b47340eef15700d2f0211576ba3506eevboxsync memcpy(pszPath, pszSrcPath, cchPathSharedLibs + 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync * @copydoc RTPathAppDocs
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath)
af062818b47340eef15700d2f0211576ba3506eevboxsync#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_DOCS)
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathAppDocs: Buffer overflow, %lu >= %lu\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync (unsigned long)cchPathAppDocs, (unsigned long)cchPath);
af062818b47340eef15700d2f0211576ba3506eevboxsync * Returns the full path to the executable.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @returns IPRT status code.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pszPath Where to store it.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param cchPath How big that buffer is.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Get the program filename.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Most UNIXes have no API for obtaining the executable path, but provides a symbolic
af062818b47340eef15700d2f0211576ba3506eevboxsync * link in the proc file system that tells who was exec'ed. The bad thing about this
af062818b47340eef15700d2f0211576ba3506eevboxsync * is that we have to use readlink, one of the weirder UNIX APIs.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Darwin, OS/2 and Windows all have proper APIs for getting the program file name.
af062818b47340eef15700d2f0211576ba3506eevboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
af062818b47340eef15700d2f0211576ba3506eevboxsync int cchLink = readlink("/proc/self/exe", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync sprintf(szFileBuf, "/proc/%ld/path/a.out", (long)getpid());
af062818b47340eef15700d2f0211576ba3506eevboxsync int cchLink = readlink(szFileBuf, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync# else /* RT_OS_FREEBSD: */
af062818b47340eef15700d2f0211576ba3506eevboxsync int cchLink = readlink("/proc/curproc/file", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (cchLink < 0 || cchLink == sizeof(g_szSupLibHardenedExePath) - 1)
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathProgram: couldn't read \"%s\", errno=%d cchLink=%d\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync _execname(g_szSupLibHardenedExePath, sizeof(g_szSupLibHardenedExePath));
af062818b47340eef15700d2f0211576ba3506eevboxsync const char *pszImageName = _dyld_get_image_name(0);
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathProgram: _dyld_get_image_name(0) failed\n");
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!cchImageName || cchImageName >= sizeof(g_szSupLibHardenedExePath))
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathProgram: _dyld_get_image_name(0) failed, cchImageName=%d\n", cchImageName);
af062818b47340eef15700d2f0211576ba3506eevboxsync memcpy(g_szSupLibHardenedExePath, pszImageName, cchImageName + 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!GetModuleFileName(hExe, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath)))
af062818b47340eef15700d2f0211576ba3506eevboxsync supR3HardenedFatal("supR3HardenedPathProgram: GetModuleFileName failed, rc=%d\n", GetLastError());
af062818b47340eef15700d2f0211576ba3506eevboxsync * Strip off the filename part (RTPathStripFilename()).
af062818b47340eef15700d2f0211576ba3506eevboxsync strcpy(g_szSupLibHardenedDirPath, g_szSupLibHardenedExePath);
af062818b47340eef15700d2f0211576ba3506eevboxsync suplibHardenedPathStripFilename(g_szSupLibHardenedDirPath);
af062818b47340eef15700d2f0211576ba3506eevboxsync * Checks if we can read /proc/self/exe.
af062818b47340eef15700d2f0211576ba3506eevboxsync * This is used on linux to see if we have to call init
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * with program path or not.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @returns true / false.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncstatic bool supR3HardenedMainIsProcSelfExeAccssible(void)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync int cchLink = readlink("/proc/self/exe", szPath, sizeof(szPath));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync#endif /* RT_OS_LINUX */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @copydoc RTPathProgram
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLHIDDEN(int) supR3HardenedPathProgram(char *pszPath, size_t cchPath)
if (!g_szSupLibHardenedDirPath[0])
return VINF_SUCCESS;
return VERR_BUFFER_OVERFLOW;
DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
switch (enmWhat)
case kSupInitOp_Driver:
case kSupInitOp_IPRT:
case kSupInitOp_Integrity:
case kSupInitOp_RootCheck:
#ifdef SUP_HARDENED_SUID
if (pid <= 0)
if (pfnTrustedError)
#ifdef _MSC_VER
DECLHIDDEN(void) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, ...)
#ifdef _MSC_VER
if (fFatal)
return rc;
return rc;
#ifdef _MSC_VER
return cch;
static void supR3HardenedMainOpenDevice(void)
switch (rc)
case VERR_ACCESS_DENIED:
#ifdef SUP_HARDENED_SUID
static void supR3HardenedMainDropPrivileges(void)
# if defined(RT_OS_LINUX)
# if defined(RT_OS_DARWIN)
# if RT_OS_LINUX
#if defined(RT_OS_WINDOWS)
if (!hMod)
if (!pfnRTInitEx)
PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
if (!pfnSUPPreInit)
if (!pvMod)
if (!pfnRTInitEx)
PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
if (!pfnSUPPreInit)
#ifdef RT_OS_LINUX
#if defined(RT_OS_WINDOWS)
if (!hMod)
return NULL;
if (!pfn)
return NULL;
if (!pvMod)
return NULL;
if (!pvSym)
return NULL;
#if defined(RT_OS_WINDOWS)
if (!hMod)
if (!pfn)
supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
if (!pvMod)
if (!pvSym)
supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
#ifdef SUP_HARDENED_SUID
# ifdef RT_OS_LINUX
#ifdef SUP_HARDENED_SUID