VirtualBox

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

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

VBoxDrv-win.cpp: Keep the error info string from failed VBoxDrv and VBoxDrvStub open operations so userland can give us better messages to work on. Fixeds a couple of odd bugs.

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