Changeset 58405 in vbox for trunk/src/VBox/HostDrivers/Support
- Timestamp:
- Oct 25, 2015 11:03:03 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 103643
- Location:
- trunk/src/VBox/HostDrivers/Support
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
r58402 r58405 31 31 * 32 32 * The VirtualBox VMM requires supervisor (kernel) level access to the CPU. For 33 * both practical and historical reasons part of the VMM is partly realized in34 * ring-3 with a rich interface to the kernel part. While the device emulations35 * can be run exclusively in ring-3, we have performance optimizations that36 * loads device emulation code into ring-0 and our special raw-mode execution37 * context (non-VT-x/AMD-V mode) for handling frequent operations a lot more33 * both practical and historical reasons, part of the VMM is realized in ring-3, 34 * with a rich interface to the kernel part. While the device emulations can be 35 * executed exclusively in ring-3, we have performance optimizations that loads 36 * device emulation code into ring-0 and our special raw-mode execution context 37 * (none VT-x/AMD-V mode) for handling frequent operations a lot more 38 38 * efficiently. These share data between all three context (ring-3, ring-0 and 39 39 * raw-mode). All this poses a rather broad attack surface, which the hardening 40 40 * protects. 41 41 * 42 * The hardening primarily focuseson restricting access to the support driver,42 * The hardening focuses primarily on restricting access to the support driver, 43 43 * VBoxDrv or vboxdrv depending on the OS, as it is ultimately the link and 44 44 * instigator of the communication between ring-3 and the ring-0 and raw-mode … … 47 47 * on the host OS. 48 48 * 49 * @section sec_hardening_supdrv The Support Driver Interfaces 50 * 51 * The support driver has several interfaces thru which it can be accessed: 52 * - /dev/vboxdrv (win: \\Device\\VBoxDrv) for full unrestricted access. 53 * Offers a rich I/O control interface, which needs protecting. 54 * - /dev/vboxdrvu (win: \\Device\\VBoxDrvU) for restricted access, which 55 * VBoxSVC uses to query VT-x and AMD-V capabilities. This does not 56 * require protecting, though we limit it to the vboxgroup on some 57 * systems. 58 * - \\Device\\VBoxDrvStub on Windows for protecting the second stub 59 * process and its child, the VM process. This is an open+close 60 * interface, only available to partially verified stub processes. 61 * - \\Device\\VBoxDrvErrorInfo on Windows for obtaining detailed error 62 * information on a previous attempt to open \\Device\\VBoxDrv or 63 * \\Device\\VBoxDrvStub. Open, read and close only interface. 64 * 65 * The rest of VBox accesses the device interface thru the support library, 66 * SUPR3 / sup.h. 67 * 68 * The support driver also exposes a set of functions and data that other VBox 69 * ring-0 modules can import from. This includes much of the IPRT we need in 70 * the ring-0 part of the VMM and device emulations. 71 * 72 * The ring-0 part of the VMM and device emulations are loaded via the 73 * SUPR3LoadModule and SUPR3LoadServiceModule support library function, which 74 * both translates to a sequence of I/O controls against /dev/vboxdrv. On 75 * Windows we use the native kernel loader to load the module, while on the 76 * other systems ring-3 prepares the bits with help from the IPRT loader code. 77 * 49 78 * 50 79 * @section sec_hardening_unix Hardening on UNIX-like OSes 51 80 * 52 81 * On UNIX-like systems (Solaris, Linux, darwin, freebsd, ...) we put our trust 53 * in root and th e root knows what he/she/it does.82 * in root and that root knows what he/she/it is doing. 54 83 * 55 84 * 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 a57 * 0600 access mode (i.e. only accessible to the owner, root). In addition to58 * this file system level restriction, the support driver also checks that the59 * effective user ID (EUID) is root when it is being opened.85 * The device node corresponding to unrestricted access (/dev/vboxdrv) is own by 86 * root and has a 0600 access mode (i.e. only accessible to the owner, root). In 87 * addition to this file system level restriction, the support driver also 88 * checks that the effective user ID (EUID) is root when it is being opened. 60 89 * 61 90 * The VM processes temporarily assume root privileges using the set-uid-bit on … … 67 96 * unnecessary library dependencies (only libc, pthreads, dynamic linker) and 68 97 * simply calls #SUPR3HardenedMain. It does the following: 69 * 1. Validate installation (supR3HardenedVerifyAll):98 * 1. Validate the VirtualBox installation (supR3HardenedVerifyAll): 70 99 * - Check that the executable file of the process is one of the known 71 100 * VirtualBox executables. … … 77 106 * if possible, only permits root (or system admin) to change them. 78 107 * This is that to rule out unintentional rename races. 79 * - On s ystems where it is possible, we may also valiadate executable80 * image signatures.108 * - On some systems we may also validate the cryptographic signtures 109 * of executable images. 81 110 * 82 111 * 2. Open a file descriptor for the support device driver 83 112 * (supR3HardenedMainOpenDevice). 84 113 * 85 * 3. Grab ICMP capabilities, if needed (supR3HardenedMainGrabCapabilites). 114 * 3. Grab ICMP capabilities for NAT ping support, if required by the OS 115 * (supR3HardenedMainGrabCapabilites). 86 116 * 87 117 * 4. Correctly drop the root privileges (supR3HardenedMainDropPrivileges). 88 118 * 89 119 * 5. Load the VBoxRT dynamic link library and hand over the file 90 * descriptor to the SUPLib code in it (supR3HardenedMainInitRuntime). 91 * 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. 106 * 107 * In addition to what the dynamic linker does for us, we will not directly 108 * call either RTLdrLoad or dlopen to load dynamic link libraries into the 109 * process. Instead we will call SUPR3HardenedLdrLoad, 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 119 * root user on UNIX-like systems. Which is fair enough, in our opinion. 120 * descriptor to the support library code in it 121 * (supR3HardenedMainInitRuntime). 122 * 123 * 6. Load the dynamic library containing the actual VM front end code and 124 * run it (tail of SUPR3HardenedMain). 125 * 126 * The set-uid-to-root stub executable is paired with a dynamic link library 127 * which export one TrustedMain entry point (see FNSUPTRUSTEDMAIN) that we call. 128 * In case of error reporting, the library may also export a TrustedError 129 * function (FNSUPTRUSTEDERROR). 130 * 131 * That the set-uid-to-root-bit modifies the dynamic linker behavior on all 132 * systems, even after we've dropped back to the real user ID, is something we 133 * take advantage of. The dynamic linkers takes special care to prevent users 134 * from using clever tricks to inject their own code into set-uid processes and 135 * causing privilege escalation issues. This is the exact help we need. 136 * 137 * The VirtualBox installation location is hardcoded, which means the any 138 * dynamic linker paths embedded or inferred from the executable and dynamic 139 * libraries are also hardcoded. This helps eliminating search path attack 140 * vectors at the cost of being inflexible regarding installation location. 141 * 142 * In addition to what the dynamic linker does for us, the VirtualBox code will 143 * not directly be calling either RTLdrLoad or dlopen to load dynamic link 144 * libraries into the process. Instead it will call SUPR3HardenedLdrLoad, 145 * SUPR3HardenedLdrLoadAppPriv and SUPR3HardenedLdrLoadPlugIn to do the loading. 146 * These functions will perform the same validations on the file being loaded as 147 * SUPR3HardenedMain did in its validation step. So, anything we load must be 148 * installed with root/wheel as owner/group, the directory we load it from must 149 * also be owned by root:wheel and now allow for renaming the file. Similar 150 * ownership restrictions applies to all the parent directories (except on 151 * darwin). 152 * 153 * So, we place the responsibility of not installing malicious software on the 154 * root user on UNIX-like systems. Which is fair enough, in our opinion. 120 155 * 121 156 * 122 157 * @section sec_hardening_win Hardening on Windows 123 158 * 124 * On Windows we cannot put the same level or trust in the Administrator user s159 * On Windows we cannot put the same level or trust in the Administrator user(s) 125 160 * (equivalent of root/wheel on unix) as on the UNIX-like systems, which 126 161 * complicates things greatly. 127 162 * 128 * Some o r the blame for this can be given to Windows being a129 * descendant/replacement for a set of single user systems: DOS,Windows130 * 1.0-3.11 Windows 95-ME, and OS/2. Users of NT 3.51 and later was inclined to131 * want to always run it with full root/administrator privileges like they had132 * done on the predecessors, while Microsoft made doing this very simple and133 * didn't help with the alternatives. Bad idea, security wise, which is good134 * for the security software industry. For this reason using a set-uid-to-root135 * approach is pointless, even if windows had one, which is doesn't.163 * Some of the blame for this can be given to Windows being a descendant / 164 * replacement for a set of single user systems: DOS, Windows 1.0-3.11 Windows 165 * 95-ME, and OS/2. Users of NT 3.1 and later was inclined to want to always 166 * run it with full root/administrator privileges like they had done on the 167 * predecessors, while Microsoft didn't provide much incentive for more secure 168 * alternatives. Bad idea, security wise, but execellent for the security 169 * software industry. For this reason using a set-uid-to-root approach is 170 * pointless, even if Windows had one. 136 171 * 137 172 * So, in order to protect access to the support driver and protect the 138 173 * VM process while it's running we have to do a lot more work. A keystone in 139 * the defences is code signing. The short version is this: 174 * the defences is cryptographic code signing. Here's the short version of what 175 * we do: 140 176 * - Minimal stub executable, signed with the same certificate as the 141 177 * kernel driver. … … 154 190 * unrestricted access. 155 191 * 192 * 156 193 * @subsection sec_hardening_win_protsoft 3rd Party "Protection" Software 157 194 * … … 159 196 * software which is more or less required to keep a Windows system safe for 160 197 * normal users and all corporate IT departments rightly insists on installing. 161 * After the kernel patching clampdown in Vista, AV software have to do a lot162 * more mucking about in user mode to get their job (kind of) done. So, it is163 * common practice to patch a lot of NTDLL, KERNEL32, the executable import198 * After the kernel patching clampdown in Vista, anti-* software has to do a 199 * lot more mucking about in user mode to get their job (kind of) done. So, it 200 * is common practice to patch a lot of NTDLL, KERNEL32, the executable import 164 201 * table, load extra DLLs into the process, allocate executable memory in the 165 202 * process (classic code injection) and more. 166 203 * 167 * The BIG problem with all this is that it is indisti guishable from what168 * malicious software would be doing in order to intercept process ac ctivity204 * The BIG problem with all this is that it is indistinguishable from what 205 * malicious software would be doing in order to intercept process activity 169 206 * (network sniffing, maybe password snooping) or gain a level of kernel access 170 * via the the support driver. 207 * via the support driver. So, the "protection" software is what is currently 208 * forcing us to do the pre-NTDLL initialization. 171 209 * 172 210 * … … 174 212 * 175 213 * We share the stub executable approach with the UNIX-like systems, so there's 176 * the SUPR3HardenedMain and a paired DLL with TrustedMain and TrustedError. 177 * However, the stub executable is fatter and much more bare metal: 178 * - It has no CRT (libc) because we don't need one and we need full 179 * control over the code in the stub. 180 * - It does not statically import anything to avoid having a import table 181 * that can be patched or extended to either intercept our calls or load 182 * additional DLLs. 183 * - System calls normally going thru NTDLL are done directly because there 184 * is so much software out there which wants to patch known NTDLL entry 185 * points to control our software (either for good or malicious reasons). 214 * the SUPR3HardenedMain calling stub executable with it's parenter DLL 215 * exporting TrustedMain and TrustedError. However, the stub executable does a 216 * lot more, while doing it in a more bare metal fashion: 217 * - It does not use the Microsoft CRT, what we need of CRT functions comes 218 * from IPRT. 219 * - It does not statically import anything. This is to avoid having an 220 * import table that can be patched to intercept our calls or extended to 221 * load additional DLLs. 222 * - Direct NT system calls. System calls normally going thru NTDLL, but 223 * since there is so much software out there which wants to patch known 224 * NTDLL entry points to control our software (either for good or 225 * malicious reasons), we do it ourselves. 186 226 * 187 227 * The initial stub process is not really to be trusted, though we try our best … … 196 236 * 197 237 * 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). 207 * 208 * The LdrInitializeThunk entrypoint of NTDLL is where the kernel sets up 209 * process execution to start executing (via a user alert, so not subject to 210 * SetThreadContext). LdrInitializeThunk performs process, NTDLL and 238 * thread is suspended before it executes a single instruction. It is also 239 * created with a less generous ACLs, though this doesn't protect us from admin 240 * users. In order for SUPR3TrustedMain to figure that it is the second stub 241 * process, the zeroth command line argument has been replaced by a known magic 242 * string (UUID). 243 * 244 * Now, before the process starts executing, the parent (initial stub) will 245 * patch the LdrInitializeThunk entry point in NTDLL to call 246 * supR3HardenedEarlyProcessInit via supR3HardenedEarlyProcessInitThunk. The 247 * parent will also plant some synchronization stuff via g_ProcParams (NTDLL 248 * location, inherited event handles and associated ping-pong equipment). 249 * 250 * The LdrInitializeThunk entry point of NTDLL is where the kernel sets up 251 * process execution to start executing (via a user alert, so it is not subject 252 * to SetThreadContext). LdrInitializeThunk performs process, NTDLL and 211 253 * sub-system client (kernel32) initialization. A lot of "protection" software 212 254 * uses triggers in this initialization sequence (like the KERNEL32.DLL load … … 214 256 * on. 215 257 * 216 * However, there is also those that uses events that triggers immediately when 217 * the process is created or/and starts executing the first instruction, we have 218 * a well know process state we can restore. The first thing that 219 * supR3HardenedEarlyProcessInit does is to signal the parent to do perform a 220 * child purification to exorcise potentially evil influences. 258 * However, there are also those that uses events that triggers immediately when 259 * the process is created or/and starts executing the first instruction. But we 260 * can easily counter these as we have a known process state we can restore. So, 261 * the first thing that supR3HardenedEarlyProcessInit does is to signal the 262 * parent to perform a child purification, so the potentially evil influences 263 * can be exorcised. 221 264 * 222 265 * What the parent does during the purification is very similar to what the 223 266 * kernel driver will do later on when verifying the second stub and the VM 224 * processes, except that instead of failing when encountering an shortcom ming225 * itwill take corrective actions:267 * processes, except that instead of failing when encountering an shortcoming it 268 * will take corrective actions: 226 269 * - Executable memory regions not belonging to a DLL mapping will be 227 * attempted freed, and we'll only fail if we can't evict it.270 * attempted freed, and we'll only fail if we can't evict them. 228 271 * - All pages in the executable images in the process (should be just the 229 272 * stub executable and NTDLL) will be compared to the pristine fixed-up … … 238 281 * influence the child in any really harmful way. (The caller of CreateProcess 239 282 * usually receives handles with unrestricted access to the child process and 240 * main thread. These could in theory be used with DuplicateHandle or283 * its main thread. These could in theory be used with DuplicateHandle or 241 284 * WriteProcessMemory to get at the VM process if we're not careful.) 242 285 * 243 286 * supR3HardenedEarlyProcessInit will continue with opening the log file 244 * (require command line parsing). It will continue to initialize a bunch of245 * global s, syscalls and trustworthy/harmless NTDLL imports.287 * (requires command line parsing). It will continue to initialize a bunch of 288 * global variables, system calls and trustworthy/harmless NTDLL imports. 246 289 * supR3HardenedWinInit is then called to setup image verification, that is: 247 * - Hook (insert jump instruction) the NtCreateSection entrypoint in NTDLL 248 * so we can check all executable mappings before they're created and can 249 * be mapped. 250 * - Hook (ditto) the LdrLoadDll entrypoint in NTDLL so we can pre-validate 251 * all images that gets loaded the normal way (partly because the 252 * NtCreateSection context is restrictive because the NTDLL loader lock 253 * is usually held, which prevents us from safely calling WinVerityTrust). 290 * - Hook the NtCreateSection entry point in NTDLL so we can check all 291 * executable mappings before they're created and can be mapped. The 292 * NtCreateSection code jumps to supR3HardenedMonitor_NtCreateSection. 293 * - Hook (ditto) the LdrLoadDll entry point in NTDLL so we can 294 * pre-validate all images that gets loaded the normal way (partly 295 * because the NtCreateSection context is restrictive because the NTDLL 296 * loader lock is usually held, which prevents us from safely calling 297 * WinVerityTrust). The LdrLoadDll code jumps to 298 * supR3HardenedMonitor_LdrLoadDll. 299 * 254 300 * The image/DLL verification hooks are at this point able to verify DLLs 255 * containing code signing signatures, and will restrict the locations from256 * which DLLs will be loaded. When SUPR3HardenedMain gets going later one, they257 * will start insisting on everything having valid signatures in the DLL or in an258 * installer catalog file.301 * containing embedded code signing signatures, and will restrict the locations 302 * from which DLLs will be loaded. When SUPR3HardenedMain gets going later on, 303 * they will start insisting on everything having valid signatures, either 304 * embedded or in a signed installer catalog file. 259 305 * 260 306 * The function also irrevocably disables debug notifications related to the 261 * current thread, just to make attaching a debugging that much more difficult. 262 * 263 * Now, the second stub process will open the so called stub device, that is a 264 * special support driver device node that tells the support driver to: 307 * current thread, just to make attaching a debugging that much more difficult 308 * and less useful. 309 * 310 * Now, the second stub process will open the so called stub device 311 * (\\Device\\VBoxDrvStub), that is a special support driver device node that 312 * tells the support driver to: 265 313 * - Protect the process against the OpenProcess and OpenThread attack 266 314 * vectors by stripping risky access rights. … … 278 326 * signed, and only accept unsigned ones in versions where they are known 279 327 * not to be signed. 280 * 281 * 282 * @subsection sec_hardening_win_3rd_stub The Final Stub 283 * 284 * Yet to be written... 328 * - Check that the code and readonly parts of the executable and DLLs 329 * mapped into the process matches the on disk content (no patches other 330 * than our own two in NTDLL are allowed). 331 * 332 * Once granted access to the stub device, supR3HardenedEarlyProcessInit will 333 * restore the LdrInitializeThunk code and let the process perform normal 334 * initialization. Leading us to SUPR3HardenedMain where we detect that this is 335 * the 2nd stub process and does another respawn. 336 * 337 * 338 * @subsection sec_hardening_win_3rd_stub The Final Stub / VM Process 339 * 340 * The third stub process is what becomes the VM process. Because the parent 341 * has opened \\Device\\VBoxDrvSub, it is protected from malicious OpenProcess & 342 * OpenThread calls from the moment of inception, practically speaking. 343 * 344 * It goes thru the same suspended creation, patching, purification and such as 345 * its parent (the second stub process). However, instead of opening 346 * \\Device\\VBoxDrvStub from supR3HardenedEarlyProcessInit, it opens the 347 * support driver for full unrestricted access, i.e. \\Device\\VBoxDrv. 348 * 349 * The support driver will perform the same checks as it did when 350 * \\Device\\VBoxDrvStub was opened, but in addition it will: 351 * - Check that the process is the first child of a process that opened 352 * \\Device\\VBoxDrvStub. 353 * - Check that the parent process is still alive. 354 * - Scan all open handles in the system for potentially harmful ones to 355 * the process or the primary thread. 356 * 357 * Knowing that the process is genuinly signed with the same certificate as the 358 * kernel driver, and the exectuable code in the process is either shipped by us 359 * or Microsoft, the support driver will trust it with full access and to keep 360 * the handle secure. 361 * 362 * We also trust the protection the support driver gives the process to keep out 363 * malicious ring-3 code, and therefore any code, patching or other mysterious 364 * stuff that enteres the process must be from kernel mode and that we can trust 365 * it (the alternative interpretation is that the kernel has been breanched 366 * already, which isn't our responsibility). This means that, the anti-software 367 * products can do whatever they like from this point on. However, should they 368 * do unrevertable changes to the process before this point, VirtualBox won't 369 * work. 370 * 371 * As in the second stub process, we'll now do normal process initialization and 372 * SUPR3HardenedMain will take control. It will detect that it is being called 373 * by the 3rd stub process because of a different magic string starting the 374 * command line, and not respawn itself any more. SUPRR3HardenedMain will 375 * recheck the VirtualBox installation, keeping all known files open just like 376 * in two previous stub processes. 377 * 378 * It will then load the Windows cryptographic API and load the trusted root 379 * certificates from the Windows store. The API enables using installation 380 * catalog files for signature checking as well as providing a second 381 * verification in addition to our own implementation (IPRT). The certificates 382 * allows our signature validation implementation to validate all embedded 383 * signatures, not just the microsoft ones and the one signed by our own 384 * certificate. 285 385 * 286 386 */ -
trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
r58363 r58405 4485 4485 /* 4486 4486 * Make sure we're alone in the stub process before creating the VM process 4487 * and that there isn't any debuggers attached.4487 * and that there aren't any debuggers attached. 4488 4488 */ 4489 4489 if (iWhich == 2)
Note:
See TracChangeset
for help on using the changeset viewer.