VirtualBox

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

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

bugfix in previous commit with some new parent watcher code (disabled).

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