VirtualBox

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

Last change on this file since 86672 was 86300, checked in by vboxsync, 4 years ago

Runtime: Add API to load kernel modules by name and add simple implementation for macOS, bugref:9836

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