VirtualBox

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

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

SUPR3HardenedMain: Solaris net raw access (testing).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.9 KB
Line 
1/* $Id: SUPR3HardenedMain.cpp 15271 2008-12-10 17:33:37Z 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
600# elif defined(RT_OS_SOLARIS)
601
602 /*
603 * Add net_rawaccess privilege to permitted, effective and inheritable privileges
604 * before dropping root privileges.
605 */
606 int rc = 0;
607 priv_set_t *pPrivSetPermitted = priv_allocset();
608 if (pPrivSetPermitted)
609 {
610 priv_set_t *pPrivSetEffective = priv_allocset();
611 if (pPrivSetEffective)
612 {
613 priv_set_t *pPrivSetInherit = priv_allocset();
614 if (pPrivSetInherit)
615 {
616 rc = getppriv(PRIV_PERMITTED, pPrivSetPermitted);
617 if (!rc)
618 {
619 rc = getppriv(PRIV_EFFECTIVE, pPrivSetEffective);
620 if (!rc)
621 {
622 rc = getppriv(PRIV_INHERITABLE, pPrivSetInherit);
623 if (!rc)
624 {
625 priv_addset(pPrivSetPermitted, PRIV_NET_RAWACCESS);
626 priv_addset(pPrivSetEffective, PRIV_NET_RAWACCESS);
627 priv_addset(pPrivSetInherit, PRIV_NET_RAWACCESS);
628 }
629 else
630 supR3HardenedFatal("SUPR3HardenedMain: failed to get inheritable privilege set rc=%d.\n", rc);
631 }
632 else
633 supR3HardenedFatal("SUPR3HardenedMain: failed to get effective privilege set rc=%d.\n", rc);
634 }
635 else
636 supR3HardenedFatal("SUPR3HardenedMain: failed to get permitted privilege set rc=%d.\n", rc);
637
638 priv_freeset(pPrivSetInherit);
639 }
640 else
641 supR3HardenedFatal("SUPR3HardenedMain: failed to allocate inheritable privilege set.\n");
642
643 priv_freeset(pPrivSetEffective);
644 }
645 else
646 supR3HardenedFatal("SUPR3HardenedMain: failed to allocate effective privilege set.\n");
647
648 priv_freeset(pPrivSetPermitted);
649 }
650 else
651 supR3HardenedFatal("SUPR3HardenedMain: failed to allocate permitted privilege set.\n");
652
653# endif
654
655 /*
656 * Try use setre[ug]id since this will clear the save uid/gid and thus
657 * leave fewer traces behind that libs like GTK+ may pick up.
658 */
659 uid_t euid, ruid, suid;
660 gid_t egid, rgid, sgid;
661# if defined(RT_OS_DARWIN)
662 /* The really great thing here is that setreuid isn't available on
663 OS X 10.4, libc emulates it. While 10.4 have a sligtly different and
664 non-standard setuid implementation compared to 10.5, the following
665 works the same way with both version since we're super user (10.5 req).
666 The following will set all three variants of the group and user IDs. */
667 setgid(g_gid);
668 setuid(g_uid);
669 euid = geteuid();
670 ruid = suid = getuid();
671 egid = getegid();
672 rgid = sgid = getgid();
673
674# elif defined(RT_OS_SOLARIS)
675 /* Solaris doesn't have setresuid, but the setreuid interface is BSD
676 compatible and will set the saved uid to euid when we pass it a ruid
677 that isn't -1 (which we do). */
678 setregid(g_gid, g_gid);
679 setreuid(g_uid, g_uid);
680 euid = geteuid();
681 ruid = suid = getuid();
682 egid = getegid();
683 rgid = sgid = getgid();
684
685# else
686 /* This is the preferred one, full control no questions about semantics.
687 PORTME: If this isn't work, try join one of two other gangs above. */
688 setresgid(g_gid, g_gid, g_gid);
689 setresuid(g_uid, g_uid, g_uid);
690 if (getresuid(&ruid, &euid, &suid) != 0)
691 {
692 euid = geteuid();
693 ruid = suid = getuid();
694 }
695 if (getresgid(&rgid, &egid, &sgid) != 0)
696 {
697 egid = getegid();
698 rgid = sgid = getgid();
699 }
700# endif
701
702
703 /* Check that it worked out all right. */
704 if ( euid != g_uid
705 || ruid != g_uid
706 || suid != g_uid
707 || egid != g_gid
708 || rgid != g_gid
709 || sgid != g_gid)
710 supR3HardenedFatal("SUPR3HardenedMain: failed to drop root privileges!"
711 " (euid=%d ruid=%d suid=%d egid=%d rgid=%d sgid=%d; wanted uid=%d and gid=%d)\n",
712 euid, ruid, suid, egid, rgid, sgid, g_uid, g_gid);
713
714# if RT_OS_LINUX
715 /*
716 * Re-enable the cap_net_raw capability which was disabled during setresuid.
717 * XXX Warn if that does not work?
718 */
719 cap_set_proc(cap_from_text("cap_net_raw+ep"));
720# endif
721}
722#endif /* SUP_HARDENED_SUID */
723
724
725/**
726 * Loads the VBoxRT DLL/SO/DYLIB, hands it the open driver,
727 * and calls RTR3Init.
728 *
729 * @param fFlags The SUPR3HardenedMain fFlags argument, passed to supR3PreInit.
730 *
731 * @remarks VBoxRT contains both IPRT and SUPR3.
732 * @remarks This function will not return on failure.
733 */
734static void supR3HardenedMainInitRuntime(uint32_t fFlags)
735{
736 /*
737 * Construct the name.
738 */
739 char szPath[RTPATH_MAX];
740 supR3HardenedPathSharedLibs(szPath, sizeof(szPath) - sizeof("/VBoxRT" SUPLIB_DLL_SUFF));
741 strcat(szPath, "/VBoxRT" SUPLIB_DLL_SUFF);
742
743 /*
744 * Open it and resolve the symbols.
745 */
746#if defined(RT_OS_WINDOWS)
747 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
748 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
749 if (!hMod)
750 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
751 "LoadLibraryEx(\"%s\",,) failed (rc=%d)",
752 szPath, GetLastError());
753 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)GetProcAddress(hMod, SUP_HARDENED_SYM("RTR3InitEx"));
754 if (!pfnRTInitEx)
755 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
756 "Entrypoint \"RTR3InitEx\" not found in \"%s\" (rc=%d)",
757 szPath, GetLastError());
758
759 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)GetProcAddress(hMod, SUP_HARDENED_SYM("supR3PreInit"));
760 if (!pfnSUPPreInit)
761 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
762 "Entrypoint \"supR3PreInit\" not found in \"%s\" (rc=%d)",
763 szPath, GetLastError());
764
765#else
766 /* the dlopen crowd */
767 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
768 if (!pvMod)
769 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_MODULE_NOT_FOUND,
770 "dlopen(\"%s\",) failed: %s",
771 szPath, dlerror());
772 PFNRTR3INITEX pfnRTInitEx = (PFNRTR3INITEX)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("RTR3InitEx"));
773 if (!pfnRTInitEx)
774 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
775 "Entrypoint \"RTR3InitEx\" not found in \"%s\"!\ndlerror: %s",
776 szPath, dlerror());
777 PFNSUPR3PREINIT pfnSUPPreInit = (PFNSUPR3PREINIT)(uintptr_t)dlsym(pvMod, SUP_HARDENED_SYM("supR3PreInit"));
778 if (!pfnSUPPreInit)
779 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, VERR_SYMBOL_NOT_FOUND,
780 "Entrypoint \"supR3PreInit\" not found in \"%s\"!\ndlerror: %s",
781 szPath, dlerror());
782#endif
783
784 /*
785 * Make the calls.
786 */
787 supR3HardenedGetPreInitData(&g_SupPreInitData);
788 int rc = pfnSUPPreInit(&g_SupPreInitData, fFlags);
789 if (RT_FAILURE(rc))
790 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
791 "supR3PreInit failed with rc=%d", rc);
792 const char *pszExePath = NULL;
793#ifdef RT_OS_LINUX
794 if (!supR3HardenedMainIsProcSelfExeAccssible())
795 pszExePath = g_szSupLibHardenedExePath;
796#endif
797 rc = pfnRTInitEx(0, pszExePath, !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV));
798 if (RT_FAILURE(rc))
799 supR3HardenedFatalMsg("supR3HardenedMainInitRuntime", kSupInitOp_IPRT, rc,
800 "RTR3Init failed with rc=%d", rc);
801}
802
803
804/**
805 * Loads the DLL/SO/DYLIB containing the actual program and
806 * resolves the TrustedError symbol.
807 *
808 * This is very similar to supR3HardenedMainGetTrustedMain().
809 *
810 * @returns Pointer to the trusted error symbol if it is exported, NULL
811 * and no error messages otherwise.
812 * @param pszProgName The program name.
813 */
814static PFNSUPTRUSTEDERROR supR3HardenedMainGetTrustedError(const char *pszProgName)
815{
816 /*
817 * Construct the name.
818 */
819 char szPath[RTPATH_MAX];
820 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
821 size_t cch = strlen(szPath);
822 supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
823
824 /*
825 * Open it and resolve the symbol.
826 */
827#if defined(RT_OS_WINDOWS)
828 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
829 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
830 if (!hMod)
831 return NULL;
832 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedError"));
833 if (!pfn)
834 return NULL;
835 return (PFNSUPTRUSTEDERROR)pfn;
836
837#else
838 /* the dlopen crowd */
839 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
840 if (!pvMod)
841 return NULL;
842 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedError"));
843 if (!pvSym)
844 return NULL;
845 return (PFNSUPTRUSTEDERROR)(uintptr_t)pvSym;
846#endif
847}
848
849
850/**
851 * Loads the DLL/SO/DYLIB containing the actual program and
852 * resolves the TrustedMain symbol.
853 *
854 * @returns Pointer to the trusted main of the actual program.
855 * @param pszProgName The program name.
856 * @remarks This function will not return on failure.
857 */
858static PFNSUPTRUSTEDMAIN supR3HardenedMainGetTrustedMain(const char *pszProgName)
859{
860 /*
861 * Construct the name.
862 */
863 char szPath[RTPATH_MAX];
864 supR3HardenedPathAppPrivateArch(szPath, sizeof(szPath) - 10);
865 size_t cch = strlen(szPath);
866 supR3HardenedStrPrintf(&szPath[cch], sizeof(szPath) - cch, "/%s%s", pszProgName, SUPLIB_DLL_SUFF);
867
868 /*
869 * Open it and resolve the symbol.
870 */
871#if defined(RT_OS_WINDOWS)
872 /** @todo consider using LOAD_WITH_ALTERED_SEARCH_PATH here! */
873 HMODULE hMod = LoadLibraryEx(szPath, NULL /*hFile*/, 0 /* dwFlags */);
874 if (!hMod)
875 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: LoadLibraryEx(\"%s\",,) failed, rc=%d\n",
876 szPath, GetLastError());
877 FARPROC pfn = GetProcAddress(hMod, SUP_HARDENED_SYM("TrustedMain"));
878 if (!pfn)
879 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\" (rc=%d)\n",
880 szPath, GetLastError());
881 return (PFNSUPTRUSTEDMAIN)pfn;
882
883#else
884 /* the dlopen crowd */
885 void *pvMod = dlopen(szPath, RTLD_NOW | RTLD_GLOBAL);
886 if (!pvMod)
887 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: dlopen(\"%s\",) failed: %s\n",
888 szPath, dlerror());
889 void *pvSym = dlsym(pvMod, SUP_HARDENED_SYM("TrustedMain"));
890 if (!pvSym)
891 supR3HardenedFatal("supR3HardenedMainGetTrustedMain: Entrypoint \"TrustedMain\" not found in \"%s\"!\ndlerror: %s\n",
892 szPath, dlerror());
893 return (PFNSUPTRUSTEDMAIN)(uintptr_t)pvSym;
894#endif
895}
896
897
898/**
899 * Secure main.
900 *
901 * This is used for the set-user-ID-on-execute binaries on unixy systems
902 * and when using the open-vboxdrv-via-root-service setup on Windows.
903 *
904 * This function will perform the integrity checks of the VirtualBox
905 * installation, open the support driver, open the root service (later),
906 * and load the DLL corresponding to \a pszProgName and execute its main
907 * function.
908 *
909 * @returns Return code appropriate for main().
910 *
911 * @param pszProgName The program name. This will be used to figure out which
912 * DLL/SO/DYLIB to load and execute.
913 * @param fFlags Flags.
914 * @param argc The argument count.
915 * @param argv The argument vector.
916 * @param envp The environment vector.
917 */
918DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp)
919{
920 /*
921 * Note! At this point there is no IPRT, so we will have to stick
922 * to basic CRT functions that everyone agree upon.
923 */
924 g_pszSupLibHardenedProgName = pszProgName;
925 g_SupPreInitData.u32Magic = SUPPREINITDATA_MAGIC;
926 g_SupPreInitData.Data.hDevice = NIL_RTFILE;
927 g_SupPreInitData.u32EndMagic = SUPPREINITDATA_MAGIC;
928
929#ifdef SUP_HARDENED_SUID
930# ifdef RT_OS_LINUX
931 /*
932 * On linux we have to make sure the path is initialized because we
933 * *might* not be able to access /proc/self/exe after the seteuid call.
934 */
935 supR3HardenedGetFullExePath();
936# endif
937
938 /*
939 * Check that we're root, if we aren't then the installation is butchered.
940 */
941 g_uid = getuid();
942 g_gid = getgid();
943 if (geteuid() != 0 /* root */)
944 supR3HardenedFatalMsg("SUPR3HardenedMain", kSupInitOp_RootCheck, VERR_PERMISSION_DENIED,
945 "Effective UID is not root (euid=%d egid=%d uid=%d gid=%d)",
946 geteuid(), getegid(), g_uid, g_gid);
947#endif
948
949 /*
950 * Validate the installation.
951 */
952 supR3HardenedVerifyAll(true /* fFatal */, false /* fLeaveFilesOpen */, pszProgName);
953
954 /*
955 * Open the vboxdrv device.
956 */
957 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
958 supR3HardenedMainOpenDevice();
959
960 /*
961 * Open the root service connection.
962 */
963 //if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_SVC))
964 //supR3HardenedMainOpenService(&g_SupPreInitData, true /* fFatal */);
965
966#ifdef SUP_HARDENED_SUID
967 /*
968 * Drop any root privileges we might be holding (won't return on failure)
969 */
970 supR3HardenedMainDropPrivileges();
971#endif
972
973 /*
974 * Load the IPRT, hand the SUPLib part the open driver and
975 * call RTR3Init.
976 */
977 supR3HardenedMainInitRuntime(fFlags);
978
979 /*
980 * Load the DLL/SO/DYLIB containing the actual program
981 * and pass control to it.
982 */
983 PFNSUPTRUSTEDMAIN pfnTrustedMain = supR3HardenedMainGetTrustedMain(pszProgName);
984 return pfnTrustedMain(argc, argv, envp);
985}
986
987
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