VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/darwin/krnlmod-darwin.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1/* $Id: krnlmod-darwin.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Kernel module, Darwin.
4 */
5
6/*
7 * Copyright (C) 2017-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
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 RTLOGGROUP_SYSTEM
42#include <iprt/krnlmod.h>
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/errcore.h>
47#include <iprt/ldr.h>
48#include <iprt/mem.h>
49#include <iprt/once.h>
50#include <iprt/string.h>
51#include <iprt/types.h>
52
53#include <CoreFoundation/CoreFoundation.h>
54#include <IOKit/IOKitLib.h>
55#include <libkern/OSReturn.h>
56
57
58/** @name Missing/private IOKitLib declarations and definitions.
59 * @{ */
60/** OSKextCopyLoadedKextInfo in IOKit. */
61typedef CFDictionaryRef (* PFNOSKEXTCOPYLOADEDKEXTINFO)(CFArrayRef, CFArrayRef);
62/** KextManagerLoadKextWithURL in IOKit. */
63typedef OSReturn (* PFNKEXTMANAGERLOADKEXTWITHURL)(CFURLRef, CFArrayRef);
64/** KextManagerLoadKextWithIdentifier in IOKit */
65typedef OSReturn (* PFNKEXTMANAGERLOADKEXTWITHIDENTIFIER)(CFStringRef, CFArrayRef);
66/** KextManagerUnloadKextWithIdentifier in IOKit */
67typedef OSReturn (* PFNKEXTMANAGERUNLOADKEXTWITHIDENTIFIER)(CFStringRef);
68
69#ifndef kOSBundleRetainCountKey
70# define kOSBundleRetainCountKey CFSTR("OSBundleRetainCount")
71#endif
72#ifndef kOSBundleLoadSizeKey
73# define kOSBundleLoadSizeKey CFSTR("OSBundleLoadSize")
74#endif
75#ifndef kOSBundleLoadAddressKey
76# define kOSBundleLoadAddressKey CFSTR("OSBundleLoadAddress")
77#endif
78/** @} */
79
80
81/*********************************************************************************************************************************
82* Structures and Typedefs *
83*********************************************************************************************************************************/
84/**
85 * Internal kernel information record state.
86 */
87typedef struct RTKRNLMODINFOINT
88{
89 /** Reference counter. */
90 volatile uint32_t cRefs;
91 /** The dictionary containing our data. */
92 CFDictionaryRef hDictKext;
93} RTKRNLMODINFOINT;
94/** Pointer to the internal kernel module information record. */
95typedef RTKRNLMODINFOINT *PRTKRNLMODINFOINT;
96/** Pointer to a const internal kernel module information record. */
97typedef const RTKRNLMODINFOINT *PCRTKRNLMODINFOINT;
98
99
100/*********************************************************************************************************************************
101* Global Variables *
102*********************************************************************************************************************************/
103static RTONCE g_GetIoKitApisOnce = RTONCE_INITIALIZER;
104static PFNOSKEXTCOPYLOADEDKEXTINFO g_pfnOSKextCopyLoadedKextInfo = NULL;
105static PFNKEXTMANAGERLOADKEXTWITHURL g_pfnKextManagerLoadKextWithUrl = NULL;
106static PFNKEXTMANAGERLOADKEXTWITHIDENTIFIER g_pfnKextManagerLoadKextWithIdentifier = NULL;
107static PFNKEXTMANAGERUNLOADKEXTWITHIDENTIFIER g_pfnKextManagerUnloadKextWithIdentifier = NULL;
108
109/** Do-once callback for setting g_pfnOSKextCopyLoadedKextInfo. */
110static DECLCALLBACK(int) rtKrnlModDarwinResolveIoKitApis(void *pvUser)
111{
112 RTLDRMOD hMod;
113// int rc = RTLdrLoad("/System/Library/Frameworks/IOKit.framework/Versions/Current/IOKit", &hMod);
114 int rc = RTLdrLoadEx("/System/Library/Frameworks/IOKit.framework/Versions/Current/IOKit", &hMod, RTLDRLOAD_FLAGS_NO_SUFFIX, NULL);
115 if (RT_SUCCESS(rc))
116 {
117 RTLdrGetSymbol(hMod, "OSKextCopyLoadedKextInfo", (void **)&g_pfnOSKextCopyLoadedKextInfo);
118 RTLdrGetSymbol(hMod, "KextManagerLoadKextWithURL", (void **)&g_pfnKextManagerLoadKextWithUrl);
119 RTLdrGetSymbol(hMod, "KextManagerLoadKextWithIdentifier", (void **)&g_pfnKextManagerLoadKextWithIdentifier);
120 RTLdrGetSymbol(hMod, "KextManagerUnloadKextWithIdentifier", (void **)&g_pfnKextManagerUnloadKextWithIdentifier);
121 }
122
123 RT_NOREF(pvUser);
124 return VINF_SUCCESS;
125}
126
127/**
128 * Returns the kext information dictionary structure matching the given name.
129 *
130 * @returns Pointer to the matching module information record on success or NULL if not found.
131 * @param pszName The name to look for.
132 */
133static CFDictionaryRef rtKrnlModDarwinGetKextInfoByName(const char *pszName)
134{
135 CFDictionaryRef hDictKext = NULL;
136
137 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
138 if (g_pfnOSKextCopyLoadedKextInfo)
139 {
140 CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
141 if (hKextName)
142 {
143 CFArrayRef hArrKextIdRef = CFArrayCreate(kCFAllocatorDefault, (const void **)&hKextName, 1, &kCFTypeArrayCallBacks);
144 if (hArrKextIdRef)
145 {
146 CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(hArrKextIdRef, NULL /* all info */);
147 if (hLoadedKexts)
148 {
149 if (CFDictionaryGetCount(hLoadedKexts) > 0)
150 {
151 hDictKext = (CFDictionaryRef)CFDictionaryGetValue(hLoadedKexts, hKextName);
152 CFRetain(hDictKext);
153 }
154
155 CFRelease(hLoadedKexts);
156 }
157 CFRelease(hArrKextIdRef);
158 }
159 CFRelease(hKextName);
160 }
161 }
162
163 return hDictKext;
164}
165
166/**
167 * Destroy the given kernel module information record.
168 *
169 * @param pThis The record to destroy.
170 */
171static void rtKrnlModInfoDestroy(PRTKRNLMODINFOINT pThis)
172{
173 CFRelease(pThis->hDictKext);
174 RTMemFree(pThis);
175}
176
177
178RTDECL(int) RTKrnlModQueryLoaded(const char *pszName, bool *pfLoaded)
179{
180 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
181 AssertPtrReturn(pfLoaded, VERR_INVALID_POINTER);
182
183 CFDictionaryRef hDictKext = rtKrnlModDarwinGetKextInfoByName(pszName);
184 *pfLoaded = hDictKext != NULL;
185 if (hDictKext)
186 CFRelease(hDictKext);
187
188 return VINF_SUCCESS;
189}
190
191
192RTDECL(int) RTKrnlModLoadedQueryInfo(const char *pszName, PRTKRNLMODINFO phKrnlModInfo)
193{
194 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
195 AssertPtrReturn(phKrnlModInfo, VERR_INVALID_POINTER);
196
197 int rc = VINF_SUCCESS;
198 CFDictionaryRef hDictKext = rtKrnlModDarwinGetKextInfoByName(pszName);
199 if (hDictKext)
200 {
201 PRTKRNLMODINFOINT pThis = (PRTKRNLMODINFOINT)RTMemAllocZ(sizeof(RTKRNLMODINFOINT));
202 if (pThis)
203 {
204 pThis->cRefs = 1;
205 pThis->hDictKext = hDictKext;
206
207 *phKrnlModInfo = pThis;
208 }
209 else
210 rc = VERR_NO_MEMORY;
211 }
212 else
213 rc = VERR_NOT_FOUND;
214
215 return rc;
216}
217
218
219RTDECL(uint32_t) RTKrnlModLoadedGetCount(void)
220{
221 uint32_t cLoadedKexts = 0;
222 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
223 if (g_pfnOSKextCopyLoadedKextInfo)
224 {
225 CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(NULL, NULL /* all info */);
226 if (hLoadedKexts)
227 {
228 cLoadedKexts = CFDictionaryGetCount(hLoadedKexts);
229 CFRelease(hLoadedKexts);
230 }
231 }
232
233 return cLoadedKexts;
234}
235
236
237RTDECL(int) RTKrnlModLoadedQueryInfoAll(PRTKRNLMODINFO pahKrnlModInfo, uint32_t cEntriesMax,
238 uint32_t *pcEntries)
239{
240 if (cEntriesMax > 0)
241 AssertPtrReturn(pahKrnlModInfo, VERR_INVALID_POINTER);
242
243 int rc = VINF_SUCCESS;
244 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
245 if (g_pfnOSKextCopyLoadedKextInfo)
246 {
247 CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(NULL, NULL /* all info */);
248 if (hLoadedKexts)
249 {
250 uint32_t cLoadedKexts = CFDictionaryGetCount(hLoadedKexts);
251 if (cLoadedKexts <= cEntriesMax)
252 {
253 CFDictionaryRef *pahDictKext = (CFDictionaryRef *)RTMemTmpAllocZ(cLoadedKexts * sizeof(CFDictionaryRef));
254 if (pahDictKext)
255 {
256 CFDictionaryGetKeysAndValues(hLoadedKexts, NULL, (const void **)pahDictKext);
257 for (uint32_t i = 0; i < cLoadedKexts; i++)
258 {
259 PRTKRNLMODINFOINT pThis = (PRTKRNLMODINFOINT)RTMemAllocZ(sizeof(RTKRNLMODINFOINT));
260 if (RT_LIKELY(pThis))
261 {
262 pThis->cRefs = 1;
263 pThis->hDictKext = pahDictKext[i];
264 CFRetain(pThis->hDictKext);
265 pahKrnlModInfo[i] = pThis;
266 }
267 else
268 {
269 rc = VERR_NO_MEMORY;
270 /* Rollback. */
271 while (i-- > 0)
272 {
273 CFRelease(pahKrnlModInfo[i]->hDictKext);
274 RTMemFree(pahKrnlModInfo[i]);
275 }
276 }
277 }
278
279 if ( RT_SUCCESS(rc)
280 && pcEntries)
281 *pcEntries = cLoadedKexts;
282
283 RTMemTmpFree(pahDictKext);
284 }
285 else
286 rc = VERR_NO_MEMORY;
287 }
288 else
289 {
290 rc = VERR_BUFFER_OVERFLOW;
291
292 if (pcEntries)
293 *pcEntries = cLoadedKexts;
294 }
295
296 CFRelease(hLoadedKexts);
297 }
298 else
299 rc = VERR_NOT_SUPPORTED;
300 }
301 else
302 rc = VERR_NOT_SUPPORTED;
303
304 return rc;
305}
306
307
308RTDECL(uint32_t) RTKrnlModInfoRetain(RTKRNLMODINFO hKrnlModInfo)
309{
310 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
311 AssertPtrReturn(pThis, UINT32_MAX);
312
313 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
314 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
315 return cRefs;
316}
317
318
319RTDECL(uint32_t) RTKrnlModInfoRelease(RTKRNLMODINFO hKrnlModInfo)
320{
321 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
322 if (!pThis)
323 return 0;
324 AssertPtrReturn(pThis, UINT32_MAX);
325
326 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
327 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
328 if (cRefs == 0)
329 rtKrnlModInfoDestroy(pThis);
330 return cRefs;
331}
332
333
334RTDECL(uint32_t) RTKrnlModInfoGetRefCnt(RTKRNLMODINFO hKrnlModInfo)
335{
336 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
337 AssertPtrReturn(pThis, 0);
338
339 uint32_t cRefCnt = 0;
340 CFNumberRef hRetainCnt = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
341 kOSBundleRetainCountKey);
342 if (hRetainCnt)
343 CFNumberGetValue(hRetainCnt, kCFNumberSInt32Type, &cRefCnt);
344
345 return cRefCnt;
346}
347
348
349RTDECL(const char *) RTKrnlModInfoGetName(RTKRNLMODINFO hKrnlModInfo)
350{
351 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
352 AssertPtrReturn(pThis, NULL);
353
354 const char *pszName = NULL;
355 CFStringRef hBundleId = (CFStringRef)CFDictionaryGetValue(pThis->hDictKext,
356 kCFBundleIdentifierKey);
357 if (hBundleId)
358 pszName = CFStringGetCStringPtr(hBundleId, kCFStringEncodingUTF8);
359
360 return pszName;
361}
362
363
364RTDECL(const char *) RTKrnlModInfoGetFilePath(RTKRNLMODINFO hKrnlModInfo)
365{
366 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
367 AssertPtrReturn(pThis, NULL);
368
369 return NULL;
370}
371
372
373RTDECL(size_t) RTKrnlModInfoGetSize(RTKRNLMODINFO hKrnlModInfo)
374{
375 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
376 AssertPtrReturn(pThis, 0);
377
378 size_t cbKrnlMod = 0;
379 CFNumberRef hKrnlModSize = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
380 kOSBundleLoadSizeKey);
381 if (hKrnlModSize)
382 {
383 uint32_t cbTmp = 0;
384 CFNumberGetValue(hKrnlModSize, kCFNumberSInt32Type, &cbTmp);
385 cbKrnlMod = cbTmp;
386 }
387
388 return cbKrnlMod;
389}
390
391
392RTDECL(RTR0UINTPTR) RTKrnlModInfoGetLoadAddr(RTKRNLMODINFO hKrnlModInfo)
393{
394 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
395 AssertPtrReturn(pThis, 0);
396
397 RTR0UINTPTR uKrnlModLoadAddr = 0;
398 CFNumberRef hKrnlModLoadAddr = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
399 kOSBundleLoadAddressKey);
400 if (hKrnlModLoadAddr)
401 {
402 uint64_t uAddrTmp = 0;
403 CFNumberGetValue(hKrnlModLoadAddr, kCFNumberSInt64Type, &uAddrTmp);
404 uKrnlModLoadAddr = uAddrTmp;
405 }
406
407 return uKrnlModLoadAddr;
408}
409
410
411RTDECL(int) RTKrnlModInfoQueryRefModInfo(RTKRNLMODINFO hKrnlModInfo, uint32_t idx,
412 PRTKRNLMODINFO phKrnlModInfoRef)
413{
414 RT_NOREF3(hKrnlModInfo, idx, phKrnlModInfoRef);
415 return VERR_NOT_IMPLEMENTED;
416}
417
418
419RTDECL(int) RTKrnlModLoadByName(const char *pszName)
420{
421 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
422
423 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
424 if (!g_pfnKextManagerLoadKextWithIdentifier) return VERR_NOT_SUPPORTED;
425
426 int rc = VINF_SUCCESS;
427 CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
428 if (hKextName)
429 {
430 OSReturn rcOsx = g_pfnKextManagerLoadKextWithIdentifier(hKextName, NULL /*dependencyKextAndFolderURLs*/);
431 if (rcOsx != kOSReturnSuccess)
432 rc = VERR_NOT_SUPPORTED; /** @todo Convert OSReturn values. */
433 CFRelease(hKextName);
434 }
435 else
436 rc = VERR_NO_MEMORY;
437
438 return rc;
439}
440
441
442RTDECL(int) RTKrnlModLoadByPath(const char *pszPath)
443{
444 AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
445
446 return VERR_NOT_SUPPORTED;
447}
448
449
450RTDECL(int) RTKrnlModUnloadByName(const char *pszName)
451{
452 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
453
454 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
455 if (!g_pfnKextManagerUnloadKextWithIdentifier) return VERR_NOT_SUPPORTED;
456
457 int rc = VINF_SUCCESS;
458 CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
459 if (hKextName)
460 {
461 OSReturn rcOsx = g_pfnKextManagerUnloadKextWithIdentifier(hKextName);
462 if (rcOsx != kOSReturnSuccess)
463 rc = VERR_NOT_SUPPORTED; /** @todo Convert OSReturn values. */
464 CFRelease(hKextName);
465 }
466 else
467 rc = VERR_NO_MEMORY;
468
469 return rc;
470}
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