From 25e41914f92dad8f95aa078fe54cbae5acda7afc Mon Sep 17 00:00:00 2001 From: Erwan Date: Mon, 19 Oct 2026 19:09:45 +0200 Subject: [PATCH] fix(skywalk): injecter IFRTYPE_SUBFAMILY_WIFI (3) et medium 802.11Auto pour Apple80211GetIfListCopy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Breakthroughs & Rétro-ingénierie : - Dissection sous LLDB de _getIfListCopy (0x7ffc267b58fb dans Apple80211.framework) : 1. Filtre SIOCGIFTYPE (0xc020699f) : vérifie ifr.ifru_type.ift_type == 6 (IFT_ETHER) ET ifr.ifru_type.ift_subfamily == 3 (IFRTYPE_SUBFAMILY_WIFI / net/if_private.h). Si ift_subfamily != 3 (notre interface renvoyait 0 par défaut), l'interface est immédiatement et silencieusement rejetée sans figurer dans le CFArray de sortie. 2. Filtre SIOCGIFMEDIA (0xc02c6938) : vérifie (ifmr.ifm_current & 0xe0) == 0x80 (IFM_IEEE80211). Si non conforme (renvoyait 0x20 / IFM_ETHER), rejet direct. - Dissection dans BootKernelExtensions.kc de IOSkywalkEthernetInterface::initRegistrationInfo (0xffffff8002b108e2) et registerNetworkInterfaceWithLogicalLink (0xffffff8002b0a204) : Le noyau copie fidèlement fSkywalkRegInfo dans priv->regInfo. initBSDInterfaceParameters lit getInterfaceSubFamily() (slot 0x9a8) qui lit priv->regInfo + 0x0c pour initialiser eparams->subfamily et ifp->if_subfamily dans BSD. Modifications apportées : - QualcommWifi/QualcommWifi.cpp : * Dans substep 8.1 : configuration de fSkywalkRegInfo + 0x0c à 3 (IFRTYPE_SUBFAMILY_WIFI), fSkywalkRegInfo + 0x24 et +0x28 à 0x80 (kIOMediumIEEE80211Auto), et MTU à 1500. * Dans substeps 8.4 et 8.5 : configuration chirurgicale de priv->regInfo et struct ifmedia (status=0x3, current=0x80, active=0x80) à fSkywalkInterface + 0xc0. * Dans createMediumTables() : publication exclusive du médium kIOMediumIEEE80211Auto (1.2 Gbps) pour éliminer tout résidu Ethernet. - docs/ISSUES_AND_POSTMORTEMS.md : * Rédaction complète du Postmortem 26 avec analyse d'assemblage et justification technique. Validation : - Compilation Release x86_64 validée à 100% avec ./build_wifi.sh. - Validation des dépendances kmutil libraries réussie sans avertissement contre BootKernelExtensions.kc. - Kext déployé sur /Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext (MD5: 918e6727043a53bbe4825671f428ab5c). --- QualcommWifi/QualcommWifi.cpp | 65 +++++++++++++++++-------- docs/ISSUES_AND_POSTMORTEMS.md | 89 ++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 21 deletions(-) diff --git a/QualcommWifi/QualcommWifi.cpp b/QualcommWifi/QualcommWifi.cpp index 3ecef4b..dfde795 100644 --- a/QualcommWifi/QualcommWifi.cpp +++ b/QualcommWifi/QualcommWifi.cpp @@ -1090,11 +1090,24 @@ bool QualcommWifi::start(IOService *provider) { fSkywalkInterface, fSkywalkRegInfo, 1, sizeof(fSkywalkRegInfo) ); if (regInit) { - // Configuration de l'adresse MAC physique et MTU + // 1. Définir le sous-type réseau BSD en Wi-Fi (IFRTYPE_SUBFAMILY_WIFI = 3) + // Découverte chirurgicale / Postmortem 26 : + // Apple80211.framework (_getIfListCopy) appelle ioctl(SIOCGIFTYPE, 0xc020699f). + // Il exige ifr.ifru_type.ift_type == 6 (IFT_ETHER) et ifr.ifru_type.ift_subfamily == 3 (IFRTYPE_SUBFAMILY_WIFI). + // Sans cette valeur (0 par défaut sur Skywalk Ethernet), Apple80211 rejette silencieusement en1 ! + *(uint32_t*)(fSkywalkRegInfo + 0x0c) = 3; // IFRTYPE_SUBFAMILY_WIFI = 3 + + // 2. Définir le type de médium sur IEEE 802.11 Auto (0x80) + // Apple80211.framework vérifie également (ifmr.ifm_current & 0xe0) == 0x80 (IFM_IEEE80211). + *(uint32_t*)(fSkywalkRegInfo + 0x24) = 0x80; // active medium: kIOMediumIEEE80211Auto + *(uint32_t*)(fSkywalkRegInfo + 0x28) = 0x80; // current medium: kIOMediumIEEE80211Auto + + // 3. Configuration de l'adresse MAC physique et MTU memcpy(fSkywalkRegInfo + 0x108, fMacAddress.bytes, 6); *(uint32_t*)(fSkywalkRegInfo + 0x48) = 1500; + *(uint32_t*)(fSkywalkRegInfo + 0x4c) = 1500; logNvramStage("s8_1_reginfo_ok"); - IOLog("QualcommWifi: [s8_1] initRegistrationInfo réussi et MAC configurée !\n"); + IOLog("QualcommWifi: [s8_1] initRegistrationInfo configuré (subfamily=WIFI/3, medium=802.11Auto/0x80, MAC OK) !\n"); } else { logNvramStage("s8_1_reginfo_err"); IOLog("QualcommWifi: [s8_1] ERREUR initRegistrationInfo !\n"); @@ -1155,6 +1168,22 @@ bool QualcommWifi::start(IOService *provider) { IOLog("QualcommWifi: ========================================================\n"); IOLog("QualcommWifi: >>> [SUCCES MAJEUR] registerEthernetInterface A REUSSI ! <<<\n"); IOLog("QualcommWifi: ========================================================\n"); + + // Postmortem 26 : Configuration des structures internes de fSkywalkInterface + // fSkywalkInterface + 0xc0 pointe sur priv + uint8_t *priv = *(uint8_t **)((uint8_t *)fSkywalkInterface + 0xc0); + if (priv) { + uint8_t *regInfo = *(uint8_t **)priv; + if (regInfo) { + *(uint32_t *)(regInfo + 0x0c) = 3; // IFRTYPE_SUBFAMILY_WIFI = 3 + *(uint32_t *)(regInfo + 0x24) = 0x80; // active medium: kIOMediumIEEE80211Auto + *(uint32_t *)(regInfo + 0x28) = 0x80; // current medium: kIOMediumIEEE80211Auto + } + *(uint32_t *)(priv + 0x30) = 0x3; // ifm_status = IFM_AVALID | IFM_ACTIVE (1 | 2) + *(uint32_t *)(priv + 0x34) = 0x80; // ifm_current = kIOMediumIEEE80211Auto (0x80) + *(uint32_t *)(priv + 0x38) = 0x80; // ifm_active = kIOMediumIEEE80211Auto (0x80) + IOLog("QualcommWifi: [s8_4] struct ifmedia (status=0x3, current=0x80, active=0x80) et regInfo configurés !\n"); + } } else { logNvramStage("s8_4_reg_eth_err"); IOLog("QualcommWifi: [s8_4] registerEthernetInterface a échoué (0x%x) !\n", regRes); @@ -1171,6 +1200,14 @@ bool QualcommWifi::start(IOService *provider) { logNvramStage("s8_6_reg_svc_done"); IOSleep(100); IOLog("QualcommWifi: >>> [SUCCES TOTAL] Service Skywalk publié, création d'en1 imminente ! <<<\n"); + + // Ré-application post-enregistrement pour garantir la persistance de l'état média + uint8_t *priv = *(uint8_t **)((uint8_t *)fSkywalkInterface + 0xc0); + if (priv) { + *(uint32_t *)(priv + 0x30) = 0x3; // ifm_status = IFM_AVALID | IFM_ACTIVE + *(uint32_t *)(priv + 0x34) = 0x80; // ifm_current = kIOMediumIEEE80211Auto + *(uint32_t *)(priv + 0x38) = 0x80; // ifm_active = kIOMediumIEEE80211Auto + } } } @@ -1338,8 +1375,8 @@ IOReturn QualcommWifi::disable(IONetworkInterface *netif) { } bool QualcommWifi::createMediumTables(void) { - IOLog("QualcommWifi: Creation et publication du dictionnaire de mediums reseau...\n"); - OSDictionary *mediumDict = OSDictionary::withCapacity(2); + IOLog("QualcommWifi: Creation et publication du dictionnaire de mediums reseau IEEE 802.11...\n"); + OSDictionary *mediumDict = OSDictionary::withCapacity(1); if (!mediumDict) { IOLog("QualcommWifi: ERREUR allocation mediumDict !\n"); return false; @@ -1347,39 +1384,25 @@ bool QualcommWifi::createMediumTables(void) { IONetworkMedium *mediumWifi = IONetworkMedium::medium( kIOMediumIEEE80211Auto, - 1000000000ULL, // 1 Gbps + 1200000000ULL, // 1.2 Gbps (Wi-Fi 7 / 6E) 0, 0, "Auto" ); - IONetworkMedium *mediumEth = IONetworkMedium::medium( - kIOMediumEthernetAuto, - 1000000000ULL, - 0, - 1, - "EthernetAuto" - ); if (mediumWifi) { IONetworkMedium::addMedium(mediumDict, mediumWifi); mediumWifi->release(); } - if (mediumEth) { - IONetworkMedium::addMedium(mediumDict, mediumEth); - mediumEth->release(); - } bool published = publishMediumDictionary(mediumDict); if (published) { const IONetworkMedium *selected = IONetworkMedium::getMediumWithType(mediumDict, kIOMediumIEEE80211Auto); - if (!selected) { - selected = IONetworkMedium::getMediumWithType(mediumDict, kIOMediumEthernetAuto); - } if (selected) { setSelectedMedium(selected); setCurrentMedium(selected); - setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, selected, 1000000000ULL, nullptr); - IOLog("QualcommWifi: Medium selectionne et linkStatus(Active) configure avec succes !\n"); + setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, selected, 1200000000ULL, nullptr); + IOLog("QualcommWifi: Medium IEEE80211Auto selectionne et linkStatus(Active) configure avec succes !\n"); } } else { IOLog("QualcommWifi: ERREUR publishMediumDictionary !\n"); diff --git a/docs/ISSUES_AND_POSTMORTEMS.md b/docs/ISSUES_AND_POSTMORTEMS.md index 14aeac7..0b67f8e 100644 --- a/docs/ISSUES_AND_POSTMORTEMS.md +++ b/docs/ISSUES_AND_POSTMORTEMS.md @@ -1060,3 +1060,92 @@ Ce document répertorie de manière exhaustive l'ensemble des anomalies, blocage - Binaire déployé sur `/Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext` (MD5: `480ca02aff49c48afbe8b381be0c3c77`). + +--- + +### Postmortem 26 : Rétro-ingénierie Chirurgicale d'`Apple80211GetIfListCopy` : Résolution du Filtre `SIOCGIFTYPE` (`IFRTYPE_SUBFAMILY_WIFI = 3`) et `SIOCGIFMEDIA` (`IFM_IEEE80211 = 0x80`) + +* **Date** : 19 Octobre 2026 +* **Cible** : macOS Tahoe 26.x (Darwin 25.6.0 x86_64), AMD Ryzen 7 5800X3D, `QualcommWifi.kext` (WCN7850 `0x17cb:0x1107`) +* **Symptômes & Retours Utilisateur (/grill-me)** : + - Démarrage 100% stable sans freeze ni crash validé avec l'Étape 8 (`qcom_step=8 qcom_substep=5`). + - L'interface `en1` existe dans le système (`ifconfig en1`), et `SIOCGIFXMEDIA: Input/output error` a été éliminée à 100% (`media: autoselect (none)`). + - Cependant, l'icône Wi-Fi ne s'allume pas dans le menu macOS, et `Apple80211GetIfListCopy` renvoie l'erreur `-3903` (`0xfffff0c1`), empêchant `airportd` d'associer `en1`. +* **Breakthroughs & Rétro-ingénierie Binaire Exhaustive (`Apple80211.framework` & `BootKernelExtensions.kc`)** : + 1. **Dissection Chirurgicale de `_getIfListCopy` (`0x7ffc267b58fb`) sous LLDB** : + - L'analyse pas-à-pas des instructions de `_getIfListCopy` lors de l'énumération `getifaddrs()` a révélé **deux filtres matériels stricts et cumulatifs** appliqués à chaque interface réseau : + - **Filtre 1 : Le Contrôle de Type BSD `SIOCGIFTYPE` (`0xc020699f`)** : + ```assembly + 0x7ffc267b5dda: movl $0xc020699f, %esi ; ioctl(fd, SIOCGIFTYPE, &ifr) + 0x7ffc267b5de4: callq ioctl + ... + 0x7ffc267b5fd9: cmpl $0x6, -0xc0(%rbp) ; ifr.ifru_type.ift_type == 6 (IFT_ETHER) + 0x7ffc267b5fee: jne 0x7ffc267b6091 ; Si != 6 -> IGNORE SILENCIEUSEMENT L'INTERFACE ! + 0x7ffc267b5ff4: cmpl $0x3, -0xb8(%rbp) ; ifr.ifru_type.ift_subfamily == 3 (IFRTYPE_SUBFAMILY_WIFI) ! + 0x7ffc267b5ffb: je 0x7ffc267b6024 ; Si == 3 -> AJOUTE DIRECTEMENT en1 AU CFArray DE SUCCÈS ! + 0x7ffc267b5ffd: jmp 0x7ffc267b6091 ; Si != 3 -> IGNORE L'INTERFACE ! + ``` + * Définition dans `net/if_private.h` : + ```c + #define IFRTYPE_SUBFAMILY_WIFI 3 + ``` + * Sur notre interface `en1`, `SIOCGIFTYPE` renvoyait `ift_type: 6, ift_family: 2, ift_subfamily: 0`. + * En raison de `ift_subfamily == 0` au lieu de `3`, `_getIfListCopy` sautait inconditionnellement à l'instruction `0x7ffc267b6091`, ignorant `en1` sans le moindre log d'erreur ! + - **Filtre 2 : Le Contrôle de Médium `SIOCGIFMEDIA` (`0xc02c6938`)** : + ```assembly + 0x7ffc267b6002: movl -0xc0(%rbp), %eax ; eax = ifmr.ifm_current + 0x7ffc267b6008: movl $0xe0, %ecx ; IFM_NMASK (0xe0) + 0x7ffc267b600d: andl %ecx, %eax ; type = ifmr.ifm_current & 0xe0 + 0x7ffc267b600f: cmpl $0x80, %eax ; 0x80 == IFM_IEEE80211 ! + 0x7ffc267b6022: jne 0x7ffc267b6091 ; Si != 0x80 -> REJET IMMÉDIAT ! + ``` + * Sur notre interface, `ifm_current` renvoyait `0x20` (`IFM_ETHER`). + * `(0x20 & 0xe0) != 0x80` provoquait également l'expulsion directe d'`en1`. + 2. **Origine Noyau de `ift_subfamily` et `ifm_current` dans Skywalk (`BootKernelExtensions.kc`)** : + - Dans `IOSkywalkEthernetInterface::initRegistrationInfo` (`0xffffff8002b108e2`) : + ```assembly + 0xffffff8002b10958: mov dword ptr [rbx + 0x08], ecx ; family = 2 (ETHERNET) + 0xffffff8002b1095e: call qword ptr [r12 + 0x9b8] ; Slot 0x9b8 = getInterfaceSubFamily() + 0xffffff8002b10966: mov dword ptr [rbx + 0x0c], eax ; subfamily = 0 (par défaut !) + 0xffffff8002b10969: mov dword ptr [rbx + 0x24], 0x22 ; active medium = 0x22 (Ethernet) + 0xffffff8002b10985: mov dword ptr [rbx + 0x28], ecx ; current medium = 0x20 (Ethernet) + ``` + - Dans `registerNetworkInterfaceWithLogicalLink` (`0xffffff8002b0a204`) : + ```assembly + 0xffffff8002b0a2a9: call memcpy ; memcpy(priv->regInfo, fSkywalkRegInfo, 0x108) + ``` + - Le noyau copie fidèlement les `0x108` octets de `fSkywalkRegInfo` dans la structure interne `priv->regInfo`. + - Lorsque `IOSkywalkNetworkBSDClient::start` enregistre le client BSD, `IOSkywalkEthernetInterface::initBSDInterfaceParameters` lit `slot 0x9a8` (`getInterfaceSubFamily`), qui renvoie la valeur de `priv->regInfo + 0x0c`. + - Si `fSkywalkRegInfo + 0x0c` n'est pas explicitement configuré à `3` (`IFRTYPE_SUBFAMILY_WIFI`), BSD initialise `en1` avec un sous-type nul (`0`). +* **Résolutions Techniques Appliquées dans `QualcommWifi.cpp`** : + 1. **Injection Directe de `IFRTYPE_SUBFAMILY_WIFI = 3` dans `fSkywalkRegInfo`** : + - Immédiatement après l'appel à `initRegistrationInfo` (substep 8.1) : + ```cpp + *(uint32_t*)(fSkywalkRegInfo + 0x0c) = 3; // IFRTYPE_SUBFAMILY_WIFI = 3 + *(uint32_t*)(fSkywalkRegInfo + 0x24) = 0x80; // active medium: kIOMediumIEEE80211Auto + *(uint32_t*)(fSkywalkRegInfo + 0x28) = 0x80; // current medium: kIOMediumIEEE80211Auto + *(uint32_t*)(fSkywalkRegInfo + 0x48) = 1500; // MTU + *(uint32_t*)(fSkywalkRegInfo + 0x4c) = 1500; // Max MTU + ``` + 2. **Mise à Jour de Sécurité des Structures Internes Skywalk (`priv` & `struct ifmedia`)** : + - Immédiatement après `registerEthernetInterface` (substep 8.4) et après `registerService()` (substep 8.5) : + ```cpp + uint8_t *priv = *(uint8_t **)((uint8_t *)fSkywalkInterface + 0xc0); + if (priv) { + uint8_t *regInfo = *(uint8_t **)priv; + if (regInfo) { + *(uint32_t *)(regInfo + 0x0c) = 3; // IFRTYPE_SUBFAMILY_WIFI + *(uint32_t *)(regInfo + 0x24) = 0x80; // kIOMediumIEEE80211Auto + *(uint32_t *)(regInfo + 0x28) = 0x80; // kIOMediumIEEE80211Auto + } + *(uint32_t *)(priv + 0x30) = 0x3; // ifm_status = IFM_AVALID | IFM_ACTIVE (0x1 | 0x2) + *(uint32_t *)(priv + 0x34) = 0x80; // ifm_current = kIOMediumIEEE80211Auto (0x80) + *(uint32_t *)(priv + 0x38) = 0x80; // ifm_active = kIOMediumIEEE80211Auto (0x80) + } + ``` + 3. **Purification du Dictionnaire de Médiums (`createMediumTables`)** : + - Restriction exclusive au médium `kIOMediumIEEE80211Auto` à 1.2 Gbps (sans résidu Ethernet) pour garantir que `getMediaList` et `selectMedium` ne sélectionnent que des médiums conformes `IFM_IEEE80211`. + 4. **Validation Binaire & Déploiement** : + - Compilation `Release` réussie sans erreur (`./build_wifi.sh`). + - Validation des symboles et dépendances réussie à 100% via `kmutil libraries`. + - Kext déployé sur l'EFI : `/Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext` (MD5: `918e6727043a53bbe4825671f428ab5c`).