VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp@ 62691

Last change on this file since 62691 was 62677, checked in by vboxsync, 9 years ago

SUPHardNt: -Wall warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.6 KB
Line 
1/* $Id: SUPR3HardenedMain.cpp 62677 2016-07-29 12:39:44Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Hardened main().
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
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.
33 * For both practical and historical reasons, part of the %VMM is realized in
34 * ring-3, with a rich interface to the kernel part. While the device
35 * emulations can be executed exclusively in ring-3, we have performance
36 * optimizations that loads device emulation code into ring-0 and our special
37 * raw-mode execution context (none VT-x/AMD-V mode) for handling frequent
38 * operations a lot more efficiently. These share data between all three
39 * context (ring-3, ring-0 and raw-mode). All this poses a rather broad attack
40 * surface, which the hardening protects.
41 *
42 * The hardening focuses primarily on restricting access to the support driver,
43 * VBoxDrv or vboxdrv depending on the OS, as it is ultimately the link and
44 * instigator of the communication between ring-3 and the ring-0 and raw-mode
45 * contexts. A secondary focus is to make sure malicious code cannot be loaded
46 * and executed in the %VM process. Exactly how we go about this depends a lot
47 * on the host OS.
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 * @ref grp_sup "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 *
78 *
79 * @section sec_hardening_unix Hardening on UNIX-like OSes
80 *
81 * On UNIX-like systems (Solaris, Linux, darwin, freebsd, ...) we put our trust
82 * in root and that root knows what he/she/it is doing.
83 *
84 * We only allow root to get full unrestricted access to the support driver.
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.
89 *
90 * The %VM processes temporarily assume root privileges using the set-uid-bit on
91 * the executable with root as owner. In fact, all the files and directories we
92 * install are owned by root and the wheel (or equivalent gid = 0) group,
93 * including extension pack files.
94 *
95 * The executable with the set-uid-to-root-bit set is a stub binary that has no
96 * unnecessary library dependencies (only libc, pthreads, dynamic linker) and
97 * simply calls #SUPR3HardenedMain. It does the following:
98 * 1. Validate the VirtualBox installation (#supR3HardenedVerifyAll):
99 * - Check that the executable file of the process is one of the known
100 * VirtualBox executables.
101 * - Check that all mandatory files are present.
102 * - Check that all installed files and directories (both optional and
103 * mandatory ones) are owned by root:wheel and are not writable by
104 * anyone except root.
105 * - Check that all the parent directories, all the way up to the root
106 * if possible, only permits root (or system admin) to change them.
107 * This is that to rule out unintentional rename races.
108 * - On some systems we may also validate the cryptographic signtures
109 * of executable images.
110 *
111 * 2. Open a file descriptor for the support device driver
112 * (#supR3HardenedMainOpenDevice).
113 *
114 * 3. Grab ICMP capabilities for NAT ping support, if required by the OS
115 * (#supR3HardenedMainGrabCapabilites).
116 *
117 * 4. Correctly drop the root privileges
118 * (#supR3HardenedMainDropPrivileges).
119 *
120 * 5. Load the VBoxRT dynamic link library and hand over the file
121 * descriptor to the support library code in it
122 * (#supR3HardenedMainInitRuntime).
123 *
124 * 6. Load the dynamic library containing the actual %VM front end code and
125 * run it (tail of #SUPR3HardenedMain).
126 *
127 * The set-uid-to-root stub executable is paired with a dynamic link library
128 * which export one TrustedMain entry point (see #FNSUPTRUSTEDMAIN) that we
129 * call. In case of error reporting, the library may also export a TrustedError
130 * function (#FNSUPTRUSTEDERROR).
131 *
132 * That the set-uid-to-root-bit modifies the dynamic linker behavior on all
133 * systems, even after we've dropped back to the real user ID, is something we
134 * take advantage of. The dynamic linkers takes special care to prevent users
135 * from using clever tricks to inject their own code into set-uid processes and
136 * causing privilege escalation issues. This is the exact help we need.
137 *
138 * The VirtualBox installation location is hardcoded, which means the any
139 * dynamic linker paths embedded or inferred from the executable and dynamic
140 * libraries are also hardcoded. This helps eliminating search path attack
141 * vectors at the cost of being inflexible regarding installation location.
142 *
143 * In addition to what the dynamic linker does for us, the VirtualBox code will
144 * not directly be calling either RTLdrLoad or dlopen to load dynamic link
145 * libraries into the process. Instead it will call #SUPR3HardenedLdrLoad,
146 * #SUPR3HardenedLdrLoadAppPriv and #SUPR3HardenedLdrLoadPlugIn to do the
147 * loading. These functions will perform the same validations on the file being
148 * loaded as #SUPR3HardenedMain did in its validation step. So, anything we
149 * load must be installed with root/wheel as owner/group, the directory we load
150 * it from must also be owned by root:wheel and now allow for renaming the file.
151 * Similar ownership restrictions applies to all the parent directories (except
152 * on darwin).
153 *
154 * So, we place the responsibility of not installing malicious software on the
155 * root user on UNIX-like systems. Which is fair enough, in our opinion.
156 *
157 *
158 * @section sec_hardening_win Hardening on Windows
159 *
160 * On Windows we cannot put the same level or trust in the Administrator user(s)
161 * (equivalent of root/wheel on unix) as on the UNIX-like systems, which
162 * complicates things greatly.
163 *
164 * Some of the blame for this can be given to Windows being a descendant /
165 * replacement for a set of single user systems: DOS, Windows 1.0-3.11 Windows
166 * 95-ME, and OS/2. Users of NT 3.1 and later was inclined to want to always
167 * run it with full root/administrator privileges like they had done on the
168 * predecessors, while Microsoft didn't provide much incentive for more secure
169 * alternatives. Bad idea, security wise, but execellent for the security
170 * software industry. For this reason using a set-uid-to-root approach is
171 * pointless, even if Windows had one.
172 *
173 * So, in order to protect access to the support driver and protect the %VM
174 * process while it's running we have to do a lot more work. A keystone in the
175 * defences is cryptographic code signing. Here's the short version of what we
176 * do:
177 * - Minimal stub executable, signed with the same certificate as the
178 * kernel driver.
179 *
180 * - The stub executable respawns itself twice, hooking the NTDLL init
181 * routine to perform protection tasks as early as possible. The parent
182 * stub helps keep in the child clean for verification as does the
183 * support driver.
184 *
185 * - In order to protect against loading unwanted code into the process,
186 * the stub processes installs DLL load hooks with NTDLL as well as
187 * directly intercepting the LdrLoadDll and NtCreateSection APIs.
188 *
189 * - The support driver will verify all but the initial process very
190 * thoroughly before allowing them protection and in the final case full
191 * unrestricted access.
192 *
193 *
194 * @subsection sec_hardening_win_protsoft 3rd Party "Protection" Software
195 *
196 * What makes our life REALLY difficult on Windows is this 3rd party "security"
197 * software which is more or less required to keep a Windows system safe for
198 * normal users and all corporate IT departments rightly insists on installing.
199 * After the kernel patching clampdown in Vista, anti-* software has to do a
200 * lot more mucking about in user mode to get their job (kind of) done. So, it
201 * is common practice to patch a lot of NTDLL, KERNEL32, the executable import
202 * table, load extra DLLs into the process, allocate executable memory in the
203 * process (classic code injection) and more.
204 *
205 * The BIG problem with all this is that it is indistinguishable from what
206 * malicious software would be doing in order to intercept process activity
207 * (network sniffing, maybe password snooping) or gain a level of kernel access
208 * via the support driver. So, the "protection" software is what is currently
209 * forcing us to do the pre-NTDLL initialization.
210 *
211 *
212 * @subsection sec_hardening_win_1st_stub The Initial Stub Process
213 *
214 * We share the stub executable approach with the UNIX-like systems, so there's
215 * the #SUPR3HardenedMain calling stub executable with its partner DLL exporting
216 * TrustedMain and TrustedError. However, the stub executable does a lot more,
217 * while doing it in a more bare metal fashion:
218 * - It does not use the Microsoft CRT, what we need of CRT functions comes
219 * from IPRT.
220 * - It does not statically import anything. This is to avoid having an
221 * import table that can be patched to intercept our calls or extended to
222 * load additional DLLs.
223 * - Direct NT system calls. System calls normally going thru NTDLL, but
224 * since there is so much software out there which wants to patch known
225 * NTDLL entry points to control our software (either for good or
226 * malicious reasons), we do it ourselves.
227 *
228 * The initial stub process is not really to be trusted, though we try our best
229 * to limit potential harm (user mode debugger checks, disable thread creation).
230 * So, when it enters #SUPR3HardenedMain we only call #supR3HardenedVerifyAll to
231 * verify the installation (known executables and DLLs, checking their code
232 * signing signatures, keeping them all open to deny deletion and replacing) and
233 * does a respawn via #supR3HardenedWinReSpawn.
234 *
235 *
236 * @subsection sec_hardening_win_2nd_stub The Second Stub Process
237 *
238 * The second stub process will be created in suspended state, i.e. the main
239 * thread is suspended before it executes a single instruction. It is also
240 * created with a less generous ACLs, though this doesn't protect us from admin
241 * users. In order for #SUPR3HardenedMain to figure that it is the second stub
242 * process, the zeroth command line argument has been replaced by a known magic
243 * string (UUID).
244 *
245 * Now, before the process starts executing, the parent (initial stub) will
246 * patch the LdrInitializeThunk entry point in NTDLL to call
247 * #supR3HardenedEarlyProcessInit via #supR3HardenedEarlyProcessInitThunk. The
248 * parent will also plant some synchronization stuff via #g_ProcParams (NTDLL
249 * location, inherited event handles and associated ping-pong equipment).
250 *
251 * The LdrInitializeThunk entry point of NTDLL is where the kernel sets up
252 * process execution to start executing (via a user alert, so it is not subject
253 * to SetThreadContext). LdrInitializeThunk performs process, NTDLL and
254 * sub-system client (kernel32) initialization. A lot of "protection" software
255 * uses triggers in this initialization sequence (like the KERNEL32.DLL load
256 * event), so we avoid quite a bit of problems by getting our stuff done early
257 * on.
258 *
259 * However, there are also those that uses events that triggers immediately when
260 * the process is created or/and starts executing the first instruction. But we
261 * can easily counter these as we have a known process state we can restore. So,
262 * the first thing that #supR3HardenedEarlyProcessInit does is to signal the
263 * parent to perform a child purification, so the potentially evil influences
264 * can be exorcised.
265 *
266 * What the parent does during the purification is very similar to what the
267 * kernel driver will do later on when verifying the second stub and the %VM
268 * processes, except that instead of failing when encountering an shortcoming it
269 * will take corrective actions:
270 * - Executable memory regions not belonging to a DLL mapping will be
271 * attempted freed, and we'll only fail if we can't evict them.
272 * - All pages in the executable images in the process (should be just the
273 * stub executable and NTDLL) will be compared to the pristine fixed-up
274 * copy prepared by the IPRT PE loader code, restoring any bytes which
275 * appears differently in the child. (#g_ProcParams is exempted,
276 * LdrInitializeThunk is set to call NtTerminateThread.)
277 * - Unwanted DLLs will be unloaded (we have a set of DLLs we like).
278 *
279 * Before signalling the second stub process that it has been purified and should
280 * get on with it, the parent will close all handles with unrestricted access to
281 * the process and thread so that the initial stub process no longer can
282 * influence the child in any really harmful way. (The caller of CreateProcess
283 * usually receives handles with unrestricted access to the child process and
284 * its main thread. These could in theory be used with DuplicateHandle or
285 * WriteProcessMemory to get at the %VM process if we're not careful.)
286 *
287 * #supR3HardenedEarlyProcessInit will continue with opening the log file
288 * (requires command line parsing). It will continue to initialize a bunch of
289 * global variables, system calls and trustworthy/harmless NTDLL imports.
290 * #supR3HardenedWinInit is then called to setup image verification, that is:
291 * - Hook the NtCreateSection entry point in NTDLL so we can check all
292 * executable mappings before they're created and can be mapped. The
293 * NtCreateSection code jumps to #supR3HardenedMonitor_NtCreateSection.
294 * - Hook (ditto) the LdrLoadDll entry point in NTDLL so we can
295 * pre-validate all images that gets loaded the normal way (partly
296 * because the NtCreateSection context is restrictive because the NTDLL
297 * loader lock is usually held, which prevents us from safely calling
298 * WinVerityTrust). The LdrLoadDll code jumps to
299 * #supR3HardenedMonitor_LdrLoadDll.
300 *
301 * The image/DLL verification hooks are at this point able to verify DLLs
302 * containing embedded code signing signatures, and will restrict the locations
303 * from which DLLs will be loaded. When #SUPR3HardenedMain gets going later on,
304 * they will start insisting on everything having valid signatures, either
305 * embedded or in a signed installer catalog file.
306 *
307 * The function also irrevocably disables debug notifications related to the
308 * current thread, just to make attaching a debugging that much more difficult
309 * and less useful.
310 *
311 * Now, the second stub process will open the so called stub device
312 * (\\Device\\VBoxDrvStub), that is a special support driver device node that
313 * tells the support driver to:
314 * - Protect the process against the OpenProcess and OpenThread attack
315 * vectors by stripping risky access rights.
316 * - Check that the process isn't being debugged.
317 * - Check that the process contains exactly one thread.
318 * - Check that the process doesn't have any unknown DLLs loaded into it.
319 * - Check that the process doesn't have any executable memory (other than
320 * DLL sections) in it.
321 * - Check that the process executable is a known VBox executable which may
322 * access the support driver.
323 * - Check that the process executable is signed with the same code signing
324 * certificate as the driver and that the on disk image is valid
325 * according to its embedded signature.
326 * - Check all the signature of all DLLs in the process (NTDLL) if they are
327 * signed, and only accept unsigned ones in versions where they are known
328 * not to be signed.
329 * - Check that the code and readonly parts of the executable and DLLs
330 * mapped into the process matches the on disk content (no patches other
331 * than our own two in NTDLL are allowed).
332 *
333 * Once granted access to the stub device, #supR3HardenedEarlyProcessInit will
334 * restore the LdrInitializeThunk code and let the process perform normal
335 * initialization. Leading us to #SUPR3HardenedMain where we detect that this
336 * is the 2nd stub process and does another respawn.
337 *
338 *
339 * @subsection sec_hardening_win_3rd_stub The Final Stub / VM Process
340 *
341 * The third stub process is what becomes the %VM process. Because the parent
342 * has opened \\Device\\VBoxDrvSub, it is protected from malicious OpenProcess &
343 * OpenThread calls from the moment of inception, practically speaking.
344 *
345 * It goes thru the same suspended creation, patching, purification and such as
346 * its parent (the second stub process). However, instead of opening
347 * \\Device\\VBoxDrvStub from #supR3HardenedEarlyProcessInit, it opens the
348 * support driver for full unrestricted access, i.e. \\Device\\VBoxDrv.
349 *
350 * The support driver will perform the same checks as it did when
351 * \\Device\\VBoxDrvStub was opened, but in addition it will:
352 * - Check that the process is the first child of a process that opened
353 * \\Device\\VBoxDrvStub.
354 * - Check that the parent process is still alive.
355 * - Scan all open handles in the system for potentially harmful ones to
356 * the process or the primary thread.
357 *
358 * Knowing that the process is genuinly signed with the same certificate as the
359 * kernel driver, and the exectuable code in the process is either shipped by us
360 * or Microsoft, the support driver will trust it with full access and to keep
361 * the handle secure.
362 *
363 * We also trust the protection the support driver gives the process to keep out
364 * malicious ring-3 code, and therefore any code, patching or other mysterious
365 * stuff that enteres the process must be from kernel mode and that we can trust
366 * it (the alternative interpretation is that the kernel has been breanched
367 * already, which isn't our responsibility). This means that, the anti-software
368 * products can do whatever they like from this point on. However, should they
369 * do unrevertable changes to the process before this point, VirtualBox won't
370 * work.
371 *
372 * As in the second stub process, we'll now do normal process initialization and
373 * #SUPR3HardenedMain will take control. It will detect that it is being called
374 * by the 3rd stub process because of a different magic string starting the
375 * command line, and not respawn itself any more. #SUPR3HardenedMain will
376 * recheck the VirtualBox installation, keeping all known files open just like
377 * in two previous stub processes.
378 *
379 * It will then load the Windows cryptographic API and load the trusted root
380 * certificates from the Windows store. The API enables using installation
381 * catalog files for signature checking as well as providing a second
382 * verification in addition to our own implementation (IPRT). The certificates
383 * allows our signature validation implementation to validate all embedded
384 * signatures, not just the microsoft ones and the one signed by our own
385 * certificate.
386 *
387 */
388
389
390/*********************************************************************************************************************************
391* Header Files *
392*********************************************************************************************************************************/
393#if defined(RT_OS_OS2)
394# define INCL_BASE
395# define INCL_ERRORS
396# include <os2.h>
397# include <stdio.h>
398# include <stdlib.h>
399# include <dlfcn.h>
400# include <unistd.h>
401
402#elif RT_OS_WINDOWS
403# include <iprt/nt/nt-and-windows.h>
404
405#else /* UNIXes */
406# include <iprt/types.h> /* stdint fun on darwin. */
407
408# include <stdio.h>
409# include <stdlib.h>
410# include <dlfcn.h>
411# include <limits.h>
412# include <errno.h>
413# include <unistd.h>
414# include <sys/stat.h>
415# include <sys/time.h>
416# include <sys/types.h>
417# if defined(RT_OS_LINUX)
418# undef USE_LIB_PCAP /* don't depend on libcap as we had to depend on either
419 libcap1 or libcap2 */
420
421# undef _POSIX_SOURCE
422# include <linux/types.h> /* sys/capabilities from uek-headers require this */
423# include <sys/capability.h>
424# include <sys/prctl.h>
425# ifndef CAP_TO_MASK
426# define CAP_TO_MASK(cap) RT_BIT(cap)
427# endif
428# elif defined(RT_OS_FREEBSD)
429# include <sys/param.h>
430# include <sys/sysctl.h>
431# elif defined(RT_OS_SOLARIS)
432# include <priv.h>
433# endif
434# include <pwd.h>
435# ifdef RT_OS_DARWIN
436# include <mach-o/dyld.h>
437# endif
438
439#endif
440
441#include <VBox/sup.h>
442#include <VBox/err.h>
443#ifdef RT_OS_WINDOWS
444# include <VBox/version.h>
445#endif
446#include <iprt/ctype.h>
447#include <iprt/string.h>
448#include <iprt/initterm.h>
449#include <iprt/param.h>
450
451#include "SUPLibInternal.h"
452
453
454/*********************************************************************************************************************************
455* Defined Constants And Macros *
456*********************************************************************************************************************************/
457/** @def SUP_HARDENED_SUID
458 * Whether we're employing set-user-ID-on-execute in the hardening.
459 */
460#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_L4)
461# define SUP_HARDENED_SUID
462#else
463# undef SUP_HARDENED_SUID
464#endif
465
466/** @def SUP_HARDENED_SYM
467 * Decorate a symbol that's resolved dynamically.
468 */
469#ifdef RT_OS_OS2
470# define SUP_HARDENED_SYM(sym) "_" sym
471#else
472# define SUP_HARDENED_SYM(sym) sym
473#endif
474
475
476/*********************************************************************************************************************************
477* Structures and Typedefs *
478*********************************************************************************************************************************/
479/** @see RTR3InitEx */
480typedef DECLCALLBACK(int) FNRTR3INITEX(uint32_t iVersion, uint32_t fFlags, int cArgs,
481 char **papszArgs, const char *pszProgramPath);
482typedef FNRTR3INITEX *PFNRTR3INITEX;
483
484/** @see RTLogRelPrintf */
485typedef DECLCALLBACK(void) FNRTLOGRELPRINTF(const char *pszFormat, ...);
486typedef FNRTLOGRELPRINTF *PFNRTLOGRELPRINTF;
487
488
489/*********************************************************************************************************************************
490* Global Variables *
491*********************************************************************************************************************************/
492/** The pre-init data we pass on to SUPR3 (residing in VBoxRT). */
493static SUPPREINITDATA g_SupPreInitData;
494/** The program executable path. */
495#ifndef RT_OS_WINDOWS
496static
497#endif
498char g_szSupLibHardenedExePath[RTPATH_MAX];
499/** The application bin directory path. */
500static char g_szSupLibHardenedAppBinPath[RTPATH_MAX];
501
502/** The program name. */
503static const char *g_pszSupLibHardenedProgName;
504/** The flags passed to SUPR3HardenedMain. */
505static uint32_t g_fSupHardenedMain;
506
507#ifdef SUP_HARDENED_SUID
508/** The real UID at startup. */
509static uid_t g_uid;
510/** The real GID at startup. */
511static gid_t g_gid;
512# ifdef RT_OS_LINUX
513static uint32_t g_uCaps;
514# endif
515#endif
516
517/** The startup log file. */
518#ifdef RT_OS_WINDOWS
519static HANDLE g_hStartupLog = NULL;
520#else
521static int g_hStartupLog = -1;
522#endif
523/** The number of bytes we've written to the startup log. */
524static uint32_t volatile g_cbStartupLog = 0;
525
526/** The current SUPR3HardenedMain state / location. */
527SUPR3HARDENEDMAINSTATE g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED;
528AssertCompileSize(g_enmSupR3HardenedMainState, sizeof(uint32_t));
529
530#ifdef RT_OS_WINDOWS
531/** Pointer to VBoxRT's RTLogRelPrintf function so we can write errors to the
532 * release log at runtime. */
533static PFNRTLOGRELPRINTF g_pfnRTLogRelPrintf = NULL;
534/** Log volume name (for attempting volume flush). */
535static RTUTF16 g_wszStartupLogVol[16];
536#endif
537
538
539/*********************************************************************************************************************************
540* Internal Functions *
541*********************************************************************************************************************************/
542#ifdef SUP_HARDENED_SUID
543static void supR3HardenedMainDropPrivileges(void);
544#endif
545static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName);
546
547
548/**
549 * Safely copy one or more strings into the given buffer.
550 *
551 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
552 * @param pszDst The destionation buffer.
553 * @param cbDst The size of the destination buffer.
554 * @param ... One or more zero terminated strings, ending with
555 * a NULL.
556 */
557static int suplibHardenedStrCopyEx(char *pszDst, size_t cbDst, ...)
558{
559 int rc = VINF_SUCCESS;
560
561 if (cbDst == 0)
562 return VERR_BUFFER_OVERFLOW;
563
564 va_list va;
565 va_start(va, cbDst);
566 for (;;)
567 {
568 const char *pszSrc = va_arg(va, const char *);
569 if (!pszSrc)
570 break;
571
572 size_t cchSrc = suplibHardenedStrLen(pszSrc);
573 if (cchSrc < cbDst)
574 {
575 suplibHardenedMemCopy(pszDst, pszSrc, cchSrc);
576 pszDst += cchSrc;
577 cbDst -= cchSrc;
578 }
579 else
580 {
581 rc = VERR_BUFFER_OVERFLOW;
582 if (cbDst > 1)
583 {
584 suplibHardenedMemCopy(pszDst, pszSrc, cbDst - 1);
585 pszDst += cbDst - 1;
586 cbDst = 1;
587 }
588 }
589 *pszDst = '\0';
590 }
591 va_end(va);
592
593 return rc;
594}
595
596
597/**
598 * Exit current process in the quickest possible fashion.
599 *
600 * @param rcExit The exit code.
601 */
602DECLNORETURN(void) suplibHardenedExit(RTEXITCODE rcExit)
603{
604 for (;;)
605 {
606#ifdef RT_OS_WINDOWS
607 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
608 ExitProcess(rcExit);
609 if (RtlExitUserProcess != NULL)
610 RtlExitUserProcess(rcExit);
611 NtTerminateProcess(NtCurrentProcess(), rcExit);
612#else
613 _Exit(rcExit);
614#endif
615 }
616}
617
618
619/**
620 * Writes a substring to standard error.
621 *
622 * @param pch The start of the substring.
623 * @param cch The length of the substring.
624 */
625static void suplibHardenedPrintStrN(const char *pch, size_t cch)
626{
627#ifdef RT_OS_WINDOWS
628 HANDLE hStdOut = NtCurrentPeb()->ProcessParameters->StandardOutput;
629 if (hStdOut != NULL)
630 {
631 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
632 {
633 DWORD cbWritten;
634 WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
635 }
636 /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
637 else if (NtWriteFile != NULL && ((uintptr_t)hStdOut & 3) == 0)
638 {
639 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
640 NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
641 &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
642 }
643 }
644#else
645 (void)write(2, pch, cch);
646#endif
647}
648
649
650/**
651 * Writes a string to standard error.
652 *
653 * @param psz The string.
654 */
655static void suplibHardenedPrintStr(const char *psz)
656{
657 suplibHardenedPrintStrN(psz, suplibHardenedStrLen(psz));
658}
659
660
661/**
662 * Writes a char to standard error.
663 *
664 * @param ch The character value to write.
665 */
666static void suplibHardenedPrintChr(char ch)
667{
668 suplibHardenedPrintStrN(&ch, 1);
669}
670
671#ifndef IPRT_NO_CRT
672
673/**
674 * Writes a decimal number to stdard error.
675 *
676 * @param uValue The value.
677 */
678static void suplibHardenedPrintDecimal(uint64_t uValue)
679{
680 char szBuf[64];
681 char *pszEnd = &szBuf[sizeof(szBuf) - 1];
682 char *psz = pszEnd;
683
684 *psz-- = '\0';
685
686 do
687 {
688 *psz-- = '0' + (uValue % 10);
689 uValue /= 10;
690 } while (uValue > 0);
691
692 psz++;
693 suplibHardenedPrintStrN(psz, pszEnd - psz);
694}
695
696
697/**
698 * Writes a hexadecimal or octal number to standard error.
699 *
700 * @param uValue The value.
701 * @param uBase The base (16 or 8).
702 * @param fFlags Format flags.
703 */
704static void suplibHardenedPrintHexOctal(uint64_t uValue, unsigned uBase, uint32_t fFlags)
705{
706 static char const s_achDigitsLower[17] = "0123456789abcdef";
707 static char const s_achDigitsUpper[17] = "0123456789ABCDEF";
708 const char *pchDigits = !(fFlags & RTSTR_F_CAPITAL) ? s_achDigitsLower : s_achDigitsUpper;
709 unsigned cShift = uBase == 16 ? 4 : 3;
710 unsigned fDigitMask = uBase == 16 ? 0xf : 7;
711 char szBuf[64];
712 char *pszEnd = &szBuf[sizeof(szBuf) - 1];
713 char *psz = pszEnd;
714
715 *psz-- = '\0';
716
717 do
718 {
719 *psz-- = pchDigits[uValue & fDigitMask];
720 uValue >>= cShift;
721 } while (uValue > 0);
722
723 if ((fFlags & RTSTR_F_SPECIAL) && uBase == 16)
724 {
725 *psz-- = !(fFlags & RTSTR_F_CAPITAL) ? 'x' : 'X';
726 *psz-- = '0';
727 }
728
729 psz++;
730 suplibHardenedPrintStrN(psz, pszEnd - psz);
731}
732
733
734/**
735 * Writes a wide character string to standard error.
736 *
737 * @param pwsz The string.
738 */
739static void suplibHardenedPrintWideStr(PCRTUTF16 pwsz)
740{
741 for (;;)
742 {
743 RTUTF16 wc = *pwsz++;
744 if (!wc)
745 return;
746 if ( (wc < 0x7f && wc >= 0x20)
747 || wc == '\n'
748 || wc == '\r')
749 suplibHardenedPrintChr((char)wc);
750 else
751 {
752 suplibHardenedPrintStrN(RT_STR_TUPLE("\\x"));
753 suplibHardenedPrintHexOctal(wc, 16, 0);
754 }
755 }
756}
757
758#else /* IPRT_NO_CRT */
759
760/** Buffer structure used by suplibHardenedOutput. */
761struct SUPLIBHARDENEDOUTPUTBUF
762{
763 size_t off;
764 char szBuf[2048];
765};
766
767/** Callback for RTStrFormatV, see FNRTSTROUTPUT. */
768static DECLCALLBACK(size_t) suplibHardenedOutput(void *pvArg, const char *pachChars, size_t cbChars)
769{
770 SUPLIBHARDENEDOUTPUTBUF *pBuf = (SUPLIBHARDENEDOUTPUTBUF *)pvArg;
771 size_t cbTodo = cbChars;
772 for (;;)
773 {
774 size_t cbSpace = sizeof(pBuf->szBuf) - pBuf->off - 1;
775
776 /* Flush the buffer? */
777 if ( cbSpace == 0
778 || (cbTodo == 0 && pBuf->off))
779 {
780 suplibHardenedPrintStrN(pBuf->szBuf, pBuf->off);
781# ifdef RT_OS_WINDOWS
782 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
783 OutputDebugString(pBuf->szBuf);
784# endif
785 pBuf->off = 0;
786 cbSpace = sizeof(pBuf->szBuf) - 1;
787 }
788
789 /* Copy the string into the buffer. */
790 if (cbTodo == 1)
791 {
792 pBuf->szBuf[pBuf->off++] = *pachChars;
793 break;
794 }
795 if (cbSpace >= cbTodo)
796 {
797 memcpy(&pBuf->szBuf[pBuf->off], pachChars, cbTodo);
798 pBuf->off += cbTodo;
799 break;
800 }
801 memcpy(&pBuf->szBuf[pBuf->off], pachChars, cbSpace);
802 pBuf->off += cbSpace;
803 cbTodo -= cbSpace;
804 }
805 pBuf->szBuf[pBuf->off] = '\0';
806
807 return cbChars;
808}
809
810#endif /* IPRT_NO_CRT */
811
812/**
813 * Simple printf to standard error.
814 *
815 * @param pszFormat The format string.
816 * @param va Arguments to format.
817 */
818DECLHIDDEN(void) suplibHardenedPrintFV(const char *pszFormat, va_list va)
819{
820#ifdef IPRT_NO_CRT
821 /*
822 * Use buffered output here to avoid character mixing on the windows
823 * console and to enable us to use OutputDebugString.
824 */
825 SUPLIBHARDENEDOUTPUTBUF Buf;
826 Buf.off = 0;
827 Buf.szBuf[0] = '\0';
828 RTStrFormatV(suplibHardenedOutput, &Buf, NULL, NULL, pszFormat, va);
829
830#else /* !IPRT_NO_CRT */
831 /*
832 * Format loop.
833 */
834 char ch;
835 const char *pszLast = pszFormat;
836 for (;;)
837 {
838 ch = *pszFormat;
839 if (!ch)
840 break;
841 pszFormat++;
842
843 if (ch == '%')
844 {
845 /*
846 * Format argument.
847 */
848
849 /* Flush unwritten bits. */
850 if (pszLast != pszFormat - 1)
851 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast - 1);
852 pszLast = pszFormat;
853 ch = *pszFormat++;
854
855 /* flags. */
856 uint32_t fFlags = 0;
857 for (;;)
858 {
859 if (ch == '#') fFlags |= RTSTR_F_SPECIAL;
860 else if (ch == '-') fFlags |= RTSTR_F_LEFT;
861 else if (ch == '+') fFlags |= RTSTR_F_PLUS;
862 else if (ch == ' ') fFlags |= RTSTR_F_BLANK;
863 else if (ch == '0') fFlags |= RTSTR_F_ZEROPAD;
864 else if (ch == '\'') fFlags |= RTSTR_F_THOUSAND_SEP;
865 else break;
866 ch = *pszFormat++;
867 }
868
869 /* Width and precision - ignored. */
870 while (RT_C_IS_DIGIT(ch))
871 ch = *pszFormat++;
872 if (ch == '*')
873 va_arg(va, int);
874 if (ch == '.')
875 {
876 do ch = *pszFormat++;
877 while (RT_C_IS_DIGIT(ch));
878 if (ch == '*')
879 va_arg(va, int);
880 }
881
882 /* Size. */
883 char chArgSize = 0;
884 switch (ch)
885 {
886 case 'z':
887 case 'L':
888 case 'j':
889 case 't':
890 chArgSize = ch;
891 ch = *pszFormat++;
892 break;
893
894 case 'l':
895 chArgSize = ch;
896 ch = *pszFormat++;
897 if (ch == 'l')
898 {
899 chArgSize = 'L';
900 ch = *pszFormat++;
901 }
902 break;
903
904 case 'h':
905 chArgSize = ch;
906 ch = *pszFormat++;
907 if (ch == 'h')
908 {
909 chArgSize = 'H';
910 ch = *pszFormat++;
911 }
912 break;
913 }
914
915 /*
916 * Do type specific formatting.
917 */
918 switch (ch)
919 {
920 case 'c':
921 ch = (char)va_arg(va, int);
922 suplibHardenedPrintChr(ch);
923 break;
924
925 case 's':
926 if (chArgSize == 'l')
927 {
928 PCRTUTF16 pwszStr = va_arg(va, PCRTUTF16 );
929 if (RT_VALID_PTR(pwszStr))
930 suplibHardenedPrintWideStr(pwszStr);
931 else
932 suplibHardenedPrintStr("<NULL>");
933 }
934 else
935 {
936 const char *pszStr = va_arg(va, const char *);
937 if (!RT_VALID_PTR(pszStr))
938 pszStr = "<NULL>";
939 suplibHardenedPrintStr(pszStr);
940 }
941 break;
942
943 case 'd':
944 case 'i':
945 {
946 int64_t iValue;
947 if (chArgSize == 'L' || chArgSize == 'j')
948 iValue = va_arg(va, int64_t);
949 else if (chArgSize == 'l')
950 iValue = va_arg(va, signed long);
951 else if (chArgSize == 'z' || chArgSize == 't')
952 iValue = va_arg(va, intptr_t);
953 else
954 iValue = va_arg(va, signed int);
955 if (iValue < 0)
956 {
957 suplibHardenedPrintChr('-');
958 iValue = -iValue;
959 }
960 suplibHardenedPrintDecimal(iValue);
961 break;
962 }
963
964 case 'p':
965 case 'x':
966 case 'X':
967 case 'u':
968 case 'o':
969 {
970 unsigned uBase = 10;
971 uint64_t uValue;
972
973 switch (ch)
974 {
975 case 'p':
976 fFlags |= RTSTR_F_ZEROPAD; /* Note not standard behaviour (but I like it this way!) */
977 uBase = 16;
978 break;
979 case 'X':
980 fFlags |= RTSTR_F_CAPITAL;
981 case 'x':
982 uBase = 16;
983 break;
984 case 'u':
985 uBase = 10;
986 break;
987 case 'o':
988 uBase = 8;
989 break;
990 }
991
992 if (ch == 'p' || chArgSize == 'z' || chArgSize == 't')
993 uValue = va_arg(va, uintptr_t);
994 else if (chArgSize == 'L' || chArgSize == 'j')
995 uValue = va_arg(va, uint64_t);
996 else if (chArgSize == 'l')
997 uValue = va_arg(va, unsigned long);
998 else
999 uValue = va_arg(va, unsigned int);
1000
1001 if (uBase == 10)
1002 suplibHardenedPrintDecimal(uValue);
1003 else
1004 suplibHardenedPrintHexOctal(uValue, uBase, fFlags);
1005 break;
1006 }
1007
1008 case 'R':
1009 if (pszFormat[0] == 'r' && pszFormat[1] == 'c')
1010 {
1011 int iValue = va_arg(va, int);
1012 if (iValue < 0)
1013 {
1014 suplibHardenedPrintChr('-');
1015 iValue = -iValue;
1016 }
1017 suplibHardenedPrintDecimal(iValue);
1018 pszFormat += 2;
1019 break;
1020 }
1021 /* fall thru */
1022
1023 /*
1024 * Custom format.
1025 */
1026 default:
1027 suplibHardenedPrintStr("[bad format: ");
1028 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast);
1029 suplibHardenedPrintChr(']');
1030 break;
1031 }
1032
1033 /* continue */
1034 pszLast = pszFormat;
1035 }
1036 }
1037
1038 /* Flush the last bits of the string. */
1039 if (pszLast != pszFormat)
1040 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast);
1041#endif /* !IPRT_NO_CRT */
1042}
1043
1044
1045/**
1046 * Prints to standard error.
1047 *
1048 * @param pszFormat The format string.
1049 * @param ... Arguments to format.
1050 */
1051DECLHIDDEN(void) suplibHardenedPrintF(const char *pszFormat, ...)
1052{
1053 va_list va;
1054 va_start(va, pszFormat);
1055 suplibHardenedPrintFV(pszFormat, va);
1056 va_end(va);
1057}
1058
1059
1060/**
1061 * @copydoc RTPathStripFilename
1062 */
1063static void suplibHardenedPathStripFilename(char *pszPath)
1064{
1065 char *psz = pszPath;
1066 char *pszLastSep = pszPath;
1067
1068 for (;; psz++)
1069 {
1070 switch (*psz)
1071 {
1072 /* handle separators. */
1073#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
1074 case ':':
1075 pszLastSep = psz + 1;
1076 break;
1077
1078 case '\\':
1079#endif
1080 case '/':
1081 pszLastSep = psz;
1082 break;
1083
1084 /* the end */
1085 case '\0':
1086 if (pszLastSep == pszPath)
1087 *pszLastSep++ = '.';
1088 *pszLastSep = '\0';
1089 return;
1090 }
1091 }
1092 /* will never get here */
1093}
1094
1095
1096/**
1097 * @copydoc RTPathFilename
1098 */
1099DECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath)
1100{
1101 const char *psz = pszPath;
1102 const char *pszLastComp = pszPath;
1103
1104 for (;; psz++)
1105 {
1106 switch (*psz)
1107 {
1108 /* handle separators. */
1109#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
1110 case ':':
1111 pszLastComp = psz + 1;
1112 break;
1113
1114 case '\\':
1115#endif
1116 case '/':
1117 pszLastComp = psz + 1;
1118 break;
1119
1120 /* the end */
1121 case '\0':
1122 if (*pszLastComp)
1123 return (char *)(void *)pszLastComp;
1124 return NULL;
1125 }
1126 }
1127
1128 /* will never get here */
1129}
1130
1131
1132/**
1133 * @copydoc RTPathAppPrivateNoArch
1134 */
1135DECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath)
1136{
1137#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
1138 const char *pszSrcPath = RTPATH_APP_PRIVATE;
1139 size_t cchPathPrivateNoArch = suplibHardenedStrLen(pszSrcPath);
1140 if (cchPathPrivateNoArch >= cchPath)
1141 supR3HardenedFatal("supR3HardenedPathAppPrivateNoArch: Buffer overflow, %zu >= %zu\n", cchPathPrivateNoArch, cchPath);
1142 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathPrivateNoArch + 1);
1143 return VINF_SUCCESS;
1144
1145#else
1146 return supR3HardenedPathAppBin(pszPath, cchPath);
1147#endif
1148}
1149
1150
1151/**
1152 * @copydoc RTPathAppPrivateArch
1153 */
1154DECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath)
1155{
1156#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE_ARCH)
1157 const char *pszSrcPath = RTPATH_APP_PRIVATE_ARCH;
1158 size_t cchPathPrivateArch = suplibHardenedStrLen(pszSrcPath);
1159 if (cchPathPrivateArch >= cchPath)
1160 supR3HardenedFatal("supR3HardenedPathAppPrivateArch: Buffer overflow, %zu >= %zu\n", cchPathPrivateArch, cchPath);
1161 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathPrivateArch + 1);
1162 return VINF_SUCCESS;
1163
1164#else
1165 return supR3HardenedPathAppBin(pszPath, cchPath);
1166#endif
1167}
1168
1169
1170/**
1171 * @copydoc RTPathSharedLibs
1172 */
1173DECLHIDDEN(int) supR3HardenedPathAppSharedLibs(char *pszPath, size_t cchPath)
1174{
1175#if !defined(RT_OS_WINDOWS) && defined(RTPATH_SHARED_LIBS)
1176 const char *pszSrcPath = RTPATH_SHARED_LIBS;
1177 size_t cchPathSharedLibs = suplibHardenedStrLen(pszSrcPath);
1178 if (cchPathSharedLibs >= cchPath)
1179 supR3HardenedFatal("supR3HardenedPathAppSharedLibs: Buffer overflow, %zu >= %zu\n", cchPathSharedLibs, cchPath);
1180 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathSharedLibs + 1);
1181 return VINF_SUCCESS;
1182
1183#else
1184 return supR3HardenedPathAppBin(pszPath, cchPath);
1185#endif
1186}
1187
1188
1189/**
1190 * @copydoc RTPathAppDocs
1191 */
1192DECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath)
1193{
1194#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_DOCS)
1195 const char *pszSrcPath = RTPATH_APP_DOCS;
1196 size_t cchPathAppDocs = suplibHardenedStrLen(pszSrcPath);
1197 if (cchPathAppDocs >= cchPath)
1198 supR3HardenedFatal("supR3HardenedPathAppDocs: Buffer overflow, %zu >= %zu\n", cchPathAppDocs, cchPath);
1199 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathAppDocs + 1);
1200 return VINF_SUCCESS;
1201
1202#else
1203 return supR3HardenedPathAppBin(pszPath, cchPath);
1204#endif
1205}
1206
1207
1208/**
1209 * Returns the full path to the executable in g_szSupLibHardenedExePath.
1210 *
1211 * @returns IPRT status code.
1212 */
1213static void supR3HardenedGetFullExePath(void)
1214{
1215 /*
1216 * Get the program filename.
1217 *
1218 * Most UNIXes have no API for obtaining the executable path, but provides a symbolic
1219 * link in the proc file system that tells who was exec'ed. The bad thing about this
1220 * is that we have to use readlink, one of the weirder UNIX APIs.
1221 *
1222 * Darwin, OS/2 and Windows all have proper APIs for getting the program file name.
1223 */
1224#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
1225# ifdef RT_OS_LINUX
1226 int cchLink = readlink("/proc/self/exe", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
1227
1228# elif defined(RT_OS_SOLARIS)
1229 char szFileBuf[PATH_MAX + 1];
1230 sprintf(szFileBuf, "/proc/%ld/path/a.out", (long)getpid());
1231 int cchLink = readlink(szFileBuf, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
1232
1233# else /* RT_OS_FREEBSD */
1234 int aiName[4];
1235 aiName[0] = CTL_KERN;
1236 aiName[1] = KERN_PROC;
1237 aiName[2] = KERN_PROC_PATHNAME;
1238 aiName[3] = getpid();
1239
1240 size_t cbPath = sizeof(g_szSupLibHardenedExePath);
1241 if (sysctl(aiName, RT_ELEMENTS(aiName), g_szSupLibHardenedExePath, &cbPath, NULL, 0) < 0)
1242 supR3HardenedFatal("supR3HardenedExecDir: sysctl failed\n");
1243 g_szSupLibHardenedExePath[sizeof(g_szSupLibHardenedExePath) - 1] = '\0';
1244 int cchLink = suplibHardenedStrLen(g_szSupLibHardenedExePath); /* paranoid? can't we use cbPath? */
1245
1246# endif
1247 if (cchLink < 0 || cchLink == sizeof(g_szSupLibHardenedExePath) - 1)
1248 supR3HardenedFatal("supR3HardenedExecDir: couldn't read \"%s\", errno=%d cchLink=%d\n",
1249 g_szSupLibHardenedExePath, errno, cchLink);
1250 g_szSupLibHardenedExePath[cchLink] = '\0';
1251
1252#elif defined(RT_OS_OS2) || defined(RT_OS_L4)
1253 _execname(g_szSupLibHardenedExePath, sizeof(g_szSupLibHardenedExePath));
1254
1255#elif defined(RT_OS_DARWIN)
1256 const char *pszImageName = _dyld_get_image_name(0);
1257 if (!pszImageName)
1258 supR3HardenedFatal("supR3HardenedExecDir: _dyld_get_image_name(0) failed\n");
1259 size_t cchImageName = suplibHardenedStrLen(pszImageName);
1260 if (!cchImageName || cchImageName >= sizeof(g_szSupLibHardenedExePath))
1261 supR3HardenedFatal("supR3HardenedExecDir: _dyld_get_image_name(0) failed, cchImageName=%d\n", cchImageName);
1262 suplibHardenedMemCopy(g_szSupLibHardenedExePath, pszImageName, cchImageName + 1);
1263
1264#elif defined(RT_OS_WINDOWS)
1265 char *pszDst = g_szSupLibHardenedExePath;
1266 int rc = RTUtf16ToUtf8Ex(g_wszSupLibHardenedExePath, RTSTR_MAX, &pszDst, sizeof(g_szSupLibHardenedExePath), NULL);
1267 if (RT_FAILURE(rc))
1268 supR3HardenedFatal("supR3HardenedExecDir: RTUtf16ToUtf8Ex failed, rc=%Rrc\n", rc);
1269#else
1270# error needs porting.
1271#endif
1272
1273 /*
1274 * Determine the application binary directory location.
1275 */
1276 suplibHardenedStrCopy(g_szSupLibHardenedAppBinPath, g_szSupLibHardenedExePath);
1277 suplibHardenedPathStripFilename(g_szSupLibHardenedAppBinPath);
1278
1279 if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED)
1280 supR3HardenedFatal("supR3HardenedExecDir: Called before SUPR3HardenedMain! (%d)\n", g_enmSupR3HardenedMainState);
1281 switch (g_fSupHardenedMain & SUPSECMAIN_FLAGS_LOC_MASK)
1282 {
1283 case SUPSECMAIN_FLAGS_LOC_APP_BIN:
1284 break;
1285 case SUPSECMAIN_FLAGS_LOC_TESTCASE:
1286 suplibHardenedPathStripFilename(g_szSupLibHardenedAppBinPath);
1287 break;
1288 default:
1289 supR3HardenedFatal("supR3HardenedExecDir: Unknown program binary location: %#x\n", g_fSupHardenedMain);
1290 }
1291}
1292
1293
1294#ifdef RT_OS_LINUX
1295/**
1296 * Checks if we can read /proc/self/exe.
1297 *
1298 * This is used on linux to see if we have to call init
1299 * with program path or not.
1300 *
1301 * @returns true / false.
1302 */
1303static bool supR3HardenedMainIsProcSelfExeAccssible(void)
1304{
1305 char szPath[RTPATH_MAX];
1306 int cchLink = readlink("/proc/self/exe", szPath, sizeof(szPath));
1307 return cchLink != -1;
1308}
1309#endif /* RT_OS_LINUX */
1310
1311
1312
1313/**
1314 * @copydoc RTPathExecDir
1315 * @remarks not quite like RTPathExecDir actually...
1316 */
1317DECLHIDDEN(int) supR3HardenedPathAppBin(char *pszPath, size_t cchPath)
1318{
1319 /*
1320 * Lazy init (probably not required).
1321 */
1322 if (!g_szSupLibHardenedAppBinPath[0])
1323 supR3HardenedGetFullExePath();
1324
1325 /*
1326 * Calc the length and check if there is space before copying.
1327 */
1328 size_t cch = suplibHardenedStrLen(g_szSupLibHardenedAppBinPath) + 1;
1329 if (cch <= cchPath)
1330 {
1331 suplibHardenedMemCopy(pszPath, g_szSupLibHardenedAppBinPath, cch + 1);
1332 return VINF_SUCCESS;
1333 }
1334
1335 supR3HardenedFatal("supR3HardenedPathAppBin: Buffer too small (%u < %u)\n", cchPath, cch);
1336 /* not reached */
1337}
1338
1339
1340#ifdef RT_OS_WINDOWS
1341extern "C" uint32_t g_uNtVerCombined;
1342#endif
1343
1344DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
1345{
1346 static const char s_szLogOption[] = "--sup-hardening-log=";
1347
1348 /*
1349 * Scan the argument vector.
1350 */
1351 int cArgs = *pcArgs;
1352 for (int iArg = 1; iArg < cArgs; iArg++)
1353 if (strncmp(papszArgs[iArg], s_szLogOption, sizeof(s_szLogOption) - 1) == 0)
1354 {
1355 const char *pszLogFile = &papszArgs[iArg][sizeof(s_szLogOption) - 1];
1356
1357 /*
1358 * Drop the argument from the vector (has trailing NULL entry).
1359 */
1360 memmove(&papszArgs[iArg], &papszArgs[iArg + 1], (cArgs - iArg) * sizeof(papszArgs[0]));
1361 *pcArgs -= 1;
1362 cArgs -= 1;
1363
1364 /*
1365 * Open the log file, unless we've already opened one.
1366 * First argument takes precedence
1367 */
1368#ifdef RT_OS_WINDOWS
1369 if (g_hStartupLog == NULL)
1370 {
1371 int rc = RTNtPathOpen(pszLogFile,
1372 GENERIC_WRITE | SYNCHRONIZE,
1373 FILE_ATTRIBUTE_NORMAL,
1374 FILE_SHARE_READ | FILE_SHARE_WRITE,
1375 FILE_OPEN_IF,
1376 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1377 OBJ_CASE_INSENSITIVE,
1378 &g_hStartupLog,
1379 NULL);
1380 if (RT_SUCCESS(rc))
1381 {
1382 SUP_DPRINTF(("Log file opened: " VBOX_VERSION_STRING "r%u g_hStartupLog=%p g_uNtVerCombined=%#x\n",
1383 VBOX_SVN_REV, g_hStartupLog, g_uNtVerCombined));
1384
1385 /*
1386 * If the path contains a drive volume, save it so we can
1387 * use it to flush the volume containing the log file.
1388 */
1389 if (RT_C_IS_ALPHA(pszLogFile[0]) && pszLogFile[1] == ':')
1390 {
1391 RTUtf16CopyAscii(g_wszStartupLogVol, RT_ELEMENTS(g_wszStartupLogVol), "\\??\\");
1392 g_wszStartupLogVol[sizeof("\\??\\") - 1] = RT_C_TO_UPPER(pszLogFile[0]);
1393 g_wszStartupLogVol[sizeof("\\??\\") + 0] = ':';
1394 g_wszStartupLogVol[sizeof("\\??\\") + 1] = '\0';
1395 }
1396 }
1397 else
1398 g_hStartupLog = NULL;
1399 }
1400#else
1401 //g_hStartupLog = open()
1402#endif
1403 }
1404}
1405
1406
1407DECLHIDDEN(void) supR3HardenedLogV(const char *pszFormat, va_list va)
1408{
1409#ifdef RT_OS_WINDOWS
1410 if ( g_hStartupLog != NULL
1411 && g_cbStartupLog < 16*_1M)
1412 {
1413 char szBuf[5120];
1414 PCLIENT_ID pSelfId = &((PTEB)NtCurrentTeb())->ClientId;
1415 size_t cchPrefix = RTStrPrintf(szBuf, sizeof(szBuf), "%x.%x: ", pSelfId->UniqueProcess, pSelfId->UniqueThread);
1416 size_t cch = RTStrPrintfV(&szBuf[cchPrefix], sizeof(szBuf) - cchPrefix, pszFormat, va) + cchPrefix;
1417
1418 if ((size_t)cch >= sizeof(szBuf))
1419 cch = sizeof(szBuf) - 1;
1420
1421 if (!cch || szBuf[cch - 1] != '\n')
1422 szBuf[cch++] = '\n';
1423
1424 ASMAtomicAddU32(&g_cbStartupLog, (uint32_t)cch);
1425
1426 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1427 LARGE_INTEGER Offset;
1428 Offset.QuadPart = -1; /* Write to end of file. */
1429 NtWriteFile(g_hStartupLog, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
1430 &Ios, szBuf, (ULONG)cch, &Offset, NULL /*Key*/);
1431 }
1432#else
1433 /* later */
1434#endif
1435}
1436
1437
1438DECLHIDDEN(void) supR3HardenedLog(const char *pszFormat, ...)
1439{
1440 va_list va;
1441 va_start(va, pszFormat);
1442 supR3HardenedLogV(pszFormat, va);
1443 va_end(va);
1444}
1445
1446
1447DECLHIDDEN(void) supR3HardenedLogFlush(void)
1448{
1449#ifdef RT_OS_WINDOWS
1450 if ( g_hStartupLog != NULL
1451 && g_cbStartupLog < 16*_1M)
1452 {
1453 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1454 NTSTATUS rcNt = NtFlushBuffersFile(g_hStartupLog, &Ios);
1455
1456 /*
1457 * Try flush the volume containing the log file too.
1458 */
1459 if (g_wszStartupLogVol[0])
1460 {
1461 HANDLE hLogVol = RTNT_INVALID_HANDLE_VALUE;
1462 UNICODE_STRING NtName;
1463 NtName.Buffer = g_wszStartupLogVol;
1464 NtName.Length = (USHORT)(RTUtf16Len(g_wszStartupLogVol) * sizeof(RTUTF16));
1465 NtName.MaximumLength = NtName.Length + 1;
1466 OBJECT_ATTRIBUTES ObjAttr;
1467 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
1468 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
1469 rcNt = NtCreateFile(&hLogVol,
1470 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1471 &ObjAttr,
1472 &Ios,
1473 NULL /* Allocation Size*/,
1474 0 /*FileAttributes*/,
1475 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1476 FILE_OPEN,
1477 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1478 NULL /*EaBuffer*/,
1479 0 /*EaLength*/);
1480 if (NT_SUCCESS(rcNt))
1481 rcNt = Ios.Status;
1482 if (NT_SUCCESS(rcNt))
1483 {
1484 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
1485 rcNt = NtFlushBuffersFile(hLogVol, &Ios);
1486 NtClose(hLogVol);
1487 }
1488 else
1489 {
1490 /* This may have sideeffects similar to what we want... */
1491 hLogVol = RTNT_INVALID_HANDLE_VALUE;
1492 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
1493 rcNt = NtCreateFile(&hLogVol,
1494 GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1495 &ObjAttr,
1496 &Ios,
1497 NULL /* Allocation Size*/,
1498 0 /*FileAttributes*/,
1499 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1500 FILE_OPEN,
1501 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1502 NULL /*EaBuffer*/,
1503 0 /*EaLength*/);
1504 if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
1505 NtClose(hLogVol);
1506 }
1507 }
1508 }
1509#else
1510 /* later */
1511#endif
1512}
1513
1514
1515/**
1516 * Prints the message prefix.
1517 */
1518static void suplibHardenedPrintPrefix(void)
1519{
1520 if (g_pszSupLibHardenedProgName)
1521 suplibHardenedPrintStr(g_pszSupLibHardenedProgName);
1522 suplibHardenedPrintStr(": ");
1523}
1524
1525
1526DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc,
1527 const char *pszMsgFmt, va_list va)
1528{
1529 /*
1530 * First to the log.
1531 */
1532 supR3HardenedLog("Error %d in %s! (enmWhat=%d)\n", rc, pszWhere, enmWhat);
1533 va_list vaCopy;
1534 va_copy(vaCopy, va);
1535 supR3HardenedLogV(pszMsgFmt, vaCopy);
1536 va_end(vaCopy);
1537
1538#ifdef RT_OS_WINDOWS
1539 /*
1540 * The release log.
1541 */
1542 if (g_pfnRTLogRelPrintf)
1543 {
1544 va_copy(vaCopy, va);
1545 g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %s enmWhat=%d rc=%Rrc (%#x)\n", pszWhere, enmWhat, rc);
1546 g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %N\n", pszMsgFmt, &vaCopy);
1547 va_end(vaCopy);
1548 }
1549#endif
1550
1551 /*
1552 * Then to the console.
1553 */
1554 suplibHardenedPrintPrefix();
1555 suplibHardenedPrintF("Error %d in %s!\n", rc, pszWhere);
1556
1557 suplibHardenedPrintPrefix();
1558 va_copy(vaCopy, va);
1559 suplibHardenedPrintFV(pszMsgFmt, vaCopy);
1560 va_end(vaCopy);
1561 suplibHardenedPrintChr('\n');
1562
1563 switch (enmWhat)
1564 {
1565 case kSupInitOp_Driver:
1566 suplibHardenedPrintChr('\n');
1567 suplibHardenedPrintPrefix();
1568 suplibHardenedPrintStr("Tip! Make sure the kernel module is loaded. It may also help to reinstall VirtualBox.\n");
1569 break;
1570
1571 case kSupInitOp_Misc:
1572 case kSupInitOp_IPRT:
1573 case kSupInitOp_Integrity:
1574 case kSupInitOp_RootCheck:
1575 suplibHardenedPrintChr('\n');
1576 suplibHardenedPrintPrefix();
1577 suplibHardenedPrintStr("Tip! It may help to reinstall VirtualBox.\n");
1578 break;
1579
1580 default:
1581 /* no hints here */
1582 break;
1583 }
1584
1585 /*
1586 * Finally, TrustedError if appropriate.
1587 */
1588 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
1589 {
1590#ifdef SUP_HARDENED_SUID
1591 /*
1592 * Drop any root privileges we might be holding, this won't return
1593 * if it fails but end up calling supR3HardenedFatal[V].
1594 */
1595 supR3HardenedMainDropPrivileges();
1596#endif
1597
1598 /*
1599 * Now try resolve and call the TrustedError entry point if we can
1600 * find it. We'll fork before we attempt this because that way the
1601 * session management in main will see us exiting immediately (if
1602 * it's involved with us).
1603 */
1604#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
1605 int pid = fork();
1606 if (pid <= 0)
1607#endif
1608 {
1609 static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
1610 if (!s_fRecursive)
1611 {
1612 s_fRecursive = true;
1613
1614 PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
1615 if (pfnTrustedError)
1616 pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
1617
1618 s_fRecursive = false;
1619 }
1620 }
1621 }
1622#if defined(RT_OS_WINDOWS)
1623 /*
1624 * Report the error to the parent if this happens during early VM init.
1625 */
1626 else if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
1627 && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
1628 supR3HardenedWinReportErrorToParent(pszWhere, enmWhat, rc, pszMsgFmt, va);
1629#endif
1630
1631 /*
1632 * Quit
1633 */
1634 suplibHardenedExit(RTEXITCODE_FAILURE);
1635}
1636
1637
1638DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc,
1639 const char *pszMsgFmt, ...)
1640{
1641 va_list va;
1642 va_start(va, pszMsgFmt);
1643 supR3HardenedFatalMsgV(pszWhere, enmWhat, rc, pszMsgFmt, va);
1644 /* not reached */
1645}
1646
1647
1648DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatalV(const char *pszFormat, va_list va)
1649{
1650 supR3HardenedLog("Fatal error:\n");
1651 va_list vaCopy;
1652 va_copy(vaCopy, va);
1653 supR3HardenedLogV(pszFormat, vaCopy);
1654 va_end(vaCopy);
1655
1656#if defined(RT_OS_WINDOWS)
1657 /*
1658 * Report the error to the parent if this happens during early VM init.
1659 */
1660 if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
1661 && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
1662 supR3HardenedWinReportErrorToParent(NULL, kSupInitOp_Invalid, VERR_INTERNAL_ERROR, pszFormat, va);
1663 else
1664#endif
1665 {
1666#ifdef RT_OS_WINDOWS
1667 if (g_pfnRTLogRelPrintf)
1668 {
1669 va_copy(vaCopy, va);
1670 g_pfnRTLogRelPrintf("supR3HardenedFatalV: %N", pszFormat, &vaCopy);
1671 va_end(vaCopy);
1672 }
1673#endif
1674
1675 suplibHardenedPrintPrefix();
1676 suplibHardenedPrintFV(pszFormat, va);
1677 }
1678
1679 suplibHardenedExit(RTEXITCODE_FAILURE);
1680}
1681
1682
1683DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatal(const char *pszFormat, ...)
1684{
1685 va_list va;
1686 va_start(va, pszFormat);
1687 supR3HardenedFatalV(pszFormat, va);
1688 /* not reached */
1689}
1690
1691
1692DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va)
1693{
1694 if (fFatal)
1695 supR3HardenedFatalV(pszFormat, va);
1696
1697 supR3HardenedLog("Error (rc=%d):\n", rc);
1698 va_list vaCopy;
1699 va_copy(vaCopy, va);
1700 supR3HardenedLogV(pszFormat, vaCopy);
1701 va_end(vaCopy);
1702
1703#ifdef RT_OS_WINDOWS
1704 if (g_pfnRTLogRelPrintf)
1705 {
1706 va_copy(vaCopy, va);
1707 g_pfnRTLogRelPrintf("supR3HardenedErrorV: %N", pszFormat, &vaCopy);
1708 va_end(vaCopy);
1709 }
1710#endif
1711
1712 suplibHardenedPrintPrefix();
1713 suplibHardenedPrintFV(pszFormat, va);
1714
1715 return rc;
1716}
1717
1718
1719DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...)
1720{
1721 va_list va;
1722 va_start(va, pszFormat);
1723 supR3HardenedErrorV(rc, fFatal, pszFormat, va);
1724 va_end(va);
1725 return rc;
1726}
1727
1728
1729
1730/**
1731 * Attempts to open /dev/vboxdrv (or equvivalent).
1732 *
1733 * @remarks This function will not return on failure.
1734 */
1735DECLHIDDEN(void) supR3HardenedMainOpenDevice(void)
1736{
1737 RTERRINFOSTATIC ErrInfo;
1738 SUPINITOP enmWhat = kSupInitOp_Driver;
1739 int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/,
1740 &enmWhat, RTErrInfoInitStatic(&ErrInfo));
1741 if (RT_SUCCESS(rc))
1742 return;
1743
1744 if (RTErrInfoIsSet(&ErrInfo.Core))
1745 supR3HardenedFatalMsg("suplibOsInit", enmWhat, rc, "%s", ErrInfo.szMsg);
1746
1747 switch (rc)
1748 {
1749 /** @todo better messages! */
1750 case VERR_VM_DRIVER_NOT_INSTALLED:
1751 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not installed");
1752 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
1753 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not accessible");
1754 case VERR_VM_DRIVER_LOAD_ERROR:
1755 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_LOAD_ERROR");
1756 case VERR_VM_DRIVER_OPEN_ERROR:
1757 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_OPEN_ERROR");
1758 case VERR_VM_DRIVER_VERSION_MISMATCH:
1759 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver version mismatch");
1760 case VERR_ACCESS_DENIED:
1761 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_ACCESS_DENIED");
1762 case VERR_NO_MEMORY:
1763 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel memory allocation/mapping failed");
1764 case VERR_SUPDRV_HARDENING_EVIL_HANDLE:
1765 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
1766 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0:
1767 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0");
1768 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1:
1769 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1");
1770 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2:
1771 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
1772 default:
1773 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Unknown rc=%d (%Rrc)", rc, rc);
1774 }
1775}
1776
1777
1778#ifdef SUP_HARDENED_SUID
1779
1780/**
1781 * Grabs extra non-root capabilities / privileges that we might require.
1782 *
1783 * This is currently only used for being able to do ICMP from the NAT engine.
1784 *
1785 * @note We still have root privileges at the time of this call.
1786 */
1787static void supR3HardenedMainGrabCapabilites(void)
1788{
1789# if defined(RT_OS_LINUX)
1790 /*
1791 * We are about to drop all our privileges. Remove all capabilities but
1792 * keep the cap_net_raw capability for ICMP sockets for the NAT stack.
1793 */
1794 if (g_uCaps != 0)
1795 {
1796# ifdef USE_LIB_PCAP
1797 /* XXX cap_net_bind_service */
1798 if (!cap_set_proc(cap_from_text("all-eip cap_net_raw+ep")))
1799 prctl(PR_SET_KEEPCAPS, 1 /*keep=*/, 0, 0, 0);
1800 prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0);
1801# else
1802 cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
1803 cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
1804 memset(hdr, 0, sizeof(*hdr));
1805 hdr->version = _LINUX_CAPABILITY_VERSION;
1806 memset(cap, 0, sizeof(*cap));
1807 cap->effective = g_uCaps;
1808 cap->permitted = g_uCaps;
1809 if (!capset(hdr, cap))
1810 prctl(PR_SET_KEEPCAPS, 1 /*keep*/, 0, 0, 0);
1811 prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0);
1812# endif /* !USE_LIB_PCAP */
1813 }
1814
1815# elif defined(RT_OS_SOLARIS)
1816 /*
1817 * Add net_icmpaccess privilege to effective privileges and limit
1818 * permitted privileges before completely dropping root privileges.
1819 * This requires dropping root privileges temporarily to get the normal
1820 * user's privileges.
1821 */
1822 seteuid(g_uid);
1823 priv_set_t *pPrivEffective = priv_allocset();
1824 priv_set_t *pPrivNew = priv_allocset();
1825 if (pPrivEffective && pPrivNew)
1826 {
1827 int rc = getppriv(PRIV_EFFECTIVE, pPrivEffective);
1828 seteuid(0);
1829 if (!rc)
1830 {
1831 priv_copyset(pPrivEffective, pPrivNew);
1832 rc = priv_addset(pPrivNew, PRIV_NET_ICMPACCESS);
1833 if (!rc)
1834 {
1835 /* Order is important, as one can't set a privilege which is
1836 * not in the permitted privilege set. */
1837 rc = setppriv(PRIV_SET, PRIV_EFFECTIVE, pPrivNew);
1838 if (rc)
1839 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set effective privilege set.\n");
1840 rc = setppriv(PRIV_SET, PRIV_PERMITTED, pPrivNew);
1841 if (rc)
1842 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set permitted privilege set.\n");
1843 }
1844 else
1845 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to add NET_ICMPACCESS privilege.\n");
1846 }
1847 }
1848 else
1849 {
1850 /* for memory allocation failures just continue */
1851 seteuid(0);
1852 }
1853
1854 if (pPrivEffective)
1855 priv_freeset(pPrivEffective);
1856 if (pPrivNew)
1857 priv_freeset(pPrivNew);
1858# endif
1859}
1860
1861/*
1862 * Look at the environment for some special options.
1863 */
1864static void supR3GrabOptions(void)
1865{
1866 const char *pszOpt;
1867
1868# ifdef RT_OS_LINUX
1869 g_uCaps = 0;
1870
1871 /*
1872 * Do _not_ perform any capability-related system calls for root processes
1873 * (leaving g_uCaps at 0).
1874 * (Hint: getuid gets the real user id, not the effective.)
1875 */
1876 if (getuid() != 0)
1877 {
1878 /*
1879 * CAP_NET_RAW.
1880 * Default: enabled.
1881 * Can be disabled with 'export VBOX_HARD_CAP_NET_RAW=0'.
1882 */
1883 pszOpt = getenv("VBOX_HARD_CAP_NET_RAW");
1884 if ( !pszOpt
1885 || memcmp(pszOpt, "0", sizeof("0")) != 0)
1886 g_uCaps = CAP_TO_MASK(CAP_NET_RAW);
1887
1888 /*
1889 * CAP_NET_BIND_SERVICE.
1890 * Default: disabled.
1891 * Can be enabled with 'export VBOX_HARD_CAP_NET_BIND_SERVICE=1'.
1892 */
1893 pszOpt = getenv("VBOX_HARD_CAP_NET_BIND_SERVICE");
1894 if ( pszOpt
1895 && memcmp(pszOpt, "0", sizeof("0")) != 0)
1896 g_uCaps |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
1897 }
1898# endif
1899}
1900
1901/**
1902 * Drop any root privileges we might be holding.
1903 */
1904static void supR3HardenedMainDropPrivileges(void)
1905{
1906 /*
1907 * Try use setre[ug]id since this will clear the save uid/gid and thus
1908 * leave fewer traces behind that libs like GTK+ may pick up.
1909 */
1910 uid_t euid, ruid, suid;
1911 gid_t egid, rgid, sgid;
1912# if defined(RT_OS_DARWIN)
1913 /* The really great thing here is that setreuid isn't available on
1914 OS X 10.4, libc emulates it. While 10.4 have a slightly different and
1915 non-standard setuid implementation compared to 10.5, the following
1916 works the same way with both version since we're super user (10.5 req).
1917 The following will set all three variants of the group and user IDs. */
1918 setgid(g_gid);
1919 setuid(g_uid);
1920 euid = geteuid();
1921 ruid = suid = getuid();
1922 egid = getegid();
1923 rgid = sgid = getgid();
1924
1925# elif defined(RT_OS_SOLARIS)
1926 /* Solaris doesn't have setresuid, but the setreuid interface is BSD
1927 compatible and will set the saved uid to euid when we pass it a ruid
1928 that isn't -1 (which we do). */
1929 setregid(g_gid, g_gid);
1930 setreuid(g_uid, g_uid);
1931 euid = geteuid();
1932 ruid = suid = getuid();
1933 egid = getegid();
1934 rgid = sgid = getgid();
1935
1936# else
1937 /* This is the preferred one, full control no questions about semantics.
1938 PORTME: If this isn't work, try join one of two other gangs above. */
1939 setresgid(g_gid, g_gid, g_gid);
1940 setresuid(g_uid, g_uid, g_uid);
1941 if (getresuid(&ruid, &euid, &suid) != 0)
1942 {
1943 euid = geteuid();
1944 ruid = suid = getuid();
1945 }
1946 if (getresgid(&rgid, &egid, &sgid) != 0)
1947 {
1948 egid = getegid();
1949 rgid = sgid = getgid();
1950 }
1951# endif
1952
1953
1954 /* Check that it worked out all right. */
1955 if ( euid != g_uid
1956 || ruid != g_uid
1957 || suid != g_uid
1958 || egid != g_gid
1959 || rgid != g_gid
1960 || sgid != g_gid)
1961 supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!"
1962 " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n",
1963 euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid);
1964
1965# if RT_OS_LINUX
1966 /*
1967 * Re-enable the cap_net_raw capability which was disabled during setresuid.
1968 */
1969 if (g_uCaps != 0)
1970 {
1971# ifdef USE_LIB_PCAP
1972 /** @todo Warn if that does not work? */
1973 /* XXX cap_net_bind_service */
1974 cap_set_proc(cap_from_text("cap_net_raw+ep"));
1975# else
1976 cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
1977 cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
1978 memset(hdr, 0, sizeof(*hdr));
1979 hdr->version = _LINUX_CAPABILITY_VERSION;
1980 memset(cap, 0, sizeof(*cap));
1981 cap->effective = g_uCaps;
1982 cap->permitted = g_uCaps;
1983 /** @todo Warn if that does not work? */
1984 capset(hdr, cap);
1985# endif /* !USE_LIB_PCAP */
1986 }
1987# endif
1988}
1989
1990#endif /* SUP_HARDENED_SUID */
1991
1992/**
1993 * Loads the VBoxRT DLL/SO/DYLIB, hands it the open driver,
1994 * and calls RTR3InitEx.
1995 *
1996 * @param fFlags The SUPR3HardenedMain fFlags argument, passed to supR3PreInit.
1997 *
1998 * @remarks VBoxRT contains both IPRT and SUPR3.
1999 * @remarks This function will not return on failure.
2000 */
2001static void supR3HardenedMainInitRuntime(uint32_t fFlags)
2002{
2003 /*
2004 * Construct the name.
2005 */
2006 char szPath[RTPATH_MAX];
2007 supR3HardenedPathAppSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxRT" SUPLIB_DLL_SUFF));
2008 suplibHardenedStrCat(szPath, "/VBoxRT" SUPLIB_DLL_SUFF);
2009
2010 /*
2011 * Open it and resolve the symbols.
2012 */
2013#if defined(RT_OS_WINDOWS)
2014 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/, g_fSupHardenedMain);
2015 if (!hMod)
2016 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
2017 "LoadLibrary \"%s\" failed (rc=%d)",
2018 szPath, RtlGetLastWin32Error());
2019 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
2020 if (!pfnRTInitEx)
2021 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2022 "Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
2023 szPath, RtlGetLastWin32Error());
2024
2025 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
2026 if (!pfnSUPPreInit)
2027 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2028 "Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
2029 szPath, RtlGetLastWin32Error());
2030
2031 g_pfnRTLogRelPrintf = (PFNRTLOGRELPRINTF)GetProcAddress(hMod, SUP_HARDENED_SYM("RTLogRelPrintf"));
2032 Assert(g_pfnRTLogRelPrintf); /* Not fatal in non-strict builds. */
2033
2034#else
2035 /* the dlopen crowd */
2036 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
2037 if (!pvMod)
2038 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
2039 "dlopen(\"%s\",) failed: %s",
2040 szPath, dlerror());
2041 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("RTR3InitEx"));
2042 if (!pfnRTInitEx)
2043 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2044 "Entrypoint \"RTR3InitEx\" not found in \"%s\"!\ndlerror: %s",
2045 szPath, dlerror());
2046 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
2047 if (!pfnSUPPreInit)
2048 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2049 "Entrypoint \"supR3PreInit\" not found in \"%s\"!\ndlerror: %s",
2050 szPath, dlerror());
2051#endif
2052
2053 /*
2054 * Make the calls.
2055 */
2056 supR3HardenedGetPreInitData(&g_SupPreInitData);
2057 int rc = pfnSUPPreInit(&g_SupPreInitData, fFlags);
2058 if (RT_FAILURE(rc))
2059 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
2060 "supR3PreInit failed with rc=%d", rc);
2061 const char *pszExePath = NULL;
2062#ifdef RT_OS_LINUX
2063 if (!supR3HardenedMainIsProcSelfExeAccssible())
2064 pszExePath = g_szSupLibHardenedExePath;
2065#endif
2066 rc = pfnRTInitEx(RTR3INIT_VER_1,
2067 fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV ? 0 : RTR3INIT_FLAGS_SUPLIB,
2068 0 /*cArgs*/, NULL /*papszArgs*/, pszExePath);
2069 if (RT_FAILURE(rc))
2070 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
2071 "RTR3InitEx failed with rc=%d", rc);
2072
2073#if defined(RT_OS_WINDOWS)
2074 /*
2075 * Windows: Create thread that terminates the process when the parent stub
2076 * process terminates (VBoxNetDHCP, Ctrl-C, etc).
2077 */
2078 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
2079 supR3HardenedWinCreateParentWatcherThread(hMod);
2080#endif
2081}
2082
2083
2084/**
2085 * Construct the path to the DLL/SO/DYLIB containing the actual program.
2086 *
2087 * @returns VBox status code.
2088 * @param pszProgName The program name.
2089 * @param fMainFlags The flags passed to SUPR3HardenedMain.
2090 * @param pszPath The output buffer.
2091 * @param cbPath The size of the output buffer, in bytes. Must be at
2092 * least 128 bytes!
2093 */
2094static int supR3HardenedMainGetTrustedLib(const char *pszProgName, uint32_t fMainFlags, char *pszPath, size_t cbPath)
2095{
2096 supR3HardenedPathAppPrivateArch(pszPath, sizeof(cbPath) - 10);
2097 const char *pszSubDirSlash;
2098 switch (g_fSupHardenedMain & SUPSECMAIN_FLAGS_LOC_MASK)
2099 {
2100 case SUPSECMAIN_FLAGS_LOC_APP_BIN:
2101 pszSubDirSlash = "/";
2102 break;
2103 case SUPSECMAIN_FLAGS_LOC_TESTCASE:
2104 pszSubDirSlash = "/testcase/";
2105 break;
2106 default:
2107 pszSubDirSlash = "/";
2108 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Unknown program binary location: %#x\n", g_fSupHardenedMain);
2109 }
2110#ifdef RT_OS_DARWIN
2111 if (fMainFlags & SUPSECMAIN_FLAGS_OSX_VM_APP)
2112 pszProgName = "VirtualBox";
2113#else
2114 RT_NOREF1(fMainFlags);
2115#endif
2116 size_t cch = suplibHardenedStrLen(pszPath);
2117 return suplibHardenedStrCopyEx(&pszPath[cch], cbPath - cch, pszSubDirSlash, pszProgName, SUPLIB_DLL_SUFF, NULL);
2118}
2119
2120
2121/**
2122 * Loads the DLL/SO/DYLIB containing the actual program and
2123 * resolves the TrustedError symbol.
2124 *
2125 * This is very similar to supR3HardenedMainGetTrustedMain().
2126 *
2127 * @returns Pointer to the trusted error symbol if it is exported, NULL
2128 * and no error messages otherwise.
2129 * @param pszProgName The program name.
2130 */
2131static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
2132{
2133 /*
2134 * Don't bother if the main() function didn't advertise any TrustedError
2135 * export. It's both a waste of time and may trigger additional problems,
2136 * confusing or obscuring the original issue.
2137 */
2138 if (!(g_fSupHardenedMain & SUPSECMAIN_FLAGS_TRUSTED_ERROR))
2139 return NULL;
2140
2141 /*
2142 * Construct the name.
2143 */
2144 char szPath[RTPATH_MAX];
2145 supR3HardenedMainGetTrustedLib(pszProgName, g_fSupHardenedMain, szPath, sizeof(szPath));
2146
2147 /*
2148 * Open it and resolve the symbol.
2149 */
2150#if defined(RT_OS_WINDOWS)
2151 supR3HardenedWinEnableThreadCreation();
2152 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/, 0 /*fMainFlags*/);
2153 if (!hMod)
2154 return NULL;
2155 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
2156 if (!pfn)
2157 return NULL;
2158 return (PFNSUPTRUSTEDERROR)pfn;
2159
2160#else
2161 /* the dlopen crowd */
2162 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
2163 if (!pvMod)
2164 return NULL;
2165 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
2166 if (!pvSym)
2167 return NULL;
2168 return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
2169#endif
2170}
2171
2172
2173/**
2174 * Loads the DLL/SO/DYLIB containing the actual program and
2175 * resolves the TrustedMain symbol.
2176 *
2177 * @returns Pointer to the trusted main of the actual program.
2178 * @param pszProgName The program name.
2179 * @param fMainFlags The flags passed to SUPR3HardenedMain.
2180 * @remarks This function will not return on failure.
2181 */
2182static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName, uint32_t fMainFlags)
2183{
2184 /*
2185 * Construct the name.
2186 */
2187 char szPath[RTPATH_MAX];
2188 supR3HardenedMainGetTrustedLib(pszProgName, fMainFlags, szPath, sizeof(szPath));
2189
2190 /*
2191 * Open it and resolve the symbol.
2192 */
2193#if defined(RT_OS_WINDOWS)
2194 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/, 0 /*fMainFlags*/);
2195 if (!hMod)
2196 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibrary \"%s\" failed, rc=%d\n",
2197 szPath, RtlGetLastWin32Error());
2198 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
2199 if (!pfn)
2200 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
2201 szPath, RtlGetLastWin32Error());
2202 return (PFNSUPTRUSTEDMAIN)pfn;
2203
2204#else
2205 /* the dlopen crowd */
2206 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
2207 if (!pvMod)
2208 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
2209 szPath, dlerror());
2210 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
2211 if (!pvSym)
2212 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
2213 szPath, dlerror());
2214 return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
2215#endif
2216}
2217
2218
2219/**
2220 * Secure main.
2221 *
2222 * This is used for the set-user-ID-on-execute binaries on unixy systems
2223 * and when using the open-vboxdrv-via-root-service setup on Windows.
2224 *
2225 * This function will perform the integrity checks of the VirtualBox
2226 * installation, open the support driver, open the root service (later),
2227 * and load the DLL corresponding to \a pszProgName and execute its main
2228 * function.
2229 *
2230 * @returns Return code appropriate for main().
2231 *
2232 * @param pszProgName The program name. This will be used to figure out which
2233 * DLL/SO/DYLIB to load and execute.
2234 * @param fFlags Flags.
2235 * @param argc The argument count.
2236 * @param argv The argument vector.
2237 * @param envp The environment vector.
2238 */
2239DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
2240{
2241 SUP_DPRINTF(("SUPR3HardenedMain: pszProgName=%s fFlags=%#x\n", pszProgName, fFlags));
2242 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED;
2243
2244 /*
2245 * Note! At this point there is no IPRT, so we will have to stick
2246 * to basic CRT functions that everyone agree upon.
2247 */
2248 g_pszSupLibHardenedProgName = pszProgName;
2249 g_fSupHardenedMain = fFlags;
2250 g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
2251 g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
2252#ifdef RT_OS_WINDOWS
2253 if (!g_fSupEarlyProcessInit)
2254#endif
2255 g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
2256
2257 /*
2258 * Determine the full exe path as we'll be needing it for the verify all
2259 * call(s) below. (We have to do this early on Linux because we * *might*
2260 * not be able to access /proc/self/exe after the seteuid call.)
2261 */
2262 supR3HardenedGetFullExePath();
2263#ifdef RT_OS_WINDOWS
2264 supR3HardenedWinInitAppBin(fFlags);
2265#endif
2266
2267#ifdef SUP_HARDENED_SUID
2268 /*
2269 * Grab any options from the environment.
2270 */
2271 supR3GrabOptions();
2272
2273 /*
2274 * Check that we're root, if we aren't then the installation is butchered.
2275 */
2276 g_uid = getuid();
2277 g_gid = getgid();
2278 if (geteuid() != 0 /* root */)
2279 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
2280 "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
2281 geteuid(), getegid(), g_uid, g_gid);
2282#endif /* SUP_HARDENED_SUID */
2283
2284#ifdef RT_OS_WINDOWS
2285 /*
2286 * Windows: First respawn. On Windows we will respawn the process twice to establish
2287 * something we can put some kind of reliable trust in. The first respawning aims
2288 * at dropping compatibility layers and process "security" solutions.
2289 */
2290 if ( !g_fSupEarlyProcessInit
2291 && !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
2292 && supR3HardenedWinIsReSpawnNeeded(1 /*iWhich*/, argc, argv))
2293 {
2294 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #1\n"));
2295 supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV, false /*fAvastKludge*/);
2296 supR3HardenedVerifyAll(true /* fFatal */, pszProgName, g_szSupLibHardenedExePath, fFlags);
2297 return supR3HardenedWinReSpawn(1 /*iWhich*/);
2298 }
2299
2300 /*
2301 * Windows: Initialize the image verification global data so we can verify the
2302 * signature of the process image and hook the core of the DLL loader API so we
2303 * can check the signature of all DLLs mapped into the process. (Already done
2304 * by early VM process init.)
2305 */
2306 if (!g_fSupEarlyProcessInit)
2307 supR3HardenedWinInit(fFlags, true /*fAvastKludge*/);
2308#endif /* RT_OS_WINDOWS */
2309
2310 /*
2311 * Validate the installation.
2312 */
2313 supR3HardenedVerifyAll(true /* fFatal */, pszProgName, g_szSupLibHardenedExePath, fFlags);
2314
2315 /*
2316 * The next steps are only taken if we actually need to access the support
2317 * driver. (Already done by early process init.)
2318 */
2319 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
2320 {
2321#ifdef RT_OS_WINDOWS
2322 /*
2323 * Windows: Must have done early process init if we get here.
2324 */
2325 if (!g_fSupEarlyProcessInit)
2326 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_Integrity, VERR_WRONG_ORDER,
2327 "Early process init was somehow skipped.");
2328
2329 /*
2330 * Windows: The second respawn. This time we make a special arrangement
2331 * with vboxdrv to monitor access to the new process from its inception.
2332 */
2333 if (supR3HardenedWinIsReSpawnNeeded(2 /* iWhich*/, argc, argv))
2334 {
2335 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #2\n"));
2336 return supR3HardenedWinReSpawn(2 /* iWhich*/);
2337 }
2338 SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
2339 supR3HardenedWinFlushLoaderCache();
2340
2341#else
2342 /*
2343 * Open the vboxdrv device.
2344 */
2345 supR3HardenedMainOpenDevice();
2346#endif /* !RT_OS_WINDOWS */
2347 }
2348
2349#ifdef RT_OS_WINDOWS
2350 /*
2351 * Windows: Enable the use of windows APIs to verify images at load time.
2352 */
2353 supR3HardenedWinEnableThreadCreation();
2354 supR3HardenedWinFlushLoaderCache();
2355 supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(g_pszSupLibHardenedProgName);
2356 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY;
2357#endif
2358
2359#ifdef SUP_HARDENED_SUID
2360 /*
2361 * Grab additional capabilities / privileges.
2362 */
2363 supR3HardenedMainGrabCapabilites();
2364
2365 /*
2366 * Drop any root privileges we might be holding (won't return on failure)
2367 */
2368 supR3HardenedMainDropPrivileges();
2369#endif
2370
2371 /*
2372 * Load the IPRT, hand the SUPLib part the open driver and
2373 * call RTR3InitEx.
2374 */
2375 SUP_DPRINTF(("SUPR3HardenedMain: Load Runtime...\n"));
2376 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_INIT_RUNTIME;
2377 supR3HardenedMainInitRuntime(fFlags);
2378#ifdef RT_OS_WINDOWS
2379 supR3HardenedWinModifyDllSearchPath(fFlags, g_szSupLibHardenedAppBinPath);
2380#endif
2381
2382 /*
2383 * Load the DLL/SO/DYLIB containing the actual program
2384 * and pass control to it.
2385 */
2386 SUP_DPRINTF(("SUPR3HardenedMain: Load TrustedMain...\n"));
2387 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_GET_TRUSTED_MAIN;
2388 PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName, fFlags);
2389
2390 SUP_DPRINTF(("SUPR3HardenedMain: Calling TrustedMain (%p)...\n", pfnTrustedMain));
2391 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN;
2392 return pfnTrustedMain(argc, argv, envp);
2393}
2394
Note: See TracBrowser for help on using the repository browser.

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