VirtualBox

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

Last change on this file since 63549 was 63474, checked in by vboxsync, 8 years ago

build fix for gcc on Ubuntu

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.7 KB
Line 
1/* $Id: SUPR3HardenedMain.cpp 63474 2016-08-15 13:07:30Z 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 int res = write(2, pch, cch);
646 NOREF(res);
647#endif
648}
649
650
651/**
652 * Writes a string to standard error.
653 *
654 * @param psz The string.
655 */
656static void suplibHardenedPrintStr(const char *psz)
657{
658 suplibHardenedPrintStrN(psz, suplibHardenedStrLen(psz));
659}
660
661
662/**
663 * Writes a char to standard error.
664 *
665 * @param ch The character value to write.
666 */
667static void suplibHardenedPrintChr(char ch)
668{
669 suplibHardenedPrintStrN(&ch, 1);
670}
671
672#ifndef IPRT_NO_CRT
673
674/**
675 * Writes a decimal number to stdard error.
676 *
677 * @param uValue The value.
678 */
679static void suplibHardenedPrintDecimal(uint64_t uValue)
680{
681 char szBuf[64];
682 char *pszEnd = &szBuf[sizeof(szBuf) - 1];
683 char *psz = pszEnd;
684
685 *psz-- = '\0';
686
687 do
688 {
689 *psz-- = '0' + (uValue % 10);
690 uValue /= 10;
691 } while (uValue > 0);
692
693 psz++;
694 suplibHardenedPrintStrN(psz, pszEnd - psz);
695}
696
697
698/**
699 * Writes a hexadecimal or octal number to standard error.
700 *
701 * @param uValue The value.
702 * @param uBase The base (16 or 8).
703 * @param fFlags Format flags.
704 */
705static void suplibHardenedPrintHexOctal(uint64_t uValue, unsigned uBase, uint32_t fFlags)
706{
707 static char const s_achDigitsLower[17] = "0123456789abcdef";
708 static char const s_achDigitsUpper[17] = "0123456789ABCDEF";
709 const char *pchDigits = !(fFlags & RTSTR_F_CAPITAL) ? s_achDigitsLower : s_achDigitsUpper;
710 unsigned cShift = uBase == 16 ? 4 : 3;
711 unsigned fDigitMask = uBase == 16 ? 0xf : 7;
712 char szBuf[64];
713 char *pszEnd = &szBuf[sizeof(szBuf) - 1];
714 char *psz = pszEnd;
715
716 *psz-- = '\0';
717
718 do
719 {
720 *psz-- = pchDigits[uValue & fDigitMask];
721 uValue >>= cShift;
722 } while (uValue > 0);
723
724 if ((fFlags & RTSTR_F_SPECIAL) && uBase == 16)
725 {
726 *psz-- = !(fFlags & RTSTR_F_CAPITAL) ? 'x' : 'X';
727 *psz-- = '0';
728 }
729
730 psz++;
731 suplibHardenedPrintStrN(psz, pszEnd - psz);
732}
733
734
735/**
736 * Writes a wide character string to standard error.
737 *
738 * @param pwsz The string.
739 */
740static void suplibHardenedPrintWideStr(PCRTUTF16 pwsz)
741{
742 for (;;)
743 {
744 RTUTF16 wc = *pwsz++;
745 if (!wc)
746 return;
747 if ( (wc < 0x7f && wc >= 0x20)
748 || wc == '\n'
749 || wc == '\r')
750 suplibHardenedPrintChr((char)wc);
751 else
752 {
753 suplibHardenedPrintStrN(RT_STR_TUPLE("\\x"));
754 suplibHardenedPrintHexOctal(wc, 16, 0);
755 }
756 }
757}
758
759#else /* IPRT_NO_CRT */
760
761/** Buffer structure used by suplibHardenedOutput. */
762struct SUPLIBHARDENEDOUTPUTBUF
763{
764 size_t off;
765 char szBuf[2048];
766};
767
768/** Callback for RTStrFormatV, see FNRTSTROUTPUT. */
769static DECLCALLBACK(size_t) suplibHardenedOutput(void *pvArg, const char *pachChars, size_t cbChars)
770{
771 SUPLIBHARDENEDOUTPUTBUF *pBuf = (SUPLIBHARDENEDOUTPUTBUF *)pvArg;
772 size_t cbTodo = cbChars;
773 for (;;)
774 {
775 size_t cbSpace = sizeof(pBuf->szBuf) - pBuf->off - 1;
776
777 /* Flush the buffer? */
778 if ( cbSpace == 0
779 || (cbTodo == 0 && pBuf->off))
780 {
781 suplibHardenedPrintStrN(pBuf->szBuf, pBuf->off);
782# ifdef RT_OS_WINDOWS
783 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
784 OutputDebugString(pBuf->szBuf);
785# endif
786 pBuf->off = 0;
787 cbSpace = sizeof(pBuf->szBuf) - 1;
788 }
789
790 /* Copy the string into the buffer. */
791 if (cbTodo == 1)
792 {
793 pBuf->szBuf[pBuf->off++] = *pachChars;
794 break;
795 }
796 if (cbSpace >= cbTodo)
797 {
798 memcpy(&pBuf->szBuf[pBuf->off], pachChars, cbTodo);
799 pBuf->off += cbTodo;
800 break;
801 }
802 memcpy(&pBuf->szBuf[pBuf->off], pachChars, cbSpace);
803 pBuf->off += cbSpace;
804 cbTodo -= cbSpace;
805 }
806 pBuf->szBuf[pBuf->off] = '\0';
807
808 return cbChars;
809}
810
811#endif /* IPRT_NO_CRT */
812
813/**
814 * Simple printf to standard error.
815 *
816 * @param pszFormat The format string.
817 * @param va Arguments to format.
818 */
819DECLHIDDEN(void) suplibHardenedPrintFV(const char *pszFormat, va_list va)
820{
821#ifdef IPRT_NO_CRT
822 /*
823 * Use buffered output here to avoid character mixing on the windows
824 * console and to enable us to use OutputDebugString.
825 */
826 SUPLIBHARDENEDOUTPUTBUF Buf;
827 Buf.off = 0;
828 Buf.szBuf[0] = '\0';
829 RTStrFormatV(suplibHardenedOutput, &Buf, NULL, NULL, pszFormat, va);
830
831#else /* !IPRT_NO_CRT */
832 /*
833 * Format loop.
834 */
835 char ch;
836 const char *pszLast = pszFormat;
837 for (;;)
838 {
839 ch = *pszFormat;
840 if (!ch)
841 break;
842 pszFormat++;
843
844 if (ch == '%')
845 {
846 /*
847 * Format argument.
848 */
849
850 /* Flush unwritten bits. */
851 if (pszLast != pszFormat - 1)
852 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast - 1);
853 pszLast = pszFormat;
854 ch = *pszFormat++;
855
856 /* flags. */
857 uint32_t fFlags = 0;
858 for (;;)
859 {
860 if (ch == '#') fFlags |= RTSTR_F_SPECIAL;
861 else if (ch == '-') fFlags |= RTSTR_F_LEFT;
862 else if (ch == '+') fFlags |= RTSTR_F_PLUS;
863 else if (ch == ' ') fFlags |= RTSTR_F_BLANK;
864 else if (ch == '0') fFlags |= RTSTR_F_ZEROPAD;
865 else if (ch == '\'') fFlags |= RTSTR_F_THOUSAND_SEP;
866 else break;
867 ch = *pszFormat++;
868 }
869
870 /* Width and precision - ignored. */
871 while (RT_C_IS_DIGIT(ch))
872 ch = *pszFormat++;
873 if (ch == '*')
874 va_arg(va, int);
875 if (ch == '.')
876 {
877 do ch = *pszFormat++;
878 while (RT_C_IS_DIGIT(ch));
879 if (ch == '*')
880 va_arg(va, int);
881 }
882
883 /* Size. */
884 char chArgSize = 0;
885 switch (ch)
886 {
887 case 'z':
888 case 'L':
889 case 'j':
890 case 't':
891 chArgSize = ch;
892 ch = *pszFormat++;
893 break;
894
895 case 'l':
896 chArgSize = ch;
897 ch = *pszFormat++;
898 if (ch == 'l')
899 {
900 chArgSize = 'L';
901 ch = *pszFormat++;
902 }
903 break;
904
905 case 'h':
906 chArgSize = ch;
907 ch = *pszFormat++;
908 if (ch == 'h')
909 {
910 chArgSize = 'H';
911 ch = *pszFormat++;
912 }
913 break;
914 }
915
916 /*
917 * Do type specific formatting.
918 */
919 switch (ch)
920 {
921 case 'c':
922 ch = (char)va_arg(va, int);
923 suplibHardenedPrintChr(ch);
924 break;
925
926 case 's':
927 if (chArgSize == 'l')
928 {
929 PCRTUTF16 pwszStr = va_arg(va, PCRTUTF16 );
930 if (RT_VALID_PTR(pwszStr))
931 suplibHardenedPrintWideStr(pwszStr);
932 else
933 suplibHardenedPrintStr("<NULL>");
934 }
935 else
936 {
937 const char *pszStr = va_arg(va, const char *);
938 if (!RT_VALID_PTR(pszStr))
939 pszStr = "<NULL>";
940 suplibHardenedPrintStr(pszStr);
941 }
942 break;
943
944 case 'd':
945 case 'i':
946 {
947 int64_t iValue;
948 if (chArgSize == 'L' || chArgSize == 'j')
949 iValue = va_arg(va, int64_t);
950 else if (chArgSize == 'l')
951 iValue = va_arg(va, signed long);
952 else if (chArgSize == 'z' || chArgSize == 't')
953 iValue = va_arg(va, intptr_t);
954 else
955 iValue = va_arg(va, signed int);
956 if (iValue < 0)
957 {
958 suplibHardenedPrintChr('-');
959 iValue = -iValue;
960 }
961 suplibHardenedPrintDecimal(iValue);
962 break;
963 }
964
965 case 'p':
966 case 'x':
967 case 'X':
968 case 'u':
969 case 'o':
970 {
971 unsigned uBase = 10;
972 uint64_t uValue;
973
974 switch (ch)
975 {
976 case 'p':
977 fFlags |= RTSTR_F_ZEROPAD; /* Note not standard behaviour (but I like it this way!) */
978 uBase = 16;
979 break;
980 case 'X':
981 fFlags |= RTSTR_F_CAPITAL;
982 case 'x':
983 uBase = 16;
984 break;
985 case 'u':
986 uBase = 10;
987 break;
988 case 'o':
989 uBase = 8;
990 break;
991 }
992
993 if (ch == 'p' || chArgSize == 'z' || chArgSize == 't')
994 uValue = va_arg(va, uintptr_t);
995 else if (chArgSize == 'L' || chArgSize == 'j')
996 uValue = va_arg(va, uint64_t);
997 else if (chArgSize == 'l')
998 uValue = va_arg(va, unsigned long);
999 else
1000 uValue = va_arg(va, unsigned int);
1001
1002 if (uBase == 10)
1003 suplibHardenedPrintDecimal(uValue);
1004 else
1005 suplibHardenedPrintHexOctal(uValue, uBase, fFlags);
1006 break;
1007 }
1008
1009 case 'R':
1010 if (pszFormat[0] == 'r' && pszFormat[1] == 'c')
1011 {
1012 int iValue = va_arg(va, int);
1013 if (iValue < 0)
1014 {
1015 suplibHardenedPrintChr('-');
1016 iValue = -iValue;
1017 }
1018 suplibHardenedPrintDecimal(iValue);
1019 pszFormat += 2;
1020 break;
1021 }
1022 /* fall thru */
1023
1024 /*
1025 * Custom format.
1026 */
1027 default:
1028 suplibHardenedPrintStr("[bad format: ");
1029 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast);
1030 suplibHardenedPrintChr(']');
1031 break;
1032 }
1033
1034 /* continue */
1035 pszLast = pszFormat;
1036 }
1037 }
1038
1039 /* Flush the last bits of the string. */
1040 if (pszLast != pszFormat)
1041 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast);
1042#endif /* !IPRT_NO_CRT */
1043}
1044
1045
1046/**
1047 * Prints to standard error.
1048 *
1049 * @param pszFormat The format string.
1050 * @param ... Arguments to format.
1051 */
1052DECLHIDDEN(void) suplibHardenedPrintF(const char *pszFormat, ...)
1053{
1054 va_list va;
1055 va_start(va, pszFormat);
1056 suplibHardenedPrintFV(pszFormat, va);
1057 va_end(va);
1058}
1059
1060
1061/**
1062 * @copydoc RTPathStripFilename
1063 */
1064static void suplibHardenedPathStripFilename(char *pszPath)
1065{
1066 char *psz = pszPath;
1067 char *pszLastSep = pszPath;
1068
1069 for (;; psz++)
1070 {
1071 switch (*psz)
1072 {
1073 /* handle separators. */
1074#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
1075 case ':':
1076 pszLastSep = psz + 1;
1077 break;
1078
1079 case '\\':
1080#endif
1081 case '/':
1082 pszLastSep = psz;
1083 break;
1084
1085 /* the end */
1086 case '\0':
1087 if (pszLastSep == pszPath)
1088 *pszLastSep++ = '.';
1089 *pszLastSep = '\0';
1090 return;
1091 }
1092 }
1093 /* will never get here */
1094}
1095
1096
1097/**
1098 * @copydoc RTPathFilename
1099 */
1100DECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath)
1101{
1102 const char *psz = pszPath;
1103 const char *pszLastComp = pszPath;
1104
1105 for (;; psz++)
1106 {
1107 switch (*psz)
1108 {
1109 /* handle separators. */
1110#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
1111 case ':':
1112 pszLastComp = psz + 1;
1113 break;
1114
1115 case '\\':
1116#endif
1117 case '/':
1118 pszLastComp = psz + 1;
1119 break;
1120
1121 /* the end */
1122 case '\0':
1123 if (*pszLastComp)
1124 return (char *)(void *)pszLastComp;
1125 return NULL;
1126 }
1127 }
1128
1129 /* will never get here */
1130}
1131
1132
1133/**
1134 * @copydoc RTPathAppPrivateNoArch
1135 */
1136DECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath)
1137{
1138#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
1139 const char *pszSrcPath = RTPATH_APP_PRIVATE;
1140 size_t cchPathPrivateNoArch = suplibHardenedStrLen(pszSrcPath);
1141 if (cchPathPrivateNoArch >= cchPath)
1142 supR3HardenedFatal("supR3HardenedPathAppPrivateNoArch: Buffer overflow, %zu >= %zu\n", cchPathPrivateNoArch, cchPath);
1143 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathPrivateNoArch + 1);
1144 return VINF_SUCCESS;
1145
1146#else
1147 return supR3HardenedPathAppBin(pszPath, cchPath);
1148#endif
1149}
1150
1151
1152/**
1153 * @copydoc RTPathAppPrivateArch
1154 */
1155DECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath)
1156{
1157#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE_ARCH)
1158 const char *pszSrcPath = RTPATH_APP_PRIVATE_ARCH;
1159 size_t cchPathPrivateArch = suplibHardenedStrLen(pszSrcPath);
1160 if (cchPathPrivateArch >= cchPath)
1161 supR3HardenedFatal("supR3HardenedPathAppPrivateArch: Buffer overflow, %zu >= %zu\n", cchPathPrivateArch, cchPath);
1162 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathPrivateArch + 1);
1163 return VINF_SUCCESS;
1164
1165#else
1166 return supR3HardenedPathAppBin(pszPath, cchPath);
1167#endif
1168}
1169
1170
1171/**
1172 * @copydoc RTPathSharedLibs
1173 */
1174DECLHIDDEN(int) supR3HardenedPathAppSharedLibs(char *pszPath, size_t cchPath)
1175{
1176#if !defined(RT_OS_WINDOWS) && defined(RTPATH_SHARED_LIBS)
1177 const char *pszSrcPath = RTPATH_SHARED_LIBS;
1178 size_t cchPathSharedLibs = suplibHardenedStrLen(pszSrcPath);
1179 if (cchPathSharedLibs >= cchPath)
1180 supR3HardenedFatal("supR3HardenedPathAppSharedLibs: Buffer overflow, %zu >= %zu\n", cchPathSharedLibs, cchPath);
1181 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathSharedLibs + 1);
1182 return VINF_SUCCESS;
1183
1184#else
1185 return supR3HardenedPathAppBin(pszPath, cchPath);
1186#endif
1187}
1188
1189
1190/**
1191 * @copydoc RTPathAppDocs
1192 */
1193DECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath)
1194{
1195#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_DOCS)
1196 const char *pszSrcPath = RTPATH_APP_DOCS;
1197 size_t cchPathAppDocs = suplibHardenedStrLen(pszSrcPath);
1198 if (cchPathAppDocs >= cchPath)
1199 supR3HardenedFatal("supR3HardenedPathAppDocs: Buffer overflow, %zu >= %zu\n", cchPathAppDocs, cchPath);
1200 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathAppDocs + 1);
1201 return VINF_SUCCESS;
1202
1203#else
1204 return supR3HardenedPathAppBin(pszPath, cchPath);
1205#endif
1206}
1207
1208
1209/**
1210 * Returns the full path to the executable in g_szSupLibHardenedExePath.
1211 *
1212 * @returns IPRT status code.
1213 */
1214static void supR3HardenedGetFullExePath(void)
1215{
1216 /*
1217 * Get the program filename.
1218 *
1219 * Most UNIXes have no API for obtaining the executable path, but provides a symbolic
1220 * link in the proc file system that tells who was exec'ed. The bad thing about this
1221 * is that we have to use readlink, one of the weirder UNIX APIs.
1222 *
1223 * Darwin, OS/2 and Windows all have proper APIs for getting the program file name.
1224 */
1225#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
1226# ifdef RT_OS_LINUX
1227 int cchLink = readlink("/proc/self/exe", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
1228
1229# elif defined(RT_OS_SOLARIS)
1230 char szFileBuf[PATH_MAX + 1];
1231 sprintf(szFileBuf, "/proc/%ld/path/a.out", (long)getpid());
1232 int cchLink = readlink(szFileBuf, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
1233
1234# else /* RT_OS_FREEBSD */
1235 int aiName[4];
1236 aiName[0] = CTL_KERN;
1237 aiName[1] = KERN_PROC;
1238 aiName[2] = KERN_PROC_PATHNAME;
1239 aiName[3] = getpid();
1240
1241 size_t cbPath = sizeof(g_szSupLibHardenedExePath);
1242 if (sysctl(aiName, RT_ELEMENTS(aiName), g_szSupLibHardenedExePath, &cbPath, NULL, 0) < 0)
1243 supR3HardenedFatal("supR3HardenedExecDir: sysctl failed\n");
1244 g_szSupLibHardenedExePath[sizeof(g_szSupLibHardenedExePath) - 1] = '\0';
1245 int cchLink = suplibHardenedStrLen(g_szSupLibHardenedExePath); /* paranoid? can't we use cbPath? */
1246
1247# endif
1248 if (cchLink < 0 || cchLink == sizeof(g_szSupLibHardenedExePath) - 1)
1249 supR3HardenedFatal("supR3HardenedExecDir: couldn't read \"%s\", errno=%d cchLink=%d\n",
1250 g_szSupLibHardenedExePath, errno, cchLink);
1251 g_szSupLibHardenedExePath[cchLink] = '\0';
1252
1253#elif defined(RT_OS_OS2) || defined(RT_OS_L4)
1254 _execname(g_szSupLibHardenedExePath, sizeof(g_szSupLibHardenedExePath));
1255
1256#elif defined(RT_OS_DARWIN)
1257 const char *pszImageName = _dyld_get_image_name(0);
1258 if (!pszImageName)
1259 supR3HardenedFatal("supR3HardenedExecDir: _dyld_get_image_name(0) failed\n");
1260 size_t cchImageName = suplibHardenedStrLen(pszImageName);
1261 if (!cchImageName || cchImageName >= sizeof(g_szSupLibHardenedExePath))
1262 supR3HardenedFatal("supR3HardenedExecDir: _dyld_get_image_name(0) failed, cchImageName=%d\n", cchImageName);
1263 suplibHardenedMemCopy(g_szSupLibHardenedExePath, pszImageName, cchImageName + 1);
1264
1265#elif defined(RT_OS_WINDOWS)
1266 char *pszDst = g_szSupLibHardenedExePath;
1267 int rc = RTUtf16ToUtf8Ex(g_wszSupLibHardenedExePath, RTSTR_MAX, &pszDst, sizeof(g_szSupLibHardenedExePath), NULL);
1268 if (RT_FAILURE(rc))
1269 supR3HardenedFatal("supR3HardenedExecDir: RTUtf16ToUtf8Ex failed, rc=%Rrc\n", rc);
1270#else
1271# error needs porting.
1272#endif
1273
1274 /*
1275 * Determine the application binary directory location.
1276 */
1277 suplibHardenedStrCopy(g_szSupLibHardenedAppBinPath, g_szSupLibHardenedExePath);
1278 suplibHardenedPathStripFilename(g_szSupLibHardenedAppBinPath);
1279
1280 if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED)
1281 supR3HardenedFatal("supR3HardenedExecDir: Called before SUPR3HardenedMain! (%d)\n", g_enmSupR3HardenedMainState);
1282 switch (g_fSupHardenedMain & SUPSECMAIN_FLAGS_LOC_MASK)
1283 {
1284 case SUPSECMAIN_FLAGS_LOC_APP_BIN:
1285 break;
1286 case SUPSECMAIN_FLAGS_LOC_TESTCASE:
1287 suplibHardenedPathStripFilename(g_szSupLibHardenedAppBinPath);
1288 break;
1289 default:
1290 supR3HardenedFatal("supR3HardenedExecDir: Unknown program binary location: %#x\n", g_fSupHardenedMain);
1291 }
1292}
1293
1294
1295#ifdef RT_OS_LINUX
1296/**
1297 * Checks if we can read /proc/self/exe.
1298 *
1299 * This is used on linux to see if we have to call init
1300 * with program path or not.
1301 *
1302 * @returns true / false.
1303 */
1304static bool supR3HardenedMainIsProcSelfExeAccssible(void)
1305{
1306 char szPath[RTPATH_MAX];
1307 int cchLink = readlink("/proc/self/exe", szPath, sizeof(szPath));
1308 return cchLink != -1;
1309}
1310#endif /* RT_OS_LINUX */
1311
1312
1313
1314/**
1315 * @copydoc RTPathExecDir
1316 * @remarks not quite like RTPathExecDir actually...
1317 */
1318DECLHIDDEN(int) supR3HardenedPathAppBin(char *pszPath, size_t cchPath)
1319{
1320 /*
1321 * Lazy init (probably not required).
1322 */
1323 if (!g_szSupLibHardenedAppBinPath[0])
1324 supR3HardenedGetFullExePath();
1325
1326 /*
1327 * Calc the length and check if there is space before copying.
1328 */
1329 size_t cch = suplibHardenedStrLen(g_szSupLibHardenedAppBinPath) + 1;
1330 if (cch <= cchPath)
1331 {
1332 suplibHardenedMemCopy(pszPath, g_szSupLibHardenedAppBinPath, cch + 1);
1333 return VINF_SUCCESS;
1334 }
1335
1336 supR3HardenedFatal("supR3HardenedPathAppBin: Buffer too small (%u < %u)\n", cchPath, cch);
1337 /* not reached */
1338}
1339
1340
1341#ifdef RT_OS_WINDOWS
1342extern "C" uint32_t g_uNtVerCombined;
1343#endif
1344
1345DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
1346{
1347 static const char s_szLogOption[] = "--sup-hardening-log=";
1348
1349 /*
1350 * Scan the argument vector.
1351 */
1352 int cArgs = *pcArgs;
1353 for (int iArg = 1; iArg < cArgs; iArg++)
1354 if (strncmp(papszArgs[iArg], s_szLogOption, sizeof(s_szLogOption) - 1) == 0)
1355 {
1356#ifdef RT_OS_WINDOWS
1357 const char *pszLogFile = &papszArgs[iArg][sizeof(s_szLogOption) - 1];
1358#endif
1359
1360 /*
1361 * Drop the argument from the vector (has trailing NULL entry).
1362 */
1363 memmove(&papszArgs[iArg], &papszArgs[iArg + 1], (cArgs - iArg) * sizeof(papszArgs[0]));
1364 *pcArgs -= 1;
1365 cArgs -= 1;
1366
1367 /*
1368 * Open the log file, unless we've already opened one.
1369 * First argument takes precedence
1370 */
1371#ifdef RT_OS_WINDOWS
1372 if (g_hStartupLog == NULL)
1373 {
1374 int rc = RTNtPathOpen(pszLogFile,
1375 GENERIC_WRITE | SYNCHRONIZE,
1376 FILE_ATTRIBUTE_NORMAL,
1377 FILE_SHARE_READ | FILE_SHARE_WRITE,
1378 FILE_OPEN_IF,
1379 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1380 OBJ_CASE_INSENSITIVE,
1381 &g_hStartupLog,
1382 NULL);
1383 if (RT_SUCCESS(rc))
1384 {
1385 SUP_DPRINTF(("Log file opened: " VBOX_VERSION_STRING "r%u g_hStartupLog=%p g_uNtVerCombined=%#x\n",
1386 VBOX_SVN_REV, g_hStartupLog, g_uNtVerCombined));
1387
1388 /*
1389 * If the path contains a drive volume, save it so we can
1390 * use it to flush the volume containing the log file.
1391 */
1392 if (RT_C_IS_ALPHA(pszLogFile[0]) && pszLogFile[1] == ':')
1393 {
1394 RTUtf16CopyAscii(g_wszStartupLogVol, RT_ELEMENTS(g_wszStartupLogVol), "\\??\\");
1395 g_wszStartupLogVol[sizeof("\\??\\") - 1] = RT_C_TO_UPPER(pszLogFile[0]);
1396 g_wszStartupLogVol[sizeof("\\??\\") + 0] = ':';
1397 g_wszStartupLogVol[sizeof("\\??\\") + 1] = '\0';
1398 }
1399 }
1400 else
1401 g_hStartupLog = NULL;
1402 }
1403#else
1404 RT_NOREF(g_hStartupLog, g_cbStartupLog);
1405 //g_hStartupLog = open()
1406#endif
1407 }
1408}
1409
1410
1411DECLHIDDEN(void) supR3HardenedLogV(const char *pszFormat, va_list va)
1412{
1413#ifdef RT_OS_WINDOWS
1414 if ( g_hStartupLog != NULL
1415 && g_cbStartupLog < 16*_1M)
1416 {
1417 char szBuf[5120];
1418 PCLIENT_ID pSelfId = &((PTEB)NtCurrentTeb())->ClientId;
1419 size_t cchPrefix = RTStrPrintf(szBuf, sizeof(szBuf), "%x.%x: ", pSelfId->UniqueProcess, pSelfId->UniqueThread);
1420 size_t cch = RTStrPrintfV(&szBuf[cchPrefix], sizeof(szBuf) - cchPrefix, pszFormat, va) + cchPrefix;
1421
1422 if ((size_t)cch >= sizeof(szBuf))
1423 cch = sizeof(szBuf) - 1;
1424
1425 if (!cch || szBuf[cch - 1] != '\n')
1426 szBuf[cch++] = '\n';
1427
1428 ASMAtomicAddU32(&g_cbStartupLog, (uint32_t)cch);
1429
1430 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1431 LARGE_INTEGER Offset;
1432 Offset.QuadPart = -1; /* Write to end of file. */
1433 NtWriteFile(g_hStartupLog, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
1434 &Ios, szBuf, (ULONG)cch, &Offset, NULL /*Key*/);
1435 }
1436#else
1437 RT_NOREF(pszFormat, va);
1438 /* later */
1439#endif
1440}
1441
1442
1443DECLHIDDEN(void) supR3HardenedLog(const char *pszFormat, ...)
1444{
1445 va_list va;
1446 va_start(va, pszFormat);
1447 supR3HardenedLogV(pszFormat, va);
1448 va_end(va);
1449}
1450
1451
1452DECLHIDDEN(void) supR3HardenedLogFlush(void)
1453{
1454#ifdef RT_OS_WINDOWS
1455 if ( g_hStartupLog != NULL
1456 && g_cbStartupLog < 16*_1M)
1457 {
1458 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1459 NTSTATUS rcNt = NtFlushBuffersFile(g_hStartupLog, &Ios);
1460
1461 /*
1462 * Try flush the volume containing the log file too.
1463 */
1464 if (g_wszStartupLogVol[0])
1465 {
1466 HANDLE hLogVol = RTNT_INVALID_HANDLE_VALUE;
1467 UNICODE_STRING NtName;
1468 NtName.Buffer = g_wszStartupLogVol;
1469 NtName.Length = (USHORT)(RTUtf16Len(g_wszStartupLogVol) * sizeof(RTUTF16));
1470 NtName.MaximumLength = NtName.Length + 1;
1471 OBJECT_ATTRIBUTES ObjAttr;
1472 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
1473 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
1474 rcNt = NtCreateFile(&hLogVol,
1475 GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1476 &ObjAttr,
1477 &Ios,
1478 NULL /* Allocation Size*/,
1479 0 /*FileAttributes*/,
1480 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1481 FILE_OPEN,
1482 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1483 NULL /*EaBuffer*/,
1484 0 /*EaLength*/);
1485 if (NT_SUCCESS(rcNt))
1486 rcNt = Ios.Status;
1487 if (NT_SUCCESS(rcNt))
1488 {
1489 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
1490 rcNt = NtFlushBuffersFile(hLogVol, &Ios);
1491 NtClose(hLogVol);
1492 }
1493 else
1494 {
1495 /* This may have sideeffects similar to what we want... */
1496 hLogVol = RTNT_INVALID_HANDLE_VALUE;
1497 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
1498 rcNt = NtCreateFile(&hLogVol,
1499 GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1500 &ObjAttr,
1501 &Ios,
1502 NULL /* Allocation Size*/,
1503 0 /*FileAttributes*/,
1504 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1505 FILE_OPEN,
1506 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1507 NULL /*EaBuffer*/,
1508 0 /*EaLength*/);
1509 if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status))
1510 NtClose(hLogVol);
1511 }
1512 }
1513 }
1514#else
1515 /* later */
1516#endif
1517}
1518
1519
1520/**
1521 * Prints the message prefix.
1522 */
1523static void suplibHardenedPrintPrefix(void)
1524{
1525 if (g_pszSupLibHardenedProgName)
1526 suplibHardenedPrintStr(g_pszSupLibHardenedProgName);
1527 suplibHardenedPrintStr(": ");
1528}
1529
1530
1531DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc,
1532 const char *pszMsgFmt, va_list va)
1533{
1534 /*
1535 * First to the log.
1536 */
1537 supR3HardenedLog("Error %d in %s! (enmWhat=%d)\n", rc, pszWhere, enmWhat);
1538 va_list vaCopy;
1539 va_copy(vaCopy, va);
1540 supR3HardenedLogV(pszMsgFmt, vaCopy);
1541 va_end(vaCopy);
1542
1543#ifdef RT_OS_WINDOWS
1544 /*
1545 * The release log.
1546 */
1547 if (g_pfnRTLogRelPrintf)
1548 {
1549 va_copy(vaCopy, va);
1550 g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %s enmWhat=%d rc=%Rrc (%#x)\n", pszWhere, enmWhat, rc);
1551 g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %N\n", pszMsgFmt, &vaCopy);
1552 va_end(vaCopy);
1553 }
1554#endif
1555
1556 /*
1557 * Then to the console.
1558 */
1559 suplibHardenedPrintPrefix();
1560 suplibHardenedPrintF("Error %d in %s!\n", rc, pszWhere);
1561
1562 suplibHardenedPrintPrefix();
1563 va_copy(vaCopy, va);
1564 suplibHardenedPrintFV(pszMsgFmt, vaCopy);
1565 va_end(vaCopy);
1566 suplibHardenedPrintChr('\n');
1567
1568 switch (enmWhat)
1569 {
1570 case kSupInitOp_Driver:
1571 suplibHardenedPrintChr('\n');
1572 suplibHardenedPrintPrefix();
1573 suplibHardenedPrintStr("Tip! Make sure the kernel module is loaded. It may also help to reinstall VirtualBox.\n");
1574 break;
1575
1576 case kSupInitOp_Misc:
1577 case kSupInitOp_IPRT:
1578 case kSupInitOp_Integrity:
1579 case kSupInitOp_RootCheck:
1580 suplibHardenedPrintChr('\n');
1581 suplibHardenedPrintPrefix();
1582 suplibHardenedPrintStr("Tip! It may help to reinstall VirtualBox.\n");
1583 break;
1584
1585 default:
1586 /* no hints here */
1587 break;
1588 }
1589
1590 /*
1591 * Finally, TrustedError if appropriate.
1592 */
1593 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
1594 {
1595#ifdef SUP_HARDENED_SUID
1596 /*
1597 * Drop any root privileges we might be holding, this won't return
1598 * if it fails but end up calling supR3HardenedFatal[V].
1599 */
1600 supR3HardenedMainDropPrivileges();
1601#endif
1602
1603 /*
1604 * Now try resolve and call the TrustedError entry point if we can
1605 * find it. We'll fork before we attempt this because that way the
1606 * session management in main will see us exiting immediately (if
1607 * it's involved with us).
1608 */
1609#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
1610 int pid = fork();
1611 if (pid <= 0)
1612#endif
1613 {
1614 static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
1615 if (!s_fRecursive)
1616 {
1617 s_fRecursive = true;
1618
1619 PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
1620 if (pfnTrustedError)
1621 pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
1622
1623 s_fRecursive = false;
1624 }
1625 }
1626 }
1627#if defined(RT_OS_WINDOWS)
1628 /*
1629 * Report the error to the parent if this happens during early VM init.
1630 */
1631 else if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
1632 && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
1633 supR3HardenedWinReportErrorToParent(pszWhere, enmWhat, rc, pszMsgFmt, va);
1634#endif
1635
1636 /*
1637 * Quit
1638 */
1639 suplibHardenedExit(RTEXITCODE_FAILURE);
1640}
1641
1642
1643DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc,
1644 const char *pszMsgFmt, ...)
1645{
1646 va_list va;
1647 va_start(va, pszMsgFmt);
1648 supR3HardenedFatalMsgV(pszWhere, enmWhat, rc, pszMsgFmt, va);
1649 /* not reached */
1650}
1651
1652
1653DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatalV(const char *pszFormat, va_list va)
1654{
1655 supR3HardenedLog("Fatal error:\n");
1656 va_list vaCopy;
1657 va_copy(vaCopy, va);
1658 supR3HardenedLogV(pszFormat, vaCopy);
1659 va_end(vaCopy);
1660
1661#if defined(RT_OS_WINDOWS)
1662 /*
1663 * Report the error to the parent if this happens during early VM init.
1664 */
1665 if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
1666 && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
1667 supR3HardenedWinReportErrorToParent(NULL, kSupInitOp_Invalid, VERR_INTERNAL_ERROR, pszFormat, va);
1668 else
1669#endif
1670 {
1671#ifdef RT_OS_WINDOWS
1672 if (g_pfnRTLogRelPrintf)
1673 {
1674 va_copy(vaCopy, va);
1675 g_pfnRTLogRelPrintf("supR3HardenedFatalV: %N", pszFormat, &vaCopy);
1676 va_end(vaCopy);
1677 }
1678#endif
1679
1680 suplibHardenedPrintPrefix();
1681 suplibHardenedPrintFV(pszFormat, va);
1682 }
1683
1684 suplibHardenedExit(RTEXITCODE_FAILURE);
1685}
1686
1687
1688DECL_NO_RETURN(DECLHIDDEN(void)) supR3HardenedFatal(const char *pszFormat, ...)
1689{
1690 va_list va;
1691 va_start(va, pszFormat);
1692 supR3HardenedFatalV(pszFormat, va);
1693 /* not reached */
1694}
1695
1696
1697DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va)
1698{
1699 if (fFatal)
1700 supR3HardenedFatalV(pszFormat, va);
1701
1702 supR3HardenedLog("Error (rc=%d):\n", rc);
1703 va_list vaCopy;
1704 va_copy(vaCopy, va);
1705 supR3HardenedLogV(pszFormat, vaCopy);
1706 va_end(vaCopy);
1707
1708#ifdef RT_OS_WINDOWS
1709 if (g_pfnRTLogRelPrintf)
1710 {
1711 va_copy(vaCopy, va);
1712 g_pfnRTLogRelPrintf("supR3HardenedErrorV: %N", pszFormat, &vaCopy);
1713 va_end(vaCopy);
1714 }
1715#endif
1716
1717 suplibHardenedPrintPrefix();
1718 suplibHardenedPrintFV(pszFormat, va);
1719
1720 return rc;
1721}
1722
1723
1724DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...)
1725{
1726 va_list va;
1727 va_start(va, pszFormat);
1728 supR3HardenedErrorV(rc, fFatal, pszFormat, va);
1729 va_end(va);
1730 return rc;
1731}
1732
1733
1734
1735/**
1736 * Attempts to open /dev/vboxdrv (or equvivalent).
1737 *
1738 * @remarks This function will not return on failure.
1739 */
1740DECLHIDDEN(void) supR3HardenedMainOpenDevice(void)
1741{
1742 RTERRINFOSTATIC ErrInfo;
1743 SUPINITOP enmWhat = kSupInitOp_Driver;
1744 int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/,
1745 &enmWhat, RTErrInfoInitStatic(&ErrInfo));
1746 if (RT_SUCCESS(rc))
1747 return;
1748
1749 if (RTErrInfoIsSet(&ErrInfo.Core))
1750 supR3HardenedFatalMsg("suplibOsInit", enmWhat, rc, "%s", ErrInfo.szMsg);
1751
1752 switch (rc)
1753 {
1754 /** @todo better messages! */
1755 case VERR_VM_DRIVER_NOT_INSTALLED:
1756 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not installed");
1757 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
1758 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not accessible");
1759 case VERR_VM_DRIVER_LOAD_ERROR:
1760 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_LOAD_ERROR");
1761 case VERR_VM_DRIVER_OPEN_ERROR:
1762 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_OPEN_ERROR");
1763 case VERR_VM_DRIVER_VERSION_MISMATCH:
1764 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver version mismatch");
1765 case VERR_ACCESS_DENIED:
1766 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_ACCESS_DENIED");
1767 case VERR_NO_MEMORY:
1768 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel memory allocation/mapping failed");
1769 case VERR_SUPDRV_HARDENING_EVIL_HANDLE:
1770 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
1771 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0:
1772 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0");
1773 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1:
1774 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1");
1775 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2:
1776 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
1777 default:
1778 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Unknown rc=%d (%Rrc)", rc, rc);
1779 }
1780}
1781
1782
1783#ifdef SUP_HARDENED_SUID
1784
1785/**
1786 * Grabs extra non-root capabilities / privileges that we might require.
1787 *
1788 * This is currently only used for being able to do ICMP from the NAT engine.
1789 *
1790 * @note We still have root privileges at the time of this call.
1791 */
1792static void supR3HardenedMainGrabCapabilites(void)
1793{
1794# if defined(RT_OS_LINUX)
1795 /*
1796 * We are about to drop all our privileges. Remove all capabilities but
1797 * keep the cap_net_raw capability for ICMP sockets for the NAT stack.
1798 */
1799 if (g_uCaps != 0)
1800 {
1801# ifdef USE_LIB_PCAP
1802 /* XXX cap_net_bind_service */
1803 if (!cap_set_proc(cap_from_text("all-eip cap_net_raw+ep")))
1804 prctl(PR_SET_KEEPCAPS, 1 /*keep=*/, 0, 0, 0);
1805 prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0);
1806# else
1807 cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
1808 cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
1809 memset(hdr, 0, sizeof(*hdr));
1810 hdr->version = _LINUX_CAPABILITY_VERSION;
1811 memset(cap, 0, sizeof(*cap));
1812 cap->effective = g_uCaps;
1813 cap->permitted = g_uCaps;
1814 if (!capset(hdr, cap))
1815 prctl(PR_SET_KEEPCAPS, 1 /*keep*/, 0, 0, 0);
1816 prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0);
1817# endif /* !USE_LIB_PCAP */
1818 }
1819
1820# elif defined(RT_OS_SOLARIS)
1821 /*
1822 * Add net_icmpaccess privilege to effective privileges and limit
1823 * permitted privileges before completely dropping root privileges.
1824 * This requires dropping root privileges temporarily to get the normal
1825 * user's privileges.
1826 */
1827 seteuid(g_uid);
1828 priv_set_t *pPrivEffective = priv_allocset();
1829 priv_set_t *pPrivNew = priv_allocset();
1830 if (pPrivEffective && pPrivNew)
1831 {
1832 int rc = getppriv(PRIV_EFFECTIVE, pPrivEffective);
1833 seteuid(0);
1834 if (!rc)
1835 {
1836 priv_copyset(pPrivEffective, pPrivNew);
1837 rc = priv_addset(pPrivNew, PRIV_NET_ICMPACCESS);
1838 if (!rc)
1839 {
1840 /* Order is important, as one can't set a privilege which is
1841 * not in the permitted privilege set. */
1842 rc = setppriv(PRIV_SET, PRIV_EFFECTIVE, pPrivNew);
1843 if (rc)
1844 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set effective privilege set.\n");
1845 rc = setppriv(PRIV_SET, PRIV_PERMITTED, pPrivNew);
1846 if (rc)
1847 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set permitted privilege set.\n");
1848 }
1849 else
1850 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to add NET_ICMPACCESS privilege.\n");
1851 }
1852 }
1853 else
1854 {
1855 /* for memory allocation failures just continue */
1856 seteuid(0);
1857 }
1858
1859 if (pPrivEffective)
1860 priv_freeset(pPrivEffective);
1861 if (pPrivNew)
1862 priv_freeset(pPrivNew);
1863# endif
1864}
1865
1866/*
1867 * Look at the environment for some special options.
1868 */
1869static void supR3GrabOptions(void)
1870{
1871# ifdef RT_OS_LINUX
1872 g_uCaps = 0;
1873
1874 /*
1875 * Do _not_ perform any capability-related system calls for root processes
1876 * (leaving g_uCaps at 0).
1877 * (Hint: getuid gets the real user id, not the effective.)
1878 */
1879 if (getuid() != 0)
1880 {
1881 /*
1882 * CAP_NET_RAW.
1883 * Default: enabled.
1884 * Can be disabled with 'export VBOX_HARD_CAP_NET_RAW=0'.
1885 */
1886 const char *pszOpt = getenv("VBOX_HARD_CAP_NET_RAW");
1887 if ( !pszOpt
1888 || memcmp(pszOpt, "0", sizeof("0")) != 0)
1889 g_uCaps = CAP_TO_MASK(CAP_NET_RAW);
1890
1891 /*
1892 * CAP_NET_BIND_SERVICE.
1893 * Default: disabled.
1894 * Can be enabled with 'export VBOX_HARD_CAP_NET_BIND_SERVICE=1'.
1895 */
1896 pszOpt = getenv("VBOX_HARD_CAP_NET_BIND_SERVICE");
1897 if ( pszOpt
1898 && memcmp(pszOpt, "0", sizeof("0")) != 0)
1899 g_uCaps |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
1900 }
1901# endif
1902}
1903
1904/**
1905 * Drop any root privileges we might be holding.
1906 */
1907static void supR3HardenedMainDropPrivileges(void)
1908{
1909 /*
1910 * Try use setre[ug]id since this will clear the save uid/gid and thus
1911 * leave fewer traces behind that libs like GTK+ may pick up.
1912 */
1913 uid_t euid, ruid, suid;
1914 gid_t egid, rgid, sgid;
1915# if defined(RT_OS_DARWIN)
1916 /* The really great thing here is that setreuid isn't available on
1917 OS X 10.4, libc emulates it. While 10.4 have a slightly different and
1918 non-standard setuid implementation compared to 10.5, the following
1919 works the same way with both version since we're super user (10.5 req).
1920 The following will set all three variants of the group and user IDs. */
1921 setgid(g_gid);
1922 setuid(g_uid);
1923 euid = geteuid();
1924 ruid = suid = getuid();
1925 egid = getegid();
1926 rgid = sgid = getgid();
1927
1928# elif defined(RT_OS_SOLARIS)
1929 /* Solaris doesn't have setresuid, but the setreuid interface is BSD
1930 compatible and will set the saved uid to euid when we pass it a ruid
1931 that isn't -1 (which we do). */
1932 setregid(g_gid, g_gid);
1933 setreuid(g_uid, g_uid);
1934 euid = geteuid();
1935 ruid = suid = getuid();
1936 egid = getegid();
1937 rgid = sgid = getgid();
1938
1939# else
1940 /* This is the preferred one, full control no questions about semantics.
1941 PORTME: If this isn't work, try join one of two other gangs above. */
1942 int res = setresgid(g_gid, g_gid, g_gid);
1943 NOREF(res);
1944 res = setresuid(g_uid, g_uid, g_uid);
1945 NOREF(res);
1946 if (getresuid(&ruid, &euid, &suid) != 0)
1947 {
1948 euid = geteuid();
1949 ruid = suid = getuid();
1950 }
1951 if (getresgid(&rgid, &egid, &sgid) != 0)
1952 {
1953 egid = getegid();
1954 rgid = sgid = getgid();
1955 }
1956# endif
1957
1958
1959 /* Check that it worked out all right. */
1960 if ( euid != g_uid
1961 || ruid != g_uid
1962 || suid != g_uid
1963 || egid != g_gid
1964 || rgid != g_gid
1965 || sgid != g_gid)
1966 supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!"
1967 " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n",
1968 euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid);
1969
1970# if RT_OS_LINUX
1971 /*
1972 * Re-enable the cap_net_raw capability which was disabled during setresuid.
1973 */
1974 if (g_uCaps != 0)
1975 {
1976# ifdef USE_LIB_PCAP
1977 /** @todo Warn if that does not work? */
1978 /* XXX cap_net_bind_service */
1979 cap_set_proc(cap_from_text("cap_net_raw+ep"));
1980# else
1981 cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
1982 cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
1983 memset(hdr, 0, sizeof(*hdr));
1984 hdr->version = _LINUX_CAPABILITY_VERSION;
1985 memset(cap, 0, sizeof(*cap));
1986 cap->effective = g_uCaps;
1987 cap->permitted = g_uCaps;
1988 /** @todo Warn if that does not work? */
1989 capset(hdr, cap);
1990# endif /* !USE_LIB_PCAP */
1991 }
1992# endif
1993}
1994
1995#endif /* SUP_HARDENED_SUID */
1996
1997/**
1998 * Loads the VBoxRT DLL/SO/DYLIB, hands it the open driver,
1999 * and calls RTR3InitEx.
2000 *
2001 * @param fFlags The SUPR3HardenedMain fFlags argument, passed to supR3PreInit.
2002 *
2003 * @remarks VBoxRT contains both IPRT and SUPR3.
2004 * @remarks This function will not return on failure.
2005 */
2006static void supR3HardenedMainInitRuntime(uint32_t fFlags)
2007{
2008 /*
2009 * Construct the name.
2010 */
2011 char szPath[RTPATH_MAX];
2012 supR3HardenedPathAppSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxRT" SUPLIB_DLL_SUFF));
2013 suplibHardenedStrCat(szPath, "/VBoxRT" SUPLIB_DLL_SUFF);
2014
2015 /*
2016 * Open it and resolve the symbols.
2017 */
2018#if defined(RT_OS_WINDOWS)
2019 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/, g_fSupHardenedMain);
2020 if (!hMod)
2021 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
2022 "LoadLibrary \"%s\" failed (rc=%d)",
2023 szPath, RtlGetLastWin32Error());
2024 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
2025 if (!pfnRTInitEx)
2026 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2027 "Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
2028 szPath, RtlGetLastWin32Error());
2029
2030 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
2031 if (!pfnSUPPreInit)
2032 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2033 "Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
2034 szPath, RtlGetLastWin32Error());
2035
2036 g_pfnRTLogRelPrintf = (PFNRTLOGRELPRINTF)GetProcAddress(hMod, SUP_HARDENED_SYM("RTLogRelPrintf"));
2037 Assert(g_pfnRTLogRelPrintf); /* Not fatal in non-strict builds. */
2038
2039#else
2040 /* the dlopen crowd */
2041 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
2042 if (!pvMod)
2043 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
2044 "dlopen(\"%s\",) failed: %s",
2045 szPath, dlerror());
2046 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("RTR3InitEx"));
2047 if (!pfnRTInitEx)
2048 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2049 "Entrypoint \"RTR3InitEx\" not found in \"%s\"!\ndlerror: %s",
2050 szPath, dlerror());
2051 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
2052 if (!pfnSUPPreInit)
2053 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
2054 "Entrypoint \"supR3PreInit\" not found in \"%s\"!\ndlerror: %s",
2055 szPath, dlerror());
2056#endif
2057
2058 /*
2059 * Make the calls.
2060 */
2061 supR3HardenedGetPreInitData(&g_SupPreInitData);
2062 int rc = pfnSUPPreInit(&g_SupPreInitData, fFlags);
2063 if (RT_FAILURE(rc))
2064 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
2065 "supR3PreInit failed with rc=%d", rc);
2066 const char *pszExePath = NULL;
2067#ifdef RT_OS_LINUX
2068 if (!supR3HardenedMainIsProcSelfExeAccssible())
2069 pszExePath = g_szSupLibHardenedExePath;
2070#endif
2071 rc = pfnRTInitEx(RTR3INIT_VER_1,
2072 fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV ? 0 : RTR3INIT_FLAGS_SUPLIB,
2073 0 /*cArgs*/, NULL /*papszArgs*/, pszExePath);
2074 if (RT_FAILURE(rc))
2075 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
2076 "RTR3InitEx failed with rc=%d", rc);
2077
2078#if defined(RT_OS_WINDOWS)
2079 /*
2080 * Windows: Create thread that terminates the process when the parent stub
2081 * process terminates (VBoxNetDHCP, Ctrl-C, etc).
2082 */
2083 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
2084 supR3HardenedWinCreateParentWatcherThread(hMod);
2085#endif
2086}
2087
2088
2089/**
2090 * Construct the path to the DLL/SO/DYLIB containing the actual program.
2091 *
2092 * @returns VBox status code.
2093 * @param pszProgName The program name.
2094 * @param fMainFlags The flags passed to SUPR3HardenedMain.
2095 * @param pszPath The output buffer.
2096 * @param cbPath The size of the output buffer, in bytes. Must be at
2097 * least 128 bytes!
2098 */
2099static int supR3HardenedMainGetTrustedLib(const char *pszProgName, uint32_t fMainFlags, char *pszPath, size_t cbPath)
2100{
2101 supR3HardenedPathAppPrivateArch(pszPath, sizeof(cbPath) - 10);
2102 const char *pszSubDirSlash;
2103 switch (g_fSupHardenedMain & SUPSECMAIN_FLAGS_LOC_MASK)
2104 {
2105 case SUPSECMAIN_FLAGS_LOC_APP_BIN:
2106 pszSubDirSlash = "/";
2107 break;
2108 case SUPSECMAIN_FLAGS_LOC_TESTCASE:
2109 pszSubDirSlash = "/testcase/";
2110 break;
2111 default:
2112 pszSubDirSlash = "/";
2113 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Unknown program binary location: %#x\n", g_fSupHardenedMain);
2114 }
2115#ifdef RT_OS_DARWIN
2116 if (fMainFlags & SUPSECMAIN_FLAGS_OSX_VM_APP)
2117 pszProgName = "VirtualBox";
2118#else
2119 RT_NOREF1(fMainFlags);
2120#endif
2121 size_t cch = suplibHardenedStrLen(pszPath);
2122 return suplibHardenedStrCopyEx(&pszPath[cch], cbPath - cch, pszSubDirSlash, pszProgName, SUPLIB_DLL_SUFF, NULL);
2123}
2124
2125
2126/**
2127 * Loads the DLL/SO/DYLIB containing the actual program and
2128 * resolves the TrustedError symbol.
2129 *
2130 * This is very similar to supR3HardenedMainGetTrustedMain().
2131 *
2132 * @returns Pointer to the trusted error symbol if it is exported, NULL
2133 * and no error messages otherwise.
2134 * @param pszProgName The program name.
2135 */
2136static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
2137{
2138 /*
2139 * Don't bother if the main() function didn't advertise any TrustedError
2140 * export. It's both a waste of time and may trigger additional problems,
2141 * confusing or obscuring the original issue.
2142 */
2143 if (!(g_fSupHardenedMain & SUPSECMAIN_FLAGS_TRUSTED_ERROR))
2144 return NULL;
2145
2146 /*
2147 * Construct the name.
2148 */
2149 char szPath[RTPATH_MAX];
2150 supR3HardenedMainGetTrustedLib(pszProgName, g_fSupHardenedMain, szPath, sizeof(szPath));
2151
2152 /*
2153 * Open it and resolve the symbol.
2154 */
2155#if defined(RT_OS_WINDOWS)
2156 supR3HardenedWinEnableThreadCreation();
2157 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/, 0 /*fMainFlags*/);
2158 if (!hMod)
2159 return NULL;
2160 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
2161 if (!pfn)
2162 return NULL;
2163 return (PFNSUPTRUSTEDERROR)pfn;
2164
2165#else
2166 /* the dlopen crowd */
2167 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
2168 if (!pvMod)
2169 return NULL;
2170 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
2171 if (!pvSym)
2172 return NULL;
2173 return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
2174#endif
2175}
2176
2177
2178/**
2179 * Loads the DLL/SO/DYLIB containing the actual program and
2180 * resolves the TrustedMain symbol.
2181 *
2182 * @returns Pointer to the trusted main of the actual program.
2183 * @param pszProgName The program name.
2184 * @param fMainFlags The flags passed to SUPR3HardenedMain.
2185 * @remarks This function will not return on failure.
2186 */
2187static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName, uint32_t fMainFlags)
2188{
2189 /*
2190 * Construct the name.
2191 */
2192 char szPath[RTPATH_MAX];
2193 supR3HardenedMainGetTrustedLib(pszProgName, fMainFlags, szPath, sizeof(szPath));
2194
2195 /*
2196 * Open it and resolve the symbol.
2197 */
2198#if defined(RT_OS_WINDOWS)
2199 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/, 0 /*fMainFlags*/);
2200 if (!hMod)
2201 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibrary \"%s\" failed, rc=%d\n",
2202 szPath, RtlGetLastWin32Error());
2203 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
2204 if (!pfn)
2205 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
2206 szPath, RtlGetLastWin32Error());
2207 return (PFNSUPTRUSTEDMAIN)pfn;
2208
2209#else
2210 /* the dlopen crowd */
2211 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
2212 if (!pvMod)
2213 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
2214 szPath, dlerror());
2215 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
2216 if (!pvSym)
2217 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
2218 szPath, dlerror());
2219 return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
2220#endif
2221}
2222
2223
2224/**
2225 * Secure main.
2226 *
2227 * This is used for the set-user-ID-on-execute binaries on unixy systems
2228 * and when using the open-vboxdrv-via-root-service setup on Windows.
2229 *
2230 * This function will perform the integrity checks of the VirtualBox
2231 * installation, open the support driver, open the root service (later),
2232 * and load the DLL corresponding to \a pszProgName and execute its main
2233 * function.
2234 *
2235 * @returns Return code appropriate for main().
2236 *
2237 * @param pszProgName The program name. This will be used to figure out which
2238 * DLL/SO/DYLIB to load and execute.
2239 * @param fFlags Flags.
2240 * @param argc The argument count.
2241 * @param argv The argument vector.
2242 * @param envp The environment vector.
2243 */
2244DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
2245{
2246 SUP_DPRINTF(("SUPR3HardenedMain: pszProgName=%s fFlags=%#x\n", pszProgName, fFlags));
2247 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED;
2248
2249 /*
2250 * Note! At this point there is no IPRT, so we will have to stick
2251 * to basic CRT functions that everyone agree upon.
2252 */
2253 g_pszSupLibHardenedProgName = pszProgName;
2254 g_fSupHardenedMain = fFlags;
2255 g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
2256 g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
2257#ifdef RT_OS_WINDOWS
2258 if (!g_fSupEarlyProcessInit)
2259#endif
2260 g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
2261
2262 /*
2263 * Determine the full exe path as we'll be needing it for the verify all
2264 * call(s) below. (We have to do this early on Linux because we * *might*
2265 * not be able to access /proc/self/exe after the seteuid call.)
2266 */
2267 supR3HardenedGetFullExePath();
2268#ifdef RT_OS_WINDOWS
2269 supR3HardenedWinInitAppBin(fFlags);
2270#endif
2271
2272#ifdef SUP_HARDENED_SUID
2273 /*
2274 * Grab any options from the environment.
2275 */
2276 supR3GrabOptions();
2277
2278 /*
2279 * Check that we're root, if we aren't then the installation is butchered.
2280 */
2281 g_uid = getuid();
2282 g_gid = getgid();
2283 if (geteuid() != 0 /* root */)
2284 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
2285 "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
2286 geteuid(), getegid(), g_uid, g_gid);
2287#endif /* SUP_HARDENED_SUID */
2288
2289#ifdef RT_OS_WINDOWS
2290 /*
2291 * Windows: First respawn. On Windows we will respawn the process twice to establish
2292 * something we can put some kind of reliable trust in. The first respawning aims
2293 * at dropping compatibility layers and process "security" solutions.
2294 */
2295 if ( !g_fSupEarlyProcessInit
2296 && !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
2297 && supR3HardenedWinIsReSpawnNeeded(1 /*iWhich*/, argc, argv))
2298 {
2299 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #1\n"));
2300 supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV, false /*fAvastKludge*/);
2301 supR3HardenedVerifyAll(true /* fFatal */, pszProgName, g_szSupLibHardenedExePath, fFlags);
2302 return supR3HardenedWinReSpawn(1 /*iWhich*/);
2303 }
2304
2305 /*
2306 * Windows: Initialize the image verification global data so we can verify the
2307 * signature of the process image and hook the core of the DLL loader API so we
2308 * can check the signature of all DLLs mapped into the process. (Already done
2309 * by early VM process init.)
2310 */
2311 if (!g_fSupEarlyProcessInit)
2312 supR3HardenedWinInit(fFlags, true /*fAvastKludge*/);
2313#endif /* RT_OS_WINDOWS */
2314
2315 /*
2316 * Validate the installation.
2317 */
2318 supR3HardenedVerifyAll(true /* fFatal */, pszProgName, g_szSupLibHardenedExePath, fFlags);
2319
2320 /*
2321 * The next steps are only taken if we actually need to access the support
2322 * driver. (Already done by early process init.)
2323 */
2324 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
2325 {
2326#ifdef RT_OS_WINDOWS
2327 /*
2328 * Windows: Must have done early process init if we get here.
2329 */
2330 if (!g_fSupEarlyProcessInit)
2331 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_Integrity, VERR_WRONG_ORDER,
2332 "Early process init was somehow skipped.");
2333
2334 /*
2335 * Windows: The second respawn. This time we make a special arrangement
2336 * with vboxdrv to monitor access to the new process from its inception.
2337 */
2338 if (supR3HardenedWinIsReSpawnNeeded(2 /* iWhich*/, argc, argv))
2339 {
2340 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #2\n"));
2341 return supR3HardenedWinReSpawn(2 /* iWhich*/);
2342 }
2343 SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
2344 supR3HardenedWinFlushLoaderCache();
2345
2346#else
2347 /*
2348 * Open the vboxdrv device.
2349 */
2350 supR3HardenedMainOpenDevice();
2351#endif /* !RT_OS_WINDOWS */
2352 }
2353
2354#ifdef RT_OS_WINDOWS
2355 /*
2356 * Windows: Enable the use of windows APIs to verify images at load time.
2357 */
2358 supR3HardenedWinEnableThreadCreation();
2359 supR3HardenedWinFlushLoaderCache();
2360 supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(g_pszSupLibHardenedProgName);
2361 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY;
2362#endif
2363
2364#ifdef SUP_HARDENED_SUID
2365 /*
2366 * Grab additional capabilities / privileges.
2367 */
2368 supR3HardenedMainGrabCapabilites();
2369
2370 /*
2371 * Drop any root privileges we might be holding (won't return on failure)
2372 */
2373 supR3HardenedMainDropPrivileges();
2374#endif
2375
2376 /*
2377 * Load the IPRT, hand the SUPLib part the open driver and
2378 * call RTR3InitEx.
2379 */
2380 SUP_DPRINTF(("SUPR3HardenedMain: Load Runtime...\n"));
2381 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_INIT_RUNTIME;
2382 supR3HardenedMainInitRuntime(fFlags);
2383#ifdef RT_OS_WINDOWS
2384 supR3HardenedWinModifyDllSearchPath(fFlags, g_szSupLibHardenedAppBinPath);
2385#endif
2386
2387 /*
2388 * Load the DLL/SO/DYLIB containing the actual program
2389 * and pass control to it.
2390 */
2391 SUP_DPRINTF(("SUPR3HardenedMain: Load TrustedMain...\n"));
2392 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_GET_TRUSTED_MAIN;
2393 PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName, fFlags);
2394
2395 SUP_DPRINTF(("SUPR3HardenedMain: Calling TrustedMain (%p)...\n", pfnTrustedMain));
2396 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN;
2397 return pfnTrustedMain(argc, argv, envp);
2398}
2399
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