VirtualBox

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

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

*: scm cleanup run.

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