VirtualBox

Changeset 58402 in vbox


Ignore:
Timestamp:
Oct 24, 2015 9:51:55 PM (9 years ago)
Author:
vboxsync
Message:

SUPR3HardenedMain.cpp: @page pg_hardening updates. No 'ing thanks to the premature spell checking / whatever someone did.

File:
1 edited

Legend:

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

    r58385 r58402  
    3131 *
    3232 * The VirtualBox VMM requires supervisor (kernel) level access to the CPU.  For
    33  * both practical and historical reasons, part of the VMM is still implemented
    34  * in ring-3 and has a rich interface to the kernel part.  While the device
    35  * emulations can be run all in ring-3, we have performance optimizations that
     33 * both practical and historical reasons part of the VMM is partly realized in
     34 * ring-3 with a rich interface to the kernel part.  While the device emulations
     35 * can be run exclusively in ring-3, we have performance optimizations that
    3636 * loads device emulation code into ring-0 and our special raw-mode execution
    37  * context (non-VT-x/AMD-V mode) for handling frequent operations.  These share
    38  * data between all three context (ring-3, ring-0 and raw-mode).  All this poses
    39  * a rather broad attack surface, which the hardening protects.
     37 * context (non-VT-x/AMD-V mode) for handling frequent operations a lot more
     38 * efficiently.  These share data between all three context (ring-3, ring-0 and
     39 * raw-mode).  All this poses a rather broad attack surface, which the hardening
     40 * protects.
    4041 *
    4142 * The hardening primarily focuses on restricting access to the support driver,
    4243 * VBoxDrv or vboxdrv depending on the OS, as it is ultimately the link and
    4344 * instigator of the communication between ring-3 and the ring-0 and raw-mode
    44  * contexts. A secondary focus is to make sure malicious code cannot be loaded
     45 * contexts.  A secondary focus is to make sure malicious code cannot be loaded
    4546 * and executed in the VM process.  Exactly how we go about this depends a lot
    4647 * on the host OS.
     
    4950 * @section sec_hardening_unix  Hardening on UNIX-like OSes
    5051 *
    51  * On UNIX-like systems (Solaris, Linux, darwin, freebsd, ...) only allow root
    52  * to get full unrestricted access to the support driver.  The device node
    53  * corresponding to unrestricted access is owned by root and has a 0600 access
    54  * mode (i.e. only accessible to the owner, root).  In addition to this file
    55  * system level restriction, the support driver also checks that the effective
    56  * user ID (EUID) is root when it is being opened.
     52 * On UNIX-like systems (Solaris, Linux, darwin, freebsd, ...) we put our trust
     53 * in root and the root knows what he/she/it does.
     54 *
     55 * We only allow root to get full unrestricted access to the support driver.
     56 * The device node corresponding to unrestricted access is own by root and has a
     57 * 0600 access mode (i.e. only accessible to the owner, root).  In addition to
     58 * this file system level restriction, the support driver also checks that the
     59 * effective user ID (EUID) is root when it is being opened.
    5760 *
    5861 * The VM processes temporarily assume root privileges using the set-uid-bit on
    59  * the executable with root as owner.  In fact, all the executable files, shared
    60  * objects and the other files and directories we install are owned by root and
    61  * the wheel (or equivalent gid = 0) group.
     62 * the executable with root as owner.  In fact, all the files and directories we
     63 * install are owned by root and the wheel (or equivalent gid = 0) group,
     64 * including extension pack files.
    6265 *
    6366 * The executable with the set-uid-to-root-bit set is a stub binary that has no
    64  * unnecessary library dependencies (only libc) and simply calls
    65  * #SUPR3HardenedMain.  SUPR3HardenedMain does the following:
    66  *
    67  *      -# Validate installation (supR3HardenedVerifyAll):
     67 * unnecessary library dependencies (only libc, pthreads, dynamic linker) and
     68 * simply calls #SUPR3HardenedMain.  It does the following:
     69 *      1. Validate installation (supR3HardenedVerifyAll):
    6870 *          - Check that the executable file of the process is one of the known
    6971 *            VirtualBox executables.
     
    7375 *            anyone except root.
    7476 *          - Check that all the parent directories, all the way up to the root
    75  *            if possible, only permits root (or system admin) to change them -
    76  *            in order to exclude directory renaming races.
    77  *          - On systems where it is possible, we may also validate signatures.
    78  *
    79  *      -# Open a file descriptor for the support device driver
     77 *            if possible, only permits root (or system admin) to change them.
     78 *            This is that to rule out unintentional rename races.
     79 *          - On systems where it is possible, we may also valiadate executable
     80 *            image signatures.
     81 *
     82 *      2. Open a file descriptor for the support device driver
    8083 *         (supR3HardenedMainOpenDevice).
    8184 *
    82  *      -# Grab ICMP capabilities, if needed (supR3HardenedMainGrabCapabilites).
    83  *
    84  *      -# Correctly drop the root privileges (supR3HardenedMainDropPrivileges).
    85  *
    86  *      -# Load the VBoxRT dynamic link library and hand over the file
     85 *      3. Grab ICMP capabilities, if needed (supR3HardenedMainGrabCapabilites).
     86 *
     87 *      4. Correctly drop the root privileges (supR3HardenedMainDropPrivileges).
     88 *
     89 *      5. Load the VBoxRT dynamic link library and hand over the file
    8790 *         descriptor to the SUPLib code in it (supR3HardenedMainInitRuntime).
    8891 *
    89  *      -# Load a dynamic library containing the VM frontend code and run it
    90  *         (tail of SUPR3HardenedMain).  The set-uid-to-root stub executable is
    91  *         paired with a dynamic link library which exports one TrustedMain
    92  *         entrypoint (see FNSUPTRUSTEDMAIN) that we call.
    93  *
    94  *         In case of error reporting, the library may also export a
    95  *         TrustedError function (FNSUPTRUSTEDERROR).
    96  *
    97  *  That a process was started with a set-uid-to-root-bit applied is something
    98  *  that sticks with the process even if after dropping the root privileges and
    99  *  becoming the original user.  The dynamic linkers take special care when
    100  *  dealing with processes of this kind to not allow the user to load arbitrary
    101  *  code into a root process and causing a privilege escalation issue.  This is
    102  *  of course exactly the kind of behavior we're looking for.
     92 *      6. Load a dynamic library containing the actual VM frontend code and run
     93 *         it (tail of SUPR3HardenedMain).
     94 *
     95 *  The set-uid-to-root stub executable is paired with a dynamic link library
     96 *  which export one TrustedMain entrypoint (see FNSUPTRUSTEDMAIN) that we call.
     97 *  In case of error reporting, the library may also export a TrustedError
     98 *  function (FNSUPTRUSTEDERROR).
     99 *
     100 *  That the set-uid-to-root-bit modifies the dynamic linker behavior on all
     101 *  relevant systems, even after we've dropped back to the real UI, is something
     102 *  we take advantage of.  The dynamic linkers takes special care to prevent
     103 *  users from using clever tricks to inject their own code into set-uid
     104 *  processes and causing privilege escalation issues.  This is of course
     105 *  exactly the kind of behavior we're looking for.
    103106 *
    104107 *  In addition to what the dynamic linker does for us, we will not directly
    105108 *  call either RTLdrLoad or dlopen to load dynamic link libraries into the
    106109 *  process.  Instead we will call SUPR3HardenedLdrLoad,
    107  *  SUPR3HardenedLdrLoadAppPriv or SUPR3HardenedLdrLoadPlugIn to do the loading.
    108  *  These functions will perform the validations on the file being loaded as
    109  *  SUPR3HardenedMain did in its validation step.  So, anything we load must be
    110  *  installed owned by root:wheel, the directory we load it from must also be
    111  *  owned by root:wheel and not allow for renaming the file.  Similar ownership
    112  *  restrictions apply to all the parent directories (except on darwin).
    113  *
    114  *  So, we leave the responsibility of not installing malicious software on the
     110 *  SUPR3HardenedLdrLoadAppPriv and SUPR3HardenedLdrLoadPlugIn to do the
     111 *  loading.  These functions will perform the validations on the file being
     112 *  loaded as SUPR3HardenedMain did in its validation step.  So, anything we
     113 *  load must be installed owned by root:wheel, the directory we load it from
     114 *  must also be owned by root:wheel and now allow for renaming the file.
     115 *  Similar ownership restricts applies to all the parent directories (except on
     116 *  darwin).
     117 *
     118 *  So, we place the responsibility of not installing malicious software on the
    115119 *  root user on UNIX-like systems.  Which is fair enough, in our opinion.
    116120 *
     
    118122 * @section sec_hardening_win   Hardening on Windows
    119123 *
    120  * On Windows things are a lot more complicated, unfortunately.  This is mainly
    121  * because on Windows you cannot trust the Administrators users.  Some of the
    122  * blame for this is that Windows is a descendant/replacement for a set of single
    123  * user systems: DOS, Windows 1.0-3.11 Windows 95-ME, and OS/2.  Users of NT
    124  * 3.51 and later were inclined to want to always run it with full
    125  * root/administrator privileges like they had done on the predecessors, which
    126  * Microsoft made doing very simple and didn't help with the alternative.
    127  * Bad idea, security wise, which is good for the security software industry.
    128  * For this reason, using a set-uid-to-root approach is pointless, even if
    129  * Windows had one, which it doesn't.
     124 * On Windows we cannot put the same level or trust in the Administrator users
     125 * (equivalent of root/wheel on unix) as on the UNIX-like systems, which
     126 * complicates things greatly.
     127 *
     128 * Some or the blame for this can be given to Windows being a
     129 * descendant/replacement for a set of single user systems: DOS, Windows
     130 * 1.0-3.11 Windows 95-ME, and OS/2.  Users of NT 3.51 and later was inclined to
     131 * want to always run it with full root/administrator privileges like they had
     132 * done on the predecessors, while Microsoft made doing this very simple and
     133 * didn't help with the alternatives.  Bad idea, security wise, which is good
     134 * for the security software industry.  For this reason using a set-uid-to-root
     135 * approach is pointless, even if windows had one, which is doesn't.
    130136 *
    131137 * So, in order to protect access to the support driver and protect the
    132138 * VM process while it's running we have to do a lot more work.  A keystone in
    133139 * the defences is code signing.  The short version is this:
    134  *
    135140 *      - Minimal stub executable, signed with the same certificate as the
    136141 *        kernel driver.
     
    148153 *        thoroughly before allowing them protection and in the final case full
    149154 *        unrestricted access.
     155 *
     156 * @subsection  sec_hardening_win_protsoft      3rd Party "Protection" Software
    150157 *
    151158 * What makes our life REALLY difficult on Windows is this 3rd party "security"
     
    156163 * common practice to patch a lot of NTDLL, KERNEL32, the executable import
    157164 * table, load extra DLLs into the process, allocate executable memory in the
    158  * process and worse.  The BIG problem with all this is that it is
    159  * indistinguishable from what malicious software would be doing in order to
    160  * intercept process activity (network sniffing, maybe password snooping) or
    161  * gain a level of kernel access via the support driver.
     165 * process (classic code injection) and more.
     166 *
     167 * The BIG problem with all this is that it is indistiguishable from what
     168 * malicious software would be doing in order to intercept process acctivity
     169 * (network sniffing, maybe password snooping) or gain a level of kernel access
     170 * via the the support driver.
     171 *
     172 *
     173 * @subsection  sec_hardening_win_1st_stub  The Initial Stub Process
    162174 *
    163175 * We share the stub executable approach with the UNIX-like systems, so there's
    164176 * the SUPR3HardenedMain and a paired DLL with TrustedMain and TrustedError.
    165  * However, the stub executable is pushed a bit further here.
     177 * However, the stub executable is fatter and much more bare metal:
    166178 *      - It has no CRT (libc) because we don't need one and we need full
    167179 *        control over the code in the stub.
     
    180192 * does a respawn via supR3HardenedWinReSpawn.
    181193 *
    182  * The second stub process will be created in suspended state (the thread hasn't
    183  * executed a single instruction) and with less generous ACLs associated with it
    184  * (skin deep protection only).  In order for SUPR3TrustedMain to figure it's
    185  * the second stub process, the zero'th command line argument has been replaced
    186  * by a known magic string (UUID).   Now, before the process starts executing,
    187  * the parent will patch the LdrInitializeThunk entrypoint in NTDLL to call
    188  * supR3HardenedEarlyProcessInit via supR3HardenedEarlyProcessInitThunk.  The
    189  * parent will also plant some synchronization stuff via SUPR3WINPROCPARAMS
    190  * (NTDLL location, inherited event handles and associated ping-pong equipment).
     194 *
     195 * @subsection  sec_hardening_win_2nd_stub  The Second Stub Process
     196 *
     197 * The second stub process will be created in suspended state, i.e. the main
     198 * thread is suspended before it executes a single instruction, and with a less
     199 * generous ACLs associated with it (skin deep protection only).  In order for
     200 * SUPR3TrustedMain to figure that it is the second stub process, the zero'th
     201 * command line argument has been replaced by a known magic string (UUID).  Now,
     202 * before the process starts executing, the parent (initial stub) will patch the
     203 * LdrInitializeThunk entrypoint in NTDLL to call supR3HardenedEarlyProcessInit
     204 * via supR3HardenedEarlyProcessInitThunk.  The parent will also plant some
     205 * synchronization stuff via SUPR3WINPROCPARAMS (NTDLL location, inherited event
     206 * handles and associated ping-pong equipment).
    191207 *
    192208 * The LdrInitializeThunk entrypoint of NTDLL is where the kernel sets up
     
    206222 * What the parent does during the purification is very similar to what the
    207223 * kernel driver will do later on when verifying the second stub and the VM
    208  * processes, except that instead of failing when encountering an issue it will
    209  * take corrective actions:
     224 * processes, except that instead of failing when encountering an shortcomming
     225 * it will take corrective actions:
    210226 *      - Executable memory regions not belonging to a DLL mapping will be
    211227 *        attempted freed, and we'll only fail if we can't evict it.
     
    264280 *
    265281 *
     282 * @subsection  sec_hardening_win_3rd_stub  The Final Stub
     283 *
     284 * Yet to be written...
    266285 *
    267286 */
Note: See TracChangeset for help on using the changeset viewer.

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