fix(wifi): eliminate bootloop CR2:0x1 by removing virtual qualifier on IO80211SkywalkInterface non-virtual ABI

### Breakthroughs & Rétro-ingénierie :
- Diagnostic de la cause racine du bootloop / crash kernel immédiat survenu lors de l'activation de qcom_skywalk=1 (commit e4c7d59).
- Rétro-ingénierie binaire approfondie de BootKernelExtensions.kc (macOS Tahoe 26.x / Darwin 25) sur la classe IO80211SkywalkInterface :
  * Découverte critique : IO80211SkywalkInterface::init(IOService*, ether_addr*) (0xffffff80022f56e2) et IO80211SkywalkInterface::setInterfaceRole(UInt32) (0xffffff80022f60f0) sont des méthodes NON-VIRTUELLES.
  * Déclarées virtual dans IO80211SkywalkInterface.h, Clang leur a alloué deux slots virtuels à la fin de la vtable IOSkywalkEthernetInterface aux offsets +0xc50 et +0xc58.
  * Dans la table virtuelle native Apple à 461 slots (0xe68 octets), le slot +0xc58 correspond à IO80211SkywalkInterface::printDataPath(userPrintCtx*).
  * L'instruction fSkywalkInterface->setInterfaceRole(1) a émis callq *0xc58(%rax), sautant dans printDataPath avec %rsi = 0x1. Le déréférencement de ce pointeur a déclenché un Page Fault kernel sur CR2: 0x0000000000000001 et provoqué un CPU triple fault instantané.

### Modifications apportées :
- QualcommWireless/include/IOKit/80211/IO80211SkywalkInterface.h :
  * Suppression du mot-clé virtual devant bool init(IOService *controller, ether_addr *mac) et void setInterfaceRole(UInt32 role).
  * Clang génère désormais des appels directs callq __ZN23IO80211SkywalkInterface4init... et callq __ZN23IO80211SkywalkInterface16setInterfaceRoleEj.
- docs/ISSUES_AND_POSTMORTEMS.md :
  * Ajout du post-mortem technique détaillé INC-14 (analyse de désassemblage, collision de vtable, résolution).
- docs/RESEARCH_AND_REVERSE_ENGINEERING.md :
  * Ajout de la section 4.1 décrivant la topologie de la vtable (461 slots) de IO80211SkywalkInterface, les méthodes non-virtuelles, et les slots d'attachement 441 (attachInterface) et 442 (detachInterface).

### Validation :
- Compilation C++ / ASM / Linker réussie sans avertissement via build_wifi.sh.
- Validation binaire kmutil libraries -p build/Release/QualcommWifi.kext validée à 100% contre BootKernelExtensions.kc.
- Désassemblage de build/Release/QualcommWifi.kext confirmant l'éradication des appels indirects vers 0xc50/0xc58 au profit des appels directs aux symboles globaux du noyau.
This commit is contained in:
Erwan committed 2026-10-18 13:48:56 +02:00
1 parent e4c7d59a5e
commit c401f7f90c
3 files changed
+57 -2

No files matched your search

@@ -21,8 +21,8 @@ class IO80211SkywalkInterface : public IOSkywalkEthernetInterface {
OSDeclareAbstractStructors(IO80211SkywalkInterface)
public:
virtual bool init(IOService *controller, ether_addr *mac);
virtual void setInterfaceRole(UInt32 role);
bool init(IOService *controller, ether_addr *mac);
void setInterfaceRole(UInt32 role);
virtual bool start(IOService *controller) APPLE_KEXT_OVERRIDE;
virtual void stop(IOService *controller) APPLE_KEXT_OVERRIDE;
virtual void free() APPLE_KEXT_OVERRIDE;
+37
View File
@@ -315,3 +315,40 @@ Ce document répertorie de manière exhaustive l'ensemble des anomalies, blocage
- Dans `QualcommWifi::start(provider)` : instanciation séquentielle de `createWorkLoop()` puis `createWorkQueue()` avant l'invocation de `super::start(provider)`.
- Dans `IONetworkController::start`, `workLoop->getThread()` invoque désormais l'implémentation native de `IOWorkLoop::getThread` (`movq 0x30(%rdi), %rax`), fournissant un `thread_t` valide à `ml_thread_policy`, et permettant l'attachement propre du `IOCommandGate` via `fWorkLoop->addEventSource`.
- Dans `QualcommWifi::stop()` et `QualcommWifi::free()` : libération propre des deux objets via `OSSafeReleaseNULL(fWorkLoop)` et `OSSafeReleaseNULL(fWorkQueue)`.
---
### INC-14 : Page Fault Kernel Trap `CR2: 0x0000000000000001` par Déroutement Vtable Virtuel dans `IO80211SkywalkInterface::printDataPath`
* **Symptômes** :
- Bootloop immédiat (triple fault / redémarrage instantané du kernel) dès l'activation de `qcom_skywalk=1`.
- Machine bloquée en boucle de redémarrage sans affichage de panic log si NVRAM inaccessible.
* **Causes Racines (Breakthroughs Majeurs & Rétro-ingénierie Noyau)** :
1. **Déclarations `virtual` indues dans les headers C++ (`IO80211SkywalkInterface.h`)** :
- Dans le header reconstruit `QualcommWireless/include/IOKit/80211/IO80211SkywalkInterface.h`, les méthodes `init(IOService*, ether_addr*)` et `setInterfaceRole(UInt32)` étaient déclarées avec le mot-clé `virtual`.
- Or, l'analyse binaire approfondie de `BootKernelExtensions.kc` démontre sans équivoque :
- `IO80211SkywalkInterface::init(IOService*, ether_addr*)` (`0xffffff80022f56e2`) est une fonction membre **NON-VIRTUELLE** (seule `init(void)` à l'offset `0x88` hérite d'`OSObject::init`).
- `IO80211SkywalkInterface::setInterfaceRole(UInt32)` (`0xffffff80022f60f0`) est une fonction membre **NON-VIRTUELLE** qui écrit directement `role` dans `this->ivars + 0x58`.
2. **Collision catastrophique de table virtuelle (Vtable Desynchronization)** :
- En déclarant ces deux méthodes comme `virtual`, Clang leur a assigné deux nouveaux slots virtuels à la fin de la vtable `IOSkywalkEthernetInterface`, aux offsets `+0xc50` (slot 394) et `+0xc58` (slot 395).
- Dans l'objet réel `IO80211SkywalkInterface` instancié par le noyau (`BootKernelExtensions.kc`), la vtable native possède 461 slots (`0xe68` octets) :
- Le slot `+0xc50` correspond en réalité à `IO80211SkywalkInterface::wowEnabled()`.
- Le slot `+0xc58` correspond à `IO80211SkywalkInterface::printDataPath(userPrintCtx*)`.
- L'appel `fSkywalkInterface->setInterfaceRole(1)` a émis l'instruction assembleur `callq *0xc58(%rax)`.
- Le noyau a donc exécuté `printDataPath` avec `%rdi = fSkywalkInterface` et `%rsi = 0x1` (le rôle 1 transmis comme pointeur `userPrintCtx*`).
- Lors du premier déréférencement mémoire de `%rsi` à l'adresse `0x1`, le processeur a déclenché un Page Fault `#PF` sur `CR2: 0x0000000000000001`, entraînant un crash critique et un redémarrage instantané (triple fault).
* **Résolutions Techniques Appliquées** :
1. **Suppression du Qualificatif `virtual`** :
- Retrait strict de `virtual` devant `bool init(IOService *controller, ether_addr *mac);` et `void setInterfaceRole(UInt32 role);` dans `QualcommWireless/include/IOKit/80211/IO80211SkywalkInterface.h`.
2. **Vérification Binaire de l'Assembleur Généré** :
- Le désassemblage de `build/Release/QualcommWifi.kext` atteste de la conversion en appels directs non-virtuels :
```assembly
0x2d9e: callq __ZN23IO80211SkywalkInterface4initEP9IOServiceP10ether_addr
0x2dc3: callq __ZN23IO80211SkywalkInterface16setInterfaceRoleEj
0x2de1: callq *0x670(%rax) ; fSkywalkInterface->attach(this)
0x2e08: callq *0x5c0(%rax) ; fSkywalkInterface->start(this)
0x2e31: callq *0xdc8(%rax) ; this->attachInterface(fSkywalkInterface, nullptr)
0x2e4f: callq *0x5b0(%rax) ; fSkywalkInterface->registerService()
```
3. **Conformité des Dépendances** :
- `kmutil libraries -p build/Release/QualcommWifi.kext` valide la résolution intégrale des symboles auprès de `BootKernelExtensions.kc`.
+18
View File
@@ -142,3 +142,21 @@ L'analyse désassemblée révèle le graphe d'appels complet exécuté lors de `
* `dataLinkLayerAttachComplete` : notifie le pilote dès que la couche Skywalk de transport est connectée.
* `setPOWER` / `getPOWER` : gestion logicielle de l'alimentation de l'émetteur radio.
* `getCARD_CAPABILITIES` : publication des capacités matérielles (chiffrements AES/WPA3, largeurs de bande, 802.11be EHT).
### 4.1. Anatomie Binaire et ABI de `IO80211SkywalkInterface` (`BootKernelExtensions.kc`)
L'analyse par désassemblage Capstone a établi l'exactitude de l'interface Skywalk native :
1. **Table Virtuelle (`__ZTV23IO80211SkywalkInterface`)** :
- Contient exactement **461 slots virtuels** (`0xe68` octets).
- Slot 184 (`+0x5c0`) : `virtual bool start(IOService *controller)` (`0xffffff80022f5792`).
- Slot 185 (`+0x5c8`) : `virtual void stop(IOService *controller)` (`0xffffff80022f885c`).
- Slot 18 (`+0x90`) : `virtual void free(void)` (`0xffffff80022f6184`).
- Slot 373 (`+0xba8`) : `virtual IO80211Controller* getController(void)` (`0xffffff80022f957a`).
2. **Méthodes Non-Virtuelles Essentielles** :
- `init(IOService *controller, ether_addr *mac)` (`0xffffff80022f56e2`) : **NON-VIRTUELLE**. Initialise les ivars internes (`this->ivars + 0x120`), alloue la structure de contrôle et copie l'adresse MAC (6 octets) dans `ivars + 0xe4` / `+0xe8`.
- `setInterfaceRole(UInt32 role)` (`0xffffff80022f60f0`) : **NON-VIRTUELLE**. Configure le rôle réseau dans `this->ivars + 0x58` (`role = 1` pour `kIO80211InterfaceRoleInfra`).
3. **Attachement au Contrôleur (`IO80211Controller`)** :
- Slot 441 (`+0xdc8`, `0xffffff8002295fce`) : `bool attachInterface(OSObject *iface, IOService *unused = nullptr)`.
Vérifie `OSDynamicCast(IO80211SkywalkInterface, iface)` et valide `iface->ivars->role == 1`, puis enregistre l'interface primaire dans `controller->ivars + 0x188`.
- Slot 442 (`+0xdd0`, `0xffffff800229604a`) : `bool detachInterface(OSObject *iface, bool arg2 = false)`.
Détache l'interface et réinitialise `controller->ivars + 0x188 = NULL`.