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);
|
// Classe simulant un IO80211FaultReporter IOKit conforme (attendu par IO80211Controller et IO80211PeerManager)
|
||||||
static addEventSource_fn sOrigAddEventSource = nullptr;
|
// - Hérite directement de OSObject (35 slots de base : 0..34)
|
||||||
static void **sOrigWorkQueueVtable = nullptr;
|
// - Déclare les 3 méthodes virtuelles de IO80211FaultReporter :
|
||||||
static void *sWorkQueueVtable[128];
|
// slot 35 (offset 0x118) : reportFault(...)
|
||||||
static int sAddEventSourceCount = 0;
|
// slot 36 (offset 0x120) : registerCallbacks(...) -> appelé par IO80211PeerManager::initWithInterface (0xffffff8002247d3d)
|
||||||
|
// slot 37 (offset 0x128) : unregisterCallbacks(...) -> appelé par IO80211PeerManager::free (0xffffff80022490ac)
|
||||||
static IOReturn hooked_addEventSource(IOWorkLoop *self, IOEventSource *event) {
|
class FakeFaultReporter : public OSObject {
|
||||||
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 {
|
|
||||||
OSDeclareDefaultStructors(FakeFaultReporter)
|
OSDeclareDefaultStructors(FakeFaultReporter)
|
||||||
private:
|
private:
|
||||||
uint8_t _pad[0x90 - sizeof(IOService)];
|
uint8_t _pad[0x80];
|
||||||
public:
|
public:
|
||||||
virtual bool init() override {
|
virtual bool init() override {
|
||||||
if (!IOService::init()) return false;
|
if (!OSObject::init()) return false;
|
||||||
bzero(_pad, sizeof(_pad));
|
bzero(_pad, sizeof(_pad));
|
||||||
return true;
|
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() {
|
static FakeFaultReporter* create() {
|
||||||
FakeFaultReporter *inst = new FakeFaultReporter;
|
FakeFaultReporter *inst = new FakeFaultReporter;
|
||||||
if (inst && !inst->init()) {
|
if (inst && !inst->init()) {
|
||||||
@@ -95,8 +99,7 @@ public:
|
|||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
OSDefineMetaClassAndStructors(FakeFaultReporter, IOService)
|
OSDefineMetaClassAndStructors(FakeFaultReporter, OSObject)
|
||||||
static_assert(sizeof(FakeFaultReporter) == 0x90, "FakeFaultReporter size must match CCFaultReporter ABI (0x90)");
|
|
||||||
|
|
||||||
// Buffers statiques globaux BSS : garantis alloués et mappés dès le chargement du kext,
|
// 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.
|
// immunisés contre tout échec de heap dynamique durant le boot précoce.
|
||||||
@@ -254,7 +257,6 @@ bool QualcommWifi::init(OSDictionary *dictionary) {
|
|||||||
sGetFaultReporterCount = 0;
|
sGetFaultReporterCount = 0;
|
||||||
sInStep6 = false;
|
sInStep6 = false;
|
||||||
sStep6WqCount = 0;
|
sStep6WqCount = 0;
|
||||||
sAddEventSourceCount = 0;
|
|
||||||
|
|
||||||
logNvramStage("init_enter");
|
logNvramStage("init_enter");
|
||||||
if (!super::init(dictionary)) {
|
if (!super::init(dictionary)) {
|
||||||
@@ -305,12 +307,7 @@ void QualcommWifi::free(void) {
|
|||||||
OSSafeReleaseNULL(fFaultReporter);
|
OSSafeReleaseNULL(fFaultReporter);
|
||||||
OSSafeReleaseNULL(fLogger);
|
OSSafeReleaseNULL(fLogger);
|
||||||
OSSafeReleaseNULL(fWorkLoop);
|
OSSafeReleaseNULL(fWorkLoop);
|
||||||
if (fWorkQueue) {
|
OSSafeReleaseNULL(fWorkQueue);
|
||||||
if (sOrigWorkQueueVtable) {
|
|
||||||
*(void ***)fWorkQueue = sOrigWorkQueueVtable;
|
|
||||||
}
|
|
||||||
OSSafeReleaseNULL(fWorkQueue);
|
|
||||||
}
|
|
||||||
if (sNvramLock) {
|
if (sNvramLock) {
|
||||||
IORecursiveLock *lock = sNvramLock;
|
IORecursiveLock *lock = sNvramLock;
|
||||||
sNvramLock = nullptr;
|
sNvramLock = nullptr;
|
||||||
@@ -1065,13 +1062,7 @@ void QualcommWifi::stop(IOService *provider) {
|
|||||||
OSSafeReleaseNULL(fWorkLoop);
|
OSSafeReleaseNULL(fWorkLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fWorkQueue) {
|
OSSafeReleaseNULL(fWorkQueue);
|
||||||
if (sOrigWorkQueueVtable) {
|
|
||||||
*(void ***)fWorkQueue = sOrigWorkQueueVtable;
|
|
||||||
}
|
|
||||||
OSSafeReleaseNULL(fWorkQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
PMstop();
|
PMstop();
|
||||||
super::stop(provider);
|
super::stop(provider);
|
||||||
}
|
}
|
||||||
@@ -1088,18 +1079,6 @@ bool QualcommWifi::createWorkQueue(void) {
|
|||||||
return false;
|
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");
|
logNvramStage("workQueue_ok");
|
||||||
IOLog("QualcommWifi: IO80211WorkQueue allouee avec succes (0x%p) !\n", fWorkQueue);
|
IOLog("QualcommWifi: IO80211WorkQueue allouee avec succes (0x%p) !\n", fWorkQueue);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in new issue
Block a user