VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp

Last change on this file was 109132, checked in by vboxsync, 12 days ago

SUPDrv/darwin: Assume TSC deltas are in sync on arm64. jiraref:VBP-1653

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.1 KB
Line 
1/* $Id: SUPDrv-darwin.cpp 109132 2025-05-01 02:19:30Z vboxsync $ */
2/** @file
3 * VirtualBox Support Driver - Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP LOG_GROUP_SUP_DRV
42#include "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
43
44#include "../SUPDrvInternal.h"
45#include <VBox/version.h>
46#include <iprt/assert.h>
47#include <iprt/asm.h>
48#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
49# include <iprt/asm-amd64-x86.h>
50#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
51# include <iprt/asm-arm.h>
52#endif
53#include <iprt/ctype.h>
54#include <iprt/dbg.h>
55#include <iprt/initterm.h>
56#include <iprt/file.h>
57#include <iprt/ldr.h>
58#include <iprt/mem.h>
59#include <iprt/power.h>
60#include <iprt/process.h>
61#include <iprt/spinlock.h>
62#include <iprt/semaphore.h>
63#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
64# include <iprt/x86.h>
65#endif
66#include <iprt/crypto/applecodesign.h>
67#include <iprt/crypto/store.h>
68#include <iprt/crypto/pkcs7.h>
69#include <iprt/crypto/x509.h>
70#include <VBox/err.h>
71#include <VBox/log.h>
72
73#include <mach/kmod.h>
74#include <miscfs/devfs/devfs.h>
75#include <sys/conf.h>
76#include <sys/errno.h>
77#include <sys/ioccom.h>
78#include <sys/malloc.h>
79#include <sys/proc.h>
80#include <sys/kauth.h>
81#include <IOKit/IOService.h>
82#include <IOKit/IOUserClient.h>
83#include <IOKit/pwr_mgt/RootDomain.h>
84#include <IOKit/IODeviceTreeSupport.h>
85#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
86# include <IOKit/usb/IOUSBHIDDriver.h>
87#endif
88#if RT_CLANG_PREREQ(15,0)
89# pragma clang diagnostic push
90# pragma GCC diagnostic ignored "-Winvalid-utf8"
91#endif
92#include <IOKit/bluetooth/IOBluetoothHIDDriver.h>
93#include <IOKit/bluetooth/IOBluetoothHIDDriverTypes.h>
94#if RT_CLANG_PREREQ(15,0)
95# pragma clang diagnostic pop
96#endif
97
98#ifdef VBOX_WITH_HOST_VMX
99# include <libkern/version.h>
100RT_C_DECLS_BEGIN
101# include <i386/vmx.h>
102RT_C_DECLS_END
103#endif
104
105
106/*********************************************************************************************************************************
107* Defined Constants And Macros *
108*********************************************************************************************************************************/
109
110/** The system device node name. */
111#define DEVICE_NAME_SYS "vboxdrv"
112/** The user device node name. */
113#define DEVICE_NAME_USR "vboxdrvu"
114
115
116/** @name For debugging/whatever, now permanent.
117 * @{ */
118#define VBOX_PROC_SELFNAME_LEN 31
119#define VBOX_RETRIEVE_CUR_PROC_NAME(a_Name) char a_Name[VBOX_PROC_SELFNAME_LEN + 1]; \
120 proc_selfname(a_Name, VBOX_PROC_SELFNAME_LEN)
121/** @} */
122
123
124/*********************************************************************************************************************************
125* Internal Functions *
126*********************************************************************************************************************************/
127RT_C_DECLS_BEGIN
128static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData);
129static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData);
130#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
131static int supdrvDarwinInitCertStores(PSUPDRVDEVEXT pDevExt);
132static void supdrvDarwinDestroyCertStores(PSUPDRVDEVEXT pDevExt);
133#endif
134
135static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
136static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
137static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
138#ifndef VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV
139static int VBoxDrvDarwinIOCtlSMAP(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
140#endif
141static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
142
143static int VBoxDrvDarwinErr2DarwinErr(int rc);
144
145static IOReturn VBoxDrvDarwinSleepHandler(void *pvTarget, void *pvRefCon, UInt32 uMessageType, IOService *pProvider, void *pvMessageArgument, vm_size_t argSize);
146RT_C_DECLS_END
147
148static int vboxdrvDarwinResolveSymbols(void);
149#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
150static bool vboxdrvDarwinCpuHasSMAP(void);
151#endif
152
153
154/*********************************************************************************************************************************
155* Structures and Typedefs *
156*********************************************************************************************************************************/
157/**
158 * The service class.
159 * This is just a formality really.
160 */
161class org_virtualbox_SupDrv : public IOService
162{
163 OSDeclareDefaultStructors(org_virtualbox_SupDrv);
164
165public:
166 virtual bool init(OSDictionary *pDictionary = 0);
167 virtual void free(void);
168 virtual bool start(IOService *pProvider);
169 virtual void stop(IOService *pProvider);
170 virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
171 virtual bool terminate(IOOptionBits fOptions);
172
173 RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT();
174
175private:
176 /** Guard against the parent class growing and us using outdated headers. */
177 uint8_t m_abSafetyPadding[256];
178};
179
180OSDefineMetaClassAndStructors(org_virtualbox_SupDrv, IOService);
181
182
183/**
184 * An attempt at getting that clientDied() notification.
185 * I don't think it'll work as I cannot figure out where/what creates the correct
186 * port right.
187 */
188class org_virtualbox_SupDrvClient : public IOUserClient
189{
190 OSDeclareDefaultStructors(org_virtualbox_SupDrvClient);
191
192private:
193 /** Guard against the parent class growing and us using outdated headers. */
194 uint8_t m_abSafetyPadding[256];
195
196 PSUPDRVSESSION m_pSession; /**< The session. */
197 task_t m_Task; /**< The client task. */
198 org_virtualbox_SupDrv *m_pProvider; /**< The service provider. */
199
200public:
201 virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
202 virtual bool start(IOService *pProvider);
203 static void sessionClose(RTPROCESS Process);
204 virtual IOReturn clientClose(void);
205 virtual IOReturn clientDied(void);
206 virtual bool terminate(IOOptionBits fOptions = 0);
207 virtual bool finalize(IOOptionBits fOptions);
208 virtual void stop(IOService *pProvider);
209
210 RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT();
211};
212
213OSDefineMetaClassAndStructors(org_virtualbox_SupDrvClient, IOUserClient);
214
215
216
217/*********************************************************************************************************************************
218* Global Variables *
219*********************************************************************************************************************************/
220/**
221 * Declare the module stuff.
222 */
223RT_C_DECLS_BEGIN
224extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
225extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
226
227KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
228DECL_HIDDEN_DATA(kmod_start_func_t *) _realmain = VBoxDrvDarwinStart;
229DECL_HIDDEN_DATA(kmod_stop_func_t *) _antimain = VBoxDrvDarwinStop;
230DECL_HIDDEN_DATA(int) _kext_apple_cc = __APPLE_CC__;
231RT_C_DECLS_END
232
233
234/**
235 * Device extention & session data association structure.
236 */
237static SUPDRVDEVEXT g_DevExt;
238
239/**
240 * The character device switch table for the driver.
241 */
242static struct cdevsw g_DevCW =
243{
244 /** @todo g++ doesn't like this syntax - it worked with gcc before renaming to .cpp. */
245 /*.d_open = */VBoxDrvDarwinOpen,
246 /*.d_close = */VBoxDrvDarwinClose,
247 /*.d_read = */eno_rdwrt,
248 /*.d_write = */eno_rdwrt,
249 /*.d_ioctl = */VBoxDrvDarwinIOCtl,
250 /*.d_stop = */eno_stop,
251 /*.d_reset = */eno_reset,
252 /*.d_ttys = */NULL,
253 /*.d_select= */eno_select,
254 /*.d_mmap = */eno_mmap,
255 /*.d_strategy = */eno_strat,
256#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1200 /* changed from 'void *' to 'rsvd_fcn_t' */
257 /*.d_getc/d_reserved_1 = */eno_getc,
258 /*.d_putc/d_reserved_2 = */eno_putc,
259#else
260 /*.d_getc = */(void *)(uintptr_t)&enodev, //eno_getc,
261 /*.d_putc = */(void *)(uintptr_t)&enodev, //eno_putc,
262#endif
263 /*.d_type = */0
264};
265
266/** Major device number. */
267static int g_iMajorDeviceNo = -1;
268/** Registered devfs device handle for the system device. */
269static void *g_hDevFsDeviceSys = NULL;
270/** Registered devfs device handle for the user device. */
271static void *g_hDevFsDeviceUsr = NULL;
272
273/** Spinlock protecting g_apSessionHashTab. */
274static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
275/** Hash table */
276static PSUPDRVSESSION g_apSessionHashTab[19];
277/** Calculates the index into g_apSessionHashTab.*/
278#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
279/** The number of open sessions. */
280static int32_t volatile g_cSessions = 0;
281/** The notifier handle for the sleep callback handler. */
282static IONotifier *g_pSleepNotifier = NULL;
283
284#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
285/** Pointer to vmx_suspend(). */
286static PFNRT g_pfnVmxSuspend = NULL;
287/** Pointer to vmx_resume(). */
288static PFNRT g_pfnVmxResume = NULL;
289/** Pointer to vmx_use_count. */
290static int volatile *g_pVmxUseCount = NULL;
291
292# ifdef SUPDRV_WITH_MSR_PROBER
293/** Pointer to rdmsr_carefully if found. Returns 0 on success. */
294static int (*g_pfnRdMsrCarefully)(uint32_t uMsr, uint32_t *puLow, uint32_t *puHigh) = NULL;
295/** Pointer to rdmsr64_carefully if found. Returns 0 on success. */
296static int (*g_pfnRdMsr64Carefully)(uint32_t uMsr, uint64_t *uValue) = NULL;
297/** Pointer to wrmsr[64]_carefully if found. Returns 0 on success. */
298static int (*g_pfnWrMsr64Carefully)(uint32_t uMsr, uint64_t uValue) = NULL;
299# endif
300#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */
301
302/** SUPKERNELFEATURES_XXX */
303static uint32_t g_fKernelFeatures = 0;
304
305/**
306 * Start the kernel module.
307 */
308static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData)
309{
310 RT_NOREF(pKModInfo, pvData);
311#ifdef DEBUG
312 printf("VBoxDrvDarwinStart\n");
313#endif
314
315 /*
316 * Initialize IPRT.
317 */
318 int rc = RTR0Init(0);
319 if (RT_SUCCESS(rc))
320 {
321 /*
322 * Initialize the device extension.
323 */
324 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
325 if (RT_SUCCESS(rc))
326 {
327#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
328 supdrvDarwinInitCertStores(&g_DevExt);
329#endif
330
331 /*
332 * Initialize the session hash table.
333 */
334 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); /* paranoia */
335 rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxDrvDarwin");
336 if (RT_SUCCESS(rc))
337 {
338#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
339 if (vboxdrvDarwinCpuHasSMAP())
340 {
341 g_fKernelFeatures |= SUPKERNELFEATURES_SMAP;
342# ifndef VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV
343 LogRel(("disabling SMAP for VBoxDrvDarwinIOCtl\n"));
344 g_DevCW.d_ioctl = VBoxDrvDarwinIOCtlSMAP;
345# endif
346 }
347#endif
348
349 /*
350 * Resolve some extra kernel symbols.
351 */
352 rc = vboxdrvDarwinResolveSymbols();
353 if (RT_SUCCESS(rc))
354 {
355
356 /*
357 * Registering ourselves as a character device.
358 */
359 g_iMajorDeviceNo = cdevsw_add(-1, &g_DevCW);
360 if (g_iMajorDeviceNo >= 0)
361 {
362#ifdef VBOX_WITH_HARDENING
363 g_hDevFsDeviceSys = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
364 UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME_SYS);
365#else
366 g_hDevFsDeviceSys = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
367 UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME_SYS);
368#endif
369 if (g_hDevFsDeviceSys)
370 {
371 g_hDevFsDeviceUsr = devfs_make_node(makedev(g_iMajorDeviceNo, 1), DEVFS_CHAR,
372 UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME_USR);
373 if (g_hDevFsDeviceUsr)
374 {
375 LogRel(("VBoxDrv: version " VBOX_VERSION_STRING " r%d; IOCtl version %#x; IDC version %#x; dev major=%d\n",
376 VBOX_SVN_REV, SUPDRV_IOC_VERSION, SUPDRV_IDC_VERSION, g_iMajorDeviceNo));
377
378 /* Register a sleep/wakeup notification callback */
379 g_pSleepNotifier = registerPrioritySleepWakeInterest(&VBoxDrvDarwinSleepHandler, &g_DevExt, NULL);
380 if (g_pSleepNotifier == NULL)
381 LogRel(("VBoxDrv: register for sleep/wakeup events failed\n"));
382
383 return KMOD_RETURN_SUCCESS;
384 }
385
386 LogRel(("VBoxDrv: devfs_make_node(makedev(%d,1),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME_USR));
387 devfs_remove(g_hDevFsDeviceSys);
388 g_hDevFsDeviceSys = NULL;
389 }
390 else
391 LogRel(("VBoxDrv: devfs_make_node(makedev(%d,0),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME_SYS));
392
393 cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
394 g_iMajorDeviceNo = -1;
395 }
396 else
397 LogRel(("VBoxDrv: cdevsw_add failed (%d)\n", g_iMajorDeviceNo));
398 }
399#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
400 supdrvDarwinDestroyCertStores(&g_DevExt);
401#endif
402 RTSpinlockDestroy(g_Spinlock);
403 g_Spinlock = NIL_RTSPINLOCK;
404 }
405 else
406 LogRel(("VBoxDrv: RTSpinlockCreate failed (rc=%d)\n", rc));
407 supdrvDeleteDevExt(&g_DevExt);
408 }
409 else
410 printf("VBoxDrv: failed to initialize device extension (rc=%d)\n", rc);
411 RTR0TermForced();
412 }
413 else
414 printf("VBoxDrv: failed to initialize IPRT (rc=%d)\n", rc);
415
416 memset(&g_DevExt, 0, sizeof(g_DevExt));
417 return KMOD_RETURN_FAILURE;
418}
419
420
421/**
422 * Resolves kernel symbols we need and some we just would like to have.
423 */
424static int vboxdrvDarwinResolveSymbols(void)
425{
426#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
427 RTDBGKRNLINFO hKrnlInfo;
428 int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0);
429 if (RT_SUCCESS(rc))
430 {
431 /*
432 * The VMX stuff - required with raw-mode (in theory for 64-bit on
433 * 32-bit too, but we never did that on darwin).
434 */
435 int rc1 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "vmx_resume", (void **)&g_pfnVmxResume);
436 int rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "vmx_suspend", (void **)&g_pfnVmxSuspend);
437 int rc3 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "vmx_use_count", (void **)&g_pVmxUseCount);
438 if (RT_SUCCESS(rc1) && RT_SUCCESS(rc2) && RT_SUCCESS(rc3))
439 {
440 LogRel(("VBoxDrv: vmx_resume=%p vmx_suspend=%p vmx_use_count=%p (%d) cr4=%#x\n",
441 g_pfnVmxResume, g_pfnVmxSuspend, g_pVmxUseCount, *g_pVmxUseCount, ASMGetCR4() ));
442 }
443 else
444 {
445 LogRel(("VBoxDrv: failed to resolve vmx stuff: vmx_resume=%Rrc vmx_suspend=%Rrc vmx_use_count=%Rrc", rc1, rc2, rc3));
446 g_pfnVmxResume = NULL;
447 g_pfnVmxSuspend = NULL;
448 g_pVmxUseCount = NULL;
449# ifdef VBOX_WITH_RAW_MODE
450 rc = VERR_SYMBOL_NOT_FOUND;
451# endif
452 }
453
454 if (RT_SUCCESS(rc))
455 {
456# ifdef SUPDRV_WITH_MSR_PROBER
457 /*
458 * MSR prober stuff - optional!
459 */
460 rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "rdmsr_carefully", (void **)&g_pfnRdMsrCarefully);
461 if (RT_FAILURE(rc2))
462 g_pfnRdMsrCarefully = NULL;
463 rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "rdmsr64_carefully", (void **)&g_pfnRdMsr64Carefully);
464 if (RT_FAILURE(rc2))
465 g_pfnRdMsr64Carefully = NULL;
466# ifdef RT_ARCH_AMD64 /* Missing 64 in name, so if implemented on 32-bit it could have different signature. */
467 rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "wrmsr_carefully", (void **)&g_pfnWrMsr64Carefully);
468 if (RT_FAILURE(rc2))
469# endif
470 g_pfnWrMsr64Carefully = NULL;
471
472 LogRel(("VBoxDrv: g_pfnRdMsrCarefully=%p g_pfnRdMsr64Carefully=%p g_pfnWrMsr64Carefully=%p\n",
473 g_pfnRdMsrCarefully, g_pfnRdMsr64Carefully, g_pfnWrMsr64Carefully));
474
475# endif /* SUPDRV_WITH_MSR_PROBER */
476 }
477
478 RTR0DbgKrnlInfoRelease(hKrnlInfo);
479 }
480 else
481 LogRel(("VBoxDrv: Failed to open kernel symbols, rc=%Rrc\n", rc));
482 return rc;
483#else /* !RT_ARCH_AMD64 && !RT_ARCH_X86 */
484 return VINF_SUCCESS;
485#endif /* !RT_ARCH_AMD64 && !RT_ARCH_X86 */
486}
487
488
489#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
490
491/**
492 * Initalizes the certificate stores (code signing) in the device extension.
493 */
494static int supdrvDarwinInitCertStores(PSUPDRVDEVEXT pDevExt)
495{
496 pDevExt->hAdditionalStore = NIL_RTCRSTORE;
497
498 pDevExt->hRootStore = NIL_RTCRSTORE;
499 int rc = RTCrStoreCreateInMem(&pDevExt->hRootStore, g_cSUPTrustedTAs + 1);
500 if (RT_SUCCESS(rc))
501 {
502 for (uint32_t i = 0; i < g_cSUPTrustedTAs; i++)
503 {
504 int rc2 = RTCrStoreCertAddEncoded(pDevExt->hRootStore, RTCRCERTCTX_F_ENC_TAF_DER,
505 g_aSUPTrustedTAs[i].pch, g_aSUPTrustedTAs[i].cb, NULL);
506 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
507 {
508 printf("VBoxDrv: Error loading g_aSUPTrustedTAs[%u]: %d\n", i, rc);
509 rc = rc2;
510 }
511 }
512
513 /* We implicitly trust the build certificate. */
514 int rc2 = RTCrStoreCertAddEncoded(pDevExt->hRootStore, RTCRCERTCTX_F_ENC_X509_DER,
515 g_abSUPBuildCert, g_cbSUPBuildCert, NULL);
516 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
517 {
518 printf("VBoxDrv: Error loading g_cbSUPBuildCert: %d\n", rc);
519 rc = rc2;
520 }
521 }
522 return rc;
523}
524
525
526/**
527 * Releases the certificate stores in the device extension.
528 */
529static void supdrvDarwinDestroyCertStores(PSUPDRVDEVEXT pDevExt)
530{
531 if (pDevExt->hRootStore != NIL_RTCRSTORE)
532 {
533 uint32_t cRefs = RTCrStoreRelease(pDevExt->hRootStore);
534 Assert(cRefs == 0); RT_NOREF(cRefs);
535 pDevExt->hRootStore = NIL_RTCRSTORE;
536 }
537 if (pDevExt->hAdditionalStore != NIL_RTCRSTORE)
538 {
539 uint32_t cRefs = RTCrStoreRelease(pDevExt->hAdditionalStore);
540 Assert(cRefs == 0); RT_NOREF(cRefs);
541 pDevExt->hAdditionalStore = NIL_RTCRSTORE;
542 }
543}
544
545#endif /* VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
546
547/**
548 * Stop the kernel module.
549 */
550static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData)
551{
552 RT_NOREF(pKModInfo, pvData);
553 int rc;
554 LogFlow(("VBoxDrvDarwinStop\n"));
555
556 /** @todo I've got a nagging feeling that we'll have to keep track of users and refuse
557 * unloading if we're busy. Investigate and implement this! */
558
559 /*
560 * Undo the work done during start (in reverse order).
561 */
562 if (g_pSleepNotifier)
563 {
564 g_pSleepNotifier->remove();
565 g_pSleepNotifier = NULL;
566 }
567
568 devfs_remove(g_hDevFsDeviceUsr);
569 g_hDevFsDeviceUsr = NULL;
570
571 devfs_remove(g_hDevFsDeviceSys);
572 g_hDevFsDeviceSys = NULL;
573
574 rc = cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
575 Assert(rc == g_iMajorDeviceNo);
576 g_iMajorDeviceNo = -1;
577
578 supdrvDeleteDevExt(&g_DevExt);
579
580 rc = RTSpinlockDestroy(g_Spinlock);
581 AssertRC(rc);
582 g_Spinlock = NIL_RTSPINLOCK;
583
584#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
585 supdrvDarwinDestroyCertStores(&g_DevExt);
586#endif
587
588 RTR0TermForced();
589
590 memset(&g_DevExt, 0, sizeof(g_DevExt));
591#ifdef DEBUG
592 printf("VBoxDrvDarwinStop - done\n");
593#endif
594 return KMOD_RETURN_SUCCESS;
595}
596
597
598/**
599 * Device open. Called on open /dev/vboxdrv
600 *
601 * @param Dev The device number.
602 * @param fFlags ???.
603 * @param fDevType ???.
604 * @param pProcess The process issuing this request.
605 */
606static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
607{
608 RT_NOREF(fFlags, fDevType);
609#ifdef DEBUG_DARWIN_GIP
610 char szName[128];
611 szName[0] = '\0';
612 proc_name(proc_pid(pProcess), szName, sizeof(szName));
613 Log(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
614#endif
615
616 /*
617 * Only two minor devices numbers are allowed.
618 */
619 if (minor(Dev) != 0 && minor(Dev) != 1)
620 return EACCES;
621
622 /*
623 * The process issuing the request must be the current process.
624 */
625 RTPROCESS Process = RTProcSelf();
626 if ((int)Process != proc_pid(pProcess))
627 return EIO;
628
629 /*
630 * Find the session created by org_virtualbox_SupDrvClient, fail
631 * if no such session, and mark it as opened. We set the uid & gid
632 * here too, since that is more straight forward at this point.
633 */
634 const bool fUnrestricted = minor(Dev) == 0;
635 int rc = VINF_SUCCESS;
636 PSUPDRVSESSION pSession = NULL;
637 kauth_cred_t pCred = kauth_cred_proc_ref(pProcess);
638 if (pCred)
639 {
640#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
641 RTUID Uid = kauth_cred_getruid(pCred);
642 RTGID Gid = kauth_cred_getrgid(pCred);
643#else
644 RTUID Uid = pCred->cr_ruid;
645 RTGID Gid = pCred->cr_rgid;
646#endif
647 unsigned iHash = SESSION_HASH(Process);
648 RTSpinlockAcquire(g_Spinlock);
649
650 pSession = g_apSessionHashTab[iHash];
651 while (pSession && pSession->Process != Process)
652 pSession = pSession->pNextHash;
653 if (pSession)
654 {
655 if (!pSession->fOpened)
656 {
657 pSession->fOpened = true;
658 pSession->fUnrestricted = fUnrestricted;
659 pSession->Uid = Uid;
660 pSession->Gid = Gid;
661 }
662 else
663 rc = VERR_ALREADY_LOADED;
664 }
665 else
666 rc = VERR_GENERAL_FAILURE;
667
668 RTSpinlockRelease(g_Spinlock);
669#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
670 kauth_cred_unref(&pCred);
671#else /* 10.4 */
672 /* The 10.4u SDK headers and 10.4.11 kernel source have inconsistent definitions
673 of kauth_cred_unref(), so use the other (now deprecated) API for releasing it. */
674 kauth_cred_rele(pCred);
675#endif /* 10.4 */
676 }
677 else
678 rc = VERR_INVALID_PARAMETER;
679
680#ifdef DEBUG_DARWIN_GIP
681 OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
682#else
683 Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
684#endif
685 return VBoxDrvDarwinErr2DarwinErr(rc);
686}
687
688
689/**
690 * Close device.
691 */
692static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
693{
694 RT_NOREF(Dev, fFlags, fDevType, pProcess);
695 Log(("VBoxDrvDarwinClose: pid=%d\n", (int)RTProcSelf()));
696 Assert(proc_pid(pProcess) == (int)RTProcSelf());
697
698 /*
699 * Hand the session closing to org_virtualbox_SupDrvClient.
700 */
701 org_virtualbox_SupDrvClient::sessionClose(RTProcSelf());
702 return 0;
703}
704
705
706/**
707 * Device I/O Control entry point.
708 *
709 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
710 * @param Dev The device number (major+minor).
711 * @param iCmd The IOCtl command.
712 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
713 * @param fFlags Flag saying we're a character device (like we didn't know already).
714 * @param pProcess The process issuing this request.
715 */
716static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
717{
718 RT_NOREF(fFlags);
719 const bool fUnrestricted = minor(Dev) == 0;
720 const RTPROCESS Process = proc_pid(pProcess);
721 const unsigned iHash = SESSION_HASH(Process);
722 PSUPDRVSESSION pSession;
723
724#ifdef VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV
725 /*
726 * Refuse all I/O control calls if we've ever detected EFLAGS.AC being cleared.
727 *
728 * This isn't a problem, as there is absolutely nothing in the kernel context that
729 * depend on user context triggering cleanups. That would be pretty wild, right?
730 */
731 if (RT_UNLIKELY(g_DevExt.cBadContextCalls > 0))
732 {
733 SUPR0Printf("VBoxDrvDarwinIOCtl: EFLAGS.AC=0 detected %u times, refusing all I/O controls!\n", g_DevExt.cBadContextCalls);
734 return EDEVERR;
735 }
736#endif
737
738 /*
739 * Find the session.
740 */
741 RTSpinlockAcquire(g_Spinlock);
742
743 pSession = g_apSessionHashTab[iHash];
744 while (pSession && (pSession->Process != Process || pSession->fUnrestricted != fUnrestricted || !pSession->fOpened))
745 pSession = pSession->pNextHash;
746
747 if (RT_LIKELY(pSession))
748 supdrvSessionRetain(pSession);
749
750 RTSpinlockRelease(g_Spinlock);
751 if (RT_UNLIKELY(!pSession))
752 {
753 OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#lx\n",
754 (int)Process, iCmd));
755 return EINVAL;
756 }
757
758 /*
759 * Deal with the two high-speed IOCtl that takes it's arguments from
760 * the session and iCmd, and only returns a VBox status code.
761 */
762 int rc;
763 AssertCompile((SUP_IOCTL_FAST_DO_FIRST & 0xff) == (SUP_IOCTL_FLAG | 64));
764 if ( (uintptr_t)(iCmd - SUP_IOCTL_FAST_DO_FIRST) < (uintptr_t)32
765 && fUnrestricted)
766 rc = supdrvIOCtlFast(iCmd - SUP_IOCTL_FAST_DO_FIRST, *(uint32_t *)pData, &g_DevExt, pSession);
767 else
768 rc = VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
769
770 supdrvSessionRelease(pSession);
771 return rc;
772}
773
774
775#ifndef VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV
776/**
777 * Alternative Device I/O Control entry point on hosts with SMAP support.
778 *
779 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
780 * @param Dev The device number (major+minor).
781 * @param iCmd The IOCtl command.
782 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
783 * @param fFlags Flag saying we're a character device (like we didn't know already).
784 * @param pProcess The process issuing this request.
785 */
786static int VBoxDrvDarwinIOCtlSMAP(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
787{
788 /*
789 * Allow VBox R0 code to touch R3 memory. Setting the AC bit disables the
790 * SMAP check.
791 */
792 RTCCUINTREG fSavedEfl = ASMAddFlags(X86_EFL_AC);
793
794 int rc = VBoxDrvDarwinIOCtl(Dev, iCmd, pData, fFlags, pProcess);
795
796# if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
797 /*
798 * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
799 * accidentially modified it or some other important flag.
800 */
801 if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL))
802 != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL)) | X86_EFL_AC) ))
803 {
804 char szTmp[48];
805 RTStrPrintf(szTmp, sizeof(szTmp), "iCmd=%#x: %#x->%#x!", iCmd, (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
806 supdrvBadContext(&g_DevExt, "SUPDrv-darwin.cpp", __LINE__, szTmp);
807 }
808# endif
809
810 ASMSetFlags(fSavedEfl);
811 return rc;
812}
813#endif /* VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV */
814
815
816/**
817 * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
818 *
819 * @returns Darwin errno.
820 *
821 * @param pSession The session.
822 * @param iCmd The IOCtl command.
823 * @param pData Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
824 * @param pProcess The calling process.
825 */
826static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
827{
828 RT_NOREF(pProcess);
829 LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
830
831
832 /*
833 * Buffered or unbuffered?
834 */
835 PSUPREQHDR pHdr;
836 user_addr_t pUser = 0;
837 void *pvPageBuf = NULL;
838 uint32_t cbReq = IOCPARM_LEN(iCmd);
839 if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
840 {
841 pHdr = (PSUPREQHDR)pData;
842 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
843 {
844 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
845 return EINVAL;
846 }
847 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
848 {
849 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
850 return EINVAL;
851 }
852 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
853 || pHdr->cbIn < sizeof(*pHdr)
854 || pHdr->cbOut < sizeof(*pHdr)))
855 {
856 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
857 return EINVAL;
858 }
859 }
860 else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
861 {
862 /*
863 * Get the header and figure out how much we're gonna have to read.
864 */
865 IPRT_DARWIN_SAVE_EFL_AC();
866 SUPREQHDR Hdr;
867 pUser = (user_addr_t)*(void **)pData;
868 int rc = copyin(pUser, &Hdr, sizeof(Hdr));
869 if (RT_UNLIKELY(rc))
870 {
871 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
872 IPRT_DARWIN_RESTORE_EFL_AC();
873 return rc;
874 }
875 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
876 {
877 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
878 IPRT_DARWIN_RESTORE_EFL_AC();
879 return EINVAL;
880 }
881 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
882 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
883 || Hdr.cbOut < sizeof(Hdr)
884 || cbReq > _1M*16))
885 {
886 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
887 IPRT_DARWIN_RESTORE_EFL_AC();
888 return EINVAL;
889 }
890
891 /*
892 * Allocate buffer and copy in the data.
893 */
894 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
895 if (!pHdr)
896 pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
897 if (RT_UNLIKELY(!pHdr))
898 {
899 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
900 IPRT_DARWIN_RESTORE_EFL_AC();
901 return ENOMEM;
902 }
903 rc = copyin(pUser, pHdr, Hdr.cbIn);
904 if (RT_UNLIKELY(rc))
905 {
906 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
907 (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
908 if (pvPageBuf)
909 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
910 else
911 RTMemTmpFree(pHdr);
912 IPRT_DARWIN_RESTORE_EFL_AC();
913 return rc;
914 }
915 if (Hdr.cbIn < cbReq)
916 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbReq - Hdr.cbIn);
917 IPRT_DARWIN_RESTORE_EFL_AC();
918 }
919 else
920 {
921 Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
922 return EINVAL;
923 }
924
925 /*
926 * Process the IOCtl.
927 */
928 int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr, cbReq);
929 if (RT_LIKELY(!rc))
930 {
931 /*
932 * If not buffered, copy back the buffer before returning.
933 */
934 if (pUser)
935 {
936 IPRT_DARWIN_SAVE_EFL_AC();
937 uint32_t cbOut = pHdr->cbOut;
938 if (cbOut > cbReq)
939 {
940 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
941 cbOut = cbReq;
942 }
943 rc = copyout(pHdr, pUser, cbOut);
944 if (RT_UNLIKELY(rc))
945 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
946 pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
947
948 /* cleanup */
949 if (pvPageBuf)
950 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
951 else
952 RTMemTmpFree(pHdr);
953 IPRT_DARWIN_RESTORE_EFL_AC();
954 }
955 }
956 else
957 {
958 /*
959 * The request failed, just clean up.
960 */
961 if (pUser)
962 {
963 if (pvPageBuf)
964 {
965 IPRT_DARWIN_SAVE_EFL_AC();
966 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
967 IPRT_DARWIN_RESTORE_EFL_AC();
968 }
969 else
970 RTMemTmpFree(pHdr);
971 }
972
973 Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
974 rc = EINVAL;
975 }
976
977 Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
978 return rc;
979}
980
981
982/**
983 * The SUPDRV IDC entry point.
984 *
985 * @returns VBox status code, see supdrvIDC.
986 * @param uReq The request code.
987 * @param pReq The request.
988 */
989DECLEXPORT(int) VBOXCALL SUPDrvDarwinIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
990{
991 PSUPDRVSESSION pSession;
992
993 /*
994 * Some quick validations.
995 */
996 if (RT_UNLIKELY(!RT_VALID_PTR(pReq)))
997 return VERR_INVALID_POINTER;
998
999 pSession = pReq->pSession;
1000 if (pSession)
1001 {
1002 if (RT_UNLIKELY(!RT_VALID_PTR(pSession)))
1003 return VERR_INVALID_PARAMETER;
1004 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
1005 return VERR_INVALID_PARAMETER;
1006 }
1007 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
1008 return VERR_INVALID_PARAMETER;
1009
1010 /*
1011 * Do the job.
1012 */
1013 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
1014}
1015
1016
1017void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1018{
1019 NOREF(pDevExt);
1020 NOREF(pSession);
1021}
1022
1023
1024void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1025{
1026 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1027}
1028
1029
1030void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1031{
1032 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1033}
1034
1035
1036/**
1037 * Initializes any OS specific object creator fields.
1038 */
1039void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
1040{
1041 NOREF(pObj);
1042 NOREF(pSession);
1043}
1044
1045
1046/**
1047 * Checks if the session can access the object.
1048 *
1049 * @returns true if a decision has been made.
1050 * @returns false if the default access policy should be applied.
1051 *
1052 * @param pObj The object in question.
1053 * @param pSession The session wanting to access the object.
1054 * @param pszObjName The object name, can be NULL.
1055 * @param prc Where to store the result when returning true.
1056 */
1057bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1058{
1059 NOREF(pObj);
1060 NOREF(pSession);
1061 NOREF(pszObjName);
1062 NOREF(prc);
1063 return false;
1064}
1065
1066/**
1067 * Callback for blah blah blah.
1068 */
1069IOReturn VBoxDrvDarwinSleepHandler(void * /* pvTarget */, void *pvRefCon, UInt32 uMessageType,
1070 IOService *pProvider, void *pvMsgArg, vm_size_t cbMsgArg)
1071{
1072 RT_NOREF(pProvider, pvMsgArg, cbMsgArg);
1073 LogFlow(("VBoxDrv: Got sleep/wake notice. Message type was %x\n", uMessageType));
1074
1075 if (uMessageType == kIOMessageSystemWillSleep)
1076 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
1077 else if (uMessageType == kIOMessageSystemHasPoweredOn)
1078 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
1079
1080 acknowledgeSleepWakeNotification(pvRefCon);
1081
1082 return 0;
1083}
1084
1085#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1086
1087# ifdef VBOX_WITH_HOST_VMX
1088/**
1089 * For cleaning up the mess we left behind on Yosemite with 4.3.28 and earlier.
1090 *
1091 * We ASSUME VT-x is supported by the CPU.
1092 *
1093 * @param idCpu Unused.
1094 * @param pvUser1 Unused.
1095 * @param pvUser2 Unused.
1096 */
1097static DECLCALLBACK(void) vboxdrvDarwinVmxEnableFix(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1098{
1099 RT_NOREF(idCpu, pvUser1, pvUser2);
1100 RTCCUINTREG uCr4 = ASMGetCR4();
1101 if (!(uCr4 & X86_CR4_VMXE))
1102 {
1103 uCr4 |= X86_CR4_VMXE;
1104 ASMSetCR4(uCr4);
1105 }
1106}
1107# endif
1108
1109
1110/**
1111 * @copydoc SUPR0EnableVTx
1112 */
1113int VBOXCALL supdrvOSEnableVTx(bool fEnable)
1114{
1115# ifdef VBOX_WITH_HOST_VMX
1116 int rc;
1117 if ( version_major >= 10 /* 10 = 10.6.x = Snow Leopard */
1118# ifdef VBOX_WITH_RAW_MODE
1119 && g_pfnVmxSuspend
1120 && g_pfnVmxResume
1121 && g_pVmxUseCount
1122# endif
1123 )
1124 {
1125 IPRT_DARWIN_SAVE_EFL_AC();
1126 if (fEnable)
1127 {
1128 /*
1129 * We screwed up on Yosemite and didn't notice that we weren't
1130 * calling host_vmxon. CR4.VMXE may therefore have been disabled
1131 * by us. So, first time around we make sure it's set so we won't
1132 * crash in the pre-4.3.28/5.0RC1 upgrade scenario.
1133 * See @bugref{7907}.
1134 */
1135 static bool volatile g_fDoneCleanup = false;
1136 if (!g_fDoneCleanup)
1137 {
1138 if (version_major == 14 /* 14 = 10.10 = yosemite */)
1139 {
1140 uint32_t fCaps;
1141 rc = supdrvQueryVTCapsInternal(&fCaps);
1142 if (RT_SUCCESS(rc))
1143 {
1144 if (fCaps & SUPVTCAPS_VT_X)
1145 rc = RTMpOnAll(vboxdrvDarwinVmxEnableFix, NULL, NULL);
1146 else
1147 rc = VERR_VMX_NO_VMX;
1148 }
1149 if (RT_FAILURE(rc))
1150 {
1151 IPRT_DARWIN_RESTORE_EFL_AC();
1152 return rc;
1153 }
1154 }
1155 g_fDoneCleanup = true;
1156 }
1157
1158 /*
1159 * Call the kernel.
1160 */
1161 AssertLogRelMsg(!g_pVmxUseCount || *g_pVmxUseCount >= 0,
1162 ("vmx_use_count=%d (@ %p, expected it to be a positive number\n",
1163 *g_pVmxUseCount, g_pVmxUseCount));
1164
1165 rc = host_vmxon(false /* exclusive */);
1166 if (rc == VMX_OK)
1167 rc = VINF_SUCCESS;
1168 else if (rc == VMX_UNSUPPORTED)
1169 rc = VERR_VMX_NO_VMX;
1170 else if (rc == VMX_INUSE)
1171 rc = VERR_VMX_IN_VMX_ROOT_MODE;
1172 else /* shouldn't happen, but just in case. */
1173 {
1174 LogRel(("host_vmxon returned %d\n", rc));
1175 rc = VERR_UNRESOLVED_ERROR;
1176 }
1177 LogRel(("VBoxDrv: host_vmxon -> vmx_use_count=%d rc=%Rrc\n", *g_pVmxUseCount, rc));
1178 }
1179 else
1180 {
1181 AssertLogRelMsgReturn(!g_pVmxUseCount || *g_pVmxUseCount >= 1,
1182 ("vmx_use_count=%d (@ %p, expected it to be a non-zero positive number\n",
1183 *g_pVmxUseCount, g_pVmxUseCount),
1184 VERR_WRONG_ORDER);
1185 host_vmxoff();
1186 rc = VINF_SUCCESS;
1187 LogRel(("VBoxDrv: host_vmxoff -> vmx_use_count=%d\n", *g_pVmxUseCount));
1188 }
1189 IPRT_DARWIN_RESTORE_EFL_AC();
1190 }
1191 else
1192 {
1193 /* In 10.5.x the host_vmxon is severely broken! Don't use it, it will
1194 frequnetly panic the host. */
1195 rc = VERR_NOT_SUPPORTED;
1196 }
1197 return rc;
1198# else /* !VBOX_WITH_HOST_VMX */
1199 return VERR_NOT_SUPPORTED;
1200# endif /* !VBOX_WITH_HOST_VMX */
1201}
1202
1203
1204/**
1205 * @copydoc SUPR0SuspendVTxOnCpu
1206 */
1207bool VBOXCALL supdrvOSSuspendVTxOnCpu(void)
1208{
1209# ifdef VBOX_WITH_HOST_VMX
1210 /*
1211 * Consult the VMX usage counter, don't try suspend if not enabled.
1212 *
1213 * Note! The host_vmxon/off code is still race prone since, but this is
1214 * currently the best we can do without always enable VMX when
1215 * loading the driver.
1216 */
1217 if ( g_pVmxUseCount
1218 && *g_pVmxUseCount > 0)
1219 {
1220 IPRT_DARWIN_SAVE_EFL_AC();
1221 g_pfnVmxSuspend();
1222 IPRT_DARWIN_RESTORE_EFL_AC();
1223 return true;
1224 }
1225 return false;
1226# else
1227 return false;
1228# endif
1229}
1230
1231
1232/**
1233 * @copydoc SUPR0ResumeVTxOnCpu
1234 */
1235void VBOXCALL supdrvOSResumeVTxOnCpu(bool fSuspended)
1236{
1237# ifdef VBOX_WITH_HOST_VMX
1238 /*
1239 * Don't consult the counter here, the state knows better.
1240 * We're executing with interrupts disabled and anyone racing us with
1241 * disabling VT-x will be waiting in the rendezvous code.
1242 */
1243 if ( fSuspended
1244 && g_pfnVmxResume)
1245 {
1246 IPRT_DARWIN_SAVE_EFL_AC();
1247 g_pfnVmxResume();
1248 IPRT_DARWIN_RESTORE_EFL_AC();
1249 }
1250 else
1251 Assert(!fSuspended);
1252# else
1253 Assert(!fSuspended);
1254# endif
1255}
1256
1257#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */
1258
1259bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1260{
1261 NOREF(pDevExt);
1262 return false;
1263}
1264
1265
1266bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
1267{
1268 /** @todo verify this. */
1269 return false;
1270}
1271
1272
1273bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
1274{
1275#ifdef RT_ARCH_ARM64
1276 return true;
1277#else
1278 return false;
1279#endif
1280}
1281
1282
1283#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1284
1285/**
1286 * @callback_method_impl{FNRTLDRIMPORT}
1287 */
1288static DECLCALLBACK(int) supdrvDarwinLdrOpenImportCallback(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
1289 unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
1290{
1291 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1292
1293 /*
1294 * First consult the VMMR0 module if there is one fully loaded.
1295 * This is necessary as VMMR0 may overload assertion and logger symbols.
1296 */
1297 if (pDevExt->pvVMMR0)
1298 for (PSUPDRVLDRIMAGE pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
1299 if (pImage->pvImage == pDevExt->pvVMMR0)
1300 {
1301 if ( pImage->uState == SUP_IOCTL_LDR_LOAD
1302 && pImage->hLdrMod != NIL_RTLDRMOD)
1303 {
1304 int rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pvImage, (uintptr_t)pImage->pvImage,
1305 UINT32_MAX, pszSymbol, pValue);
1306 if (RT_SUCCESS(rc))
1307 return VINF_SUCCESS;
1308 }
1309 break;
1310 }
1311
1312 /*
1313 * Then we consult the SUPDrv export table.
1314 */
1315 uintptr_t uValue = 0;
1316 int rc = supdrvLdrGetExportedSymbol(pszSymbol, &uValue);
1317 if (RT_SUCCESS(rc))
1318 {
1319 *pValue = uValue;
1320 return VINF_SUCCESS;
1321 }
1322
1323 /*
1324 * Failed.
1325 */
1326 printf("VBoxDrv: Unable to resolve symbol '%s'.\n", pszSymbol);
1327 RT_NOREF(hLdrMod, pszModule, uSymbol);
1328 return VERR_SYMBOL_NOT_FOUND;
1329}
1330
1331
1332/**
1333 * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
1334 * Verify that the signing certificate is sane.}
1335 */
1336static DECLCALLBACK(int) supdrvDarwinLdrOpenVerifyCertificatCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths,
1337 uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo)
1338{
1339 RT_NOREF(pvUser); //PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1340# ifdef DEBUG_bird
1341 printf("supdrvDarwinLdrOpenVerifyCertificatCallback: pCert=%p hCertPaths=%p\n", (void *)pCert, (void *)hCertPaths);
1342# endif
1343
1344# if 0
1345 /*
1346 * Test signing certificates normally doesn't have all the necessary
1347 * features required below. So, treat them as special cases.
1348 */
1349 if ( hCertPaths == NIL_RTCRX509CERTPATHS
1350 && RTCrX509Name_Compare(&pCert->TbsCertificate.Issuer, &pCert->TbsCertificate.Subject) == 0)
1351 {
1352 RTMsgInfo("Test signed.\n");
1353 return VINF_SUCCESS;
1354 }
1355# endif
1356
1357 /*
1358 * Standard code signing capabilites required.
1359 */
1360 int rc = RTCrPkcs7VerifyCertCallbackCodeSigning(pCert, hCertPaths, fFlags, NULL, pErrInfo);
1361 if ( RT_SUCCESS(rc)
1362 && (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA))
1363 {
1364 uint32_t cDevIdApp = 0;
1365 uint32_t cDevIdKext = 0;
1366 uint32_t cDevIdMacDev = 0;
1367 for (uint32_t i = 0; i < pCert->TbsCertificate.T3.Extensions.cItems; i++)
1368 {
1369 PCRTCRX509EXTENSION pExt = pCert->TbsCertificate.T3.Extensions.papItems[i];
1370 if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_APPLICATION_OID) == 0)
1371 {
1372 cDevIdApp++;
1373 if (!pExt->Critical.fValue)
1374 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1375 "Dev ID Application certificate extension is not flagged critical");
1376 }
1377 else if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_KEXT_OID) == 0)
1378 {
1379 cDevIdKext++;
1380 if (!pExt->Critical.fValue)
1381 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1382 "Dev ID kext certificate extension is not flagged critical");
1383 }
1384 else if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_MAC_SW_DEV_OID) == 0)
1385 {
1386 cDevIdMacDev++;
1387 if (!pExt->Critical.fValue)
1388 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1389 "Dev ID MAC SW dev certificate extension is not flagged critical");
1390 }
1391 }
1392# ifdef VBOX_WITH_DARWIN_R0_TEST_SIGN
1393 /*
1394 * Mac application software development certs do not have the usually required extensions.
1395 */
1396 if (cDevIdMacDev)
1397 {
1398 cDevIdApp++;
1399 cDevIdKext++;
1400 }
1401# endif
1402 if (cDevIdApp == 0)
1403 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1404 "Certificate is missing the 'Dev ID Application' extension");
1405 if (cDevIdKext == 0)
1406 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1407 "Certificate is missing the 'Dev ID kext' extension");
1408 }
1409
1410 return rc;
1411}
1412
1413
1414/**
1415 * @callback_method_impl{FNRTLDRVALIDATESIGNEDDATA}
1416 */
1417static DECLCALLBACK(int) supdrvDarwinLdrOpenVerifyCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREINFO pInfo,
1418 PRTERRINFO pErrInfo, void *pvUser)
1419{
1420 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1421 RT_NOREF_PV(hLdrMod);
1422
1423 switch (pInfo->enmType)
1424 {
1425 case RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA:
1426 if (pInfo->pvExternalData)
1427 {
1428 PCRTCRPKCS7CONTENTINFO pContentInfo = (PCRTCRPKCS7CONTENTINFO)pInfo->pvSignature;
1429 RTTIMESPEC ValidationTime;
1430 RTTimeNow(&ValidationTime);
1431
1432 return RTCrPkcs7VerifySignedDataWithExternalData(pContentInfo,
1433 RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
1434 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT
1435 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT,
1436 pDevExt->hAdditionalStore, pDevExt->hRootStore, &ValidationTime,
1437 supdrvDarwinLdrOpenVerifyCertificatCallback, pDevExt,
1438 pInfo->pvExternalData, pInfo->cbExternalData, pErrInfo);
1439 }
1440 return RTErrInfoSetF(pErrInfo, VERR_NOT_SUPPORTED, "Expected external data with signature!");
1441
1442 default:
1443 return RTErrInfoSetF(pErrInfo, VERR_NOT_SUPPORTED, "Unsupported signature type: %d", pInfo->enmType);
1444 }
1445}
1446
1447#endif /* VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
1448
1449int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1450{
1451#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1452 /*
1453 * Initialize our members.
1454 */
1455 pImage->hLdrMod = NIL_RTLDRMOD;
1456 pImage->hMemAlloc = NIL_RTR0MEMOBJ;
1457
1458 /*
1459 * We have to double buffer the file to be avoid a potential race between
1460 * validation and actual image loading. This could be eliminated later by
1461 * baking the image validation into the RTLdrGetBits operation.
1462 *
1463 * Note! After calling RTLdrOpenInMemory, pvFile is owned by the loader and will be
1464 * freed via the RTFileReadAllFree callback when the loader module is closed.
1465 */
1466 void *pvFile = NULL;
1467 size_t cbFile = 0;
1468 int rc = RTFileReadAllEx(pszFilename, 0, _32M, RTFILE_RDALL_O_DENY_WRITE, &pvFile, &cbFile);
1469 if (RT_SUCCESS(rc))
1470 {
1471 PRTERRINFOSTATIC pErrInfo = (PRTERRINFOSTATIC)RTMemTmpAlloc(sizeof(RTERRINFOSTATIC));
1472 RTLDRMOD hLdrMod = NIL_RTLDRMOD;
1473 rc = RTLdrOpenInMemory(pszFilename, 0 /*fFlags*/, RTLDRARCH_HOST, cbFile,
1474 NULL /*pfnRead*/, RTFileReadAllFree, pvFile,
1475 &hLdrMod, pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
1476 if (RT_SUCCESS(rc))
1477 {
1478 /*
1479 * Validate the image.
1480 */
1481 rc = RTLdrVerifySignature(hLdrMod, supdrvDarwinLdrOpenVerifyCallback, pDevExt,
1482 pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
1483 if (RT_SUCCESS(rc))
1484 {
1485 /*
1486 * Allocate memory for the object and load it into it.
1487 */
1488 size_t cbImage = RTLdrSize(hLdrMod);
1489 if (cbImage == pImage->cbImageBits)
1490 {
1491 RTR0MEMOBJ hMemAlloc;
1492 rc = RTR0MemObjAllocPage(&hMemAlloc, cbImage, true /*fExecutable*/);
1493 if (RT_SUCCESS(rc))
1494 {
1495 void *pvImageBits = RTR0MemObjAddress(hMemAlloc);
1496 rc = RTLdrGetBits(hLdrMod, pvImageBits, (uintptr_t)pvImageBits,
1497 supdrvDarwinLdrOpenImportCallback, pDevExt);
1498 if (RT_SUCCESS(rc))
1499 {
1500 /*
1501 * Commit.
1502 */
1503 pImage->hMemAlloc = hMemAlloc;
1504 pImage->hLdrMod = hLdrMod;
1505 pImage->pvImage = pvImageBits;
1506 RTMemTmpFree(pErrInfo);
1507 /** @todo Call RTLdrDone. */
1508 kprintf("VBoxDrv: Loaded %s at %p\n", pImage->szName, pvImageBits);
1509 return VINF_SUCCESS;
1510 }
1511
1512 RTR0MemObjFree(hMemAlloc, true /*fFreeMappings*/);
1513 }
1514 else
1515 printf("VBoxDrv: Failed to allocate %u bytes for %s: %d\n", (unsigned)cbImage, pszFilename, rc);
1516 }
1517 else
1518 {
1519 printf("VBoxDrv: Image size mismatch for %s: %#x, ring-3 says %#x\n",
1520 pszFilename, (unsigned)cbImage, (unsigned)pImage->cbImageBits);
1521 rc = VERR_LDR_MISMATCH_NATIVE;
1522 }
1523 }
1524 else if (pErrInfo && RTErrInfoIsSet(&pErrInfo->Core))
1525 printf("VBoxDrv: RTLdrVerifySignature(%s) failed: %d - %s\n", pszFilename, rc, pErrInfo->Core.pszMsg);
1526 else
1527 printf("VBoxDrv: RTLdrVerifySignature(%s) failed: %d\n", pszFilename, rc);
1528 RTLdrClose(hLdrMod);
1529 }
1530 else if (pErrInfo && RTErrInfoIsSet(&pErrInfo->Core))
1531 printf("VBoxDrv: RTLdrOpenInMemory(%s) failed: %d - %s\n", pszFilename, rc, pErrInfo->Core.pszMsg);
1532 else
1533 printf("VBoxDrv: RTLdrOpenInMemory(%s) failed: %d\n", pszFilename, rc);
1534 RTMemTmpFree(pErrInfo);
1535 }
1536 return rc;
1537#else /* !VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
1538 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
1539 return VERR_NOT_SUPPORTED;
1540#endif /* !VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
1541}
1542
1543
1544#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1545/**
1546 * @callback_method_impl{FNRTLDRENUMSYMS,
1547 * Worker for supdrvOSLdrValidatePointer.
1548 */
1549static DECLCALLBACK(int) supdrvDarwinLdrValidatePointerCallback(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
1550 RTLDRADDR Value, void *pvUser)
1551{
1552 RT_NOREF(hLdrMod, pszSymbol, uSymbol);
1553 if (Value == (uintptr_t)pvUser)
1554 return VINF_CALLBACK_RETURN;
1555 return VINF_SUCCESS;
1556}
1557#endif
1558
1559
1560int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv,
1561 const uint8_t *pbImageBits, const char *pszSymbol)
1562{
1563#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1564 AssertReturn(pImage->hLdrMod != NIL_RTLDRMOD, VERR_INVALID_STATE);
1565
1566 /*
1567 * If we've got a symbol name, just to a lookup and compare addresses.
1568 */
1569 int rc;
1570 if (RT_C_IS_UPPER(*pszSymbol))
1571 {
1572 RTLDRADDR uValueFound;
1573 rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pvImage, (uintptr_t)pImage->pvImage, UINT32_MAX, pszSymbol, &uValueFound);
1574 if (RT_SUCCESS(rc))
1575 {
1576 if (uValueFound == (uintptr_t)pv)
1577 rc = VINF_SUCCESS;
1578 else
1579 {
1580 SUPR0Printf("SUPDrv: Different exports found for %s in %s: %RTptr, expected %p\n",
1581 pszSymbol, pImage->szName, (RTUINTPTR)uValueFound, pv);
1582 rc = VERR_LDR_BAD_FIXUP;
1583 }
1584 }
1585 else
1586 SUPR0Printf("SUPDrv: No export named %s (%p) in %s!\n", pszSymbol, pv, pImage->szName);
1587 }
1588 /*
1589 * Otherwise do a symbol enumeration and look for the entrypoint.
1590 */
1591 else
1592 {
1593 rc = RTLdrEnumSymbols(pImage->hLdrMod, 0 /*fFlags*/, pImage->pvImage, (uintptr_t)pImage->pvImage,
1594 supdrvDarwinLdrValidatePointerCallback, pv);
1595 if (rc == VINF_CALLBACK_RETURN)
1596 rc = VINF_SUCCESS;
1597 else if (RT_SUCCESS(rc))
1598 {
1599 SUPR0Printf("SUPDrv: No export with address %p (%s) in %s!\n", pv, pszSymbol, pImage->szName);
1600 rc = VERR_NOT_FOUND;
1601 }
1602 else
1603 SUPR0Printf("SUPDrv: RTLdrEnumSymbols failed on %s: %Rrc\n", pImage->szName, rc);
1604 }
1605 RT_NOREF(pDevExt, pbImageBits);
1606 return rc;
1607#else
1608 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits); NOREF(pszSymbol);
1609 return VERR_NOT_SUPPORTED;
1610#endif
1611}
1612
1613
1614int VBOXCALL supdrvOSLdrQuerySymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage,
1615 const char *pszSymbol, size_t cchSymbol, void **ppvSymbol)
1616{
1617#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1618 /*
1619 * Just hand the problem to RTLdrGetSymbolEx.
1620 */
1621 RTLDRADDR uValueFound;
1622 int rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pvImage, (uintptr_t)pImage->pvImage, UINT32_MAX, pszSymbol, &uValueFound);
1623 if (RT_SUCCESS(rc))
1624 {
1625 *ppvSymbol = (void *)(uintptr_t)uValueFound;
1626 return VINF_SUCCESS;
1627 }
1628 RT_NOREF(pDevExt, cchSymbol);
1629 return rc;
1630
1631#else
1632 RT_NOREF(pDevExt, pImage, pszSymbol, cchSymbol, ppvSymbol);
1633 return VERR_WRONG_ORDER;
1634#endif
1635}
1636
1637
1638int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
1639{
1640#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1641 /* State paranoia. */
1642 AssertReturn(pImage->hLdrMod != NIL_RTLDRMOD, VERR_INVALID_STATE);
1643 AssertReturn(pImage->hMemAlloc != NIL_RTR0MEMOBJ, VERR_INVALID_STATE);
1644 AssertReturn(pImage->pvImage, VERR_INVALID_STATE);
1645
1646 /*
1647 * We should get an identical match with ring-3 here, so the code here is
1648 * trivial in comparision to SUPDrv-win.cpp.
1649 */
1650 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
1651 return VINF_SUCCESS;
1652
1653 /*
1654 * Try show what when wrong (code is copied from supdrvNtCompare).
1655 */
1656 uint32_t cbLeft = pImage->cbImageBits;
1657 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
1658 for (size_t off = 0; cbLeft > 0; off++, cbLeft--)
1659 if (pbNativeBits[off] != pbImageBits[off])
1660 {
1661 /* Note! We need to copy image bits into a temporary stack buffer here as we'd
1662 otherwise risk overwriting them while formatting the error message. */
1663 uint8_t abBytes[64];
1664 memcpy(abBytes, &pbImageBits[off], RT_MIN(64, cbLeft));
1665 supdrvLdrLoadError(VERR_LDR_MISMATCH_NATIVE, pReq,
1666 "Mismatch at %#x (%p) of %s loaded at %p:\n"
1667 "ring-0: %.*Rhxs\n"
1668 "ring-3: %.*Rhxs",
1669 off, &pbNativeBits[off], pImage->szName, pImage->pvImage,
1670 RT_MIN(64, cbLeft), &pbNativeBits[off],
1671 RT_MIN(64, cbLeft), &abBytes[0]);
1672 printf("SUPDrv: %s\n", pReq->u.Out.szError);
1673 break;
1674 }
1675
1676 RT_NOREF(pDevExt);
1677 return VERR_LDR_MISMATCH_NATIVE;
1678
1679#else
1680 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
1681 return VERR_NOT_SUPPORTED;
1682#endif
1683}
1684
1685
1686void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1687{
1688#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1689 if (pImage->hLdrMod != NIL_RTLDRMOD)
1690 {
1691 int rc = RTLdrClose(pImage->hLdrMod);
1692 AssertRC(rc);
1693 pImage->hLdrMod = NIL_RTLDRMOD;
1694 }
1695 if (pImage->hMemAlloc != NIL_RTR0MEMOBJ)
1696 {
1697 RTR0MemObjFree(pImage->hMemAlloc, true /*fFreeMappings*/);
1698 pImage->hMemAlloc = NIL_RTR0MEMOBJ;
1699 }
1700 NOREF(pDevExt);
1701#else
1702 NOREF(pDevExt); NOREF(pImage);
1703#endif
1704}
1705
1706
1707void VBOXCALL supdrvOSLdrNotifyLoaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1708{
1709 NOREF(pDevExt); NOREF(pImage);
1710}
1711
1712
1713void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1714{
1715#if 1
1716 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
1717#else
1718 /*
1719 * Try store the image load address in NVRAM so we can retrived it on panic.
1720 * Note! This only works if you're root! - Acutally, it doesn't work at all at the moment. FIXME!
1721 */
1722 IORegistryEntry *pEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
1723 if (pEntry)
1724 {
1725 char szVar[80];
1726 RTStrPrintf(szVar, sizeof(szVar), "vboximage"/*-%s*/, pImage->szName);
1727 char szValue[48];
1728 RTStrPrintf(szValue, sizeof(szValue), "%#llx,%#llx", (uint64_t)(uintptr_t)pImage->pvImage,
1729 (uint64_t)(uintptr_t)pImage->pvImage + pImage->cbImageBits - 1);
1730 bool fRc = pEntry->setProperty(szVar, szValue); NOREF(fRc);
1731 pEntry->release();
1732 SUPR0Printf("fRc=%d '%s'='%s'\n", fRc, szVar, szValue);
1733 }
1734 /*else
1735 SUPR0Printf("failed to find /options in gIODTPlane\n");*/
1736#endif
1737}
1738
1739
1740void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1741{
1742 NOREF(pDevExt); NOREF(pImage);
1743}
1744
1745
1746void VBOXCALL supdrvOSLdrRetainWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1747{
1748 RT_NOREF(pDevExt, pImage);
1749 AssertFailed();
1750}
1751
1752
1753void VBOXCALL supdrvOSLdrReleaseWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1754{
1755 RT_NOREF(pDevExt, pImage);
1756 AssertFailed();
1757}
1758
1759
1760#if defined(SUPDRV_WITH_MSR_PROBER) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86))
1761
1762typedef struct SUPDRVDARWINMSRARGS
1763{
1764 RTUINT64U uValue;
1765 uint32_t uMsr;
1766 int rc;
1767} SUPDRVDARWINMSRARGS, *PSUPDRVDARWINMSRARGS;
1768
1769/**
1770 * On CPU worker for supdrvOSMsrProberRead.
1771 *
1772 * @param idCpu Ignored.
1773 * @param pvUser1 Pointer to a SUPDRVDARWINMSRARGS.
1774 * @param pvUser2 Ignored.
1775 */
1776static DECLCALLBACK(void) supdrvDarwinMsrProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1777{
1778 PSUPDRVDARWINMSRARGS pArgs = (PSUPDRVDARWINMSRARGS)pvUser1;
1779 if (g_pfnRdMsr64Carefully)
1780 pArgs->rc = g_pfnRdMsr64Carefully(pArgs->uMsr, &pArgs->uValue.u);
1781 else if (g_pfnRdMsrCarefully)
1782 pArgs->rc = g_pfnRdMsrCarefully(pArgs->uMsr, &pArgs->uValue.s.Lo, &pArgs->uValue.s.Hi);
1783 else
1784 pArgs->rc = 2;
1785 NOREF(idCpu); NOREF(pvUser2);
1786}
1787
1788
1789int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
1790{
1791 if (!g_pfnRdMsr64Carefully && !g_pfnRdMsrCarefully)
1792 return VERR_NOT_SUPPORTED;
1793
1794 SUPDRVDARWINMSRARGS Args;
1795 Args.uMsr = uMsr;
1796 Args.uValue.u = 0;
1797 Args.rc = -1;
1798
1799 if (idCpu == NIL_RTCPUID)
1800 {
1801 IPRT_DARWIN_SAVE_EFL_AC();
1802 supdrvDarwinMsrProberReadOnCpu(idCpu, &Args, NULL);
1803 IPRT_DARWIN_RESTORE_EFL_AC();
1804 }
1805 else
1806 {
1807 int rc = RTMpOnSpecific(idCpu, supdrvDarwinMsrProberReadOnCpu, &Args, NULL);
1808 if (RT_FAILURE(rc))
1809 return rc;
1810 }
1811
1812 if (Args.rc)
1813 return VERR_ACCESS_DENIED;
1814 *puValue = Args.uValue.u;
1815 return VINF_SUCCESS;
1816}
1817
1818
1819/**
1820 * On CPU worker for supdrvOSMsrProberWrite.
1821 *
1822 * @param idCpu Ignored.
1823 * @param pvUser1 Pointer to a SUPDRVDARWINMSRARGS.
1824 * @param pvUser2 Ignored.
1825 */
1826static DECLCALLBACK(void) supdrvDarwinMsrProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1827{
1828 PSUPDRVDARWINMSRARGS pArgs = (PSUPDRVDARWINMSRARGS)pvUser1;
1829 if (g_pfnWrMsr64Carefully)
1830 pArgs->rc = g_pfnWrMsr64Carefully(pArgs->uMsr, pArgs->uValue.u);
1831 else
1832 pArgs->rc = 2;
1833 NOREF(idCpu); NOREF(pvUser2);
1834}
1835
1836
1837int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
1838{
1839 if (!g_pfnWrMsr64Carefully)
1840 return VERR_NOT_SUPPORTED;
1841
1842 SUPDRVDARWINMSRARGS Args;
1843 Args.uMsr = uMsr;
1844 Args.uValue.u = uValue;
1845 Args.rc = -1;
1846
1847 if (idCpu == NIL_RTCPUID)
1848 {
1849 IPRT_DARWIN_SAVE_EFL_AC();
1850 supdrvDarwinMsrProberWriteOnCpu(idCpu, &Args, NULL);
1851 IPRT_DARWIN_RESTORE_EFL_AC();
1852 }
1853 else
1854 {
1855 int rc = RTMpOnSpecific(idCpu, supdrvDarwinMsrProberWriteOnCpu, &Args, NULL);
1856 if (RT_FAILURE(rc))
1857 return rc;
1858 }
1859
1860 if (Args.rc)
1861 return VERR_ACCESS_DENIED;
1862 return VINF_SUCCESS;
1863}
1864
1865
1866/**
1867 * Worker for supdrvOSMsrProberModify.
1868 */
1869static DECLCALLBACK(void) supdrvDarwinMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1870{
1871 RT_NOREF(idCpu, pvUser2);
1872 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
1873 register uint32_t uMsr = pReq->u.In.uMsr;
1874 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
1875 uint64_t uBefore;
1876 uint64_t uWritten;
1877 uint64_t uAfter;
1878 int rcBefore, rcWrite, rcAfter, rcRestore;
1879 RTCCUINTREG fOldFlags;
1880
1881 /* Initialize result variables. */
1882 uBefore = uWritten = uAfter = 0;
1883 rcWrite = rcAfter = rcRestore = -1;
1884
1885 /*
1886 * Do the job.
1887 */
1888 fOldFlags = ASMIntDisableFlags();
1889 ASMCompilerBarrier(); /* paranoia */
1890 if (!fFaster)
1891 ASMWriteBackAndInvalidateCaches();
1892
1893 rcBefore = g_pfnRdMsr64Carefully(uMsr, &uBefore);
1894 if (rcBefore >= 0)
1895 {
1896 register uint64_t uRestore = uBefore;
1897 uWritten = uRestore;
1898 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
1899 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
1900
1901 rcWrite = g_pfnWrMsr64Carefully(uMsr, uWritten);
1902 rcAfter = g_pfnRdMsr64Carefully(uMsr, &uAfter);
1903 rcRestore = g_pfnWrMsr64Carefully(uMsr, uRestore);
1904
1905 if (!fFaster)
1906 {
1907 ASMWriteBackAndInvalidateCaches();
1908 ASMReloadCR3();
1909 ASMNopPause();
1910 }
1911 }
1912
1913 ASMCompilerBarrier(); /* paranoia */
1914 ASMSetFlags(fOldFlags);
1915
1916 /*
1917 * Write out the results.
1918 */
1919 pReq->u.Out.uResults.Modify.uBefore = uBefore;
1920 pReq->u.Out.uResults.Modify.uWritten = uWritten;
1921 pReq->u.Out.uResults.Modify.uAfter = uAfter;
1922 pReq->u.Out.uResults.Modify.fBeforeGp = rcBefore != 0;
1923 pReq->u.Out.uResults.Modify.fModifyGp = rcWrite != 0;
1924 pReq->u.Out.uResults.Modify.fAfterGp = rcAfter != 0;
1925 pReq->u.Out.uResults.Modify.fRestoreGp = rcRestore != 0;
1926 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
1927}
1928
1929
1930int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
1931{
1932 if (!g_pfnWrMsr64Carefully || !g_pfnRdMsr64Carefully)
1933 return VERR_NOT_SUPPORTED;
1934 if (idCpu == NIL_RTCPUID)
1935 {
1936 IPRT_DARWIN_SAVE_EFL_AC();
1937 supdrvDarwinMsrProberModifyOnCpu(idCpu, pReq, NULL);
1938 IPRT_DARWIN_RESTORE_EFL_AC();
1939 return VINF_SUCCESS;
1940 }
1941 return RTMpOnSpecific(idCpu, supdrvDarwinMsrProberModifyOnCpu, pReq, NULL);
1942}
1943
1944#endif /* SUPDRV_WITH_MSR_PROBER || (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) */
1945
1946/**
1947 * Resume Bluetooth keyboard.
1948 * If there is no Bluetooth keyboard device connected to the system we just ignore this.
1949 */
1950static void supdrvDarwinResumeBluetoothKbd(void)
1951{
1952 OSDictionary *pDictionary = IOService::serviceMatching("AppleBluetoothHIDKeyboard");
1953 if (pDictionary)
1954 {
1955 OSIterator *pIter;
1956 IOBluetoothHIDDriver *pDriver;
1957
1958 pIter = IOService::getMatchingServices(pDictionary);
1959 if (pIter)
1960 {
1961 while ((pDriver = (IOBluetoothHIDDriver *)pIter->getNextObject()))
1962 if (pDriver->isKeyboard())
1963 (void)pDriver->hidControl(IOBTHID_CONTROL_EXIT_SUSPEND);
1964
1965 pIter->release();
1966 }
1967 pDictionary->release();
1968 }
1969}
1970
1971/**
1972 * Resume built-in keyboard on MacBook Air and Pro hosts.
1973 * If there is no built-in keyboard device attached to the system we just ignore this.
1974 */
1975static void supdrvDarwinResumeBuiltinKbd(void)
1976{
1977 /** @todo macbook pro 16 w/ 10.15.5 as the "Apple Internal Keyboard /
1978 * Trackpad" hooked up to "HID Relay" / "AppleUserUSBHostHIDDevice"
1979 * and "AppleUserUSBHostHIDDevice" among other things, but not
1980 * "AppleUSBTCKeyboard". This change is probably older than 10.15,
1981 * given that IOUSBHIDDriver not is present in the 10.11 SDK. */
1982#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
1983 /*
1984 * AppleUSBTCKeyboard KEXT is responsible for built-in keyboard management.
1985 * We resume keyboard by accessing to its IOService.
1986 */
1987 OSDictionary *pDictionary = IOService::serviceMatching("AppleUSBTCKeyboard");
1988 if (pDictionary)
1989 {
1990 OSIterator *pIter;
1991 IOUSBHIDDriver *pDriver;
1992
1993 pIter = IOService::getMatchingServices(pDictionary);
1994 if (pIter)
1995 {
1996 while ((pDriver = (IOUSBHIDDriver *)pIter->getNextObject()))
1997 if (pDriver->IsPortSuspended())
1998 pDriver->SuspendPort(false, 0);
1999
2000 pIter->release();
2001 }
2002 pDictionary->release();
2003 }
2004#endif
2005}
2006
2007
2008/**
2009 * Resume suspended keyboard devices (if any).
2010 */
2011int VBOXCALL supdrvDarwinResumeSuspendedKbds(void)
2012{
2013 IPRT_DARWIN_SAVE_EFL_AC();
2014 supdrvDarwinResumeBuiltinKbd();
2015 supdrvDarwinResumeBluetoothKbd();
2016 IPRT_DARWIN_RESTORE_EFL_AC();
2017 return 0;
2018}
2019
2020
2021/**
2022 * Converts an IPRT error code to a darwin error code.
2023 *
2024 * @returns corresponding darwin error code.
2025 * @param rc IPRT status code.
2026 */
2027static int VBoxDrvDarwinErr2DarwinErr(int rc)
2028{
2029 switch (rc)
2030 {
2031 case VINF_SUCCESS: return 0;
2032 case VERR_GENERAL_FAILURE: return EACCES;
2033 case VERR_INVALID_PARAMETER: return EINVAL;
2034 case VERR_INVALID_MAGIC: return EILSEQ;
2035 case VERR_INVALID_HANDLE: return ENXIO;
2036 case VERR_INVALID_POINTER: return EFAULT;
2037 case VERR_LOCK_FAILED: return ENOLCK;
2038 case VERR_ALREADY_LOADED: return EEXIST;
2039 case VERR_PERMISSION_DENIED: return EPERM;
2040 case VERR_VERSION_MISMATCH: return ENOSYS;
2041 }
2042
2043 return EPERM;
2044}
2045
2046
2047#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
2048/**
2049 * Check if the CPU has SMAP support.
2050 */
2051static bool vboxdrvDarwinCpuHasSMAP(void)
2052{
2053 uint32_t uMaxId, uEAX, uEBX, uECX, uEDX;
2054 ASMCpuId(0, &uMaxId, &uEBX, &uECX, &uEDX);
2055 if ( RTX86IsValidStdRange(uMaxId)
2056 && uMaxId >= 0x00000007)
2057 {
2058 ASMCpuId_Idx_ECX(0x00000007, 0, &uEAX, &uEBX, &uECX, &uEDX);
2059 if (uEBX & X86_CPUID_STEXT_FEATURE_EBX_SMAP)
2060 return true;
2061 }
2062# ifdef VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV
2063 return true;
2064# else
2065 return false;
2066# endif
2067}
2068#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */
2069
2070
2071RTDECL(int) SUPR0PrintfV(const char *pszFormat, va_list va)
2072{
2073 IPRT_DARWIN_SAVE_EFL_AC();
2074
2075 char szMsg[512];
2076 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2077 szMsg[sizeof(szMsg) - 1] = '\0';
2078
2079 printf("%s", szMsg);
2080 kprintf("%s", szMsg);
2081
2082 IPRT_DARWIN_RESTORE_EFL_AC();
2083 return 0;
2084}
2085
2086
2087SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
2088{
2089 return g_fKernelFeatures;
2090}
2091
2092
2093SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook)
2094{
2095 RT_NOREF(fCtxHook);
2096 return false;
2097}
2098
2099
2100SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook)
2101{
2102 RT_NOREF(fCtxHook);
2103}
2104
2105/*
2106 *
2107 * org_virtualbox_SupDrv
2108 *
2109 * - IOService diff resync -
2110 * - IOService diff resync -
2111 * - IOService diff resync -
2112 *
2113 */
2114
2115
2116/**
2117 * Initialize the object.
2118 */
2119bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
2120{
2121 LogFlow(("IOService::init([%p], %p)\n", this, pDictionary));
2122 if (IOService::init(pDictionary))
2123 {
2124 /* init members. */
2125 return true;
2126 }
2127 return false;
2128}
2129
2130
2131/**
2132 * Free the object.
2133 */
2134void org_virtualbox_SupDrv::free(void)
2135{
2136 LogFlow(("IOService::free([%p])\n", this));
2137 IOService::free();
2138}
2139
2140
2141/**
2142 * Check if it's ok to start this service.
2143 * It's always ok by us, so it's up to IOService to decide really.
2144 */
2145IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
2146{
2147 LogFlow(("IOService::probe([%p])\n", this));
2148 return IOService::probe(pProvider, pi32Score);
2149}
2150
2151
2152/**
2153 * Start this service.
2154 */
2155bool org_virtualbox_SupDrv::start(IOService *pProvider)
2156{
2157 LogFlow(("org_virtualbox_SupDrv::start([%p])\n", this));
2158
2159 if (IOService::start(pProvider))
2160 {
2161 /* register the service. */
2162 registerService();
2163 return true;
2164 }
2165 return false;
2166}
2167
2168
2169/**
2170 * Stop this service.
2171 */
2172void org_virtualbox_SupDrv::stop(IOService *pProvider)
2173{
2174 LogFlow(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
2175 IOService::stop(pProvider);
2176}
2177
2178
2179/**
2180 * Termination request.
2181 *
2182 * @return true if we're ok with shutting down now, false if we're not.
2183 * @param fOptions Flags.
2184 */
2185bool org_virtualbox_SupDrv::terminate(IOOptionBits fOptions)
2186{
2187 bool fRc;
2188 LogFlow(("org_virtualbox_SupDrv::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
2189 KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
2190 if ( KMOD_INFO_NAME.reference_count != 0
2191 || ASMAtomicUoReadS32(&g_cSessions))
2192 fRc = false;
2193 else
2194 fRc = IOService::terminate(fOptions);
2195 LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
2196 return fRc;
2197}
2198
2199
2200/*
2201 *
2202 * org_virtualbox_SupDrvClient
2203 *
2204 */
2205
2206
2207/**
2208 * Initializer called when the client opens the service.
2209 */
2210bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
2211{
2212 LogFlow(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x) (cur pid=%d proc=%p)\n",
2213 this, OwningTask, pvSecurityId, u32Type, RTProcSelf(), RTR0ProcHandleSelf()));
2214 AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
2215
2216 if (!OwningTask)
2217 return false;
2218
2219 if (u32Type != SUP_DARWIN_IOSERVICE_COOKIE)
2220 {
2221 VBOX_RETRIEVE_CUR_PROC_NAME(szProcName);
2222 LogRelMax(10,("org_virtualbox_SupDrvClient::initWithTask: Bad cookie %#x (%s)\n", u32Type, szProcName));
2223 return false;
2224 }
2225
2226 if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
2227 {
2228 /*
2229 * In theory we have to call task_reference() to make sure that the task is
2230 * valid during the lifetime of this object. The pointer is only used to check
2231 * for the context this object is called in though and never dereferenced
2232 * or passed to anything which might, so we just skip this step.
2233 */
2234 m_Task = OwningTask;
2235 m_pSession = NULL;
2236 m_pProvider = NULL;
2237 return true;
2238 }
2239 return false;
2240}
2241
2242
2243/**
2244 * Start the client service.
2245 */
2246bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
2247{
2248 LogFlow(("org_virtualbox_SupDrvClient::start([%p], %p) (cur pid=%d proc=%p)\n",
2249 this, pProvider, RTProcSelf(), RTR0ProcHandleSelf() ));
2250 AssertMsgReturn((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(),
2251 ("%p %p\n", m_Task, RTR0ProcHandleSelf()),
2252 false);
2253
2254 if (IOUserClient::start(pProvider))
2255 {
2256 m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
2257 if (m_pProvider)
2258 {
2259 Assert(!m_pSession);
2260
2261 /*
2262 * Create a new session.
2263 */
2264 int rc = supdrvCreateSession(&g_DevExt, true /* fUser */, false /*fUnrestricted*/, &m_pSession);
2265 if (RT_SUCCESS(rc))
2266 {
2267 m_pSession->fOpened = false;
2268 /* The Uid, Gid and fUnrestricted fields are set on open. */
2269
2270 /*
2271 * Insert it into the hash table, checking that there isn't
2272 * already one for this process first. (One session per proc!)
2273 */
2274 unsigned iHash = SESSION_HASH(m_pSession->Process);
2275 RTSpinlockAcquire(g_Spinlock);
2276
2277 PSUPDRVSESSION pCur = g_apSessionHashTab[iHash];
2278 while (pCur && pCur->Process != m_pSession->Process)
2279 pCur = pCur->pNextHash;
2280 if (!pCur)
2281 {
2282 m_pSession->pNextHash = g_apSessionHashTab[iHash];
2283 g_apSessionHashTab[iHash] = m_pSession;
2284 m_pSession->pvSupDrvClient = this;
2285 ASMAtomicIncS32(&g_cSessions);
2286 rc = VINF_SUCCESS;
2287 }
2288 else
2289 rc = VERR_ALREADY_LOADED;
2290
2291 RTSpinlockRelease(g_Spinlock);
2292 if (RT_SUCCESS(rc))
2293 {
2294 Log(("org_virtualbox_SupDrvClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
2295 return true;
2296 }
2297
2298 LogFlow(("org_virtualbox_SupDrvClient::start: already got a session for this process (%p)\n", pCur));
2299 supdrvSessionRelease(m_pSession);
2300 }
2301
2302 m_pSession = NULL;
2303 LogFlow(("org_virtualbox_SupDrvClient::start: rc=%Rrc from supdrvCreateSession\n", rc));
2304 }
2305 else
2306 LogFlow(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
2307 }
2308 return false;
2309}
2310
2311
2312/**
2313 * Common worker for clientClose and VBoxDrvDarwinClose.
2314 */
2315/* static */ void org_virtualbox_SupDrvClient::sessionClose(RTPROCESS Process)
2316{
2317 /*
2318 * Find the session and remove it from the hash table.
2319 *
2320 * Note! Only one session per process. (Both start() and
2321 * VBoxDrvDarwinOpen makes sure this is so.)
2322 */
2323 const unsigned iHash = SESSION_HASH(Process);
2324 RTSpinlockAcquire(g_Spinlock);
2325 PSUPDRVSESSION pSession = g_apSessionHashTab[iHash];
2326 if (pSession)
2327 {
2328 if (pSession->Process == Process)
2329 {
2330 g_apSessionHashTab[iHash] = pSession->pNextHash;
2331 pSession->pNextHash = NULL;
2332 ASMAtomicDecS32(&g_cSessions);
2333 }
2334 else
2335 {
2336 PSUPDRVSESSION pPrev = pSession;
2337 pSession = pSession->pNextHash;
2338 while (pSession)
2339 {
2340 if (pSession->Process == Process)
2341 {
2342 pPrev->pNextHash = pSession->pNextHash;
2343 pSession->pNextHash = NULL;
2344 ASMAtomicDecS32(&g_cSessions);
2345 break;
2346 }
2347
2348 /* next */
2349 pPrev = pSession;
2350 pSession = pSession->pNextHash;
2351 }
2352 }
2353 }
2354 RTSpinlockRelease(g_Spinlock);
2355 if (!pSession)
2356 {
2357 Log(("SupDrvClient::sessionClose: pSession == NULL, pid=%d; freed already?\n", (int)Process));
2358 return;
2359 }
2360
2361 /*
2362 * Remove it from the client object.
2363 */
2364 org_virtualbox_SupDrvClient *pThis = (org_virtualbox_SupDrvClient *)pSession->pvSupDrvClient;
2365 pSession->pvSupDrvClient = NULL;
2366 if (pThis)
2367 {
2368 Assert(pThis->m_pSession == pSession);
2369 pThis->m_pSession = NULL;
2370 }
2371
2372 /*
2373 * Close the session.
2374 */
2375 supdrvSessionRelease(pSession);
2376}
2377
2378
2379/**
2380 * Client exits normally.
2381 */
2382IOReturn org_virtualbox_SupDrvClient::clientClose(void)
2383{
2384 LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
2385 AssertMsg((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(), ("%p %p\n", m_Task, RTR0ProcHandleSelf()));
2386
2387 /*
2388 * Clean up the session if it's still around.
2389 *
2390 * We cannot rely 100% on close, and in the case of a dead client
2391 * we'll end up hanging inside vm_map_remove() if we postpone it.
2392 */
2393 if (m_pSession)
2394 {
2395 sessionClose(RTProcSelf());
2396 Assert(!m_pSession);
2397 }
2398
2399 m_pProvider = NULL;
2400 terminate();
2401
2402 return kIOReturnSuccess;
2403}
2404
2405
2406/**
2407 * The client exits abnormally / forgets to do cleanups. (logging)
2408 */
2409IOReturn org_virtualbox_SupDrvClient::clientDied(void)
2410{
2411 LogFlow(("IOService::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n", this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
2412
2413 /* IOUserClient::clientDied() calls clientClose, so we'll just do the work there. */
2414 return IOUserClient::clientDied();
2415}
2416
2417
2418/**
2419 * Terminate the service (initiate the destruction). (logging)
2420 */
2421bool org_virtualbox_SupDrvClient::terminate(IOOptionBits fOptions)
2422{
2423 LogFlow(("IOService::terminate([%p], %#x)\n", this, fOptions));
2424 return IOUserClient::terminate(fOptions);
2425}
2426
2427
2428/**
2429 * The final stage of the client service destruction. (logging)
2430 */
2431bool org_virtualbox_SupDrvClient::finalize(IOOptionBits fOptions)
2432{
2433 LogFlow(("IOService::finalize([%p], %#x)\n", this, fOptions));
2434 return IOUserClient::finalize(fOptions);
2435}
2436
2437
2438/**
2439 * Stop the client service. (logging)
2440 */
2441void org_virtualbox_SupDrvClient::stop(IOService *pProvider)
2442{
2443 LogFlow(("IOService::stop([%p])\n", this));
2444 IOUserClient::stop(pProvider);
2445}
2446
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