VirtualBox

Changeset 33701 in vbox for trunk/src/VBox/HostDrivers


Ignore:
Timestamp:
Nov 2, 2010 4:47:11 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
67327
Message:

SUPLib: Some new hardening APIs (almost done).

Location:
trunk/src/VBox/HostDrivers/Support
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPLib.cpp

    r33623 r33701  
    14281428     */
    14291429#ifdef VBOX_WITH_HARDENING
    1430     int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
     1430    int rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
    14311431    if (RT_FAILURE(rc))
    14321432        LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
     
    14511451     */
    14521452#ifdef VBOX_WITH_HARDENING
    1453 /** @todo implement me! */
    1454     return VINF_SUCCESS;
     1453    int rc = supR3HardenedVerifyDir(pszDirPath, fRecursive, fCheckFiles, pszErr, cbErr);
     1454    if (RT_FAILURE(rc) && (!pszErr || !cbErr))
     1455        LogRel(("supR3HardenedVerifyDir: Verification of \"%s\" failed, rc=%Rrc\n", pszDirPath, rc));
     1456    return rc;
    14551457#else
    14561458    return VINF_SUCCESS;
     
    14721474     */
    14731475#ifdef VBOX_WITH_HARDENING
    1474 /** @todo implement me! */
    1475     return VINF_SUCCESS;
     1476    int rc = supR3HardenedVerifyFile(pszFilename, pszErr, cbErr);
     1477    if (RT_FAILURE(rc) && (!pszErr || !cbErr))
     1478        LogRel(("supR3HardenedVerifyFile: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
     1479    return rc;
    14761480#else
    14771481    return VINF_SUCCESS;
     
    14871491     * Check that the module can be trusted.
    14881492     */
    1489     rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
     1493    rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
    14901494#endif
    14911495    if (RT_SUCCESS(rc))
     
    15071511     * Check that the module can be trusted.
    15081512     */
    1509     rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
     1513    rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
    15101514#endif
    15111515    if (RT_SUCCESS(rc))
     
    20162020     * Verify the image file.
    20172021     */
    2018     int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
     2022    int rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
    20192023    if (RT_FAILURE(rc))
    20202024    {
  • trunk/src/VBox/HostDrivers/Support/SUPLibInternal.h

    r28800 r33701  
    9090# define supR3HardenedError                supR3HardenedStaticError
    9191# define supR3HardenedVerifyAll            supR3HardenedStaticVerifyAll
     92# define supR3HardenedVerifyFixedDir       supR3HardenedStaticVerifyFixedDir
     93# define supR3HardenedVerifyFixedFile      supR3HardenedStaticVerifyFixedFile
    9294# define supR3HardenedVerifyDir            supR3HardenedStaticVerifyDir
    93 # define supR3HardenedVerifyFile           supR3HardenedStaticVerifyFile
     95# define supR3HardenedVerifyPlugIn         supR3HardenedStaticVerifyPlugIn
    9496# define supR3HardenedGetPreInitData       supR3HardenedStaticGetPreInitData
    9597# define supR3HardenedRecvPreInitData      supR3HardenedStaticRecvPreInitData
     
    316318DECLHIDDEN(int)    supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...);
    317319DECLHIDDEN(int)    supR3HardenedVerifyAll(bool fFatal, bool fLeaveFilesOpen, const char *pszProgName);
    318 DECLHIDDEN(int)    supR3HardenedVerifyDir(SUPINSTDIR enmDir, bool fFatal);
    319 DECLHIDDEN(int)    supR3HardenedVerifyFile(const char *pszFilename, bool fFatal);
     320DECLHIDDEN(int)    supR3HardenedVerifyFixedDir(SUPINSTDIR enmDir, bool fFatal);
     321DECLHIDDEN(int)    supR3HardenedVerifyFixedFile(const char *pszFilename, bool fFatal);
     322DECLHIDDEN(int)    supR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, char *pszErr, size_t cbErr);
     323DECLHIDDEN(int)    supR3HardenedVerifyFile(const char *pszFilename, char *pszErr, size_t cbErr);
    320324DECLHIDDEN(void)   supR3HardenedGetPreInitData(PSUPPREINITDATA pPreInitData);
    321325DECLHIDDEN(int)    supR3HardenedRecvPreInitData(PCSUPPREINITDATA pPreInitData);
  • trunk/src/VBox/HostDrivers/Support/SUPR3HardenedVerify.cpp

    r33590 r33701  
    4747# include <stdio.h>
    4848# include <stdlib.h>
     49# include <dirent.h>
    4950# include <dlfcn.h>
    5051# include <fcntl.h>
     
    6869#include <iprt/string.h>
    6970#include <iprt/param.h>
     71#include <iprt/path.h>
    7072
    7173#include "SUPLibInternal.h"
     
    292294 *                              fatal (true) or not (false).
    293295 */
    294 DECLHIDDEN(int) supR3HardenedVerifyDir(SUPINSTDIR enmDir, bool fFatal)
     296DECLHIDDEN(int) supR3HardenedVerifyFixedDir(SUPINSTDIR enmDir, bool fFatal)
    295297{
    296298    /*
     
    439441     *  use openat if we wish.)
    440442     */
    441     int rc = supR3HardenedVerifyDir(pFile->enmDir, fFatal);
     443    int rc = supR3HardenedVerifyFixedDir(pFile->enmDir, fFatal);
    442444    if (RT_SUCCESS(rc))
    443445    {
     
    618620 *                              fatal (true) or not (false).
    619621 */
    620 DECLHIDDEN(int) supR3HardenedVerifyFile(const char *pszFilename, bool fFatal)
     622DECLHIDDEN(int) supR3HardenedVerifyFixedFile(const char *pszFilename, bool fFatal)
    621623{
    622624    /*
     
    704706
    705707
    706 
    707708/**
    708709 * Verifies all the known files.
     
    744745
    745746    return rc;
     747}
     748
     749
     750/** Wrapper macro that adds the message length argument. */
     751#define supR3HardenedSetError(rc, pszErr, cbErr, szMsg)  \
     752    supR3HardenedSetErrorInt(rc, pszErr, cbErr, szMsg, sizeof(szMsg) - 1)
     753
     754/**
     755 * Copies the error message to the error buffer and returns @a rc.
     756 *
     757 * @returns Returns @a rc
     758 * @param   rc                  The return code.
     759 * @param   pszErr              The error buffer.
     760 * @param   cbErr               The size of the error buffer.
     761 * @param   pszMsg              The message.
     762 * @param   cchMsg              The length of the message text.
     763 */
     764static int supR3HardenedSetErrorInt(int rc, char *pszErr, size_t cbErr, const char *pszMsg, size_t cchMsg)
     765{
     766    if (cbErr <= cchMsg)
     767        cchMsg = cbErr - 1;
     768    memcpy(pszErr, pszMsg, cchMsg);
     769    pszErr[cchMsg] = '\0';
     770
     771    return rc;
     772}
     773
     774
     775/**
     776 * Verifies that the path is absolutely sane.
     777 *
     778 * A sane path starts at the root (w/ drive letter on DOS derived systems) and
     779 * does not have any relative bits (/../) or unnecessary slashes (/bin//ls).
     780 * Sane paths are less or equal to 260 bytes in length.  UNC paths are not
     781 * supported.
     782 *
     783 * @returns VBox status code.
     784 * @param   pszPath             The path to check.
     785 * @param   pszErr              The error buffer.
     786 * @param   cbErr               The size of the error buffer.
     787 * @param   pcchPath            Where to return the path length.
     788 */
     789static int supR3HardenedVerifyPathSanity(const char *pszPath, char *pszErr, size_t cbErr, size_t *pcchPath)
     790{
     791    const char * const pszPathStart = pszPath;
     792
     793    /*
     794     * Check that it's an absolute path.
     795     */
     796#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     797    if (   !(   (pszPath[0] >= 'A' && pszPath[0] <= 'Z')
     798             || (pszPath[0] >= 'a' && pszPath[0] <= 'z'))
     799        || pszPath[1] != ':'
     800        || !RTPATH_IS_SLASH(pszPath[2]))
     801        return supR3HardenedSetError(VERR_SUPLIB_PATH_NOT_ABSOLUTE, pszErr, cbErr, "The path is not absolute");
     802    size_t const cchRootSpec = 3;
     803#else
     804    if (!RTPATH_IS_SLASH(pszPath[0]))
     805        return supR3HardenedSetError(VERR_SUPLIB_PATH_NOT_ABSOLUTE, pszErr, cbErr, "The path is not absolute");
     806    size_t const cchRootSpec = 1;
     807#endif
     808    pszPath += cchRootSpec;
     809
     810    /*
     811     * Check each component.  No parent references or double slashes.
     812     */
     813    while (pszPath[0])
     814    {
     815        if (   pszPath[0] == '.'
     816            && pszPath[1] == '.'
     817            && RTPATH_IS_SLASH(pszPath[2]))
     818            return supR3HardenedSetError(VERR_SUPLIB_PATH_NOT_ABSOLUTE, pszErr, cbErr, "The path is not absolute");
     819        if (RTPATH_IS_SLASH(pszPath[0]))
     820            return supR3HardenedSetError(VERR_SUPLIB_PATH_NOT_CLEAN, pszErr, cbErr, "The path is not clean of double slashes");
     821        while (pszPath[0])
     822        {
     823            if (RTPATH_IS_SLASH(pszPath[0]))
     824            {
     825                pszPath++;
     826                break;
     827            }
     828            pszPath++;
     829        }
     830    }
     831
     832    /*
     833     * Check the path length, root specifications are not permitted and we
     834     * think paths longer than 260 bytes for are insane.
     835     */
     836    size_t cchPath = pszPath - pszPathStart;
     837    if (cchPath <= cchRootSpec)
     838        return supR3HardenedSetError(VERR_SUPLIB_PATH_IS_ROOT, pszErr, cbErr, "The path is too root");
     839    if (cchPath > 260)
     840        return supR3HardenedSetError(VERR_SUPLIB_PATH_TOO_LONG, pszErr, cbErr, "The path is too long");
     841
     842    if (pcchPath)
     843        *pcchPath = (size_t)(pszPath - pszPathStart);
     844    return VINF_SUCCESS;
     845}
     846
     847
     848/**
     849 * Verifies on file system object (file or directory).
     850 *
     851 * @returns VBox status code, error buffer filled on failure.
     852 * @param   pszPath             The path to the object.
     853 * @param   fDir                Whether this is a directory or a file.
     854 * @param   pszErr              The error buffer.
     855 * @param   cbErr               The size of the error buffer.
     856 */
     857static int supR3HardenedVerifyFsObject(char *pszPath, bool fDir, char *pszErr, size_t cbErr)
     858{
     859#if defined(RT_OS_WINDOWS)
     860    /** @todo Windows hardening. */
     861    return VINF_SUCCESS;
     862
     863#elif defined(RT_OS_OS2)
     864    /* No hardening here - it's a single user system. */
     865    return VINF_SUCCESS;
     866
     867#else
     868    /*
     869     * Stat the file and check that only root can modify it.
     870     */
     871    struct stat st;
     872    if (stat(pszPath, &st) != 0)
     873    {
     874        /* Ignore access errors */
     875        if (errno != EACCES)
     876            return supR3HardenedSetError(VERR_SUPLIB_STAT_FAILED, pszErr, cbErr, pszPath);
     877    }
     878
     879    /** @todo continue here tomorrow. */
     880
     881    return VINF_SUCCESS;
     882#endif
     883}
     884
     885
     886/**
     887 * Does the recursive directory enumeration.
     888 *
     889 * @returns VBox status code, error buffer filled on failure.
     890 * @param   pszDirPath          The path buffer containing the subdirectory to
     891 *                              enumerate followed by a slash (this is never
     892 *                              the root slash).  The buffer is RTPATH_MAX in
     893 *                              size and anything starting at @a cchDirPath
     894 *                              - 1 and beyond is scratch space.
     895 * @param   cchDirPath          The length of the directory path + slash.
     896 * @param   fRecursive          Whether to recurse into subdirectories.
     897 * @param   fCheckFiles         Whether to check files.
     898 * @param   pszErr              The error buffer.
     899 * @param   cbErr               The size of the error buffer.
     900 */
     901static int supR3HardenedVerifyDirRecursive(char *pszDirPath, size_t cchDirPath, bool fRecursive, bool fCheckFiles,
     902                                           char *pszErr, size_t cbErr)
     903{
     904#if defined(RT_OS_WINDOWS)
     905    /** @todo Windows hardening. */
     906    return VINF_SUCCESS;
     907
     908#elif defined(RT_OS_OS2)
     909    /* No hardening here - it's a single user system. */
     910    return VINF_SUCCESS;
     911
     912#else
     913    DIR *pDir = opendir(pszDirPath);
     914    if (!pDir)
     915    {
     916        /* Ignore access errors. */
     917        if (errno == EACCES)
     918            return VINF_SUCCESS;
     919        return supR3HardenedSetError(VERR_SUPLIB_DIR_ENUM_FAILED, pszErr, cbErr, pszDirPath);
     920    }
     921
     922    int rc = VINF_SUCCESS;
     923    for (;;)
     924    {
     925        struct dirent Entry;
     926        struct dirent *pEntry;
     927        int iErr = readdir_r(pDir, &Entry, &pEntry);
     928        if (iErr)
     929        {
     930            rc = supR3HardenedSetError(VERR_SUPLIB_DIR_ENUM_FAILED, pszErr, cbErr, pszDirPath);
     931            break;
     932        }
     933        if (!pEntry)
     934            break;
     935
     936        /*
     937         * Check the length and copy it into the path buffer so it can be
     938         * stat()'ed.
     939         */
     940        size_t cchName = strlen(pEntry->d_name);
     941        if (cchName + cchDirPath > 260)
     942        {
     943            rc = supR3HardenedSetError(VERR_SUPLIB_PATH_TOO_LONG, pszErr, cbErr, pszDirPath);
     944            break;
     945        }
     946        memcpy(&pszDirPath[cchName], pEntry->d_name, cchName + 1);
     947
     948        struct stat st;
     949        if (stat(pszDirPath, &st) != 0)
     950        {
     951            /* Ignore access errors */
     952            if (errno == EACCES)
     953                continue;
     954            rc = supR3HardenedSetError(VERR_SUPLIB_STAT_ENUM_FAILED, pszErr, cbErr, pszDirPath);
     955            break;
     956        }
     957
     958        /*
     959         * Only files and directories are allowed.
     960         */
     961        if (!S_ISDIR(st.st_mode) && S_ISREG(st.st_mode))
     962        {
     963            if (S_ISLNK(st.st_mode))
     964                rc = supR3HardenedSetError(VERR_SUPLIB_SYMLINKS_ARE_NOT_PERMITTED, pszErr, cbErr, pszDirPath);
     965            rc = supR3HardenedSetError(VERR_SUPLIB_NOT_DIR_NOT_FILE, pszErr, cbErr, pszDirPath);
     966            break;
     967        }
     968
     969        /*
     970         * Verify it.
     971         */
     972        if (   S_ISDIR(st.st_mode)
     973            || fCheckFiles)
     974        {
     975            rc = supR3HardenedVerifyFsObject(pszDirPath, S_ISDIR(st.st_mode), pszErr, cbErr);
     976            if (RT_FAILURE(rc))
     977                break;
     978        }
     979
     980        /*
     981         * Recurse.
     982         */
     983        if (    fRecursive
     984            &&  S_ISDIR(st.st_mode)
     985            &&  strcmp(pEntry->d_name, ".")
     986            &&  strcmp(pEntry->d_name, ".."))
     987        {
     988            pszDirPath[cchDirPath + cchName]     = RTPATH_SLASH;
     989            pszDirPath[cchDirPath + cchName + 1] = '\0';
     990
     991            rc = supR3HardenedVerifyDirRecursive(pszDirPath, cchDirPath + cchName + 1, fRecursive, fCheckFiles, pszErr, cbErr);
     992            if (RT_FAILURE(rc))
     993                break;
     994        }
     995    }
     996
     997    closedir(pDir);
     998    return VINF_SUCCESS;
     999#endif
     1000}
     1001
     1002
     1003/**
     1004 * Worker for SUPR3HardenedVerifyDir.
     1005 *
     1006 * @returns See SUPR3HardenedVerifyDir.
     1007 * @param   pszDirPath          See SUPR3HardenedVerifyDir.
     1008 * @param   fRecursive          See SUPR3HardenedVerifyDir.
     1009 * @param   fCheckFiles         See SUPR3HardenedVerifyDir.
     1010 * @param   pszErr              See SUPR3HardenedVerifyDir.
     1011 * @param   cbErr               See SUPR3HardenedVerifyDir.
     1012 */
     1013DECLHIDDEN(int) supR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, char *pszErr, size_t cbErr)
     1014{
     1015    /*
     1016     * Validate the input so we can be lazy when parsing it.
     1017     */
     1018    size_t cchDirPath;
     1019    int rc = supR3HardenedVerifyPathSanity(pszDirPath, pszErr, cbErr, &cchDirPath);
     1020    if (RT_FAILURE(rc))
     1021        return rc;
     1022
     1023    /*
     1024     * Make a copy of the input path and verify each component from the
     1025     * root and up.  This is the same as for supR3HardenedVerifyFile.
     1026     */
     1027    char szPath[RTPATH_MAX];
     1028    memcpy(szPath, pszDirPath, cchDirPath + 1);
     1029#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     1030    size_t off = 3;
     1031#else
     1032    size_t off = 1;
     1033#endif
     1034    while (off < cchDirPath)
     1035    {
     1036        size_t offSlash = off + 1;
     1037        while (szPath[offSlash] && !RTPATH_IS_SLASH(szPath[offSlash]))
     1038            offSlash++;
     1039
     1040        char chSaved = szPath[offSlash];
     1041        szPath[offSlash] = '\0';
     1042
     1043        rc = supR3HardenedVerifyFsObject(szPath, true /*fDir*/, pszErr, cbErr);
     1044        if (RT_FAILURE(rc))
     1045            return rc;
     1046
     1047        szPath[offSlash] = chSaved;
     1048        off = offSlash + 1;
     1049    }
     1050
     1051    /*
     1052     * Do we need to check files or/and recurse into subdirectories?
     1053     */
     1054    if (fCheckFiles || fRecursive)
     1055    {
     1056        if (!RTPATH_IS_SLASH(szPath[cchDirPath - 1]))
     1057        {
     1058            szPath[cchDirPath++] = RTPATH_SLASH;
     1059            szPath[cchDirPath] = '\0';
     1060        }
     1061        return supR3HardenedVerifyDirRecursive(szPath, cchDirPath, fRecursive, fCheckFiles, pszErr, cbErr);
     1062    }
     1063
     1064    return VINF_SUCCESS;
     1065}
     1066
     1067
     1068/**
     1069 * Verfies a file.
     1070 *
     1071 * @returns VBox status code, error buffer filled on failure.
     1072 * @param   pszFilename         The file to verify.
     1073 * @param   pszErr              The error buffer.
     1074 * @param   cbErr               The size of the error buffer.
     1075 */
     1076DECLHIDDEN(int) supR3HardenedVerifyFile(const char *pszFilename, char *pszErr, size_t cbErr)
     1077{
     1078    /*
     1079     * Validate the input so we can be lazy when parsing it.
     1080     */
     1081    size_t cchFilename;
     1082    int rc = supR3HardenedVerifyPathSanity(pszFilename, pszErr, cbErr, &cchFilename);
     1083    if (RT_FAILURE(rc))
     1084        return rc;
     1085
     1086    /*
     1087     * Make a copy of the input filename and verify each component from the
     1088     * root and up.
     1089     */
     1090    char szPath[RTPATH_MAX];
     1091    memcpy(szPath, pszFilename, cchFilename + 1);
     1092#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     1093    size_t off = 3;
     1094#else
     1095    size_t off = 1;
     1096#endif
     1097    while (off < cchFilename)
     1098    {
     1099        size_t offSlash = off + 1;
     1100        while (szPath[offSlash] && !RTPATH_IS_SLASH(szPath[offSlash]))
     1101            offSlash++;
     1102
     1103        char chSaved = szPath[offSlash];
     1104        szPath[offSlash] = '\0';
     1105
     1106        rc = supR3HardenedVerifyFsObject(szPath, offSlash < cchFilename /*fDir*/, pszErr, cbErr);
     1107        if (RT_FAILURE(rc))
     1108            return rc;
     1109
     1110        szPath[offSlash] = chSaved;
     1111        off = offSlash + 1;
     1112    }
     1113
     1114    return VINF_SUCCESS;
    7461115}
    7471116
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette