VirtualBox

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

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

SUPR3HardenedMain.cpp: @page pg_hardening updates.

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