VirtualBox

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

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

Only VirtualBox.dll has a TrustedError method, so add a flag to advertise it so we don't wast a lot of effort with VBoxHeadless, VBoxSDL and others that doesn't have it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.7 KB
Line 
1/* $Id: SUPR3HardenedMain.cpp 52424 2014-08-20 03:25:37Z 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
1528
1529/**
1530 * Loads the DLL/SO/DYLIB containing the actual program and
1531 * resolves the TrustedError symbol.
1532 *
1533 * This is very similar to supR3HardenedMainGetTrustedMain().
1534 *
1535 * @returns Pointer to the trusted error symbol if it is exported, NULL
1536 * and no error messages otherwise.
1537 * @param pszProgName The program name.
1538 */
1539static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
1540{
1541 /*
1542 * Don't bother if the main() function didn't advertise any TrustedError
1543 * export. It's both a waste of time and may trigger additional problems,
1544 * confusing or obscuring the original issue.
1545 */
1546 if (!(g_fSupHardenedMain & SUPSECMAIN_FLAGS_TRUSTED_ERROR))
1547 return NULL;
1548
1549 /*
1550 * Construct the name.
1551 */
1552 char szPath[RTPATH_MAX];
1553 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
1554 size_t cch = suplibHardenedStrLen(szPath);
1555 suplibHardenedStrCopyEx(&szPath[cch], sizeof(szPath) - cch, "/", pszProgName, SUPLIB_DLL_SUFF, NULL);
1556
1557 /*
1558 * Open it and resolve the symbol.
1559 */
1560#if defined(RT_OS_WINDOWS)
1561 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/);
1562 if (!hMod)
1563 return NULL;
1564 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
1565 if (!pfn)
1566 return NULL;
1567 return (PFNSUPTRUSTEDERROR)pfn;
1568
1569#else
1570 /* the dlopen crowd */
1571 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
1572 if (!pvMod)
1573 return NULL;
1574 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
1575 if (!pvSym)
1576 return NULL;
1577 return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
1578#endif
1579}
1580
1581
1582/**
1583 * Loads the DLL/SO/DYLIB containing the actual program and
1584 * resolves the TrustedMain symbol.
1585 *
1586 * @returns Pointer to the trusted main of the actual program.
1587 * @param pszProgName The program name.
1588 * @remarks This function will not return on failure.
1589 */
1590static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName)
1591{
1592 /*
1593 * Construct the name.
1594 */
1595 char szPath[RTPATH_MAX];
1596 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
1597 size_t cch = suplibHardenedStrLen(szPath);
1598 suplibHardenedStrCopyEx(&szPath[cch], sizeof(szPath) - cch, "/", pszProgName, SUPLIB_DLL_SUFF, NULL);
1599
1600 /*
1601 * Open it and resolve the symbol.
1602 */
1603#if defined(RT_OS_WINDOWS)
1604 HMODULE hMod = (HMODULE)supR3HardenedWinLoadLibrary(szPath, false /*fSystem32Only*/);
1605 if (!hMod)
1606 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibrary \"%s\" failed, rc=%d\n",
1607 szPath, GetLastError());
1608 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
1609 if (!pfn)
1610 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
1611 szPath, GetLastError());
1612 return (PFNSUPTRUSTEDMAIN)pfn;
1613
1614#else
1615 /* the dlopen crowd */
1616 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
1617 if (!pvMod)
1618 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
1619 szPath, dlerror());
1620 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
1621 if (!pvSym)
1622 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
1623 szPath, dlerror());
1624 return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
1625#endif
1626}
1627
1628
1629/**
1630 * Secure main.
1631 *
1632 * This is used for the set-user-ID-on-execute binaries on unixy systems
1633 * and when using the open-vboxdrv-via-root-service setup on Windows.
1634 *
1635 * This function will perform the integrity checks of the VirtualBox
1636 * installation, open the support driver, open the root service (later),
1637 * and load the DLL corresponding to \a pszProgName and execute its main
1638 * function.
1639 *
1640 * @returns Return code appropriate for main().
1641 *
1642 * @param pszProgName The program name. This will be used to figure out which
1643 * DLL/SO/DYLIB to load and execute.
1644 * @param fFlags Flags.
1645 * @param argc The argument count.
1646 * @param argv The argument vector.
1647 * @param envp The environment vector.
1648 */
1649DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
1650{
1651 SUP_DPRINTF(("SUPR3HardenedMain: pszProgName=%s fFlags=%#x\n", pszProgName, fFlags));
1652
1653 /*
1654 * Note! At this point there is no IPRT, so we will have to stick
1655 * to basic CRT functions that everyone agree upon.
1656 */
1657 g_pszSupLibHardenedProgName = pszProgName;
1658 g_fSupHardenedMain = fFlags;
1659 g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
1660 g_SupPreInitData.Data.hDevice = SUP_HDEVICE_NIL;
1661 g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
1662
1663#ifdef SUP_HARDENED_SUID
1664# ifdef RT_OS_LINUX
1665 /*
1666 * On linux we have to make sure the path is initialized because we
1667 * *might* not be able to access /proc/self/exe after the seteuid call.
1668 */
1669 supR3HardenedGetFullExePath();
1670
1671# endif
1672
1673 /*
1674 * Grab any options from the environment.
1675 */
1676 supR3GrabOptions();
1677
1678 /*
1679 * Check that we're root, if we aren't then the installation is butchered.
1680 */
1681 g_uid = getuid();
1682 g_gid = getgid();
1683 if (geteuid() != 0 /* root */)
1684 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
1685 "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
1686 geteuid(), getegid(), g_uid, g_gid);
1687#endif /* SUP_HARDENED_SUID */
1688
1689#ifdef RT_OS_WINDOWS
1690 /*
1691 * Windows: First respawn. On Windows we will respawn the process twice to establish
1692 * something we can put some kind of reliable trust in. The first respawning aims
1693 * at dropping compatibility layers and process "security" solutions.
1694 */
1695 if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
1696 && supR3HardenedWinIsReSpawnNeeded(1 /*iWhich*/, argc, argv))
1697 {
1698 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #1\n"));
1699 supR3HardenedWinInit(SUPSECMAIN_FLAGS_DONT_OPEN_DEV);
1700 supR3HardenedVerifyAll(true /* fFatal */, pszProgName);
1701 return supR3HardenedWinReSpawn(1 /*iWhich*/);
1702 }
1703
1704 /*
1705 * Windows: Initialize the image verification global data so we can verify the
1706 * signature of the process image and hook the core of the DLL loader API so we
1707 * can check the signature of all DLLs mapped into the process.
1708 */
1709 supR3HardenedWinInit(fFlags);
1710#endif /* RT_OS_WINDOWS */
1711
1712 /*
1713 * Validate the installation.
1714 */
1715 supR3HardenedVerifyAll(true /* fFatal */, pszProgName);
1716
1717 /*
1718 * The next steps are only taken if we actually need to access the support
1719 * driver.
1720 */
1721 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
1722 {
1723#ifdef RT_OS_WINDOWS
1724 /*
1725 * Windows: Verify the process (repeated by the kernel later.
1726 */
1727 supR3HardenedWinVerifyProcess();
1728
1729 /*
1730 * Windows: The second respawn. This time we make a special arrangement
1731 * with vboxdrv to monitor access to the new process from its inception.
1732 */
1733 if (supR3HardenedWinIsReSpawnNeeded(2 /* iWhich*/, argc, argv))
1734 {
1735 SUP_DPRINTF(("SUPR3HardenedMain: Respawn #2\n"));
1736 return supR3HardenedWinReSpawn(2 /* iWhich*/);
1737 }
1738 SUP_DPRINTF(("SUPR3HardenedMain: Final process, opening VBoxDrv...\n"));
1739 supR3HardenedWinFlushLoaderCache();
1740#endif /* RT_OS_WINDOWS */
1741
1742 /*
1743 * Open the vboxdrv device.
1744 */
1745 supR3HardenedMainOpenDevice();
1746 }
1747
1748#ifdef RT_OS_WINDOWS
1749 /*
1750 * Windows: Enable the use of windows APIs to verify images at load time.
1751 */
1752 supR3HardenedWinFlushLoaderCache();
1753 supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(g_pszSupLibHardenedProgName);
1754 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_VERIFY_TRUST_READY;
1755#endif
1756
1757#ifdef SUP_HARDENED_SUID
1758 /*
1759 * Grab additional capabilities / privileges.
1760 */
1761 supR3HardenedMainGrabCapabilites();
1762
1763 /*
1764 * Drop any root privileges we might be holding (won't return on failure)
1765 */
1766 supR3HardenedMainDropPrivileges();
1767#endif
1768
1769 /*
1770 * Load the IPRT, hand the SUPLib part the open driver and
1771 * call RTR3InitEx.
1772 */
1773 SUP_DPRINTF(("SUPR3HardenedMain: Load Runtime...\n"));
1774 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_INIT_RUNTIME;
1775 supR3HardenedMainInitRuntime(fFlags);
1776
1777 /*
1778 * Load the DLL/SO/DYLIB containing the actual program
1779 * and pass control to it.
1780 */
1781 SUP_DPRINTF(("SUPR3HardenedMain: Load TrustedMain...\n"));
1782 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_GET_TRUSTED_MAIN;
1783 PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName);
1784
1785 SUP_DPRINTF(("SUPR3HardenedMain: Calling TrustedMain (%p)...\n", pfnTrustedMain));
1786 g_enmSupR3HardenedMainState = SUPR3HARDENEDMAINSTATE_CALLED_TRUSTED_MAIN;
1787 return pfnTrustedMain(argc, argv, envp);
1788}
1789
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