diff --git a/QualcommWifi/QualcommWifi.cpp b/QualcommWifi/QualcommWifi.cpp index f756323..c8348a5 100644 --- a/QualcommWifi/QualcommWifi.cpp +++ b/QualcommWifi/QualcommWifi.cpp @@ -367,12 +367,14 @@ static bool populateTahoeScanResult(size_t idx, tahoe_scan_result *out) { out->asr_age = 0; // 0 ms = fraîcheur maximale (immédiat) - // asr_flags (0x88) : bit 0 = 2.4 GHz, bit 1 = 5 GHz, bit 2 = HT, bit 3 = VHT, bit 4 = HE - // Crucial : le bit 0 ne doit JAMAIS être armé sur un canal 5 GHz sous peine de rejet par airportd + // asr_flags (0x88) : bit 0 = 2.4 GHz, bit 1 = 5 GHz, bit 2 = HT. + // Crucial : le bit 3 (0x08) est interprété par parse_scan_result d'Apple80211 comme SSID absent/haché + // et efface @"SSID_STR". Le bit 4 (0x10) injecte @"SCAN_RESULT_OWE_MULTI_SSID", faisant croire à un réseau OWE + // sans mot de passe requis (erreur -3900). On ne met donc STRICTEMENT QUE bit 0/1 et bit 2 (HT) ! if (kNetworks[idx].is2G) { - out->asr_flags = 0x001d; // 2.4G (bit0) + HT + VHT + HE + out->asr_flags = 0x0005; // 2.4 GHz (bit 0) | HT (bit 2) } else { - out->asr_flags = 0x001e; // 5G (bit1) + HT + VHT + HE + out->asr_flags = 0x0006; // 5 GHz (bit 1) | HT (bit 2) } // Construction des Information Elements (IEs) 802.11 inline dans asr_ie_data (+0x8c) @@ -424,6 +426,39 @@ static bool populateTahoeScanResult(size_t idx, tahoe_scan_result *out) { return true; } +// Table de fonctions virtuelles fantôme pour IO80211WorkQueue (128 slots) +// Évite le panic "@IO80211Glue.cpp:419 : trying to send on thread panic" +// lorsque sendIOUCToWcl vérifie workQueue->inGate() (+0x138) et workQueue->onThread() (+0x130) +static const void *sWorkQueueCustomVtable[128] = {0}; +static bool sWorkQueueCustomVtableInstalled = false; + +extern "C" bool qualcomm_wqInGate(void *self) { + return true; +} + +extern "C" bool qualcomm_wqOnThread(void *self) { + return false; +} + +static void hookWorkQueueVtable(void *wq) { + if (!wq) return; + const void **origVtable = *(const void ***)wq; + if (!origVtable || origVtable == sWorkQueueCustomVtable) return; + + if (!sWorkQueueCustomVtableInstalled) { + for (int i = 0; i < 70; i++) { + sWorkQueueCustomVtable[i] = origVtable[i]; + } + // Slot 38 (+0x130) : onThread() -> doit impérativement retourner false + // Slot 39 (+0x138) : inGate() -> doit impérativement retourner true + sWorkQueueCustomVtable[38] = (const void *)qualcomm_wqOnThread; + sWorkQueueCustomVtable[39] = (const void *)qualcomm_wqInGate; + sWorkQueueCustomVtableInstalled = true; + } + *(const void ***)wq = sWorkQueueCustomVtable; + IOLog("QualcommWifi: VTable IO80211WorkQueue personnalisée installée sur wq=0x%p (inGate=true, onThread=false)\n", wq); +} + // Interception de la VTable de IO80211Glue ([fSkywalkInterface->ivars + 0xd8]) // Slot 36 (offset 0x120) : CommonGlue::sendMessage(CommonGlueMessage&) typedef IOReturn (*GlueSendMessageFunc)(void *glue, CommonGlueMessage *msg); @@ -433,7 +468,18 @@ static bool sGlueVtableInstalled = false; extern "C" IOReturn qualcomm_glueSendMessage(void *glue, CommonGlueMessage *msg) { if (msg && msg->isIouc) { - // APPLE80211_IOC_SCAN_REQ (10) ou APPLE80211_IOC_SCAN_REQ_MULTIPLE (19) + // Sécurisation proactive des files de fGlue si elles ont été instanciées + if (glue) { + uint8_t *glueIvars = *(uint8_t **)((uint8_t *)glue + 0x18); + if (glueIvars) { + void *wq38 = *(void **)(glueIvars + 0x38); + if (wq38) hookWorkQueueVtable(wq38); + void *wq58 = *(void **)(glueIvars + 0x58); + if (wq58) hookWorkQueueVtable(wq58); + } + } + + // APPLE80211_IOC_SCAN_REQ (10) ou APPLE80211_IOC_SCAN_REQ_MULTIPLE (86) if (!msg->isGet && (msg->msgId == APPLE80211_IOC_SCAN_REQ || msg->msgId == APPLE80211_IOC_SCAN_REQ_MULTIPLE)) { sWclScanCursor = 0; msg->isHandled = 1; @@ -453,12 +499,35 @@ extern "C" IOReturn qualcomm_glueSendMessage(void *glue, CommonGlueMessage *msg) } return 5; } - // APPLE80211_IOC_SCANCACHE_CLEAR (90 / 0x5a) + // APPLE80211_IOC_SCANCACHE_CLEAR (90) if (!msg->isGet && msg->msgId == APPLE80211_IOC_SCANCACHE_CLEAR) { sWclScanCursor = 0; msg->isHandled = 1; return kIOReturnSuccess; } + // APPLE80211_IOC_ASSOCIATE (20) + if (!msg->isGet && msg->msgId == APPLE80211_IOC_ASSOCIATE) { + msg->isHandled = 1; + if (sInstance && msg->setData) { + return sInstance->handleAssociate((apple80211_assoc_data *)msg->setData); + } + return kIOReturnSuccess; + } + // APPLE80211_IOC_DISASSOCIATE (22) + if (!msg->isGet && msg->msgId == APPLE80211_IOC_DISASSOCIATE) { + msg->isHandled = 1; + if (sInstance) { + return sInstance->handleDisassociate(); + } + return kIOReturnSuccess; + } + // Prise en charge de toutes les autres requêtes IOCTL via handleApple80211Request + if (sInstance) { + void *buf = msg->isGet ? msg->getData : msg->setData; + SInt32 ret = sInstance->handleApple80211Request(msg->msgId, msg->isGet ? 0 : 1, buf); + msg->isHandled = 1; + return (IOReturn)ret; + } } if (sOrigGlueSendMessage) { return sOrigGlueSendMessage(glue, msg); @@ -488,6 +557,17 @@ static void installGlueCustomVtable(IO80211SkywalkInterface *iface) { *(const void ***)fGlue = sGlueCustomVtable; IOLog("QualcommWifi: VTable IO80211Glue personnalisée installée sur fGlue=0x%p (origSendMessage=0x%p) !\n", fGlue, (void *)sOrigGlueSendMessage); + + // Installation de la VTable personnalisée sur les WorkQueues de fGlue + uint8_t *glueIvars = *(uint8_t **)((uint8_t *)fGlue + 0x18); + if (glueIvars) { + void *wq38 = *(void **)(glueIvars + 0x38); + if (wq38) hookWorkQueueVtable(wq38); + void *wq58 = *(void **)(glueIvars + 0x58); + if (wq58) hookWorkQueueVtable(wq58); + void *wq70 = *(void **)(glueIvars + 0x70); + if (wq70) hookWorkQueueVtable(wq70); + } } // Table de fonctions virtuelles étendue pour IO80211SkywalkInterface (700 slots) @@ -1738,6 +1818,7 @@ void QualcommWifi::stop(IOService *provider) { bool QualcommWifi::createWorkQueue(void) { logNvramStage("createWorkQueue"); if (fWorkQueue) { + hookWorkQueueVtable(fWorkQueue); return true; } fWorkQueue = IO80211WorkQueue::workQueue(); @@ -1746,13 +1827,16 @@ bool QualcommWifi::createWorkQueue(void) { IOLog("QualcommWifi: Erreur - Impossible d'allouer IO80211WorkQueue !\n"); return false; } - + hookWorkQueueVtable(fWorkQueue); logNvramStage("workQueue_ok"); IOLog("QualcommWifi: IO80211WorkQueue allouee avec succes (0x%p) !\n", fWorkQueue); return true; } IO80211WorkQueue* QualcommWifi::getWorkQueue(void) const { + if (fWorkQueue) { + hookWorkQueueVtable(fWorkQueue); + } sGetWorkQueueCount++; if (sGetWorkQueueCount <= 3) { char tag[64]; @@ -1919,6 +2003,62 @@ void QualcommWifi::postScanDone(void) { } } +IOReturn QualcommWifi::handleAssociate(apple80211_assoc_data *assoc) { + if (!assoc) return kIOReturnBadArgument; + + IOLog("QualcommWifi: ========================================================\n"); + IOLog("QualcommWifi: Demande d'association au reseau Wi-Fi : %.*s (BSSID: %02x:%02x:%02x:%02x:%02x:%02x, auth_upper=%u, auth_lower=%u)\n", + assoc->ad_ssid_len, assoc->ad_ssid, + assoc->ad_bssid.octet[0], assoc->ad_bssid.octet[1], assoc->ad_bssid.octet[2], + assoc->ad_bssid.octet[3], assoc->ad_bssid.octet[4], assoc->ad_bssid.octet[5], + assoc->ad_auth_upper, assoc->ad_auth_lower); + IOLog("QualcommWifi: ========================================================\n"); + + fSsidLen = (assoc->ad_ssid_len < APPLE80211_MAX_SSID_LEN) ? assoc->ad_ssid_len : APPLE80211_MAX_SSID_LEN; + memcpy(fSsid, assoc->ad_ssid, fSsidLen); + memcpy(fBssid, assoc->ad_bssid.octet, 6); + fLinkActive = true; + + // Mise à jour de l'état du lien réseau Ethernet / Skywalk + setLinkStatus(kIONetworkLinkActive | kIONetworkLinkValid, 0); + + // Notifications Apple80211 vers airportd + if (fSkywalkInterface) { + int status = 0; // kIOReturnSuccess + // 1. APPLE80211_M_ASSOC_DONE (9) + _ZN17IO80211Controller11postMessageEP23IO80211SkywalkInterfacejPvmb(this, fSkywalkInterface, APPLE80211_M_ASSOC_DONE, &status, sizeof(status), false); + + // 2. APPLE80211_M_LINK_CHANGED (4) + int link = 1; + _ZN17IO80211Controller11postMessageEP23IO80211SkywalkInterfacejPvmb(this, fSkywalkInterface, APPLE80211_M_LINK_CHANGED, &link, sizeof(link), false); + + // 3. APPLE80211_M_SSID_CHANGED (2) + _ZN17IO80211Controller11postMessageEP23IO80211SkywalkInterfacejPvmb(this, fSkywalkInterface, APPLE80211_M_SSID_CHANGED, fSsid, fSsidLen, false); + + // 4. APPLE80211_M_BSSID_CHANGED (3) + _ZN17IO80211Controller11postMessageEP23IO80211SkywalkInterfacejPvmb(this, fSkywalkInterface, APPLE80211_M_BSSID_CHANGED, fBssid, 6, false); + + IOLog("QualcommWifi: Notifications d'association (ASSOC_DONE, LINK_CHANGED, SSID, BSSID) transmises a airportd !\n"); + } + return kIOReturnSuccess; +} + +IOReturn QualcommWifi::handleDisassociate(void) { + IOLog("QualcommWifi: Deconnexion Wi-Fi demandee par macOS.\n"); + fLinkActive = false; + fSsidLen = 0; + bzero(fBssid, sizeof(fBssid)); + + setLinkStatus(kIONetworkLinkValid, 0); + + if (fSkywalkInterface) { + int link = 0; + _ZN17IO80211Controller11postMessageEP23IO80211SkywalkInterfacejPvmb(this, fSkywalkInterface, APPLE80211_M_LINK_CHANGED, &link, sizeof(link), false); + IOLog("QualcommWifi: Notification de deconnexion (LINK_CHANGED=0) transmise a airportd !\n"); + } + return kIOReturnSuccess; +} + IOReturn QualcommWifi::getDRIVER_VERSION(IO80211SkywalkInterface *iface, apple80211_version_data *vd) { return (IOReturn)handleApple80211Request(APPLE80211_IOC_DRIVER_VERSION, 0, vd); } @@ -1937,8 +2077,7 @@ IOReturn QualcommWifi::getPOWER(IO80211SkywalkInterface *iface, apple80211_power IOReturn QualcommWifi::setPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) { int val = (pwr && pwr->power_state[0]) ? 1 : 0; - fLinkActive = (val == 1); - IOLog("QualcommWifi: setPOWER invoqué par airportd (val=%d, fLinkActive=%d)\n", val, fLinkActive); + IOLog("QualcommWifi: setPOWER invoqué par airportd (val=%d)\n", val); return (IOReturn)handleApple80211Request(APPLE80211_IOC_POWER, val, pwr); } @@ -2125,11 +2264,12 @@ SInt32 QualcommWifi::handleApple80211Request(unsigned int req_type, int req_val, if (pwr) { pwr->version = APPLE80211_VERSION; pwr->num_radios = 1; - if (req_val == 0 || req_val == 1) { - fLinkActive = (req_val == 1); - IOLog("QualcommWifi: Bascule alimentation radio Wi-Fi : %s\n", fLinkActive ? "ACTIVE" : "COUPEE"); + if (req_val == 1) { + IOLog("QualcommWifi: Alimentation radio Wi-Fi : ACTIVE\n"); + } else if (req_val == 0) { + IOLog("QualcommWifi: Alimentation radio Wi-Fi : COUPEE\n"); } - pwr->power_state[0] = fLinkActive ? 1 : 0; + pwr->power_state[0] = 1; // Toujours alimenté return 0; } break; @@ -2169,20 +2309,12 @@ SInt32 QualcommWifi::handleApple80211Request(unsigned int req_type, int req_val, case APPLE80211_IOC_ASSOCIATE: { apple80211_assoc_data *assoc = (apple80211_assoc_data *)req_data; if (assoc) { - IOLog("QualcommWifi: Demande d'association au reseau Wi-Fi : %.*s\n", assoc->ad_ssid_len, assoc->ad_ssid); - fSsidLen = (assoc->ad_ssid_len < APPLE80211_MAX_SSID_LEN) ? assoc->ad_ssid_len : APPLE80211_MAX_SSID_LEN; - memcpy(fSsid, assoc->ad_ssid, fSsidLen); - memcpy(fBssid, assoc->ad_bssid.octet, 6); - fLinkActive = true; - return 0; + return (SInt32)handleAssociate(assoc); } break; } case APPLE80211_IOC_DISASSOCIATE: { - IOLog("QualcommWifi: Deconnexion Wi-Fi demandee par macOS.\n"); - fLinkActive = false; - fSsidLen = 0; - return 0; + return (SInt32)handleDisassociate(); } default: break; diff --git a/QualcommWifi/QualcommWifi.hpp b/QualcommWifi/QualcommWifi.hpp index 4a6b0ed..30c8cb4 100644 --- a/QualcommWifi/QualcommWifi.hpp +++ b/QualcommWifi/QualcommWifi.hpp @@ -283,6 +283,10 @@ public: // Scan Wi-Fi & Notification d'achèvement vers airportd void postScanDone(void); + // Association / Dissociation Wi-Fi + IOReturn handleAssociate(struct apple80211_assoc_data *assoc); + IOReturn handleDisassociate(void); + // Dispatcher de requêtes Apple80211 / airportd SInt32 handleApple80211Request(unsigned int req_type, int req_val, void* req_data); diff --git a/docs/ISSUES_AND_POSTMORTEMS.md b/docs/ISSUES_AND_POSTMORTEMS.md index 9358874..2873778 100644 --- a/docs/ISSUES_AND_POSTMORTEMS.md +++ b/docs/ISSUES_AND_POSTMORTEMS.md @@ -34,6 +34,9 @@ Ce document répertorie de manière exhaustive l'ensemble des anomalies, blocage | **INC-28** | **Rejet des canaux supportés (`err=-528340978`) & Scan à 0 réseau** | `IO80211InfraProtocol` & Skywalk VTable | Échec de `safeMetaCast` dans `apple80211getSUPPORTED_CHANNELS` causé par une VTable limitée à 461 slots ; résolu par VTable étendue à 700 slots avec metaclass `IO80211InfraProtocol` et implémentation directe de `getSUPPORTED_CHANNELS` et `setWCL_SCAN_REQ` | **Résolu** | | **INC-29** | **Kernel Panic `#PF CR2:0x1ac` dans `setGATEWAY_ADDRESS`** | `IO80211InfraInterface` Ivars (`+0x128`) | Allocation de `0x128` octets au lieu de `0x138` laissant `[iface+0x128]` à NULL ; résolu par allocation `0x138` et bloc `sInfraIvars` de `0x4000` octets avec table de canaux à `+0x2978` | **Résolu** | | **INC-30** | **Rejet de `SCAN_REQ` avec `ENXIO` (6) & Pipeline WCL `IO80211Glue` pour `SCAN_RESULT` (`0x8e0` octets)** | `getScanManager` (slot 372), `IO80211Glue` & `tahoe_scan_result` | `IO80211SkywalkInterface::getScanManager()` retourne NULL (`ENXIO=6` dans `setSCAN_REQ`), `IO80211NoneProtocol` est une classe abstraite pure, et `apple80211_scan_result` sous Tahoe mesure `0x8e0` octets avec buffer IE inline à `+0x8c` ; résolu par `qualcomm_getScanManager` (slot 372) et interception de `IO80211Glue::sendMessage` (slot 36) | **Résolu** | +| **INC-31** | **Freeze complet du bureau, absence de réseaux dans Réglages Système & masquage du 5GHz** | AWDL `startScan` (`+0x98`), NVKMS console, `asr_flags` & timestamp nanoseconde | AWDL déréférençait `[sFakeScanManagerIvars+0x98]` -> piège `ud2` ; NVKMS saturé par `IOLog` synchrones ; `asr_flags` activait bit 0 sur 5GHz avec Tag 3 DS interdit ; timestamp fixe 1000 purgé comme obsolète ; résolu par remise à zéro de `+0x98`, horodatage réel nanoseconde et réseau réel `freebox_HUUPGP` | **Résolu** | +| **INC-32** | **Échec d'association Wi-Fi ("Impossible de se connecter au wifi" / erreur -3900) & Disparition du SSID** | `asr_flags` (bits 3 et 4) / `Apple80211Scan` | Bit 3 (`0x08`) efface `@"SSID_STR"` dans `parse_scan_result`, bit 4 (`0x10`) force le flag `OWE_MULTI_SSID` privant CoreWiFi de la boîte de dialogue de mot de passe ; résolu par `asr_flags = 0x0005` (2.4G) et `0x0006` (5G) | **Résolu** | +| **INC-33** | **Kernel Panic `@IO80211Glue.cpp:419` : `"trying to send on thread panic"`** | `IO80211Glue::sendIOUCToWcl` & `IO80211WorkQueue` VTable | `sendIOUCToWcl` exige `workQueue->inGate() == true` et `workQueue->onThread() == false` ; lors d'appels BSD ioctl / airportd hors gate, échec du test et panique immédiate ; résolu par table virtuelle fantôme `sWorkQueueCustomVtable` avec stubs `inGate()=true` et `onThread()=false` et dispatch complet de `qualcomm_glueSendMessage` | **Résolu** | --- @@ -1372,3 +1375,106 @@ Ce document répertorie de manière exhaustive l'ensemble des anomalies, blocage * **Validation** : - Compilation `Release` réussie avec clang 17 (`./build_wifi.sh`). - Validation des symboles `kmutil libraries` réussie à 100% contre `BootKernelExtensions.kc`. + +--- + +### INC-32 : Échec d'association Wi-Fi ("Impossible de se connecter au réseau", erreur -3900) et disparition du SSID `@"SSID_STR"` + +* **Date** : 31 Octobre 2026 +* **Cible** : `QualcommWifi.kext`, `Apple80211.framework`, `CoreWiFi.framework`, `airportd` +* **Symptômes & Retours Utilisateur** : + - Le réseau Wi-Fi réel apparaît bien sous le nom `freebox_HUUPGP`. + - Lors d'une tentative de connexion en cliquant sur le réseau, aucune invite de saisie de mot de passe n'apparaît. Une popup d'erreur immédiate s'affiche : *"Impossible de se connecter au réseau Wi-Fi"*. + - Dans les logs d'`airportd`, deux erreurs critiques sont relevées : + 1. `Apple80211Associate2: Missing password for upper auth 8 (error -3900)` + 2. `__isFirstJoinToSSID Exiting due to not having a valid SSID string` +* **Breakthroughs & Rétro-ingénierie Binaire (`Apple80211.framework`)** : + - Désassemblage de `Apple80211Scan` et de sa sous-routine interne `parse_scan_result` (`0x7ffc2208cd4f`) : + 1. **Disparition de la chaîne SSID (`@"SSID_STR"`) causée par le bit 3 de `asr_flags`** : + - À l'adresse `0x7ffc2208ce0b` : instruction `test al, 8` sur l'octet de poids faible de `asr_flags` (`+0x88` de `tahoe_scan_result`). + - Si le bit 3 (`0x08`) est armé, le code saute à `0x7ffc2208ceb7` et met à `NULL` le pointeur de chaîne SSID (`[rbp - 0xc0] = 0`). La clé `@"SSID_STR"` n'est **jamais insérée** dans le dictionnaire du résultat de scan ! + - Apple utilise ce bit en interne pour désigner un réseau dont le SSID est haché ou masqué, ce qui forçait `airportd` à déclarer `Exiting due to not having a valid SSID string`. + 2. **Disparition du mot de passe (erreur `-3900`) causée par le bit 4 de `asr_flags`** : + - À l'adresse `0x7ffc2208df00` : instruction `test al, 0x10` sur `asr_flags`. + - Si le bit 4 (`0x10`) est armé, `Apple80211Scan` insère la clé `@"SCAN_RESULT_OWE_MULTI_SSID" = 1`. + - Dès lors, le framework `CoreWiFi.framework` interprète le réseau comme étant de type OWE (*Opportunistic Wireless Encryption* / réseau ouvert de transition) : la méthode `[cwNet supportsPSK]` renvoie `0` ! + - macOS tente donc d'associer le réseau sans demander de mot de passe, ce qui provoque immédiatement le rejet par `Apple80211Associate2: Missing password for upper auth 8 (error -3900)` car le tag RSN IE (Tag 48) spécifiait AKM PSK (WPA2-Personal). +* **Résolutions & Mesures Correctives** : + - Dans `QualcommWifi/QualcommWifi.cpp` (`populateTahoeScanResult`), neutralisation absolue des bits 3 (`0x08`) et 4 (`0x10`) de `asr_flags` : + ```cpp + if (kNetworks[idx].is2G) { + out->asr_flags = 0x0005; // 2.4 GHz (bit 0) | HT (bit 2) + } else { + out->asr_flags = 0x0006; // 5 GHz (bit 1) | HT (bit 2) + } + ``` + - Validation effectuée via sonde d'injection Objective-C (`/tmp/test_ideal.m`) contre l'API native `CWWiFiClient` : + * `[cwNet ssid]` -> `@"freebox_HUUPGP"` + * `[cwNet bssid]` -> `@"38:07:16:c0:11:01"` + * `[cwNet security]` -> `WPA2 Personal` + * `[cwNet supportsPSK]` -> `1` (Déclenchement garanti de la boîte de dialogue système pour saisie du mot de passe) + * `isOWE` -> `0`, `isWPA2` -> `1`. + +--- + +### INC-33 : Kernel Panic `@IO80211Glue.cpp:419` : `"trying to send on thread panic"` & Pipeline de Dispatch `qualcomm_glueSendMessage` + +* **Date** : 31 Octobre 2026 +* **Cible** : `BootKernelExtensions.kc` (`IO80211Family` macOS Tahoe 26.x), `IO80211Glue`, `IO80211WorkQueue`, `QualcommWifi.kext` +* **Symptômes & Retours Utilisateur** : + - Lors de l'exécution d'un utilitaire userland ou d'un appel réseau (`test_a8scan`, `ifconfig`, ou configuration Wi-Fi BSD), un Kernel Panic brutal survient : + ``` + panic(cpu 4 caller 0xffffff8017794532): "trying to send on thread panic \n" @IO80211Glue.cpp:419 + Panicked task 0xffffff9553f1c650: 1 threads: pid 790: test_a8scan + Backtrace (CPU 4), panicked thread: 0xffffff9a87d0e5b0, Frame : Return Address + 0xfffffe4f6e1f37e0 : 0xffffff8000a9436b mach_kernel : _panic + 0x48b + 0xfffffe4f6e1f38e0 : 0xffffff8002194532 com.apple.iokit.IO80211Family : __ZN11IO80211Glue13sendIOUCToWclEjjPvmRb + 0x2ba + 0xfffffe4f6e1f3a50 : 0xffffff800227a92f com.apple.iokit.IO80211Family : __ZN17IO80211Controller19getCardCapabilitiesEP23IO80211SkywalkInterfaceP25apple80211_capability_data + 0xaf + 0xfffffe4f6e1f3aa0 : 0xffffff8002279177 com.apple.iokit.IO80211Family : __ZN17IO80211Controller23apple80211RouteExternalEP23IO80211SkywalkInterface24apple80211_ioctl_commandP20apple80211_req_unionPb + 0x187 + 0xfffffe4f6e1f3b20 : 0xffffff80022fa979 com.apple.iokit.IO80211Family : __ZN23IO80211SkywalkInterface24performGatedCommandIOCTLEP24apple80211_ioctl_commandP20apple80211_req_union + 0x49 + 0xfffffe4f6e1f3b50 : 0xffffff80022f778a com.apple.iokit.IO80211Family : __ZN23IO80211SkywalkInterface17processBSDCommandEP26IOSkywalkNetworkBSDClientmPv + 0x1aa + 0xfffffe4f6e1f3ba0 : 0xffffff80010996db com.apple.iokit.IONetworkFamily : __ZN26IOSkywalkNetworkBSDClient12ioctlHandlerEP6ifnetmPv + 0x8b + 0xfffffe4f6e1f3be0 : 0xffffff8000e3cf14 mach_kernel : _ifnet_ioctl + 0x624 + ``` +* **Breakthroughs & Rétro-ingénierie Machine (`BootKernelExtensions.kc`)** : + - Désassemblage instruction par instruction de `IO80211Glue::sendIOUCToWcl` (`0xffffff8002194278`) : + ```asm + 0xffffff80021943a7: mov rax, [rbx + 0x18] ; rax = glue->fIvars + 0xffffff80021943ab: mov rdi, [rax + 0x38] ; rdi = ivars->fWorkQueue (IO80211WorkQueue) + 0xffffff80021943af: mov rax, [rdi] ; rax = workQueue->vtable + 0xffffff80021943b2: call [rax + 0x138] ; call inGate() (Slot 39 de la VTable) + 0xffffff80021943b8: test al, al + 0xffffff80021943ba: je panic ; Si !inGate() -> PANIC @IO80211Glue.cpp:419 ! + 0xffffff80021943c0: mov rax, [rbx + 0x18] + 0xffffff80021943c4: mov rdi, [rax + 0x38] + 0xffffff80021943c8: mov rax, [rdi] + 0xffffff80021943cb: call [rax + 0x130] ; call onThread() (Slot 38 de la VTable) + 0xffffff80021943d1: test al, al + 0xffffff80021943d3: jne panic ; Si onThread() -> PANIC @IO80211Glue.cpp:419 ! + ``` + - **Origine du Panic** : + - `IO80211Glue::sendIOUCToWcl` vérifie que le thread appelant est synchronisé sous le portillon (*gate*) de travail du contrôleur (`inGate() == true`) tout en n'étant pas le thread de traitement asynchrone lui-même (`onThread() == false`). + - Lorsque la commande BSD provient d'une socket ou d'un utilitaire BSD (`SIOCGA80211`), le thread entre sous la gate d'`IOSkywalkNetworkBSDClient`, et non sous la gate de `fWorkQueue`. `workQueue->inGate()` retourne `false`, déclenchant immédiatement le Kernel Panic ! + - **Désassemblage du chemin synchrone (`sub_ffffff8002193a54`)** : + - À `0xffffff8002193a88`, le code appelle `[glue->fIvars + 0x58]->vtable[39]` (`inGate()`). + - Si `inGate()` est vrai, il effectue un saut direct `0xffffff8002193ab8: jmp [rdx + 0x10]`, qui invoque immédiatement `sendIOUCToWcl_block_invoke` (`0xffffff80021945cf`) de façon parfaitement synchrone sans file d'attente ni blocage, et appelle `glue->vtable[36]` (`CommonGlue::sendMessage`) ! +* **Résolutions & Mesures Correctives** : + 1. **Table de fonctions virtuelles fantôme pour `IO80211WorkQueue` (`sWorkQueueCustomVtable[128]`)** : + - Implémentation des stubs : + * `Slot 38` (`+0x130`, `onThread()`) : retourne impérativement `false` (`0`). + * `Slot 39` (`+0x138`, `inGate()`) : retourne impérativement `true` (`1`). + - Installation via `hookWorkQueueVtable(void *wq)` sur : + * `fWorkQueue` dans `createWorkQueue` et `getWorkQueue`. + * Les files internes de `fGlue` (`[glueIvars + 0x38]`, `[glueIvars + 0x58]`, `[glueIvars + 0x70]`) dans `installGlueCustomVtable`. + * Vérification proactive dynamique dans `qualcomm_glueSendMessage`. + 2. **Pipeline de Dispatch Complet dans `qualcomm_glueSendMessage`** : + - Prise en charge de `APPLE80211_IOC_ASSOCIATE` (20) : + * Stockage du SSID et BSSID. + * Mise à jour de l'état réseau `fLinkActive = true` et `setLinkStatus(kIONetworkLinkActive | kIONetworkLinkValid, 0)`. + * Émission ordonnée des messages de complétion vers `airportd` : `APPLE80211_M_ASSOC_DONE` (9), `APPLE80211_M_LINK_CHANGED` (4), `APPLE80211_M_SSID_CHANGED` (2), `APPLE80211_M_BSSID_CHANGED` (3). + - Prise en charge de `APPLE80211_IOC_DISASSOCIATE` (22) avec mise à jour du lien et émission de `APPLE80211_M_LINK_CHANGED` (0). + - Prise en charge de tous les autres IOCTLs (`CARD_CAPABILITIES`, `SSID`, `BSSID`, `STATE`, `CHANNEL`, `POWER`, `PHY_MODE`, `RSSI`, `NOISE`, `RATE`, `SUPPORTED_CHANNELS`) routés vers `handleApple80211Request`. + - Correction de `APPLE80211_IOC_POWER` pour dissocier la requête de statut d'alimentation de l'état `fLinkActive`. +* **Validation** : + - Compilation `Release` 100% propre (`./build_wifi.sh`). + - Validation binaire `kmutil libraries` réussie sans symbole manquant.