VirtualBox

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

Last change on this file since 99196 was 98103, checked in by vboxsync, 2 years 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.7 KB
Line 
1/* $Id: krnlmod-darwin.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Kernel module, Darwin.
4 */
5
6/*
7 * Copyright (C) 2017-2023 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 * @returns nothing.
170 * @param pThis The record to destroy.
171 */
172static void rtKrnlModInfoDestroy(PRTKRNLMODINFOINT pThis)
173{
174 CFRelease(pThis->hDictKext);
175 RTMemFree(pThis);
176}
177
178
179RTDECL(int) RTKrnlModQueryLoaded(const char *pszName, bool *pfLoaded)
180{
181 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
182 AssertPtrReturn(pfLoaded, VERR_INVALID_POINTER);
183
184 CFDictionaryRef hDictKext = rtKrnlModDarwinGetKextInfoByName(pszName);
185 *pfLoaded = hDictKext != NULL;
186 if (hDictKext)
187 CFRelease(hDictKext);
188
189 return VINF_SUCCESS;
190}
191
192
193RTDECL(int) RTKrnlModLoadedQueryInfo(const char *pszName, PRTKRNLMODINFO phKrnlModInfo)
194{
195 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
196 AssertPtrReturn(phKrnlModInfo, VERR_INVALID_POINTER);
197
198 int rc = VINF_SUCCESS;
199 CFDictionaryRef hDictKext = rtKrnlModDarwinGetKextInfoByName(pszName);
200 if (hDictKext)
201 {
202 PRTKRNLMODINFOINT pThis = (PRTKRNLMODINFOINT)RTMemAllocZ(sizeof(RTKRNLMODINFOINT));
203 if (pThis)
204 {
205 pThis->cRefs = 1;
206 pThis->hDictKext = hDictKext;
207
208 *phKrnlModInfo = pThis;
209 }
210 else
211 rc = VERR_NO_MEMORY;
212 }
213 else
214 rc = VERR_NOT_FOUND;
215
216 return rc;
217}
218
219
220RTDECL(uint32_t) RTKrnlModLoadedGetCount(void)
221{
222 uint32_t cLoadedKexts = 0;
223 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
224 if (g_pfnOSKextCopyLoadedKextInfo)
225 {
226 CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(NULL, NULL /* all info */);
227 if (hLoadedKexts)
228 {
229 cLoadedKexts = CFDictionaryGetCount(hLoadedKexts);
230 CFRelease(hLoadedKexts);
231 }
232 }
233
234 return cLoadedKexts;
235}
236
237
238RTDECL(int) RTKrnlModLoadedQueryInfoAll(PRTKRNLMODINFO pahKrnlModInfo, uint32_t cEntriesMax,
239 uint32_t *pcEntries)
240{
241 if (cEntriesMax > 0)
242 AssertPtrReturn(pahKrnlModInfo, VERR_INVALID_POINTER);
243
244 int rc = VINF_SUCCESS;
245 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
246 if (g_pfnOSKextCopyLoadedKextInfo)
247 {
248 CFDictionaryRef hLoadedKexts = g_pfnOSKextCopyLoadedKextInfo(NULL, NULL /* all info */);
249 if (hLoadedKexts)
250 {
251 uint32_t cLoadedKexts = CFDictionaryGetCount(hLoadedKexts);
252 if (cLoadedKexts <= cEntriesMax)
253 {
254 CFDictionaryRef *pahDictKext = (CFDictionaryRef *)RTMemTmpAllocZ(cLoadedKexts * sizeof(CFDictionaryRef));
255 if (pahDictKext)
256 {
257 CFDictionaryGetKeysAndValues(hLoadedKexts, NULL, (const void **)pahDictKext);
258 for (uint32_t i = 0; i < cLoadedKexts; i++)
259 {
260 PRTKRNLMODINFOINT pThis = (PRTKRNLMODINFOINT)RTMemAllocZ(sizeof(RTKRNLMODINFOINT));
261 if (RT_LIKELY(pThis))
262 {
263 pThis->cRefs = 1;
264 pThis->hDictKext = pahDictKext[i];
265 CFRetain(pThis->hDictKext);
266 pahKrnlModInfo[i] = pThis;
267 }
268 else
269 {
270 rc = VERR_NO_MEMORY;
271 /* Rollback. */
272 while (i-- > 0)
273 {
274 CFRelease(pahKrnlModInfo[i]->hDictKext);
275 RTMemFree(pahKrnlModInfo[i]);
276 }
277 }
278 }
279
280 if ( RT_SUCCESS(rc)
281 && pcEntries)
282 *pcEntries = cLoadedKexts;
283
284 RTMemTmpFree(pahDictKext);
285 }
286 else
287 rc = VERR_NO_MEMORY;
288 }
289 else
290 {
291 rc = VERR_BUFFER_OVERFLOW;
292
293 if (pcEntries)
294 *pcEntries = cLoadedKexts;
295 }
296
297 CFRelease(hLoadedKexts);
298 }
299 else
300 rc = VERR_NOT_SUPPORTED;
301 }
302 else
303 rc = VERR_NOT_SUPPORTED;
304
305 return rc;
306}
307
308
309RTDECL(uint32_t) RTKrnlModInfoRetain(RTKRNLMODINFO hKrnlModInfo)
310{
311 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
312 AssertPtrReturn(pThis, UINT32_MAX);
313
314 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
315 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
316 return cRefs;
317}
318
319
320RTDECL(uint32_t) RTKrnlModInfoRelease(RTKRNLMODINFO hKrnlModInfo)
321{
322 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
323 if (!pThis)
324 return 0;
325 AssertPtrReturn(pThis, UINT32_MAX);
326
327 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
328 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
329 if (cRefs == 0)
330 rtKrnlModInfoDestroy(pThis);
331 return cRefs;
332}
333
334
335RTDECL(uint32_t) RTKrnlModInfoGetRefCnt(RTKRNLMODINFO hKrnlModInfo)
336{
337 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
338 AssertPtrReturn(pThis, 0);
339
340 uint32_t cRefCnt = 0;
341 CFNumberRef hRetainCnt = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
342 kOSBundleRetainCountKey);
343 if (hRetainCnt)
344 CFNumberGetValue(hRetainCnt, kCFNumberSInt32Type, &cRefCnt);
345
346 return cRefCnt;
347}
348
349
350RTDECL(const char *) RTKrnlModInfoGetName(RTKRNLMODINFO hKrnlModInfo)
351{
352 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
353 AssertPtrReturn(pThis, NULL);
354
355 const char *pszName = NULL;
356 CFStringRef hBundleId = (CFStringRef)CFDictionaryGetValue(pThis->hDictKext,
357 kCFBundleIdentifierKey);
358 if (hBundleId)
359 pszName = CFStringGetCStringPtr(hBundleId, kCFStringEncodingUTF8);
360
361 return pszName;
362}
363
364
365RTDECL(const char *) RTKrnlModInfoGetFilePath(RTKRNLMODINFO hKrnlModInfo)
366{
367 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
368 AssertPtrReturn(pThis, NULL);
369
370 return NULL;
371}
372
373
374RTDECL(size_t) RTKrnlModInfoGetSize(RTKRNLMODINFO hKrnlModInfo)
375{
376 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
377 AssertPtrReturn(pThis, 0);
378
379 size_t cbKrnlMod = 0;
380 CFNumberRef hKrnlModSize = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
381 kOSBundleLoadSizeKey);
382 if (hKrnlModSize)
383 {
384 uint32_t cbTmp = 0;
385 CFNumberGetValue(hKrnlModSize, kCFNumberSInt32Type, &cbTmp);
386 cbKrnlMod = cbTmp;
387 }
388
389 return cbKrnlMod;
390}
391
392
393RTDECL(RTR0UINTPTR) RTKrnlModInfoGetLoadAddr(RTKRNLMODINFO hKrnlModInfo)
394{
395 PRTKRNLMODINFOINT pThis = hKrnlModInfo;
396 AssertPtrReturn(pThis, 0);
397
398 RTR0UINTPTR uKrnlModLoadAddr = 0;
399 CFNumberRef hKrnlModLoadAddr = (CFNumberRef)CFDictionaryGetValue(pThis->hDictKext,
400 kOSBundleLoadAddressKey);
401 if (hKrnlModLoadAddr)
402 {
403 uint64_t uAddrTmp = 0;
404 CFNumberGetValue(hKrnlModLoadAddr, kCFNumberSInt64Type, &uAddrTmp);
405 uKrnlModLoadAddr = uAddrTmp;
406 }
407
408 return uKrnlModLoadAddr;
409}
410
411
412RTDECL(int) RTKrnlModInfoQueryRefModInfo(RTKRNLMODINFO hKrnlModInfo, uint32_t idx,
413 PRTKRNLMODINFO phKrnlModInfoRef)
414{
415 RT_NOREF3(hKrnlModInfo, idx, phKrnlModInfoRef);
416 return VERR_NOT_IMPLEMENTED;
417}
418
419
420RTDECL(int) RTKrnlModLoadByName(const char *pszName)
421{
422 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
423
424 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
425 if (!g_pfnKextManagerLoadKextWithIdentifier) return VERR_NOT_SUPPORTED;
426
427 int rc = VINF_SUCCESS;
428 CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
429 if (hKextName)
430 {
431 OSReturn rcOsx = g_pfnKextManagerLoadKextWithIdentifier(hKextName, NULL /*dependencyKextAndFolderURLs*/);
432 if (rcOsx != kOSReturnSuccess)
433 rc = VERR_NOT_SUPPORTED; /** @todo Convert OSReturn values. */
434 CFRelease(hKextName);
435 }
436 else
437 rc = VERR_NO_MEMORY;
438
439 return rc;
440}
441
442
443RTDECL(int) RTKrnlModLoadByPath(const char *pszPath)
444{
445 AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
446
447 return VERR_NOT_SUPPORTED;
448}
449
450
451RTDECL(int) RTKrnlModUnloadByName(const char *pszName)
452{
453 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
454
455 RTOnce(&g_GetIoKitApisOnce, rtKrnlModDarwinResolveIoKitApis, NULL);
456 if (!g_pfnKextManagerUnloadKextWithIdentifier) return VERR_NOT_SUPPORTED;
457
458 int rc = VINF_SUCCESS;
459 CFStringRef hKextName = CFStringCreateWithCString(kCFAllocatorDefault, pszName, kCFStringEncodingUTF8);
460 if (hKextName)
461 {
462 OSReturn rcOsx = g_pfnKextManagerUnloadKextWithIdentifier(hKextName);
463 if (rcOsx != kOSReturnSuccess)
464 rc = VERR_NOT_SUPPORTED; /** @todo Convert OSReturn values. */
465 CFRelease(hKextName);
466 }
467 else
468 rc = VERR_NO_MEMORY;
469
470 return rc;
471}
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