VirtualBox

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

Last change on this file since 13468 was 13458, checked in by vboxsync, 16 years ago

SUPR3HardenedMain: Added optional TrustedError callback to the wrapped up executable. This gets called when something goes wrong and we think we can things enough to display a message. The messages may need some more words and work, there are also more cases for which we could display messages.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 KB
Line 
1/* $Id: SUPR3HardenedMain.cpp 13458 2008-10-21 18:40:56Z 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.
437 */
438 PFNSUPTRUSTEDERROR pfnTrustedError = supR3HardenedMainGetTrustedError(g_pszSupLibHardenedProgName);
439 if (pfnTrustedError)
440 pfnTrustedError(pszWhere, enmWhat, rc, pszMsgFmt, va);
441
442 /*
443 * Quit
444 */
445 for (;;)
446#ifdef _MSC_VER
447 exit(1);
448#else
449 _Exit(1);
450#endif
451}
452
453
454DECLHIDDEN(void) supR3HardenedFatalMsg(const char *pszWhere, SUPINITOP enmWhat, int rc, const char *pszMsgFmt, ...)
455{
456 va_list va;
457 va_start(va, pszMsgFmt);
458 supR3HardenedFatalMsgV(pszWhere, enmWhat, rc, pszMsgFmt, va);
459 va_end(va);
460}
461
462
463DECLHIDDEN(void) supR3HardenedFatalV(const char *pszFormat, va_list va)
464{
465 fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
466 vfprintf(stderr, pszFormat, va);
467 for (;;)
468#ifdef _MSC_VER
469 exit(1);
470#else
471 _Exit(1);
472#endif
473}
474
475
476DECLHIDDEN(void) supR3HardenedFatal(const char *pszFormat, ...)
477{
478 va_list va;
479 va_start(va, pszFormat);
480 supR3HardenedFatalV(pszFormat, va);
481 va_end(va);
482}
483
484
485DECLHIDDEN(int) supR3HardenedErrorV(int rc, bool fFatal, const char *pszFormat, va_list va)
486{
487 if (fFatal)
488 supR3HardenedFatalV(pszFormat, va);
489
490 fprintf(stderr, "%s: ", g_pszSupLibHardenedProgName);
491 vfprintf(stderr, pszFormat, va);
492 return rc;
493}
494
495
496DECLHIDDEN(int) supR3HardenedError(int rc, bool fFatal, const char *pszFormat, ...)
497{
498 va_list va;
499 va_start(va, pszFormat);
500 supR3HardenedErrorV(rc, fFatal, pszFormat, va);
501 va_end(va);
502 return rc;
503}
504
505
506/**
507 * Wrapper around snprintf which will throw a fatal error on buffer overflow.
508 *
509 * @returns Number of chars in the result string.
510 * @param pszDst The destination buffer.
511 * @param cchDst The size of the buffer.
512 * @param pszFormat The format string.
513 * @param ... Format arguments.
514 */
515static size_t supR3HardenedStrPrintf(char *pszDst, size_t cchDst, const char *pszFormat, ...)
516{
517 va_list va;
518 va_start(va, pszFormat);
519#ifdef _MSC_VER
520 int cch = _vsnprintf(pszDst, cchDst, pszFormat, va);
521#else
522 int cch = vsnprintf(pszDst, cchDst, pszFormat, va);
523#endif
524 va_end(va);
525 if ((unsigned)cch >= cchDst || cch < 0)
526 supR3HardenedFatal("supR3HardenedStrPrintf: buffer overflow, %d >= %lu\n", cch, (long)cchDst);
527 return cch;
528}
529
530
531/**
532 * Attempts to open /dev/vboxdrv (or equvivalent).
533 *
534 * @remarks This function will not return on failure.
535 */
536static void supR3HardenedMainOpenDevice(void)
537{
538 int rc = suplibOsInit(&g_SupPreInitData.Data, false);
539 if (RT_SUCCESS(rc))
540 return;
541
542 switch (rc)
543 {
544 /** @todo better messages! */
545 case VERR_VM_DRIVER_NOT_INSTALLED:
546 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
547 "VERR_VM_DRIVER_NOT_INSTALLED");
548 case VERR_VM_DRIVER_NOT_ACCESSIBLE:
549 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
550 "VERR_VM_DRIVER_NOT_ACCESSIBLE");
551 case VERR_VM_DRIVER_LOAD_ERROR:
552 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
553 "VERR_VM_DRIVER_LOAD_ERROR");
554 case VERR_VM_DRIVER_OPEN_ERROR:
555 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
556 "VERR_VM_DRIVER_OPEN_ERROR");
557 case VERR_VM_DRIVER_VERSION_MISMATCH:
558 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
559 "VERR_VM_DRIVER_VERSION_MISMATCH");
560 case VERR_ACCESS_DENIED:
561 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
562 "VERR_ACCESS_DENIED");
563 default:
564 supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
565 "Unknown rc=%d", rc);
566 }
567}
568
569
570#ifdef SUP_HARDENED_SUID
571/**
572 * Drop any root privileges we might be holding.
573 */
574static void supR3HardenedMainDropPrivileges(void)
575{
576 /*
577 * Try use setre[ug]id since this will clear the save uid/gid and thus
578 * leave fewer traces behind that libs like GTK+ may pick up.
579 */
580 uid_t euid, ruid, suid;
581 gid_t egid, rgid, sgid;
582# if defined(RT_OS_DARWIN)
583 /* The really great thing here is that setreuid isn't available on
584 OS X 10.4, libc emulates it. While 10.4 have a sligtly different and
585 non-standard setuid implementation compared to 10.5, the following
586 works the same way with both version since we're super user (10.5 req).
587 The following will set all three variants of the group and user IDs. */
588 setgid(g_gid);
589 setuid(g_uid);
590 euid = geteuid();
591 ruid = suid = getuid();
592 egid = getegid();
593 rgid = sgid = getgid();
594
595# elif defined(RT_OS_SOLARIS)
596 /* Solaris doesn't have setresuid, but the setreuid interface is BSD
597 compatible and will set the saved uid to euid when we pass it a ruid
598 that isn't -1 (which we do). */
599 setregid(g_gid, g_gid);
600 setreuid(g_uid, g_uid);
601 euid = geteuid();
602 ruid = suid = getuid();
603 egid = getegid();
604 rgid = sgid = getgid();
605
606# else
607 /* This is the preferred one, full control no questions about semantics.
608 PORTME: If this isn't work, try join one of two other gangs above. */
609 setresgid(g_gid, g_gid, g_gid);
610 setresuid(g_uid, g_uid, g_uid);
611 if (getresuid(&ruid, &euid, &suid) != 0)
612 {
613 euid = geteuid();
614 ruid = suid = getuid();
615 }
616 if (getresgid(&rgid, &egid, &sgid) != 0)
617 {
618 egid = getegid();
619 rgid = sgid = getgid();
620 }
621# endif
622
623 /* Check that it worked out all right. */
624 if ( euid != g_uid
625 || ruid != g_uid
626 || suid != g_uid
627 || egid != g_gid
628 || rgid != g_gid
629 || sgid != g_gid)
630 supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!"
631 " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n",
632 euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid);
633}
634#endif /* SUP_HARDENED_SUID */
635
636
637/**
638 * Loads the VBoxRT DLL/SO/DYLIB, hands it the open driver,
639 * and calls RTR3Init.
640 *
641 * @param fFlags The SUPR3HardenedMain fFlags argument, passed to supR3PreInit.
642 *
643 * @remarks VBoxRT contains both IPRT and SUPR3.
644 * @remarks This function will not return on failure.
645 */
646static void supR3HardenedMainInitRuntime(uint32_t fFlags)
647{
648 /*
649 * Construct the name.
650 */
651 char szPath[RTPATH_MAX];
652 supR3HardenedPathSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxRT" SUPLIB_DLL_SUFF));
653 strcat(szPath, "/VBoxRT" SUPLIB_DLL_SUFF);
654
655 /*
656 * Open it and resolve the symbols.
657 */
658#if defined(RT_OS_WINDOWS)
659 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
660 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
661 if (!hMod)
662 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
663 "LoadLibraryEx(\"%s\",,) failed (rc=%d)",
664 szPath, GetLastError());
665 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
666 if (!pfnRTInitEx)
667 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
668 "Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
669 szPath, GetLastError());
670
671 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
672 if (!pfnSUPPreInit)
673 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
674 "Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
675 szPath, GetLastError());
676
677#else
678 /* the dlopen crowd */
679 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
680 if (!pvMod)
681 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
682 "dlopen(\"%s\",) failed: %s",
683 szPath, dlerror());
684 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("RTR3InitEx"));
685 if (!pfnRTInitEx)
686 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
687 "Entrypoint \"RTR3InitEx\" not found in \"%s\"!\ndlerror: %s",
688 szPath, dlerror());
689 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
690 if (!pfnSUPPreInit)
691 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
692 "Entrypoint \"supR3PreInit\" not found in \"%s\"!\ndlerror: %s",
693 szPath, dlerror());
694#endif
695
696 /*
697 * Make the calls.
698 */
699 supR3HardenedGetPreInitData(&g_SupPreInitData);
700 int rc = pfnSUPPreInit(&g_SupPreInitData, fFlags);
701 if (RT_FAILURE(rc))
702 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
703 "supR3PreInit failed with rc=%d", rc);
704 const char *pszExePath = NULL;
705#ifdef RT_OS_LINUX
706 if (!supR3HardenedMainIsProcSelfExeAccssible())
707 pszExePath = g_szSupLibHardenedExePath;
708#endif
709 rc = pfnRTInitEx(0, pszExePath, !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV));
710 if (RT_FAILURE(rc))
711 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
712 "RTR3Init failed with rc=%d", rc);
713}
714
715
716/**
717 * Loads the DLL/SO/DYLIB containing the actual program and
718 * resolves the TrustedError symbol.
719 *
720 * This is very similar to supR3HardenedMainGetTrustedMain().
721 *
722 * @returns Pointer to the trusted error symbol if it is exported, NULL
723 * and no error messages otherwise.
724 * @param pszProgName The program name.
725 */
726static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
727{
728 /*
729 * Construct the name.
730 */
731 char szPath[RTPATH_MAX];
732 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
733 size_t cch = strlen(szPath);
734 supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
735
736 /*
737 * Open it and resolve the symbol.
738 */
739#if defined(RT_OS_WINDOWS)
740 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
741 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
742 if (!hMod)
743 return NULL;
744 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
745 if (!pfn)
746 return NULL;
747 return (PFNSUPTRUSTEDERROR)pfn;
748
749#else
750 /* the dlopen crowd */
751 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
752 if (!pvMod)
753 return NULL;
754 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
755 if (!pvSym)
756 return NULL;
757 return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
758#endif
759}
760
761
762/**
763 * Loads the DLL/SO/DYLIB containing the actual program and
764 * resolves the TrustedMain symbol.
765 *
766 * @returns Pointer to the trusted main of the actual program.
767 * @param pszProgName The program name.
768 * @remarks This function will not return on failure.
769 */
770static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName)
771{
772 /*
773 * Construct the name.
774 */
775 char szPath[RTPATH_MAX];
776 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
777 size_t cch = strlen(szPath);
778 supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
779
780 /*
781 * Open it and resolve the symbol.
782 */
783#if defined(RT_OS_WINDOWS)
784 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
785 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
786 if (!hMod)
787 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibraryEx(\"%s\",,) failed, rc=%d\n",
788 szPath, GetLastError());
789 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
790 if (!pfn)
791 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
792 szPath, GetLastError());
793 return (PFNSUPTRUSTEDMAIN)pfn;
794
795#else
796 /* the dlopen crowd */
797 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
798 if (!pvMod)
799 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
800 szPath, dlerror());
801 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
802 if (!pvSym)
803 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
804 szPath, dlerror());
805 return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
806#endif
807}
808
809
810/**
811 * Secure main.
812 *
813 * This is used for the set-user-ID-on-execute binaries on unixy systems
814 * and when using the open-vboxdrv-via-root-service setup on Windows.
815 *
816 * This function will perform the integrity checks of the VirtualBox
817 * installation, open the support driver, open the root service (later),
818 * and load the DLL corresponding to \a pszProgName and execute its main
819 * function.
820 *
821 * @returns Return code appropriate for main().
822 *
823 * @param pszProgName The program name. This will be used to figure out which
824 * DLL/SO/DYLIB to load and execute.
825 * @param fFlags Flags.
826 * @param argc The argument count.
827 * @param argv The argument vector.
828 * @param envp The environment vector.
829 */
830DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
831{
832 /*
833 * Note! At this point there is no IPRT, so we will have to stick
834 * to basic CRT functions that everyone agree upon.
835 */
836 g_pszSupLibHardenedProgName = pszProgName;
837 g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
838 g_SupPreInitData.Data.hDevice = NIL_RTFILE;
839 g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
840
841#ifdef SUP_HARDENED_SUID
842# ifdef RT_OS_LINUX
843 /*
844 * On linux we have to make sure the path is initialized because we
845 * *might* not be able to access /proc/self/exe after the seteuid call.
846 */
847 supR3HardenedGetFullExePath();
848# endif
849
850 /*
851 * Check that we're root, if we aren't then the installation is butchered.
852 */
853 g_uid = getuid();
854 g_gid = getgid();
855 if (geteuid() != 0 /* root */)
856 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
857 "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
858 geteuid(), getegid(), g_uid, g_gid);
859#endif
860
861 /*
862 * Validate the installation.
863 */
864 supR3HardenedVerifyAll(true /* fFatal */, false /* fLeaveFilesOpen */, pszProgName);
865
866 /*
867 * Open the vboxdrv device.
868 */
869 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
870 supR3HardenedMainOpenDevice();
871
872 /*
873 * Open the root service connection.
874 */
875 //if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_SVC))
876 //supR3HardenedMainOpenService(&g_SupPreInitData, true /* fFatal */);
877
878#ifdef SUP_HARDENED_SUID
879 /*
880 * Drop any root privileges we might be holding (won't return on failure)
881 */
882 supR3HardenedMainDropPrivileges();
883#endif
884
885 /*
886 * Load the IPRT, hand the SUPLib part the open driver and
887 * call RTR3Init.
888 */
889 supR3HardenedMainInitRuntime(fFlags);
890
891 /*
892 * Load the DLL/SO/DYLIB containing the actual program
893 * and pass control to it.
894 */
895 PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName);
896 return pfnTrustedMain(argc, argv, envp);
897}
898
899
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette