VirtualBox

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

Last change on this file since 13637 was 13503, checked in by vboxsync, 16 years ago

SUPR3HardendedMain: fork before calling TrustedError.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.2 KB
Line 
1/* $Id: SUPR3HardenedMain.cpp 13503 2008-10-22 16:55:52Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Hardened main().
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#if defined(RT_OS_OS2)
35# define INCL_BASE
36# define INCL_ERRORS
37# include <os2.h>
38# include <stdio.h>
39
40#elif RT_OS_WINDOWS
41# include <Windows.h>
42# include <stdio.h>
43
44#else /* UNIXes */
45# include <iprt/types.h> /* stdint fun on darwin. */
46
47# include <stdio.h>
48# include <stdlib.h>
49# include <dlfcn.h>
50# include <limits.h>
51# include <errno.h>
52# include <unistd.h>
53# include <sys/stat.h>
54# include <sys/time.h>
55# include <stdio.h>
56# include <sys/types.h>
57# include <pwd.h>
58# ifdef RT_OS_DARWIN
59# include <mach-o/dyld.h>
60# endif
61
62#endif
63
64#include <VBox/sup.h>
65#include <VBox/err.h>
66#include <iprt/string.h>
67#include <iprt/param.h>
68
69#include "SUPLibInternal.h"
70
71
72/*******************************************************************************
73* Defined Constants And Macros *
74*******************************************************************************/
75/** @def SUP_HARDENED_SUID
76 * Whether we're employing set-user-ID-on-execute in the hardening.
77 */
78#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) && !defined(RT_OS_L4)
79# define SUP_HARDENED_SUID
80#else
81# undef SUP_HARDENED_SUID
82#endif
83
84/** @def SUP_HARDENED_SYM
85 * Decorate a symbol that's resolved dynamically.
86 */
87#ifdef RT_OS_OS2
88# define SUP_HARDENED_SYM(sym) "_" ## sym
89#else
90# define SUP_HARDENED_SYM(sym) sym
91#endif
92
93
94/*******************************************************************************
95* Structures and Typedefs *
96*******************************************************************************/
97/** @see RTR3InitEx */
98typedef DECLCALLBACK(int) FNRTR3INITEX(uint32_t iVersion, const char *pszProgramPath, bool fInitSUPLib);
99typedef FNRTR3INITEX *PFNRTR3INITEX;
100
101
102/*******************************************************************************
103* Global Variables *
104*******************************************************************************/
105/** The pre-init data we pass on to SUPR3 (residing in VBoxRT). */
106static SUPPREINITDATA g_SupPreInitData;
107/** The progam executable path. */
108static char g_szSupLibHardenedExePath[RTPATH_MAX];
109/** The program directory path. */
110static char g_szSupLibHardenedDirPath[RTPATH_MAX];
111
112/** The program name. */
113static const char *g_pszSupLibHardenedProgName;
114
115#ifdef SUP_HARDENED_SUID
116/** The real UID at startup. */
117static uid_t g_uid;
118/** The real GID at startup. */
119static gid_t g_gid;
120#endif
121
122/*******************************************************************************
123* Internal Functions *
124*******************************************************************************/
125#ifdef SUP_HARDENED_SUID
126static void supR3HardenedMainDropPrivileges(void);
127#endif
128static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName);
129
130
131/**
132 * @copydoc RTPathStripFilename.
133 */
134static void suplibHardenedPathStripFilename(char *pszPath)
135{
136 char *psz = pszPath;
137 char *pszLastSep = pszPath;
138
139 for (;; psz++)
140 {
141 switch (*psz)
142 {
143 /* handle separators. */
144#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
145 case ':':
146 pszLastSep = psz + 1;
147 break;
148
149 case '\\':
150#endif
151 case '/':
152 pszLastSep = psz;
153 break;
154
155 /* the end */
156 case '\0':
157 if (pszLastSep == pszPath)
158 *pszLastSep++ = '.';
159 *pszLastSep = '\0';
160 return;
161 }
162 }
163 /* will never get here */
164}
165
166
167/**
168 * @copydoc RTPathFilename
169 */
170DECLHIDDEN(char *) supR3HardenedPathFilename(const char *pszPath)
171{
172 const char *psz = pszPath;
173 const char *pszLastComp = pszPath;
174
175 for (;; psz++)
176 {
177 switch (*psz)
178 {
179 /* handle separators. */
180#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
181 case ':':
182 pszLastComp = psz + 1;
183 break;
184
185 case '\\':
186#endif
187 case '/':
188 pszLastComp = psz + 1;
189 break;
190
191 /* the end */
192 case '\0':
193 if (*pszLastComp)
194 return (char *)(void *)pszLastComp;
195 return NULL;
196 }
197 }
198
199 /* will never get here */
200 return NULL;
201}
202
203
204/**
205 * @copydoc RTPathAppPrivateNoArch
206 */
207DECLHIDDEN(int) supR3HardenedPathAppPrivateNoArch(char *pszPath, size_t cchPath)
208{
209#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
210 const char *pszSrcPath = RTPATH_APP_PRIVATE;
211 size_t cchPathPrivateNoArch = strlen(pszSrcPath);
212 if (cchPathPrivateNoArch >= cchPath)
213 supR3HardenedFatal("supR3HardenedPathAppPrivateNoArch: Buffer overflow, %lu >= %lu\n",
214 (unsigned long)cchPathPrivateNoArch, (unsigned long)cchPath);
215 memcpy(pszPath, pszSrcPath, cchPathPrivateNoArch + 1);
216 return VINF_SUCCESS;
217
218#else
219 return supR3HardenedPathProgram(pszPath, cchPath);
220#endif
221}
222
223
224/**
225 * @copydoc RTPathAppPrivateArch
226 */
227DECLHIDDEN(int) supR3HardenedPathAppPrivateArch(char *pszPath, size_t cchPath)
228{
229#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE_ARCH)
230 const char *pszSrcPath = RTPATH_APP_PRIVATE_ARCH;
231 size_t cchPathPrivateArch = strlen(pszSrcPath);
232 if (cchPathPrivateArch >= cchPath)
233 supR3HardenedFatal("supR3HardenedPathAppPrivateArch: Buffer overflow, %lu >= %lu\n",
234 (unsigned long)cchPathPrivateArch, (unsigned long)cchPath);
235 memcpy(pszPath, pszSrcPath, cchPathPrivateArch + 1);
236 return VINF_SUCCESS;
237
238#else
239 return supR3HardenedPathProgram(pszPath, cchPath);
240#endif
241}
242
243
244/**
245 * @copydoc RTPathSharedLibs
246 */
247DECLHIDDEN(int) supR3HardenedPathSharedLibs(char *pszPath, size_t cchPath)
248{
249#if !defined(RT_OS_WINDOWS) && defined(RTPATH_SHARED_LIBS)
250 const char *pszSrcPath = RTPATH_SHARED_LIBS;
251 size_t cchPathSharedLibs = strlen(pszSrcPath);
252 if (cchPathSharedLibs >= cchPath)
253 supR3HardenedFatal("supR3HardenedPathSharedLibs: Buffer overflow, %lu >= %lu\n",
254 (unsigned long)cchPathSharedLibs, (unsigned long)cchPath);
255 memcpy(pszPath, pszSrcPath, cchPathSharedLibs + 1);
256 return VINF_SUCCESS;
257
258#else
259 return supR3HardenedPathProgram(pszPath, cchPath);
260#endif
261}
262
263
264/**
265 * @copydoc RTPathAppDocs
266 */
267DECLHIDDEN(int) supR3HardenedPathAppDocs(char *pszPath, size_t cchPath)
268{
269#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_DOCS)
270 const char *pszSrcPath = RTPATH_APP_DOCS;
271 size_t cchPathAppDocs = strlen(pszSrcPath);
272 if (cchPathAppDocs >= cchPath)
273 supR3HardenedFatal("supR3HardenedPathAppDocs: Buffer overflow, %lu >= %lu\n",
274 (unsigned long)cchPathAppDocs, (unsigned long)cchPath);
275 memcpy(pszPath, pszSrcPath, cchPathAppDocs + 1);
276 return VINF_SUCCESS;
277
278#else
279 return supR3HardenedPathProgram(pszPath, cchPath);
280#endif
281}
282
283
284/**
285 * Returns the full path to the executable.
286 *
287 * @returns IPRT status code.
288 * @param pszPath Where to store it.
289 * @param cchPath How big that buffer is.
290 */
291static void supR3HardenedGetFullExePath(void)
292{
293 /*
294 * Get the program filename.
295 *
296 * Most UNIXes have no API for obtaining the executable path, but provides a symbolic
297 * link in the proc file system that tells who was exec'ed. The bad thing about this
298 * is that we have to use readlink, one of the weirder UNIX APIs.
299 *
300 * Darwin, OS/2 and Windows all have proper APIs for getting the program file name.
301 */
302#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
303# ifdef RT_OS_LINUX
304 int cchLink = readlink("/proc/self/exe", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
305# elif defined(RT_OS_SOLARIS)
306 char szFileBuf[PATH_MAX + 1];
307 sprintf(szFileBuf, "/proc/%ld/path/a.out", (long)getpid());
308 int cchLink = readlink(szFileBuf, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
309# else /* RT_OS_FREEBSD: */
310 int cchLink = readlink("/proc/curproc/file", &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath) - 1);
311# endif
312 if (cchLink < 0 || cchLink == sizeof(g_szSupLibHardenedExePath) - 1)
313 supR3HardenedFatal("supR3HardenedPathProgram: couldn't read \"%s\", errno=%d cchLink=%d\n",
314 g_szSupLibHardenedExePath, errno, cchLink);
315 g_szSupLibHardenedExePath[cchLink] = '\0';
316
317#elif defined(RT_OS_OS2) || defined(RT_OS_L4)
318 _execname(g_szSupLibHardenedExePath, sizeof(g_szSupLibHardenedExePath));
319
320#elif defined(RT_OS_DARWIN)
321 const char *pszImageName = _dyld_get_image_name(0);
322 if (!pszImageName)
323 supR3HardenedFatal("supR3HardenedPathProgram: _dyld_get_image_name(0) failed\n");
324 size_t cchImageName = strlen(pszImageName);
325 if (!cchImageName || cchImageName >= sizeof(g_szSupLibHardenedExePath))
326 supR3HardenedFatal("supR3HardenedPathProgram: _dyld_get_image_name(0) failed, cchImageName=%d\n", cchImageName);
327 memcpy(g_szSupLibHardenedExePath, pszImageName, cchImageName + 1);
328
329#elif defined(RT_OS_WINDOWS)
330 HMODULE hExe = GetModuleHandle(NULL);
331 if (!GetModuleFileName(hExe, &g_szSupLibHardenedExePath[0], sizeof(g_szSupLibHardenedExePath)))
332 supR3HardenedFatal("supR3HardenedPathProgram: GetModuleFileName failed, rc=%d\n", GetLastError());
333#else
334# error needs porting.
335#endif
336
337 /*
338 * Strip off the filename part (RTPathStripFilename()).
339 */
340 strcpy(g_szSupLibHardenedDirPath, g_szSupLibHardenedExePath);
341 suplibHardenedPathStripFilename(g_szSupLibHardenedDirPath);
342}
343
344
345#ifdef RT_OS_LINUX
346/**
347 * Checks if we can read /proc/self/exe.
348 *
349 * This is used on linux to see if we have to call init
350 * with program path or not.
351 *
352 * @returns true / false.
353 */
354static bool supR3HardenedMainIsProcSelfExeAccssible(void)
355{
356 char szPath[RTPATH_MAX];
357 int cchLink = readlink("/proc/self/exe", szPath, sizeof(szPath));
358 return cchLink != -1;
359}
360#endif /* RT_OS_LINUX */
361
362
363
364/**
365 * @copydoc RTPathProgram
366 */
367DECLHIDDEN(int) supR3HardenedPathProgram(char *pszPath, size_t cchPath)
368{
369 /*
370 * Lazy init (probably not required).
371 */
372 if (!g_szSupLibHardenedDirPath[0])
373 supR3HardenedGetFullExePath();
374
375 /*
376 * Calc the length and check if there is space before copying.
377 */
378 unsigned cch = strlen(g_szSupLibHardenedDirPath) + 1;
379 if (cch <= cchPath)
380 {
381 memcpy(pszPath, g_szSupLibHardenedDirPath, cch + 1);
382 return VINF_SUCCESS;
383 }
384
385 supR3HardenedFatal("supR3HardenedPathProgram: Buffer too small (%u < %u)\n", cchPath, cch);
386 return VERR_BUFFER_OVERFLOW;
387}
388
389
390DECLHIDDEN(void) supR3HardenedFatalMsgV(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, va_list va)
391{
392 /*
393 * To the console first, like supR3HardenedFatalV.
394 */
395 fprintf(stderr, "%s: Error %d in %s!\n", g_pszSupLibHardenedProgName, rc, pszWhere);
396 fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
397 va_list vaCopy;
398 va_copy(vaCopy, va);
399 vfprintf(stderr, pszMsgFmt, vaCopy);
400 va_end(vaCopy);
401 fprintf(stderr, "\n");
402
403 switch (enmWhat)
404 {
405 case kSupInitOp_Driver:
406 fprintf(stderr,
407 "\n"
408 "%s: Tip! Make sure the kernel module is loaded. It may also help to reinstall VirtualBox.\n",
409 g_pszSupLibHardenedProgName);
410 break;
411
412 case kSupInitOp_IPRT:
413 case kSupInitOp_Integrity:
414 case kSupInitOp_RootCheck:
415 fprintf(stderr,
416 "\n"
417 "%s: Tip! It may help to reinstall VirtualBox.\n",
418 g_pszSupLibHardenedProgName);
419 break;
420
421 default:
422 /* no hints here */
423 break;
424 }
425
426#ifdef SUP_HARDENED_SUID
427 /*
428 * Drop any root privileges we might be holding, this won't return
429 * if it fails but end up calling supR3HardenedFatal[V].
430 */
431 supR3HardenedMainDropPrivileges();
432#endif /* SUP_HARDENED_SUID */
433
434 /*
435 * Now try resolve and call the TrustedError entry point if we can
436 * find it. We'll fork before we attempt this because that way the
437 * session management in main will see us exiting immediately (if
438 * it's invovled with us).
439 */
440#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
441 int pid = fork();
442 if (pid <= 0)
443#endif
444 {
445 PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
446 if (pfnTrustedError)
447 pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
448 }
449
450 /*
451 * Quit
452 */
453 for (;;)
454#ifdef _MSC_VER
455 exit(1);
456#else
457 _Exit(1);
458#endif
459}
460
461
462DECLHIDDEN(void) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, ...)
463{
464 va_list va;
465 va_start(va, pszMsgFmt);
466 supR3HardenedFatalMsgV(pszWhere, enmWhat, rc, pszMsgFmt, va);
467 va_end(va);
468}
469
470
471DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va)
472{
473 fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
474 vfprintf(stderr, pszFormat, va);
475 for (;;)
476#ifdef _MSC_VER
477 exit(1);
478#else
479 _Exit(1);
480#endif
481}
482
483
484DECLHIDDEN(void) supR3HardenedFatal(const char *pszFormat, ...)
485{
486 va_list va;
487 va_start(va, pszFormat);
488 supR3HardenedFatalV(pszFormat, va);
489 va_end(va);
490}
491
492
493DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va)
494{
495 if (fFatal)
496 supR3HardenedFatalV(pszFormat, va);
497
498 fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
499 vfprintf(stderr, pszFormat, va);
500 return rc;
501}
502
503
504DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...)
505{
506 va_list va;
507 va_start(va, pszFormat);
508 supR3HardenedErrorV(rc, fFatal, pszFormat, va);
509 va_end(va);
510 return rc;
511}
512
513
514/**
515 * Wrapper around snprintf which will throw a fatal error on buffer overflow.
516 *
517 * @returns Number of chars in the result string.
518 * @param pszDst The destination buffer.
519 * @param cchDst The size of the buffer.
520 * @param pszFormat The format string.
521 * @param ... Format arguments.
522 */
523static size_t supR3HardenedStrPrintf(char *pszDst, size_t cchDst, const char *pszFormat, ...)
524{
525 va_list va;
526 va_start(va, pszFormat);
527#ifdef _MSC_VER
528 int cch = _vsnprintf(pszDst, cchDst, pszFormat, va);
529#else
530 int cch = vsnprintf(pszDst, cchDst, pszFormat, va);
531#endif
532 va_end(va);
533 if ((unsigned)cch >= cchDst || cch < 0)
534 supR3HardenedFatal("supR3HardenedStrPrintf: buffer overflow, %d >= %lu\n", cch, (long)cchDst);
535 return cch;
536}
537
538
539/**
540 * Attempts to open /dev/vboxdrv (or equvivalent).
541 *
542 * @remarks This function will not return on failure.
543 */
544static void supR3HardenedMainOpenDevice(void)
545{
546 int rc = suplibOsInit(&g_SupPreInitData.Data, false);
547 if (RT_SUCCESS(rc))
548 return;
549
550 switch (rc)
551 {
552 /** @todo better messages! */
553 case VERR_VM_DRIVER_NOT_INSTALLED:
554 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
555 "VERR_VM_DRIVER_NOT_INSTALLED");
556 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
557 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
558 "VERR_VM_DRIVER_NOT_ACCESSIBLE");
559 case VERR_VM_DRIVER_LOAD_ERROR:
560 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
561 "VERR_VM_DRIVER_LOAD_ERROR");
562 case VERR_VM_DRIVER_OPEN_ERROR:
563 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
564 "VERR_VM_DRIVER_OPEN_ERROR");
565 case VERR_VM_DRIVER_VERSION_MISMATCH:
566 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
567 "VERR_VM_DRIVER_VERSION_MISMATCH");
568 case VERR_ACCESS_DENIED:
569 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
570 "VERR_ACCESS_DENIED");
571 default:
572 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
573 "Unknown rc=%d", rc);
574 }
575}
576
577
578#ifdef SUP_HARDENED_SUID
579/**
580 * Drop any root privileges we might be holding.
581 */
582static void supR3HardenedMainDropPrivileges(void)
583{
584 /*
585 * Try use setre[ug]id since this will clear the save uid/gid and thus
586 * leave fewer traces behind that libs like GTK+ may pick up.
587 */
588 uid_t euid, ruid, suid;
589 gid_t egid, rgid, sgid;
590# if defined(RT_OS_DARWIN)
591 /* The really great thing here is that setreuid isn't available on
592 OS X 10.4, libc emulates it. While 10.4 have a sligtly different and
593 non-standard setuid implementation compared to 10.5, the following
594 works the same way with both version since we're super user (10.5 req).
595 The following will set all three variants of the group and user IDs. */
596 setgid(g_gid);
597 setuid(g_uid);
598 euid = geteuid();
599 ruid = suid = getuid();
600 egid = getegid();
601 rgid = sgid = getgid();
602
603# elif defined(RT_OS_SOLARIS)
604 /* Solaris doesn't have setresuid, but the setreuid interface is BSD
605 compatible and will set the saved uid to euid when we pass it a ruid
606 that isn't -1 (which we do). */
607 setregid(g_gid, g_gid);
608 setreuid(g_uid, g_uid);
609 euid = geteuid();
610 ruid = suid = getuid();
611 egid = getegid();
612 rgid = sgid = getgid();
613
614# else
615 /* This is the preferred one, full control no questions about semantics.
616 PORTME: If this isn't work, try join one of two other gangs above. */
617 setresgid(g_gid, g_gid, g_gid);
618 setresuid(g_uid, g_uid, g_uid);
619 if (getresuid(&ruid, &euid, &suid) != 0)
620 {
621 euid = geteuid();
622 ruid = suid = getuid();
623 }
624 if (getresgid(&rgid, &egid, &sgid) != 0)
625 {
626 egid = getegid();
627 rgid = sgid = getgid();
628 }
629# endif
630
631 /* Check that it worked out all right. */
632 if ( euid != g_uid
633 || ruid != g_uid
634 || suid != g_uid
635 || egid != g_gid
636 || rgid != g_gid
637 || sgid != g_gid)
638 supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!"
639 " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n",
640 euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid);
641}
642#endif /* SUP_HARDENED_SUID */
643
644
645/**
646 * Loads the VBoxRT DLL/SO/DYLIB, hands it the open driver,
647 * and calls RTR3Init.
648 *
649 * @param fFlags The SUPR3HardenedMain fFlags argument, passed to supR3PreInit.
650 *
651 * @remarks VBoxRT contains both IPRT and SUPR3.
652 * @remarks This function will not return on failure.
653 */
654static void supR3HardenedMainInitRuntime(uint32_t fFlags)
655{
656 /*
657 * Construct the name.
658 */
659 char szPath[RTPATH_MAX];
660 supR3HardenedPathSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxRT" SUPLIB_DLL_SUFF));
661 strcat(szPath, "/VBoxRT" SUPLIB_DLL_SUFF);
662
663 /*
664 * Open it and resolve the symbols.
665 */
666#if defined(RT_OS_WINDOWS)
667 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
668 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
669 if (!hMod)
670 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
671 "LoadLibraryEx(\"%s\",,) failed (rc=%d)",
672 szPath, GetLastError());
673 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
674 if (!pfnRTInitEx)
675 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
676 "Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
677 szPath, GetLastError());
678
679 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
680 if (!pfnSUPPreInit)
681 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
682 "Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
683 szPath, GetLastError());
684
685#else
686 /* the dlopen crowd */
687 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
688 if (!pvMod)
689 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
690 "dlopen(\"%s\",) failed: %s",
691 szPath, dlerror());
692 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("RTR3InitEx"));
693 if (!pfnRTInitEx)
694 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
695 "Entrypoint \"RTR3InitEx\" not found in \"%s\"!\ndlerror: %s",
696 szPath, dlerror());
697 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
698 if (!pfnSUPPreInit)
699 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
700 "Entrypoint \"supR3PreInit\" not found in \"%s\"!\ndlerror: %s",
701 szPath, dlerror());
702#endif
703
704 /*
705 * Make the calls.
706 */
707 supR3HardenedGetPreInitData(&g_SupPreInitData);
708 int rc = pfnSUPPreInit(&g_SupPreInitData, fFlags);
709 if (RT_FAILURE(rc))
710 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
711 "supR3PreInit failed with rc=%d", rc);
712 const char *pszExePath = NULL;
713#ifdef RT_OS_LINUX
714 if (!supR3HardenedMainIsProcSelfExeAccssible())
715 pszExePath = g_szSupLibHardenedExePath;
716#endif
717 rc = pfnRTInitEx(0, pszExePath, !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV));
718 if (RT_FAILURE(rc))
719 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
720 "RTR3Init failed with rc=%d", rc);
721}
722
723
724/**
725 * Loads the DLL/SO/DYLIB containing the actual program and
726 * resolves the TrustedError symbol.
727 *
728 * This is very similar to supR3HardenedMainGetTrustedMain().
729 *
730 * @returns Pointer to the trusted error symbol if it is exported, NULL
731 * and no error messages otherwise.
732 * @param pszProgName The program name.
733 */
734static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
735{
736 /*
737 * Construct the name.
738 */
739 char szPath[RTPATH_MAX];
740 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
741 size_t cch = strlen(szPath);
742 supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
743
744 /*
745 * Open it and resolve the symbol.
746 */
747#if defined(RT_OS_WINDOWS)
748 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
749 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
750 if (!hMod)
751 return NULL;
752 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
753 if (!pfn)
754 return NULL;
755 return (PFNSUPTRUSTEDERROR)pfn;
756
757#else
758 /* the dlopen crowd */
759 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
760 if (!pvMod)
761 return NULL;
762 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
763 if (!pvSym)
764 return NULL;
765 return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
766#endif
767}
768
769
770/**
771 * Loads the DLL/SO/DYLIB containing the actual program and
772 * resolves the TrustedMain symbol.
773 *
774 * @returns Pointer to the trusted main of the actual program.
775 * @param pszProgName The program name.
776 * @remarks This function will not return on failure.
777 */
778static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName)
779{
780 /*
781 * Construct the name.
782 */
783 char szPath[RTPATH_MAX];
784 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
785 size_t cch = strlen(szPath);
786 supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
787
788 /*
789 * Open it and resolve the symbol.
790 */
791#if defined(RT_OS_WINDOWS)
792 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
793 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
794 if (!hMod)
795 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibraryEx(\"%s\",,) failed, rc=%d\n",
796 szPath, GetLastError());
797 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
798 if (!pfn)
799 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
800 szPath, GetLastError());
801 return (PFNSUPTRUSTEDMAIN)pfn;
802
803#else
804 /* the dlopen crowd */
805 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
806 if (!pvMod)
807 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
808 szPath, dlerror());
809 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
810 if (!pvSym)
811 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
812 szPath, dlerror());
813 return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
814#endif
815}
816
817
818/**
819 * Secure main.
820 *
821 * This is used for the set-user-ID-on-execute binaries on unixy systems
822 * and when using the open-vboxdrv-via-root-service setup on Windows.
823 *
824 * This function will perform the integrity checks of the VirtualBox
825 * installation, open the support driver, open the root service (later),
826 * and load the DLL corresponding to \a pszProgName and execute its main
827 * function.
828 *
829 * @returns Return code appropriate for main().
830 *
831 * @param pszProgName The program name. This will be used to figure out which
832 * DLL/SO/DYLIB to load and execute.
833 * @param fFlags Flags.
834 * @param argc The argument count.
835 * @param argv The argument vector.
836 * @param envp The environment vector.
837 */
838DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
839{
840 /*
841 * Note! At this point there is no IPRT, so we will have to stick
842 * to basic CRT functions that everyone agree upon.
843 */
844 g_pszSupLibHardenedProgName = pszProgName;
845 g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
846 g_SupPreInitData.Data.hDevice = NIL_RTFILE;
847 g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
848
849#ifdef SUP_HARDENED_SUID
850# ifdef RT_OS_LINUX
851 /*
852 * On linux we have to make sure the path is initialized because we
853 * *might* not be able to access /proc/self/exe after the seteuid call.
854 */
855 supR3HardenedGetFullExePath();
856# endif
857
858 /*
859 * Check that we're root, if we aren't then the installation is butchered.
860 */
861 g_uid = getuid();
862 g_gid = getgid();
863 if (geteuid() != 0 /* root */)
864 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
865 "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
866 geteuid(), getegid(), g_uid, g_gid);
867#endif
868
869 /*
870 * Validate the installation.
871 */
872 supR3HardenedVerifyAll(true /* fFatal */, false /* fLeaveFilesOpen */, pszProgName);
873
874 /*
875 * Open the vboxdrv device.
876 */
877 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
878 supR3HardenedMainOpenDevice();
879
880 /*
881 * Open the root service connection.
882 */
883 //if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_SVC))
884 //supR3HardenedMainOpenService(&g_SupPreInitData, true /* fFatal */);
885
886#ifdef SUP_HARDENED_SUID
887 /*
888 * Drop any root privileges we might be holding (won't return on failure)
889 */
890 supR3HardenedMainDropPrivileges();
891#endif
892
893 /*
894 * Load the IPRT, hand the SUPLib part the open driver and
895 * call RTR3Init.
896 */
897 supR3HardenedMainInitRuntime(fFlags);
898
899 /*
900 * Load the DLL/SO/DYLIB containing the actual program
901 * and pass control to it.
902 */
903 PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName);
904 return pfnTrustedMain(argc, argv, envp);
905}
906
907
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