VirtualBox

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

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

SUPR3HardenedMain: Solaris ICMP access.

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