VirtualBox

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

Last change on this file since 52083 was 52083, checked in by vboxsync, 11 years ago

SUP: delay signature checking of the vbox files till we actually use them. Should speed up startup time a little.

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