fix(wifi): conformer FakeFaultReporter à l'ABI IO80211FaultReporter (OSObject) et éliminer le #PF slot 0x120
### Breakthroughs & Rétro-ingénierie - Disséction binaire de IO80211PeerManager::initWithInterface (0xffffff8002247d3d dans BootKernelExtensions.kc). - Constat : IO80211PeerManager récupère le faultReporter depuis le contrôleur (+0x58), puis invoque vtable slot 36 (+0x120) : registerCallbacks(callbacks, 16, peerManager, "IO80211PeerManager"). - Cause racine du freeze : FakeFaultReporter dérivait de IOService (taille 0x90). Dans IOService, le slot 36 (+0x120) est copyProperty(const OSString*, ...), qui s'exécutait en tentant de déréférencer les variables locales de pile passées en argument au lieu d'un OSString*, déclenchant un #PF immédiat sur page zéro et un gel processeur matériel. - Conformité : IO80211FaultReporter dérive directement de OSObject (35 slots virtuels de base, slots 35..37 dédiés à reportFault, registerCallbacks, unregisterCallbacks). ### Modifications apportées - QualcommWifi/QualcommWifi.cpp : * Migration de FakeFaultReporter pour hériter de OSObject au lieu de IOService. * Déclaration des méthodes virtuelles reportFault (slot 35), registerCallbacks (slot 36) et unregisterCallbacks (slot 37). * Balisage télémétrique NVRAM cb_fault_reg et cb_fault_unreg. * Retrait des hooks expérimentaux addEventSource de fWorkQueue désormais obsolètes. ### Validation - Compilation réussie sous ./build_wifi.sh (Clang C++20, SDK MacOSX26.0). - kmutil libraries --bundle-path build/Release/QualcommWifi.kext validé à 100% contre BootKernelExtensions.kc.
This commit is contained in:
1 parent
05b3c5eec1
commit
a4e77c9a53
1 file changed
+36
-57
@@ -50,42 +50,46 @@ static inline void logNvramStage(const char *tag) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef IOReturn (*addEventSource_fn)(IOWorkLoop *self, IOEventSource *event);
|
||||
static addEventSource_fn sOrigAddEventSource = nullptr;
|
||||
static void **sOrigWorkQueueVtable = nullptr;
|
||||
static void *sWorkQueueVtable[128];
|
||||
static int sAddEventSourceCount = 0;
|
||||
|
||||
static IOReturn hooked_addEventSource(IOWorkLoop *self, IOEventSource *event) {
|
||||
sAddEventSourceCount++;
|
||||
char tag[64];
|
||||
snprintf(tag, sizeof(tag), "cb_addEvSrc_%d", sAddEventSourceCount);
|
||||
logNvramStage(tag);
|
||||
IOSleep(50);
|
||||
IOLog("QualcommWifi: >>> HOOK fWorkQueue->addEventSource(#%d, event=0x%p) [ENTER] <<<\n",
|
||||
sAddEventSourceCount, event);
|
||||
IOReturn res = sOrigAddEventSource(self, event);
|
||||
char tagExit[64];
|
||||
snprintf(tagExit, sizeof(tagExit), "cb_addEvSrc_%d_ok", sAddEventSourceCount);
|
||||
logNvramStage(tagExit);
|
||||
IOSleep(50);
|
||||
IOLog("QualcommWifi: >>> HOOK fWorkQueue->addEventSource(#%d) -> 0x%x [EXIT] <<<\n",
|
||||
sAddEventSourceCount, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Classe simulant un FaultReporter IOKit valide (attendu par IO80211Controller::findAndAttachToFaultReporter)
|
||||
// Conforme à l'ABI CCFaultReporter / IOService (267 slots de vtable, taille 0x90)
|
||||
class FakeFaultReporter : public IOService {
|
||||
// Classe simulant un IO80211FaultReporter IOKit conforme (attendu par IO80211Controller et IO80211PeerManager)
|
||||
// - Hérite directement de OSObject (35 slots de base : 0..34)
|
||||
// - Déclare les 3 méthodes virtuelles de IO80211FaultReporter :
|
||||
// slot 35 (offset 0x118) : reportFault(...)
|
||||
// slot 36 (offset 0x120) : registerCallbacks(...) -> appelé par IO80211PeerManager::initWithInterface (0xffffff8002247d3d)
|
||||
// slot 37 (offset 0x128) : unregisterCallbacks(...) -> appelé par IO80211PeerManager::free (0xffffff80022490ac)
|
||||
class FakeFaultReporter : public OSObject {
|
||||
OSDeclareDefaultStructors(FakeFaultReporter)
|
||||
private:
|
||||
uint8_t _pad[0x90 - sizeof(IOService)];
|
||||
uint8_t _pad[0x80];
|
||||
public:
|
||||
virtual bool init() override {
|
||||
if (!IOService::init()) return false;
|
||||
if (!OSObject::init()) return false;
|
||||
bzero(_pad, sizeof(_pad));
|
||||
return true;
|
||||
}
|
||||
|
||||
// slot 35 (offset 0x118): reportFault
|
||||
virtual IOReturn reportFault(uint32_t a, const char *b, uint32_t c, const char *d, void *e, int f, const char *g, ...) {
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
// slot 36 (offset 0x120): registerCallbacks
|
||||
// Invoqué par IO80211PeerManager::initWithInterface (0xffffff8002247d3d)
|
||||
virtual IOReturn registerCallbacks(void *callbacks, unsigned int count, OSObject *owner, const char *owner_name) {
|
||||
logNvramStage("cb_fault_reg");
|
||||
IOSleep(50);
|
||||
IOLog("QualcommWifi: >>> FakeFaultReporter::registerCallbacks(count=%u, owner=%s) [SUCCESS] <<<\n",
|
||||
count, owner_name ? owner_name : "null");
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
// slot 37 (offset 0x128): unregisterCallbacks
|
||||
// Invoqué par IO80211PeerManager::free (0xffffff80022490ac)
|
||||
virtual IOReturn unregisterCallbacks(OSObject *owner) {
|
||||
logNvramStage("cb_fault_unreg");
|
||||
IOLog("QualcommWifi: >>> FakeFaultReporter::unregisterCallbacks() [SUCCESS] <<<\n");
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
static FakeFaultReporter* create() {
|
||||
FakeFaultReporter *inst = new FakeFaultReporter;
|
||||
if (inst && !inst->init()) {
|
||||
@@ -95,8 +99,7 @@ public:
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
OSDefineMetaClassAndStructors(FakeFaultReporter, IOService)
|
||||
static_assert(sizeof(FakeFaultReporter) == 0x90, "FakeFaultReporter size must match CCFaultReporter ABI (0x90)");
|
||||
OSDefineMetaClassAndStructors(FakeFaultReporter, OSObject)
|
||||
|
||||
// Buffers statiques globaux BSS : garantis alloués et mappés dès le chargement du kext,
|
||||
// immunisés contre tout échec de heap dynamique durant le boot précoce.
|
||||
@@ -254,7 +257,6 @@ bool QualcommWifi::init(OSDictionary *dictionary) {
|
||||
sGetFaultReporterCount = 0;
|
||||
sInStep6 = false;
|
||||
sStep6WqCount = 0;
|
||||
sAddEventSourceCount = 0;
|
||||
|
||||
logNvramStage("init_enter");
|
||||
if (!super::init(dictionary)) {
|
||||
@@ -305,12 +307,7 @@ void QualcommWifi::free(void) {
|
||||
OSSafeReleaseNULL(fFaultReporter);
|
||||
OSSafeReleaseNULL(fLogger);
|
||||
OSSafeReleaseNULL(fWorkLoop);
|
||||
if (fWorkQueue) {
|
||||
if (sOrigWorkQueueVtable) {
|
||||
*(void ***)fWorkQueue = sOrigWorkQueueVtable;
|
||||
}
|
||||
OSSafeReleaseNULL(fWorkQueue);
|
||||
}
|
||||
OSSafeReleaseNULL(fWorkQueue);
|
||||
if (sNvramLock) {
|
||||
IORecursiveLock *lock = sNvramLock;
|
||||
sNvramLock = nullptr;
|
||||
@@ -1065,13 +1062,7 @@ void QualcommWifi::stop(IOService *provider) {
|
||||
OSSafeReleaseNULL(fWorkLoop);
|
||||
}
|
||||
|
||||
if (fWorkQueue) {
|
||||
if (sOrigWorkQueueVtable) {
|
||||
*(void ***)fWorkQueue = sOrigWorkQueueVtable;
|
||||
}
|
||||
OSSafeReleaseNULL(fWorkQueue);
|
||||
}
|
||||
|
||||
OSSafeReleaseNULL(fWorkQueue);
|
||||
PMstop();
|
||||
super::stop(provider);
|
||||
}
|
||||
@@ -1088,18 +1079,6 @@ bool QualcommWifi::createWorkQueue(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Interception chirurgicale de addEventSource sur fWorkQueue (slot 42 = offset 0x150)
|
||||
sOrigWorkQueueVtable = *(void ***)fWorkQueue;
|
||||
if (sOrigWorkQueueVtable && !sOrigAddEventSource) {
|
||||
memcpy(&sWorkQueueVtable[2], sOrigWorkQueueVtable, sizeof(void *) * 100);
|
||||
sWorkQueueVtable[0] = sOrigWorkQueueVtable[-2];
|
||||
sWorkQueueVtable[1] = sOrigWorkQueueVtable[-1];
|
||||
sOrigAddEventSource = (addEventSource_fn)sOrigWorkQueueVtable[42];
|
||||
sWorkQueueVtable[2 + 42] = (void *)&hooked_addEventSource;
|
||||
*(void ***)fWorkQueue = &sWorkQueueVtable[2];
|
||||
IOLog("QualcommWifi: Vtable de fWorkQueue interceptée avec succès (addEventSource=slot 42) !\n");
|
||||
}
|
||||
|
||||
logNvramStage("workQueue_ok");
|
||||
IOLog("QualcommWifi: IO80211WorkQueue allouee avec succes (0x%p) !\n", fWorkQueue);
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user