VirtualBox

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

Last change on this file since 53004 was 53004, checked in by vboxsync, 10 years ago

SUP: Resolve and call RTLogRelPrintf dynamically to put errors in the release log (makes them more visible to the user).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.7 KB
Line 
1/* $Id: SUPR3HardenedMain.cpp 53004 2014-10-09 01:10:20Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Hardened main().
4 */
5
6/*
7 * Copyright (C) 2006-2014 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/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#if defined(RT_OS_OS2)
31# define INCL_BASE
32# define INCL_ERRORS
33# include <os2.h>
34# include <stdio.h>
35# include <stdlib.h>
36# include <dlfcn.h>
37# include <unistd.h>
38
39#elif RT_OS_WINDOWS
40# include <iprt/nt/nt-and-windows.h>
41
42#else /* UNIXes */
43# include <iprt/types.h> /* stdint fun on darwin. */
44
45# include <stdio.h>
46# include <stdlib.h>
47# include <dlfcn.h>
48# include <limits.h>
49# include <errno.h>
50# include <unistd.h>
51# include <sys/stat.h>
52# include <sys/time.h>
53# include <sys/types.h>
54# if defined(RT_OS_LINUX)
55# undef USE_LIB_PCAP /* don't depend on libcap as we had to depend on either
56 libcap1 or libcap2 */
57
58# undef _POSIX_SOURCE
59# include <linux/types.h> /* sys/capabilities from uek-headers require this */
60# include <sys/capability.h>
61# include <sys/prctl.h>
62# ifndef CAP_TO_MASK
63# define CAP_TO_MASK(cap) RT_BIT(cap)
64# endif
65# elif defined(RT_OS_FREEBSD)
66# include <sys/param.h>
67# include <sys/sysctl.h>
68# elif defined(RT_OS_SOLARIS)
69# include <priv.h>
70# endif
71# include <pwd.h>
72# ifdef RT_OS_DARWIN
73# include <mach-o/dyld.h>
74# endif
75
76#endif
77
78#include <VBox/sup.h>
79#include <VBox/err.h>
80#ifdef RT_OS_WINDOWS
81# include <VBox/version.h>
82#endif
83#include <iprt/ctype.h>
84#include <iprt/string.h>
85#include <iprt/initterm.h>
86#include <iprt/param.h>
87
88#include "SUPLibInternal.h"
89
90
91/*******************************************************************************
92* Defined Constants And Macros *
93*******************************************************************************/
94/** @def SUP_HARDENED_SUID
95 * Whether we're employing set-user-ID-on-execute in the hardening.
96 */
97#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_L4)
98# define SUP_HARDENED_SUID
99#else
100# undef SUP_HARDENED_SUID
101#endif
102
103/** @def SUP_HARDENED_SYM
104 * Decorate a symbol that's resolved dynamically.
105 */
106#ifdef RT_OS_OS2
107# define SUP_HARDENED_SYM(sym) "_" sym
108#else
109# define SUP_HARDENED_SYM(sym) sym
110#endif
111
112
113/*******************************************************************************
114* Structures and Typedefs *
115*******************************************************************************/
116/** @see RTR3InitEx */
117typedef DECLCALLBACK(int) FNRTR3INITEX(uint32_t iVersion, uint32_t fFlags, int cArgs,
118 char **papszArgs, const char *pszProgramPath);
119typedef FNRTR3INITEX *PFNRTR3INITEX;
120
121/** @see RTLogRelPrintf */
122typedef DECLCALLBACK(void) FNRTLOGRELPRINTF(const char *pszFormat, ...);
123typedef FNRTLOGRELPRINTF *PFNRTLOGRELPRINTF;
124
125
126/*******************************************************************************
127* Global Variables *
128*******************************************************************************/
129/** The pre-init data we pass on to SUPR3 (residing in VBoxRT). */
130static SUPPREINITDATA g_SupPreInitData;
131/** The program executable path. */
132#ifndef RT_OS_WINDOWS
133static
134#endif
135char g_szSupLibHardenedExePath[RTPATH_MAX];
136/** The program directory path. */
137static char g_szSupLibHardenedDirPath[RTPATH_MAX];
138
139/** The program name. */
140static const char *g_pszSupLibHardenedProgName;
141/** The flags passed to SUPR3HardenedMain. */
142static uint32_t g_fSupHardenedMain;
143
144#ifdef SUP_HARDENED_SUID
145/** The real UID at startup. */
146static uid_t g_uid;
147/** The real GID at startup. */
148static gid_t g_gid;
149# ifdef RT_OS_LINUX
150static uint32_t g_uCaps;
151# endif
152#endif
153
154/** The startup log file. */
155#ifdef RT_OS_WINDOWS
156static HANDLE g_hStartupLog = NULL;
157#else
158static int g_hStartupLog = -1;
159#endif
160/** The number of bytes we've written to the startup log. */
161static uint32_t volatile g_cbStartupLog = 0;
162
163/** The current SUPR3HardenedMain state / location. */
164SUPR3HARDENEDMAINSTATE g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED;
165AssertCompileSize(g_enmSupR3HardenedMainState, sizeof(uint32_t));
166
167#ifdef RT_OS_WINDOWS
168/** Pointer to VBoxRT's RTLogRelPrintf function so we can write errors to the
169 * release log at runtime. */
170static PFNRTLOGRELPRINTF g_pfnRTLogRelPrintf = NULL;
171#endif
172
173
174/*******************************************************************************
175* Internal Functions *
176*******************************************************************************/
177#ifdef SUP_HARDENED_SUID
178static void supR3HardenedMainDropPrivileges(void);
179#endif
180static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName);
181
182
183/**
184 * Safely copy one or more strings into the given buffer.
185 *
186 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW.
187 * @param pszDst The destionation buffer.
188 * @param cbDst The size of the destination buffer.
189 * @param ... One or more zero terminated strings, ending with
190 * a NULL.
191 */
192static int suplibHardenedStrCopyEx(char *pszDst, size_t cbDst, ...)
193{
194 int rc = VINF_SUCCESS;
195
196 if (cbDst == 0)
197 return VERR_BUFFER_OVERFLOW;
198
199 va_list va;
200 va_start(va, cbDst);
201 for (;;)
202 {
203 const char *pszSrc = va_arg(va, const char *);
204 if (!pszSrc)
205 break;
206
207 size_t cchSrc = suplibHardenedStrLen(pszSrc);
208 if (cchSrc < cbDst)
209 {
210 suplibHardenedMemCopy(pszDst, pszSrc, cchSrc);
211 pszDst += cchSrc;
212 cbDst -= cchSrc;
213 }
214 else
215 {
216 rc = VERR_BUFFER_OVERFLOW;
217 if (cbDst > 1)
218 {
219 suplibHardenedMemCopy(pszDst, pszSrc, cbDst - 1);
220 pszDst += cbDst - 1;
221 cbDst = 1;
222 }
223 }
224 *pszDst = '\0';
225 }
226 va_end(va);
227
228 return rc;
229}
230
231
232/**
233 * Exit current process in the quickest possible fashion.
234 *
235 * @param rcExit The exit code.
236 */
237DECLNORETURN(void) suplibHardenedExit(RTEXITCODE rcExit)
238{
239 for (;;)
240 {
241#ifdef RT_OS_WINDOWS
242 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
243 ExitProcess(rcExit);
244 if (RtlExitUserProcess != NULL)
245 RtlExitUserProcess(rcExit);
246 NtTerminateProcess(NtCurrentProcess(), rcExit);
247#else
248 _Exit(rcExit);
249#endif
250 }
251}
252
253
254/**
255 * Writes a substring to standard error.
256 *
257 * @param pch The start of the substring.
258 * @param cch The length of the substring.
259 */
260static void suplibHardenedPrintStrN(const char *pch, size_t cch)
261{
262#ifdef RT_OS_WINDOWS
263 HANDLE hStdOut = NtCurrentPeb()->ProcessParameters->StandardOutput;
264 if (hStdOut != NULL)
265 {
266 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
267 {
268 DWORD cbWritten;
269 WriteFile(hStdOut, pch, (DWORD)cch, &cbWritten, NULL);
270 }
271 /* Windows 7 and earlier uses fake handles, with the last two bits set ((hStdOut & 3) == 3). */
272 else if (NtWriteFile != NULL && ((uintptr_t)hStdOut & 3) == 0)
273 {
274 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
275 NtWriteFile(hStdOut, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
276 &Ios, (PVOID)pch, (ULONG)cch, NULL /*ByteOffset*/, NULL /*Key*/);
277 }
278 }
279#else
280 (void)write(2, pch, cch);
281#endif
282}
283
284
285/**
286 * Writes a string to standard error.
287 *
288 * @param psz The string.
289 */
290static void suplibHardenedPrintStr(const char *psz)
291{
292 suplibHardenedPrintStrN(psz, suplibHardenedStrLen(psz));
293}
294
295
296/**
297 * Writes a char to standard error.
298 *
299 * @param ch The character value to write.
300 */
301static void suplibHardenedPrintChr(char ch)
302{
303 suplibHardenedPrintStrN(&ch, 1);
304}
305
306
307/**
308 * Writes a decimal number to stdard error.
309 *
310 * @param uValue The value.
311 */
312static void suplibHardenedPrintDecimal(uint64_t uValue)
313{
314 char szBuf[64];
315 char *pszEnd = &szBuf[sizeof(szBuf) - 1];
316 char *psz = pszEnd;
317
318 *psz-- = '\0';
319
320 do
321 {
322 *psz-- = '0' + (uValue % 10);
323 uValue /= 10;
324 } while (uValue > 0);
325
326 psz++;
327 suplibHardenedPrintStrN(psz, pszEnd - psz);
328}
329
330
331/**
332 * Writes a hexadecimal or octal number to standard error.
333 *
334 * @param uValue The value.
335 * @param uBase The base (16 or 8).
336 * @param fFlags Format flags.
337 */
338static void suplibHardenedPrintHexOctal(uint64_t uValue, unsigned uBase, uint32_t fFlags)
339{
340 static char const s_achDigitsLower[17] = "0123456789abcdef";
341 static char const s_achDigitsUpper[17] = "0123456789ABCDEF";
342 const char *pchDigits = !(fFlags & RTSTR_F_CAPITAL) ? s_achDigitsLower : s_achDigitsUpper;
343 unsigned cShift = uBase == 16 ? 4 : 3;
344 unsigned fDigitMask = uBase == 16 ? 0xf : 7;
345 char szBuf[64];
346 char *pszEnd = &szBuf[sizeof(szBuf) - 1];
347 char *psz = pszEnd;
348
349 *psz-- = '\0';
350
351 do
352 {
353 *psz-- = pchDigits[uValue & fDigitMask];
354 uValue >>= cShift;
355 } while (uValue > 0);
356
357 if ((fFlags & RTSTR_F_SPECIAL) && uBase == 16)
358 {
359 *psz-- = !(fFlags & RTSTR_F_CAPITAL) ? 'x' : 'X';
360 *psz-- = '0';
361 }
362
363 psz++;
364 suplibHardenedPrintStrN(psz, pszEnd - psz);
365}
366
367
368/**
369 * Writes a wide character string to standard error.
370 *
371 * @param pwsz The string.
372 */
373static void suplibHardenedPrintWideStr(PCRTUTF16 pwsz)
374{
375 for (;;)
376 {
377 RTUTF16 wc = *pwsz++;
378 if (!wc)
379 return;
380 if ( (wc < 0x7f && wc >= 0x20)
381 || wc == '\n'
382 || wc == '\r')
383 suplibHardenedPrintChr((char)wc);
384 else
385 {
386 suplibHardenedPrintStrN(RT_STR_TUPLE("\\x"));
387 suplibHardenedPrintHexOctal(wc, 16, 0);
388 }
389 }
390}
391
392#ifdef IPRT_NO_CRT
393
394/** Buffer structure used by suplibHardenedOutput. */
395struct SUPLIBHARDENEDOUTPUTBUF
396{
397 size_t off;
398 char szBuf[2048];
399};
400
401/** Callback for RTStrFormatV, see FNRTSTROUTPUT. */
402static DECLCALLBACK(size_t) suplibHardenedOutput(void *pvArg, const char *pachChars, size_t cbChars)
403{
404 SUPLIBHARDENEDOUTPUTBUF *pBuf = (SUPLIBHARDENEDOUTPUTBUF *)pvArg;
405 size_t cbTodo = cbChars;
406 for (;;)
407 {
408 size_t cbSpace = sizeof(pBuf->szBuf) - pBuf->off - 1;
409
410 /* Flush the buffer? */
411 if ( cbSpace == 0
412 || (cbTodo == 0 && pBuf->off))
413 {
414 suplibHardenedPrintStrN(pBuf->szBuf, pBuf->off);
415# ifdef RT_OS_WINDOWS
416 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
417 OutputDebugString(pBuf->szBuf);
418# endif
419 pBuf->off = 0;
420 cbSpace = sizeof(pBuf->szBuf) - 1;
421 }
422
423 /* Copy the string into the buffer. */
424 if (cbTodo == 1)
425 {
426 pBuf->szBuf[pBuf->off++] = *pachChars;
427 break;
428 }
429 if (cbSpace >= cbTodo)
430 {
431 memcpy(&pBuf->szBuf[pBuf->off], pachChars, cbTodo);
432 pBuf->off += cbTodo;
433 break;
434 }
435 memcpy(&pBuf->szBuf[pBuf->off], pachChars, cbSpace);
436 pBuf->off += cbSpace;
437 cbTodo -= cbSpace;
438 }
439 pBuf->szBuf[pBuf->off] = '\0';
440
441 return cbChars;
442}
443
444#endif /* IPRT_NO_CRT */
445
446/**
447 * Simple printf to standard error.
448 *
449 * @param pszFormat The format string.
450 * @param va Arguments to format.
451 */
452DECLHIDDEN(void) suplibHardenedPrintFV(const char *pszFormat, va_list va)
453{
454#ifdef IPRT_NO_CRT
455 /*
456 * Use buffered output here to avoid character mixing on the windows
457 * console and to enable us to use OutputDebugString.
458 */
459 SUPLIBHARDENEDOUTPUTBUF Buf;
460 Buf.off = 0;
461 Buf.szBuf[0] = '\0';
462 RTStrFormatV(suplibHardenedOutput, &Buf, NULL, NULL, pszFormat, va);
463
464#else /* !IPRT_NO_CRT */
465 /*
466 * Format loop.
467 */
468 char ch;
469 const char *pszLast = pszFormat;
470 for (;;)
471 {
472 ch = *pszFormat;
473 if (!ch)
474 break;
475 pszFormat++;
476
477 if (ch == '%')
478 {
479 /*
480 * Format argument.
481 */
482
483 /* Flush unwritten bits. */
484 if (pszLast != pszFormat - 1)
485 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast - 1);
486 pszLast = pszFormat;
487 ch = *pszFormat++;
488
489 /* flags. */
490 uint32_t fFlags = 0;
491 for (;;)
492 {
493 if (ch == '#') fFlags |= RTSTR_F_SPECIAL;
494 else if (ch == '-') fFlags |= RTSTR_F_LEFT;
495 else if (ch == '+') fFlags |= RTSTR_F_PLUS;
496 else if (ch == ' ') fFlags |= RTSTR_F_BLANK;
497 else if (ch == '0') fFlags |= RTSTR_F_ZEROPAD;
498 else if (ch == '\'') fFlags |= RTSTR_F_THOUSAND_SEP;
499 else break;
500 ch = *pszFormat++;
501 }
502
503 /* Width and precision - ignored. */
504 while (RT_C_IS_DIGIT(ch))
505 ch = *pszFormat++;
506 if (ch == '*')
507 va_arg(va, int);
508 if (ch == '.')
509 {
510 do ch = *pszFormat++;
511 while (RT_C_IS_DIGIT(ch));
512 if (ch == '*')
513 va_arg(va, int);
514 }
515
516 /* Size. */
517 char chArgSize = 0;
518 switch (ch)
519 {
520 case 'z':
521 case 'L':
522 case 'j':
523 case 't':
524 chArgSize = ch;
525 ch = *pszFormat++;
526 break;
527
528 case 'l':
529 chArgSize = ch;
530 ch = *pszFormat++;
531 if (ch == 'l')
532 {
533 chArgSize = 'L';
534 ch = *pszFormat++;
535 }
536 break;
537
538 case 'h':
539 chArgSize = ch;
540 ch = *pszFormat++;
541 if (ch == 'h')
542 {
543 chArgSize = 'H';
544 ch = *pszFormat++;
545 }
546 break;
547 }
548
549 /*
550 * Do type specific formatting.
551 */
552 switch (ch)
553 {
554 case 'c':
555 ch = (char)va_arg(va, int);
556 suplibHardenedPrintChr(ch);
557 break;
558
559 case 's':
560 if (chArgSize == 'l')
561 {
562 PCRTUTF16 pwszStr = va_arg(va, PCRTUTF16 );
563 if (RT_VALID_PTR(pwszStr))
564 suplibHardenedPrintWideStr(pwszStr);
565 else
566 suplibHardenedPrintStr("<NULL>");
567 }
568 else
569 {
570 const char *pszStr = va_arg(va, const char *);
571 if (!RT_VALID_PTR(pszStr))
572 pszStr = "<NULL>";
573 suplibHardenedPrintStr(pszStr);
574 }
575 break;
576
577 case 'd':
578 case 'i':
579 {
580 int64_t iValue;
581 if (chArgSize == 'L' || chArgSize == 'j')
582 iValue = va_arg(va, int64_t);
583 else if (chArgSize == 'l')
584 iValue = va_arg(va, signed long);
585 else if (chArgSize == 'z' || chArgSize == 't')
586 iValue = va_arg(va, intptr_t);
587 else
588 iValue = va_arg(va, signed int);
589 if (iValue < 0)
590 {
591 suplibHardenedPrintChr('-');
592 iValue = -iValue;
593 }
594 suplibHardenedPrintDecimal(iValue);
595 break;
596 }
597
598 case 'p':
599 case 'x':
600 case 'X':
601 case 'u':
602 case 'o':
603 {
604 unsigned uBase = 10;
605 uint64_t uValue;
606
607 switch (ch)
608 {
609 case 'p':
610 fFlags |= RTSTR_F_ZEROPAD; /* Note not standard behaviour (but I like it this way!) */
611 uBase = 16;
612 break;
613 case 'X':
614 fFlags |= RTSTR_F_CAPITAL;
615 case 'x':
616 uBase = 16;
617 break;
618 case 'u':
619 uBase = 10;
620 break;
621 case 'o':
622 uBase = 8;
623 break;
624 }
625
626 if (ch == 'p' || chArgSize == 'z' || chArgSize == 't')
627 uValue = va_arg(va, uintptr_t);
628 else if (chArgSize == 'L' || chArgSize == 'j')
629 uValue = va_arg(va, uint64_t);
630 else if (chArgSize == 'l')
631 uValue = va_arg(va, unsigned long);
632 else
633 uValue = va_arg(va, unsigned int);
634
635 if (uBase == 10)
636 suplibHardenedPrintDecimal(uValue);
637 else
638 suplibHardenedPrintHexOctal(uValue, uBase, fFlags);
639 break;
640 }
641
642 case 'R':
643 if (pszFormat[0] == 'r' && pszFormat[1] == 'c')
644 {
645 int iValue = va_arg(va, int);
646 if (iValue < 0)
647 {
648 suplibHardenedPrintChr('-');
649 iValue = -iValue;
650 }
651 suplibHardenedPrintDecimal(iValue);
652 pszFormat += 2;
653 break;
654 }
655 /* fall thru */
656
657 /*
658 * Custom format.
659 */
660 default:
661 suplibHardenedPrintStr("[bad format: ");
662 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast);
663 suplibHardenedPrintChr(']');
664 break;
665 }
666
667 /* continue */
668 pszLast = pszFormat;
669 }
670 }
671
672 /* Flush the last bits of the string. */
673 if (pszLast != pszFormat)
674 suplibHardenedPrintStrN(pszLast, pszFormat - pszLast);
675#endif /* !IPRT_NO_CRT */
676}
677
678
679/**
680 * Prints to standard error.
681 *
682 * @param pszFormat The format string.
683 * @param ... Arguments to format.
684 */
685DECLHIDDEN(void) suplibHardenedPrintF(const char *pszFormat, ...)
686{
687 va_list va;
688 va_start(va, pszFormat);
689 suplibHardenedPrintFV(pszFormat, va);
690 va_end(va);
691}
692
693
694/**
695 * @copydoc RTPathStripFilename.
696 */
697static void suplibHardenedPathStripFilename(char *pszPath)
698{
699 char *psz = pszPath;
700 char *pszLastSep = pszPath;
701
702 for (;; psz++)
703 {
704 switch (*psz)
705 {
706 /* handle separators. */
707#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
708 case ':':
709 pszLastSep = psz + 1;
710 break;
711
712 case '\\':
713#endif
714 case '/':
715 pszLastSep = psz;
716 break;
717
718 /* the end */
719 case '\0':
720 if (pszLastSep == pszPath)
721 *pszLastSep++ = '.';
722 *pszLastSep = '\0';
723 return;
724 }
725 }
726 /* will never get here */
727}
728
729
730/**
731 * @copydoc RTPathFilename
732 */
733DECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath)
734{
735 const char *psz = pszPath;
736 const char *pszLastComp = pszPath;
737
738 for (;; psz++)
739 {
740 switch (*psz)
741 {
742 /* handle separators. */
743#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
744 case ':':
745 pszLastComp = psz + 1;
746 break;
747
748 case '\\':
749#endif
750 case '/':
751 pszLastComp = psz + 1;
752 break;
753
754 /* the end */
755 case '\0':
756 if (*pszLastComp)
757 return (char *)(void *)pszLastComp;
758 return NULL;
759 }
760 }
761
762 /* will never get here */
763 return NULL;
764}
765
766
767/**
768 * @copydoc RTPathAppPrivateNoArch
769 */
770DECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath)
771{
772#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
773 const char *pszSrcPath = RTPATH_APP_PRIVATE;
774 size_t cchPathPrivateNoArch = suplibHardenedStrLen(pszSrcPath);
775 if (cchPathPrivateNoArch >= cchPath)
776 supR3HardenedFatal("supR3HardenedPathAppPrivateNoArch: Buffer overflow, %zu >= %zu\n", cchPathPrivateNoArch, cchPath);
777 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathPrivateNoArch + 1);
778 return VINF_SUCCESS;
779
780#else
781 return supR3HardenedPathExecDir(pszPath, cchPath);
782#endif
783}
784
785
786/**
787 * @copydoc RTPathAppPrivateArch
788 */
789DECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath)
790{
791#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE_ARCH)
792 const char *pszSrcPath = RTPATH_APP_PRIVATE_ARCH;
793 size_t cchPathPrivateArch = suplibHardenedStrLen(pszSrcPath);
794 if (cchPathPrivateArch >= cchPath)
795 supR3HardenedFatal("supR3HardenedPathAppPrivateArch: Buffer overflow, %zu >= %zu\n", cchPathPrivateArch, cchPath);
796 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathPrivateArch + 1);
797 return VINF_SUCCESS;
798
799#else
800 return supR3HardenedPathExecDir(pszPath, cchPath);
801#endif
802}
803
804
805/**
806 * @copydoc RTPathSharedLibs
807 */
808DECLHIDDEN(int) supR3HardenedPathSharedLibs(char *pszPath, size_t cchPath)
809{
810#if !defined(RT_OS_WINDOWS) && defined(RTPATH_SHARED_LIBS)
811 const char *pszSrcPath = RTPATH_SHARED_LIBS;
812 size_t cchPathSharedLibs = suplibHardenedStrLen(pszSrcPath);
813 if (cchPathSharedLibs >= cchPath)
814 supR3HardenedFatal("supR3HardenedPathSharedLibs: Buffer overflow, %zu >= %zu\n", cchPathSharedLibs, cchPath);
815 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathSharedLibs + 1);
816 return VINF_SUCCESS;
817
818#else
819 return supR3HardenedPathExecDir(pszPath, cchPath);
820#endif
821}
822
823
824/**
825 * @copydoc RTPathAppDocs
826 */
827DECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath)
828{
829#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_DOCS)
830 const char *pszSrcPath = RTPATH_APP_DOCS;
831 size_t cchPathAppDocs = suplibHardenedStrLen(pszSrcPath);
832 if (cchPathAppDocs >= cchPath)
833 supR3HardenedFatal("supR3HardenedPathAppDocs: Buffer overflow, %zu >= %zu\n", cchPathAppDocs, cchPath);
834 suplibHardenedMemCopy(pszPath, pszSrcPath, cchPathAppDocs + 1);
835 return VINF_SUCCESS;
836
837#else
838 return supR3HardenedPathExecDir(pszPath, cchPath);
839#endif
840}
841
842
843/**
844 * Returns the full path to the executable.
845 *
846 * @returns IPRT status code.
847 * @param pszPath Where to store it.
848 * @param cchPath How big that buffer is.
849 */
850static void supR3HardenedGetFullExePath(void)
851{
852 /*
853 * Get the program filename.
854 *
855 * Most UNIXes have no API for obtaining the executable path, but provides a symbolic
856 * link in the proc file system that tells who was exec'ed. The bad thing about this
857 * is that we have to use readlink, one of the weirder UNIX APIs.
858 *
859 * Darwin, OS/2 and Windows all have proper APIs for getting the program file name.
860 */
861#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
862# ifdef RT_OS_LINUX
863 int cchLink = readlink("/proc/self/exe", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
864
865# elif defined(RT_OS_SOLARIS)
866 char szFileBuf[PATH_MAX + 1];
867 sprintf(szFileBuf, "/proc/%ld/path/a.out", (long)getpid());
868 int cchLink = readlink(szFileBuf, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
869
870# else /* RT_OS_FREEBSD */
871 int aiName[4];
872 aiName[0] = CTL_KERN;
873 aiName[1] = KERN_PROC;
874 aiName[2] = KERN_PROC_PATHNAME;
875 aiName[3] = getpid();
876
877 size_t cbPath = sizeof(g_szSupLibHardenedExePath);
878 if (sysctl(aiName, RT_ELEMENTS(aiName), g_szSupLibHardenedExePath, &cbPath, NULL, 0) < 0)
879 supR3HardenedFatal("supR3HardenedExecDir: sysctl failed\n");
880 g_szSupLibHardenedExePath[sizeof(g_szSupLibHardenedExePath) - 1] = '\0';
881 int cchLink = suplibHardenedStrLen(g_szSupLibHardenedExePath); /* paranoid? can't we use cbPath? */
882
883# endif
884 if (cchLink < 0 || cchLink == sizeof(g_szSupLibHardenedExePath) - 1)
885 supR3HardenedFatal("supR3HardenedExecDir: couldn't read \"%s\", errno=%d cchLink=%d\n",
886 g_szSupLibHardenedExePath, errno, cchLink);
887 g_szSupLibHardenedExePath[cchLink] = '\0';
888
889#elif defined(RT_OS_OS2) || defined(RT_OS_L4)
890 _execname(g_szSupLibHardenedExePath, sizeof(g_szSupLibHardenedExePath));
891
892#elif defined(RT_OS_DARWIN)
893 const char *pszImageName = _dyld_get_image_name(0);
894 if (!pszImageName)
895 supR3HardenedFatal("supR3HardenedExecDir: _dyld_get_image_name(0) failed\n");
896 size_t cchImageName = suplibHardenedStrLen(pszImageName);
897 if (!cchImageName || cchImageName >= sizeof(g_szSupLibHardenedExePath))
898 supR3HardenedFatal("supR3HardenedExecDir: _dyld_get_image_name(0) failed, cchImageName=%d\n", cchImageName);
899 suplibHardenedMemCopy(g_szSupLibHardenedExePath, pszImageName, cchImageName + 1);
900
901#elif defined(RT_OS_WINDOWS)
902 char *pszDst = g_szSupLibHardenedExePath;
903 int rc = RTUtf16ToUtf8Ex(g_wszSupLibHardenedExePath, RTSTR_MAX, &pszDst, sizeof(g_szSupLibHardenedExePath), NULL);
904 if (RT_FAILURE(rc))
905 supR3HardenedFatal("supR3HardenedExecDir: RTUtf16ToUtf8Ex failed, rc=%Rrc\n", rc);
906#else
907# error needs porting.
908#endif
909
910 /*
911 * Strip off the filename part (RTPathStripFilename()).
912 */
913 suplibHardenedStrCopy(g_szSupLibHardenedDirPath, g_szSupLibHardenedExePath);
914 suplibHardenedPathStripFilename(g_szSupLibHardenedDirPath);
915}
916
917
918#ifdef RT_OS_LINUX
919/**
920 * Checks if we can read /proc/self/exe.
921 *
922 * This is used on linux to see if we have to call init
923 * with program path or not.
924 *
925 * @returns true / false.
926 */
927static bool supR3HardenedMainIsProcSelfExeAccssible(void)
928{
929 char szPath[RTPATH_MAX];
930 int cchLink = readlink("/proc/self/exe", szPath, sizeof(szPath));
931 return cchLink != -1;
932}
933#endif /* RT_OS_LINUX */
934
935
936
937/**
938 * @copydoc RTPathExecDir
939 */
940DECLHIDDEN(int) supR3HardenedPathExecDir(char *pszPath, size_t cchPath)
941{
942 /*
943 * Lazy init (probably not required).
944 */
945 if (!g_szSupLibHardenedDirPath[0])
946 supR3HardenedGetFullExePath();
947
948 /*
949 * Calc the length and check if there is space before copying.
950 */
951 size_t cch = suplibHardenedStrLen(g_szSupLibHardenedDirPath) + 1;
952 if (cch <= cchPath)
953 {
954 suplibHardenedMemCopy(pszPath, g_szSupLibHardenedDirPath, cch + 1);
955 return VINF_SUCCESS;
956 }
957
958 supR3HardenedFatal("supR3HardenedPathExecDir: Buffer too small (%u < %u)\n", cchPath, cch);
959 return VERR_BUFFER_OVERFLOW;
960}
961
962
963#ifdef RT_OS_WINDOWS
964extern "C" uint32_t g_uNtVerCombined;
965#endif
966
967DECLHIDDEN(void) supR3HardenedOpenLog(int *pcArgs, char **papszArgs)
968{
969 static const char s_szLogOption[] = "--sup-startup-log=";
970
971 /*
972 * Scan the argument vector.
973 */
974 int cArgs = *pcArgs;
975 for (int iArg = 1; iArg < cArgs; iArg++)
976 if (strncmp(papszArgs[iArg], s_szLogOption, sizeof(s_szLogOption) - 1) == 0)
977 {
978 const char *pszLogFile = &papszArgs[iArg][sizeof(s_szLogOption) - 1];
979
980 /*
981 * Drop the argument from the vector (has trailing NULL entry).
982 */
983 memmove(&papszArgs[iArg], &papszArgs[iArg + 1], (cArgs - iArg) * sizeof(papszArgs[0]));
984 *pcArgs -= 1;
985 cArgs -= 1;
986
987 /*
988 * Open the log file, unless we've already opened one.
989 * First argument takes precedence
990 */
991#ifdef RT_OS_WINDOWS
992 if (g_hStartupLog == NULL)
993 {
994 int rc = RTNtPathOpen(pszLogFile,
995 GENERIC_WRITE | SYNCHRONIZE,
996 FILE_ATTRIBUTE_NORMAL,
997 FILE_SHARE_READ | FILE_SHARE_WRITE,
998 FILE_OPEN_IF,
999 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
1000 OBJ_CASE_INSENSITIVE,
1001 &g_hStartupLog,
1002 NULL);
1003 if (RT_SUCCESS(rc))
1004 SUP_DPRINTF(("Log file opened: " VBOX_VERSION_STRING "r%u g_hStartupLog=%p g_uNtVerCombined=%#x\n",
1005 VBOX_SVN_REV, g_hStartupLog, g_uNtVerCombined));
1006 else
1007 g_hStartupLog = NULL;
1008 }
1009#else
1010 //g_hStartupLog = open()
1011#endif
1012 }
1013}
1014
1015
1016DECLHIDDEN(void) supR3HardenedLogV(const char *pszFormat, va_list va)
1017{
1018#ifdef RT_OS_WINDOWS
1019 if ( g_hStartupLog != NULL
1020 && g_cbStartupLog < 128*_1M)
1021 {
1022 char szBuf[5120];
1023 PCLIENT_ID pSelfId = &((PTEB)NtCurrentTeb())->ClientId;
1024 size_t cchPrefix = RTStrPrintf(szBuf, sizeof(szBuf), "%x.%x: ", pSelfId->UniqueProcess, pSelfId->UniqueThread);
1025 size_t cch = RTStrPrintfV(&szBuf[cchPrefix], sizeof(szBuf) - cchPrefix, pszFormat, va) + cchPrefix;
1026
1027 if ((size_t)cch >= sizeof(szBuf))
1028 cch = sizeof(szBuf) - 1;
1029
1030 if (!cch || szBuf[cch - 1] != '\n')
1031 szBuf[cch++] = '\n';
1032
1033 ASMAtomicAddU32(&g_cbStartupLog, (uint32_t)cch);
1034
1035 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
1036 LARGE_INTEGER Offset;
1037 Offset.QuadPart = -1; /* Write to end of file. */
1038 NtWriteFile(g_hStartupLog, NULL /*Event*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/,
1039 &Ios, szBuf, (ULONG)cch, &Offset, NULL /*Key*/);
1040 }
1041#else
1042 /* later */
1043#endif
1044}
1045
1046
1047DECLHIDDEN(void) supR3HardenedLog(const char *pszFormat, ...)
1048{
1049 va_list va;
1050 va_start(va, pszFormat);
1051 supR3HardenedLogV(pszFormat, va);
1052 va_end(va);
1053}
1054
1055
1056/**
1057 * Prints the message prefix.
1058 */
1059static void suplibHardenedPrintPrefix(void)
1060{
1061 if (g_pszSupLibHardenedProgName)
1062 suplibHardenedPrintStr(g_pszSupLibHardenedProgName);
1063 suplibHardenedPrintStr(": ");
1064}
1065
1066
1067DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
1068{
1069 /*
1070 * First to the log.
1071 */
1072 supR3HardenedLog("Error %d in %s! (enmWhat=%d)\n", rc, pszWhere, enmWhat);
1073 va_list vaCopy;
1074 va_copy(vaCopy, va);
1075 supR3HardenedLogV(pszMsgFmt, vaCopy);
1076 va_end(vaCopy);
1077
1078#ifdef RT_OS_WINDOWS
1079 /*
1080 * The release log.
1081 */
1082 if (g_pfnRTLogRelPrintf)
1083 {
1084 va_copy(vaCopy, va);
1085 g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %s enmWhat=%d rc=%Rrc (%#x)\n", pszWhere, enmWhat, rc);
1086 g_pfnRTLogRelPrintf("supR3HardenedFatalMsgV: %N\n", pszMsgFmt, &vaCopy);
1087 va_end(vaCopy);
1088 }
1089#endif
1090
1091 /*
1092 * Then to the console.
1093 */
1094 suplibHardenedPrintPrefix();
1095 suplibHardenedPrintF("Error %d in %s!\n", rc, pszWhere);
1096
1097 suplibHardenedPrintPrefix();
1098 va_copy(vaCopy, va);
1099 suplibHardenedPrintFV(pszMsgFmt, vaCopy);
1100 va_end(vaCopy);
1101 suplibHardenedPrintChr('\n');
1102
1103 switch (enmWhat)
1104 {
1105 case kSupInitOp_Driver:
1106 suplibHardenedPrintChr('\n');
1107 suplibHardenedPrintPrefix();
1108 suplibHardenedPrintStr("Tip! Make sure the kernel module is loaded. It may also help to reinstall VirtualBox.\n");
1109 break;
1110
1111 case kSupInitOp_Misc:
1112 case kSupInitOp_IPRT:
1113 case kSupInitOp_Integrity:
1114 case kSupInitOp_RootCheck:
1115 suplibHardenedPrintChr('\n');
1116 suplibHardenedPrintPrefix();
1117 suplibHardenedPrintStr("Tip! It may help to reinstall VirtualBox.\n");
1118 break;
1119
1120 default:
1121 /* no hints here */
1122 break;
1123 }
1124
1125 /*
1126 * Finally, TrustedError if appropriate.
1127 */
1128 if (g_enmSupR3HardenedMainState >= SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED)
1129 {
1130#ifdef SUP_HARDENED_SUID
1131 /*
1132 * Drop any root privileges we might be holding, this won't return
1133 * if it fails but end up calling supR3HardenedFatal[V].
1134 */
1135 supR3HardenedMainDropPrivileges();
1136#endif
1137
1138 /*
1139 * Now try resolve and call the TrustedError entry point if we can
1140 * find it. We'll fork before we attempt this because that way the
1141 * session management in main will see us exiting immediately (if
1142 * it's involved with us).
1143 */
1144#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
1145 int pid = fork();
1146 if (pid <= 0)
1147#endif
1148 {
1149 static volatile bool s_fRecursive = false; /* Loader hooks may cause recursion. */
1150 if (!s_fRecursive)
1151 {
1152 s_fRecursive = true;
1153
1154 PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
1155 if (pfnTrustedError)
1156 pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
1157
1158 s_fRecursive = false;
1159 }
1160 }
1161 }
1162#if defined(RT_OS_WINDOWS)
1163 /*
1164 * Report the error to the parent if this happens during early VM init.
1165 */
1166 else if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
1167 && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
1168 supR3HardenedWinReportErrorToParent(pszWhere, enmWhat, rc, pszMsgFmt, va);
1169#endif
1170
1171 /*
1172 * Quit
1173 */
1174 suplibHardenedExit(RTEXITCODE_FAILURE);
1175}
1176
1177
1178DECLHIDDEN(void) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, ...)
1179{
1180 va_list va;
1181 va_start(va, pszMsgFmt);
1182 supR3HardenedFatalMsgV(pszWhere, enmWhat, rc, pszMsgFmt, va);
1183 va_end(va);
1184}
1185
1186
1187DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va)
1188{
1189 supR3HardenedLog("Fatal error:\n");
1190 va_list vaCopy;
1191 va_copy(vaCopy, va);
1192 supR3HardenedLogV(pszFormat, vaCopy);
1193 va_end(vaCopy);
1194
1195#if defined(RT_OS_WINDOWS)
1196 /*
1197 * Report the error to the parent if this happens during early VM init.
1198 */
1199 if ( g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_WIN_IMPORTS_RESOLVED
1200 && g_enmSupR3HardenedMainState != SUPR3HARDENEDMAINSTATE_NOT_YET_CALLED)
1201 supR3HardenedWinReportErrorToParent(NULL, kSupInitOp_Invalid, VERR_INTERNAL_ERROR, pszFormat, va);
1202 else
1203#endif
1204 {
1205#ifdef RT_OS_WINDOWS
1206 if (g_pfnRTLogRelPrintf)
1207 {
1208 va_copy(vaCopy, va);
1209 g_pfnRTLogRelPrintf("supR3HardenedFatalV: %N", pszFormat, &vaCopy);
1210 va_end(vaCopy);
1211 }
1212#endif
1213
1214 suplibHardenedPrintPrefix();
1215 suplibHardenedPrintFV(pszFormat, va);
1216 }
1217
1218 suplibHardenedExit(RTEXITCODE_FAILURE);
1219}
1220
1221
1222DECLHIDDEN(void) supR3HardenedFatal(const char *pszFormat, ...)
1223{
1224 va_list va;
1225 va_start(va, pszFormat);
1226 supR3HardenedFatalV(pszFormat, va);
1227 va_end(va);
1228}
1229
1230
1231DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va)
1232{
1233 if (fFatal)
1234 supR3HardenedFatalV(pszFormat, va);
1235
1236 supR3HardenedLog("Error (rc=%d):\n", rc);
1237 va_list vaCopy;
1238 va_copy(vaCopy, va);
1239 supR3HardenedLogV(pszFormat, vaCopy);
1240 va_end(vaCopy);
1241
1242#ifdef RT_OS_WINDOWS
1243 if (g_pfnRTLogRelPrintf)
1244 {
1245 va_copy(vaCopy, va);
1246 g_pfnRTLogRelPrintf("supR3HardenedErrorV: %N", pszFormat, &vaCopy);
1247 va_end(vaCopy);
1248 }
1249#endif
1250
1251 suplibHardenedPrintPrefix();
1252 suplibHardenedPrintFV(pszFormat, va);
1253
1254 return rc;
1255}
1256
1257
1258DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...)
1259{
1260 va_list va;
1261 va_start(va, pszFormat);
1262 supR3HardenedErrorV(rc, fFatal, pszFormat, va);
1263 va_end(va);
1264 return rc;
1265}
1266
1267
1268
1269/**
1270 * Attempts to open /dev/vboxdrv (or equvivalent).
1271 *
1272 * @remarks This function will not return on failure.
1273 */
1274DECLHIDDEN(void) supR3HardenedMainOpenDevice(void)
1275{
1276 RTERRINFOSTATIC ErrInfo;
1277 SUPINITOP enmWhat = kSupInitOp_Driver;
1278 int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/,
1279 &enmWhat, RTErrInfoInitStatic(&ErrInfo));
1280 if (RT_SUCCESS(rc))
1281 return;
1282
1283 if (RTErrInfoIsSet(&ErrInfo.Core))
1284 supR3HardenedFatalMsg("suplibOsInit", enmWhat, rc, "%s", ErrInfo.szMsg);
1285
1286 switch (rc)
1287 {
1288 /** @todo better messages! */
1289 case VERR_VM_DRIVER_NOT_INSTALLED:
1290 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not installed");
1291 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
1292 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not accessible");
1293 case VERR_VM_DRIVER_LOAD_ERROR:
1294 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_LOAD_ERROR");
1295 case VERR_VM_DRIVER_OPEN_ERROR:
1296 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_OPEN_ERROR");
1297 case VERR_VM_DRIVER_VERSION_MISMATCH:
1298 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver version mismatch");
1299 case VERR_ACCESS_DENIED:
1300 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_ACCESS_DENIED");
1301 case VERR_NO_MEMORY:
1302 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel memory allocation/mapping failed");
1303 case VERR_SUPDRV_HARDENING_EVIL_HANDLE:
1304 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
1305 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0:
1306 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0");
1307 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1:
1308 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1");
1309 case VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2:
1310 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
1311 default:
1312 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Unknown rc=%d (%Rrc)", rc, rc);
1313 }
1314}
1315
1316
1317#ifdef SUP_HARDENED_SUID
1318
1319/**
1320 * Grabs extra non-root capabilities / privileges that we might require.
1321 *
1322 * This is currently only used for being able to do ICMP from the NAT engine.
1323 *
1324 * @note We still have root privileges at the time of this call.
1325 */
1326static void supR3HardenedMainGrabCapabilites(void)
1327{
1328# if defined(RT_OS_LINUX)
1329 /*
1330 * We are about to drop all our privileges. Remove all capabilities but
1331 * keep the cap_net_raw capability for ICMP sockets for the NAT stack.
1332 */
1333 if (g_uCaps != 0)
1334 {
1335# ifdef USE_LIB_PCAP
1336 /* XXX cap_net_bind_service */
1337 if (!cap_set_proc(cap_from_text("all-eip cap_net_raw+ep")))
1338 prctl(PR_SET_KEEPCAPS, 1 /*keep=*/, 0, 0, 0);
1339 prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0);
1340# else
1341 cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
1342 cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
1343 memset(hdr, 0, sizeof(*hdr));
1344 hdr->version = _LINUX_CAPABILITY_VERSION;
1345 memset(cap, 0, sizeof(*cap));
1346 cap->effective = g_uCaps;
1347 cap->permitted = g_uCaps;
1348 if (!capset(hdr, cap))
1349 prctl(PR_SET_KEEPCAPS, 1 /*keep*/, 0, 0, 0);
1350 prctl(PR_SET_DUMPABLE, 1 /*dump*/, 0, 0, 0);
1351# endif /* !USE_LIB_PCAP */
1352 }
1353
1354# elif defined(RT_OS_SOLARIS)
1355 /*
1356 * Add net_icmpaccess privilege to effective privileges and limit
1357 * permitted privileges before completely dropping root privileges.
1358 * This requires dropping root privileges temporarily to get the normal
1359 * user's privileges.
1360 */
1361 seteuid(g_uid);
1362 priv_set_t *pPrivEffective = priv_allocset();
1363 priv_set_t *pPrivNew = priv_allocset();
1364 if (pPrivEffective && pPrivNew)
1365 {
1366 int rc = getppriv(PRIV_EFFECTIVE, pPrivEffective);
1367 seteuid(0);
1368 if (!rc)
1369 {
1370 priv_copyset(pPrivEffective, pPrivNew);
1371 rc = priv_addset(pPrivNew, PRIV_NET_ICMPACCESS);
1372 if (!rc)
1373 {
1374 /* Order is important, as one can't set a privilege which is
1375 * not in the permitted privilege set. */
1376 rc = setppriv(PRIV_SET, PRIV_EFFECTIVE, pPrivNew);
1377 if (rc)
1378 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set effective privilege set.\n");
1379 rc = setppriv(PRIV_SET, PRIV_PERMITTED, pPrivNew);
1380 if (rc)
1381 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to set permitted privilege set.\n");
1382 }
1383 else
1384 supR3HardenedError(rc, false, "SUPR3HardenedMain: failed to add NET_ICMPACCESS privilege.\n");
1385 }
1386 }
1387 else
1388 {
1389 /* for memory allocation failures just continue */
1390 seteuid(0);
1391 }
1392
1393 if (pPrivEffective)
1394 priv_freeset(pPrivEffective);
1395 if (pPrivNew)
1396 priv_freeset(pPrivNew);
1397# endif
1398}
1399
1400/*
1401 * Look at the environment for some special options.
1402 */
1403static void supR3GrabOptions(void)
1404{
1405 const char *pszOpt;
1406
1407# ifdef RT_OS_LINUX
1408 g_uCaps = 0;
1409
1410 /*
1411 * Do _not_ perform any capability-related system calls for root processes
1412 * (leaving g_uCaps at 0).
1413 * (Hint: getuid gets the real user id, not the effective.)
1414 */
1415 if (getuid() != 0)
1416 {
1417 /*
1418 * CAP_NET_RAW.
1419 * Default: enabled.
1420 * Can be disabled with 'export VBOX_HARD_CAP_NET_RAW=0'.
1421 */
1422 pszOpt = getenv("VBOX_HARD_CAP_NET_RAW");
1423 if ( !pszOpt
1424 || memcmp(pszOpt, "0", sizeof("0")) != 0)
1425 g_uCaps = CAP_TO_MASK(CAP_NET_RAW);
1426
1427 /*
1428 * CAP_NET_BIND_SERVICE.
1429 * Default: disabled.
1430 * Can be enabled with 'export VBOX_HARD_CAP_NET_BIND_SERVICE=1'.
1431 */
1432 pszOpt = getenv("VBOX_HARD_CAP_NET_BIND_SERVICE");
1433 if ( pszOpt
1434 && memcmp(pszOpt, "0", sizeof("0")) != 0)
1435 g_uCaps |= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
1436 }
1437# endif
1438}
1439
1440/**
1441 * Drop any root privileges we might be holding.
1442 */
1443static void supR3HardenedMainDropPrivileges(void)
1444{
1445 /*
1446 * Try use setre[ug]id since this will clear the save uid/gid and thus
1447 * leave fewer traces behind that libs like GTK+ may pick up.
1448 */
1449 uid_t euid, ruid, suid;
1450 gid_t egid, rgid, sgid;
1451# if defined(RT_OS_DARWIN)
1452 /* The really great thing here is that setreuid isn't available on
1453 OS X 10.4, libc emulates it. While 10.4 have a slightly different and
1454 non-standard setuid implementation compared to 10.5, the following
1455 works the same way with both version since we're super user (10.5 req).
1456 The following will set all three variants of the group and user IDs. */
1457 setgid(g_gid);
1458 setuid(g_uid);
1459 euid = geteuid();
1460 ruid = suid = getuid();
1461 egid = getegid();
1462 rgid = sgid = getgid();
1463
1464# elif defined(RT_OS_SOLARIS)
1465 /* Solaris doesn't have setresuid, but the setreuid interface is BSD
1466 compatible and will set the saved uid to euid when we pass it a ruid
1467 that isn't -1 (which we do). */
1468 setregid(g_gid, g_gid);
1469 setreuid(g_uid, g_uid);
1470 euid = geteuid();
1471 ruid = suid = getuid();
1472 egid = getegid();
1473 rgid = sgid = getgid();
1474
1475# else
1476 /* This is the preferred one, full control no questions about semantics.
1477 PORTME: If this isn't work, try join one of two other gangs above. */
1478 setresgid(g_gid, g_gid, g_gid);
1479 setresuid(g_uid, g_uid, g_uid);
1480 if (getresuid(&ruid, &euid, &suid) != 0)
1481 {
1482 euid = geteuid();
1483 ruid = suid = getuid();
1484 }
1485 if (getresgid(&rgid, &egid, &sgid) != 0)
1486 {
1487 egid = getegid();
1488 rgid = sgid = getgid();
1489 }
1490# endif
1491
1492
1493 /* Check that it worked out all right. */
1494 if ( euid != g_uid
1495 || ruid != g_uid
1496 || suid != g_uid
1497 || egid != g_gid
1498 || rgid != g_gid
1499 || sgid != g_gid)
1500 supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!"
1501 " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n",
1502 euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid);
1503
1504# if RT_OS_LINUX
1505 /*
1506 * Re-enable the cap_net_raw capability which was disabled during setresuid.
1507 */
1508 if (g_uCaps != 0)
1509 {
1510# ifdef USE_LIB_PCAP
1511 /** @todo Warn if that does not work? */
1512 /* XXX cap_net_bind_service */
1513 cap_set_proc(cap_from_text("cap_net_raw+ep"));
1514# else
1515 cap_user_header_t hdr = (cap_user_header_t)alloca(sizeof(*hdr));
1516 cap_user_data_t cap = (cap_user_data_t)alloca(sizeof(*cap));
1517 memset(hdr, 0, sizeof(*hdr));
1518 hdr->version = _LINUX_CAPABILITY_VERSION;
1519 memset(cap, 0, sizeof(*cap));
1520 cap->effective = g_uCaps;
1521 cap->permitted = g_uCaps;
1522 /** @todo Warn if that does not work? */
1523 capset(hdr, cap);
1524# endif /* !USE_LIB_PCAP */
1525 }
1526# endif
1527}
1528
1529#endif /* SUP_HARDENED_SUID */
1530
1531/**
1532 * Loads the VBoxRT DLL/SO/DYLIB, hands it the open driver,
1533 * and calls RTR3InitEx.
1534 *
1535 * @param fFlags The SUPR3HardenedMain fFlags argument, passed to supR3PreInit.
1536 *
1537 * @remarks VBoxRT contains both IPRT and SUPR3.
1538 * @remarks This function will not return on failure.
1539 */
1540static void supR3HardenedMainInitRuntime(uint32_t fFlags)
1541{
1542 /*
1543 * Construct the name.
1544 */
1545 char szPath[RTPATH_MAX];
1546 supR3HardenedPathSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxRT" SUPLIB_DLL_SUFF));
1547 suplibHardenedStrCat(szPath, "/VBoxRT" SUPLIB_DLL_SUFF);
1548
1549 /*
1550 * Open it and resolve the symbols.
1551 */
1552#if defined(RT_OS_WINDOWS)
1553 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/);
1554 if (!hMod)
1555 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
1556 "LoadLibrary \"%s\" failed (rc=%d)",
1557 szPath, RtlGetLastWin32Error());
1558 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
1559 if (!pfnRTInitEx)
1560 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
1561 "Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
1562 szPath, RtlGetLastWin32Error());
1563
1564 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
1565 if (!pfnSUPPreInit)
1566 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
1567 "Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
1568 szPath, RtlGetLastWin32Error());
1569
1570 g_pfnRTLogRelPrintf = (PFNRTLOGRELPRINTF)GetProcAddress(hMod, SUP_HARDENED_SYM("RTLogRelPrintf"));
1571 Assert(g_pfnRTLogRelPrintf); /* Not fatal in non-strict builds. */
1572
1573#else
1574 /* the dlopen crowd */
1575 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
1576 if (!pvMod)
1577 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
1578 "dlopen(\"%s\",) failed: %s",
1579 szPath, dlerror());
1580 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("RTR3InitEx"));
1581 if (!pfnRTInitEx)
1582 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
1583 "Entrypoint \"RTR3InitEx\" not found in \"%s\"!\ndlerror: %s",
1584 szPath, dlerror());
1585 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
1586 if (!pfnSUPPreInit)
1587 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
1588 "Entrypoint \"supR3PreInit\" not found in \"%s\"!\ndlerror: %s",
1589 szPath, dlerror());
1590#endif
1591
1592 /*
1593 * Make the calls.
1594 */
1595 supR3HardenedGetPreInitData(&g_SupPreInitData);
1596 int rc = pfnSUPPreInit(&g_SupPreInitData, fFlags);
1597 if (RT_FAILURE(rc))
1598 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
1599 "supR3PreInit failed with rc=%d", rc);
1600 const char *pszExePath = NULL;
1601#ifdef RT_OS_LINUX
1602 if (!supR3HardenedMainIsProcSelfExeAccssible())
1603 pszExePath = g_szSupLibHardenedExePath;
1604#endif
1605 rc = pfnRTInitEx(RTR3INIT_VER_1,
1606 fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV ? 0 : RTR3INIT_FLAGS_SUPLIB,
1607 0 /*cArgs*/, NULL /*papszArgs*/, pszExePath);
1608 if (RT_FAILURE(rc))
1609 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
1610 "RTR3InitEx failed with rc=%d", rc);
1611
1612#if defined(RT_OS_WINDOWS)
1613 /*
1614 * Windows: Create thread that terminates the process when the parent stub
1615 * process terminates (VBoxNetDHCP, Ctrl-C, etc).
1616 */
1617 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
1618 supR3HardenedWinCreateParentWatcherThread(hMod);
1619#endif
1620}
1621
1622
1623/**
1624 * Loads the DLL/SO/DYLIB containing the actual program and
1625 * resolves the TrustedError symbol.
1626 *
1627 * This is very similar to supR3HardenedMainGetTrustedMain().
1628 *
1629 * @returns Pointer to the trusted error symbol if it is exported, NULL
1630 * and no error messages otherwise.
1631 * @param pszProgName The program name.
1632 */
1633static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
1634{
1635 /*
1636 * Don't bother if the main() function didn't advertise any TrustedError
1637 * export. It's both a waste of time and may trigger additional problems,
1638 * confusing or obscuring the original issue.
1639 */
1640 if (!(g_fSupHardenedMain & SUPSECMAIN_FLAGS_TRUSTED_ERROR))
1641 return NULL;
1642
1643 /*
1644 * Construct the name.
1645 */
1646 char szPath[RTPATH_MAX];
1647 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
1648 size_t cch = suplibHardenedStrLen(szPath);
1649 suplibHardenedStrCopyEx(&szPath[cch], sizeof(szPath) - cch, "/", pszProgName, SUPLIB_DLL_SUFF, NULL);
1650
1651 /*
1652 * Open it and resolve the symbol.
1653 */
1654#if defined(RT_OS_WINDOWS)
1655 supR3HardenedWinEnableThreadCreation();
1656 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/);
1657 if (!hMod)
1658 return NULL;
1659 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
1660 if (!pfn)
1661 return NULL;
1662 return (PFNSUPTRUSTEDERROR)pfn;
1663
1664#else
1665 /* the dlopen crowd */
1666 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
1667 if (!pvMod)
1668 return NULL;
1669 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
1670 if (!pvSym)
1671 return NULL;
1672 return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
1673#endif
1674}
1675
1676
1677/**
1678 * Loads the DLL/SO/DYLIB containing the actual program and
1679 * resolves the TrustedMain symbol.
1680 *
1681 * @returns Pointer to the trusted main of the actual program.
1682 * @param pszProgName The program name.
1683 * @remarks This function will not return on failure.
1684 */
1685static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName)
1686{
1687 /*
1688 * Construct the name.
1689 */
1690 char szPath[RTPATH_MAX];
1691 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
1692 size_t cch = suplibHardenedStrLen(szPath);
1693 suplibHardenedStrCopyEx(&szPath[cch], sizeof(szPath) - cch, "/", pszProgName, SUPLIB_DLL_SUFF, NULL);
1694
1695 /*
1696 * Open it and resolve the symbol.
1697 */
1698#if defined(RT_OS_WINDOWS)
1699 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/);
1700 if (!hMod)
1701 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibrary \"%s\" failed, rc=%d\n",
1702 szPath, RtlGetLastWin32Error());
1703 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
1704 if (!pfn)
1705 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
1706 szPath, RtlGetLastWin32Error());
1707 return (PFNSUPTRUSTEDMAIN)pfn;
1708
1709#else
1710 /* the dlopen crowd */
1711 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
1712 if (!pvMod)
1713 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
1714 szPath, dlerror());
1715 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
1716 if (!pvSym)
1717 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
1718 szPath, dlerror());
1719 return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
1720#endif
1721}
1722
1723
1724/**
1725 * Secure main.
1726 *
1727 * This is used for the set-user-ID-on-execute binaries on unixy systems
1728 * and when using the open-vboxdrv-via-root-service setup on Windows.
1729 *
1730 * This function will perform the integrity checks of the VirtualBox
1731 * installation, open the support driver, open the root service (later),
1732 * and load the DLL corresponding to \a pszProgName and execute its main
1733 * function.
1734 *
1735 * @returns Return code appropriate for main().
1736 *
1737 * @param pszProgName The program name. This will be used to figure out which
1738 * DLL/SO/DYLIB to load and execute.
1739 * @param fFlags Flags.
1740 * @param argc The argument count.
1741 * @param argv The argument vector.
1742 * @param envp The environment vector.
1743 */
1744DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
1745{
1746 SUP_DPRINTF(("SUPR3HardenedMain: pszProgName=%s fFlags=%#x\n", pszProgName, fFlags));
1747 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED;
1748
1749 /*
1750 * Note! At this point there is no IPRT, so we will have to stick
1751 * to basic CRT functions that everyone agree upon.
1752 */
1753 g_pszSupLibHardenedProgName = pszProgName;
1754 g_fSupHardenedMain = fFlags;
1755 g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
1756 g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
1757#ifdef RT_OS_WINDOWS
1758 if (!g_fSupEarlyProcessInit)
1759#endif
1760 g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
1761
1762#ifdef SUP_HARDENED_SUID
1763# ifdef RT_OS_LINUX
1764 /*
1765 * On linux we have to make sure the path is initialized because we
1766 * *might* not be able to access /proc/self/exe after the seteuid call.
1767 */
1768 supR3HardenedGetFullExePath();
1769# endif
1770
1771 /*
1772 * Grab any options from the environment.
1773 */
1774 supR3GrabOptions();
1775
1776 /*
1777 * Check that we're root, if we aren't then the installation is butchered.
1778 */
1779 g_uid = getuid();
1780 g_gid = getgid();
1781 if (geteuid() != 0 /* root */)
1782 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
1783 "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
1784 geteuid(), getegid(), g_uid, g_gid);
1785#endif /* SUP_HARDENED_SUID */
1786
1787#ifdef RT_OS_WINDOWS
1788 /*
1789 * Windows: First respawn. On Windows we will respawn the process twice to establish
1790 * something we can put some kind of reliable trust in. The first respawning aims
1791 * at dropping compatibility layers and process "security" solutions.
1792 */
1793 if ( !g_fSupEarlyProcessInit
1794 && !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
1795 && supR3HardenedWinIsReSpawnNeeded(1 /*iWhich*/, argc, argv))
1796 {
1797 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #1\n"));
1798 supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV, false /*fAvastKludge*/);
1799 supR3HardenedVerifyAll(true /* fFatal */, pszProgName);
1800 return supR3HardenedWinReSpawn(1 /*iWhich*/);
1801 }
1802
1803 /*
1804 * Windows: Initialize the image verification global data so we can verify the
1805 * signature of the process image and hook the core of the DLL loader API so we
1806 * can check the signature of all DLLs mapped into the process. (Already done
1807 * by early VM process init.)
1808 */
1809 if (!g_fSupEarlyProcessInit)
1810 supR3HardenedWinInit(fFlags, true /*fAvastKludge*/);
1811#endif /* RT_OS_WINDOWS */
1812
1813 /*
1814 * Validate the installation.
1815 */
1816 supR3HardenedVerifyAll(true /* fFatal */, pszProgName);
1817
1818 /*
1819 * The next steps are only taken if we actually need to access the support
1820 * driver. (Already done by early process init.)
1821 */
1822 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
1823 {
1824#ifdef RT_OS_WINDOWS
1825 /*
1826 * Windows: Must have done early process init if we get here.
1827 */
1828 if (!g_fSupEarlyProcessInit)
1829 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_Integrity, VERR_WRONG_ORDER,
1830 "Early process init was somehow skipped.");
1831
1832 /*
1833 * Windows: The second respawn. This time we make a special arrangement
1834 * with vboxdrv to monitor access to the new process from its inception.
1835 */
1836 if (supR3HardenedWinIsReSpawnNeeded(2 /* iWhich*/, argc, argv))
1837 {
1838 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #2\n"));
1839 return supR3HardenedWinReSpawn(2 /* iWhich*/);
1840 }
1841 SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
1842 supR3HardenedWinFlushLoaderCache();
1843
1844#else
1845 /*
1846 * Open the vboxdrv device.
1847 */
1848 supR3HardenedMainOpenDevice();
1849#endif /* !RT_OS_WINDOWS */
1850 }
1851
1852#ifdef RT_OS_WINDOWS
1853 /*
1854 * Windows: Enable the use of windows APIs to verify images at load time.
1855 */
1856 supR3HardenedWinEnableThreadCreation();
1857 supR3HardenedWinFlushLoaderCache();
1858 supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(g_pszSupLibHardenedProgName);
1859 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_WIN_VERIFY_TRUST_READY;
1860#endif
1861
1862#ifdef SUP_HARDENED_SUID
1863 /*
1864 * Grab additional capabilities / privileges.
1865 */
1866 supR3HardenedMainGrabCapabilites();
1867
1868 /*
1869 * Drop any root privileges we might be holding (won't return on failure)
1870 */
1871 supR3HardenedMainDropPrivileges();
1872#endif
1873
1874 /*
1875 * Load the IPRT, hand the SUPLib part the open driver and
1876 * call RTR3InitEx.
1877 */
1878 SUP_DPRINTF(("SUPR3HardenedMain: Load Runtime...\n"));
1879 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_INIT_RUNTIME;
1880 supR3HardenedMainInitRuntime(fFlags);
1881
1882 /*
1883 * Load the DLL/SO/DYLIB containing the actual program
1884 * and pass control to it.
1885 */
1886 SUP_DPRINTF(("SUPR3HardenedMain: Load TrustedMain...\n"));
1887 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_GET_TRUSTED_MAIN;
1888 PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName);
1889
1890 SUP_DPRINTF(("SUPR3HardenedMain: Calling TrustedMain (%p)...\n", pfnTrustedMain));
1891 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN;
1892 return pfnTrustedMain(argc, argv, envp);
1893}
1894
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