VirtualBox

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

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

supHardNt: Some more memory replacment hacking - take evasive action on failure; flush log file and if possible log volume as we process.

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