VirtualBox

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

Last change on this file since 64883 was 63674, checked in by vboxsync, 8 years ago

build fix

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

© 2023 Oracle
ContactPrivacy policyTerms of Use