VirtualBox

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

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

SUP,IPRT: Extended RTLdrQueryPropEx with a pvBits parameter, RTLDRPROP_IMPORT_COUNT and RTLDRPROP_IMPORT_MODULE. Hook LdrLoadDll to validate DLLs before they get to NtCreateSection and the loader code/data can be messed up (windows 7 / 32-bit crash). Allow the kernel to buffer the log file, no real need that each write hits the disk.

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