fix(skywalk): injecter IFRTYPE_SUBFAMILY_WIFI (3) et medium 802.11Auto pour Apple80211GetIfListCopy

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).
This commit is contained in:
Erwan committed 2026-10-19 19:09:45 +02:00
1 parent 5efd0dfbae
commit 25e41914f9
2 files changed
+133 -21

No files matched your search

+44 -21
View File
@@ -1090,11 +1090,24 @@ bool QualcommWifi::start(IOService *provider) {
fSkywalkInterface, fSkywalkRegInfo, 1, sizeof(fSkywalkRegInfo) fSkywalkInterface, fSkywalkRegInfo, 1, sizeof(fSkywalkRegInfo)
); );
if (regInit) { 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); memcpy(fSkywalkRegInfo + 0x108, fMacAddress.bytes, 6);
*(uint32_t*)(fSkywalkRegInfo + 0x48) = 1500; *(uint32_t*)(fSkywalkRegInfo + 0x48) = 1500;
*(uint32_t*)(fSkywalkRegInfo + 0x4c) = 1500;
logNvramStage("s8_1_reginfo_ok"); 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 { } else {
logNvramStage("s8_1_reginfo_err"); logNvramStage("s8_1_reginfo_err");
IOLog("QualcommWifi: [s8_1] ERREUR initRegistrationInfo !\n"); IOLog("QualcommWifi: [s8_1] ERREUR initRegistrationInfo !\n");
@@ -1155,6 +1168,22 @@ bool QualcommWifi::start(IOService *provider) {
IOLog("QualcommWifi: ========================================================\n"); IOLog("QualcommWifi: ========================================================\n");
IOLog("QualcommWifi: >>> [SUCCES MAJEUR] registerEthernetInterface A REUSSI ! <<<\n"); IOLog("QualcommWifi: >>> [SUCCES MAJEUR] registerEthernetInterface A REUSSI ! <<<\n");
IOLog("QualcommWifi: ========================================================\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 { } else {
logNvramStage("s8_4_reg_eth_err"); logNvramStage("s8_4_reg_eth_err");
IOLog("QualcommWifi: [s8_4] registerEthernetInterface a échoué (0x%x) !\n", regRes); 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"); logNvramStage("s8_6_reg_svc_done");
IOSleep(100); IOSleep(100);
IOLog("QualcommWifi: >>> [SUCCES TOTAL] Service Skywalk publié, création d'en1 imminente ! <<<\n"); 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) { bool QualcommWifi::createMediumTables(void) {
IOLog("QualcommWifi: Creation et publication du dictionnaire de mediums reseau...\n"); IOLog("QualcommWifi: Creation et publication du dictionnaire de mediums reseau IEEE 802.11...\n");
OSDictionary *mediumDict = OSDictionary::withCapacity(2); OSDictionary *mediumDict = OSDictionary::withCapacity(1);
if (!mediumDict) { if (!mediumDict) {
IOLog("QualcommWifi: ERREUR allocation mediumDict !\n"); IOLog("QualcommWifi: ERREUR allocation mediumDict !\n");
return false; return false;
@@ -1347,39 +1384,25 @@ bool QualcommWifi::createMediumTables(void) {
IONetworkMedium *mediumWifi = IONetworkMedium::medium( IONetworkMedium *mediumWifi = IONetworkMedium::medium(
kIOMediumIEEE80211Auto, kIOMediumIEEE80211Auto,
1000000000ULL, // 1 Gbps 1200000000ULL, // 1.2 Gbps (Wi-Fi 7 / 6E)
0, 0,
0, 0,
"Auto" "Auto"
); );
IONetworkMedium *mediumEth = IONetworkMedium::medium(
kIOMediumEthernetAuto,
1000000000ULL,
0,
1,
"EthernetAuto"
);
if (mediumWifi) { if (mediumWifi) {
IONetworkMedium::addMedium(mediumDict, mediumWifi); IONetworkMedium::addMedium(mediumDict, mediumWifi);
mediumWifi->release(); mediumWifi->release();
} }
if (mediumEth) {
IONetworkMedium::addMedium(mediumDict, mediumEth);
mediumEth->release();
}
bool published = publishMediumDictionary(mediumDict); bool published = publishMediumDictionary(mediumDict);
if (published) { if (published) {
const IONetworkMedium *selected = IONetworkMedium::getMediumWithType(mediumDict, kIOMediumIEEE80211Auto); const IONetworkMedium *selected = IONetworkMedium::getMediumWithType(mediumDict, kIOMediumIEEE80211Auto);
if (!selected) {
selected = IONetworkMedium::getMediumWithType(mediumDict, kIOMediumEthernetAuto);
}
if (selected) { if (selected) {
setSelectedMedium(selected); setSelectedMedium(selected);
setCurrentMedium(selected); setCurrentMedium(selected);
setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, selected, 1000000000ULL, nullptr); setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, selected, 1200000000ULL, nullptr);
IOLog("QualcommWifi: Medium selectionne et linkStatus(Active) configure avec succes !\n"); IOLog("QualcommWifi: Medium IEEE80211Auto selectionne et linkStatus(Active) configure avec succes !\n");
} }
} else { } else {
IOLog("QualcommWifi: ERREUR publishMediumDictionary !\n"); IOLog("QualcommWifi: ERREUR publishMediumDictionary !\n");
+89
View File
@@ -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`). - 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`).