Changeset 58363 in vbox for trunk/src/VBox/HostDrivers/Support
- Timestamp:
- Oct 22, 2015 12:23:07 AM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 103578
- Location:
- trunk/src/VBox/HostDrivers/Support
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
r58340 r58363 23 23 * You may elect to license modified versions of this file under the 24 24 * terms and conditions of either the GPL or the CDDL or both. 25 */ 26 27 /** @page pg_hardening VirtualBox VM Process Hardening 28 * 29 * The VM process hardening is to prevent malicious software from using 30 * VirtualBox as a vehicle to obtain kernel level access. 31 * 32 * 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 in 34 * 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 36 * 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. 40 * 41 * The hardening primarily focuses on restricting access to the support driver, 42 * VBoxDrv or vboxdrv depending on the OS, as it is ultimately the link and 43 * 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 * and executed in the VM process. Exactly how we go about this depends a lot 46 * on the host OS. 47 * 48 * 49 * @section sec_hardening_unix Hardening on UNIX-like OSes 50 * 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 own 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. 57 * 58 * 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 * 63 * 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): 68 * - Check that the executable file of the process is one of the known 69 * VirtualBox executables. 70 * - Check that all mandatory files are present. 71 * - Check that all installed files and directories (both optional and 72 * mandatory ones) are owned by root:wheel and are not writable by 73 * anyone except root. 74 * - 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 valiadate signatures. 78 * 79 * -# Open a file descriptor for the support device driver 80 * (supR3HardenedMainOpenDevice). 81 * 82 * -# Grab ICMP capabilites, if needed (supR3HardenedMainGrabCapabilites). 83 * 84 * -# Correctly drop the root privileges (supR3HardenedMainDropPrivileges). 85 * 86 * -# Load the VBoxRT dynamic link library and hand over the file 87 * descriptor to the SUPLib code in it (supR3HardenedMainInitRuntime). 88 * 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 export 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. 103 * 104 * In addition to what the dynamic linker does for us, we will not directly 105 * call either RTLdrLoad or dlopen to load dynamic link libraries into the 106 * 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 now allow for renaming the file. Similar ownership 112 * restricts applies to all the parent directories (except on darwin). 113 * 114 * So, we leave the responsibility of not installing malicious software on the 115 * root user on UNIX-like systems. Which is fair enough, in our opinion. 116 * 117 * 118 * @section sec_hardening_win Hardening on Windows 119 * 120 * On Windows things are a lot more complicated, unforunately. This is mainly 121 * because on windows you cannot trust the Administrators users. Some or the 122 * blame for this is that Windows is a decentant/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 was inclied to want to always run it with full 125 * root/administrator privileges like they had done on the predecessors, while 126 * Microsoft made doing some 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 is doesn't. 130 * 131 * So, in order to protect access to the support driver and protect the 132 * VM process while it's running we have to do a lot more work. A keystone in 133 * the defences is code signing. The short version is this: 134 * 135 * - Minimal stub executable, signed with the same certificate as the 136 * kernel driver. 137 * 138 * - The stub executable respawns itself twice, hooking the NTDLL init 139 * routine to perform protection tasks as early as possible. The parent 140 * stub helps keep in the child clean for verification as does the 141 * support driver. 142 * 143 * - In order to protect against loading unwanted code into the process, 144 * the stub processes installs DLL load hooks with NTDLL as well as 145 * directly intercepting the LdrLoadDll and NtCreateSection APIs. 146 * 147 * - The support driver will verify all but the initial process very 148 * thoroughly before allowing them protection and in the final case full 149 * unrestricted access. 150 * 151 * What makes our life REALLY difficult on Windows is this 3rd party "security" 152 * software which is more or less required to keep a Windows system safe for 153 * normal users and all corporate IT departments righly insists on installing. 154 * After the kernel patching clampdown in Vista, AV software have to do a lot 155 * more mucking about in user mode to get their job (kind of) done. So, it 156 * common practice to patch a lot of NTDLL, KERNEL32, the executable import 157 * 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 * indistiguishable from what malicious software would be doing in order to 160 * intercept process acctivity (network sniffing, maybe password snooping) or 161 * gain a level of kernel access via the the support driver. 162 * 163 * We share the stub executable approach with the UNIX-like systems, so there's 164 * the SUPR3HardenedMain and a paried DLL with TrustedMain and TrustedError. 165 * However, the stub executable is pushed a bit further here. 166 * - It has no CRT (libc) because we don't need one and we need full 167 * control over the code in the stub. 168 * - It does not statically import anything to avoid having a import table 169 * that can be patched or extended to either intercept our calls or load 170 * additional DLLs. 171 * - System calls normally going thru NTDLL are done directly because there 172 * is so much software out there which wants to patch known NTDLL entry 173 * points to control our software (either for good or malicious reasons). 174 * 175 * The initial stub process is not really to be trusted, though we try our best 176 * to limit potential harm (user mode debugger checks, disable thread creation). 177 * So, when it enters SUPR3HardenedMain we only call supR3HardenedVerifyAll to 178 * verify the installation (known executables and dlls, checking their code 179 * signing signatures, keeping them all open to deny deletion and replacing) and 180 * does a respawn via supR3HardenedWinReSpawn. 181 * 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). 191 * 192 * The LdrInitializeThunk entrypoint of NTDLL is where the kernel sets up 193 * process execution to start executing (via a user alert, so not subject to 194 * SetThreadContext). LdrInitializeThunk performs process, NTDLL and 195 * sub-system client (kernel32) initialization. A lot of "protection" software 196 * uses triggers in this initialization sequence (like the KERNEL32.DLL load 197 * event), so we avoid quite a bit problems by getting our stuff done early on. 198 * 199 * However, there is also those that uses events that triggers immediately when 200 * the process is created or/and starts executing the first instruction, we have 201 * a well know process state we can restore. The first thing that 202 * supR3HardenedEarlyProcessInit does is to signal the parent to do perform a 203 * child purification to exorcise potentially evil influences. 204 * 205 * What the parent does during the purification is very similar to what the 206 * kernel driver will do later on when verifying the second stub and the VM 207 * processes, except that instead of failing when encountering an issue it will 208 * take corrective actions: 209 * - Executable memory regions not belonging to a DLL mapping will be 210 * attempted freed, and we'll only fail if we cann evict it. 211 * - All pages in the executable images in the process (should be just the 212 * stub executable and NTDLL) will be compared to the pristine fixed-up 213 * copy prepared by the IPRT PE loader code, restoring any bytes which 214 * appears differently in the child. (g_ProcParams (SUPR3WINPROCPARAMS) 215 * is exempted, LdrInitializeThunk is set to call NtTerminateThread.) 216 * - Unwanted DLLs will be unloaded (we have a set of DLLs we like). 217 * 218 * Before signalling the second stub process that it has been purified and shoud 219 * get on with it, the parent will close all handles with unrestricted access to 220 * the process and thread so that the initial stub process no longer can 221 * influence the child in any really harmful way. (The caller of CreateProcess 222 * usually receives handles with unrestricted access to the child process and 223 * main thread. These could in theory be used with DuplicateHandle or 224 * WriteProcessMemory to get at the VM process if we're not careful.) 225 * 226 * supR3HardenedEarlyProcessInit will continue with opening the log file 227 * (require command line parsing). It will continue to initialize a bunch of 228 * globals, syscalls and trustworthy/harmless NTDLL imports. 229 * supR3HardenedWinInit is then called to setup image verification, that is: 230 * - Hook (insert jump instruction) the NtCreateSection entrypoint in NTDLL 231 * so we can check all executable mappings before they're created and can 232 * be mapped. 233 * - Hook (ditto) the LdrLoadDll entrypoint in NTDLL so we can prevalidate 234 * all images that gets loaded the normal way (partly because the 235 * NtCreateSection context is restrictive because the NTDLL loader lock 236 * is usally held, which prevents us from safely calling WinVerityTrust). 237 * The image/dll verification hooks are at this point able to verify DLLs 238 * containing code signing signatures, and will restrict the locations from 239 * which DLLs will be loaded. When SUPR3HardenedMain gets going later one, they 240 * will start insiting on everything having valid signatures in the DLL or in an 241 * installer catalog file. 242 * 243 * The function also irrevocably disables debug notifications related to teh 244 * current thread, just to make attaching a debugging that much more difficult. 245 * 246 * Now, the second stub process will open the so called stub device, that is a 247 * special support driver device node that tells the support driver to: 248 * - Protect the process against the OpenProcess and OpenThread attack 249 * vectors by stripping risky access rights. 250 * - Check that the process isn't being debugged. 251 * - Check that the process contains exactly one thread. 252 * - Check that the process doesn't have any unknown DLLs loaded into it. 253 * - Check that the process doesn't have any executable memory (other that 254 * DLL sections) in it. 255 * - Check that the process executable is a known VBox executable which may 256 * access the support driver. 257 * - Check that the process executable is signed with the same code signing 258 * certificate as the driver and that the on disk image is valid 259 * according to its embedded signature. 260 * - Check all the signature of all DLLs in the process (NTDLL) if they are 261 * signed, and only accept unsigned ones in versions where they are known 262 * not to be signed. 263 * 264 * 265 * 25 266 */ 26 267 -
trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
r58339 r58363 5588 5588 /** 5589 5589 * Routine called by the supR3HardenedEarlyProcessInitThunk assembly routine 5590 * when LdrInitializeThunk is executed induring process initialization.5590 * when LdrInitializeThunk is executed during process initialization. 5591 5591 * 5592 5592 * This initializes the Stub and VM processes, hooking NTDLL APIs and opening -
trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainImports-win.cpp
r58339 r58363 701 701 702 702 /* 703 * Point erthe other imports at the early init stubs.703 * Point the other imports at the early init stubs. 704 704 */ 705 705 for (uint32_t iDll = 1; iDll < RT_ELEMENTS(g_aSupNtImpDlls); iDll++)
Note:
See TracChangeset
for help on using the changeset viewer.