- En activant le contrôleur xDCI caché du ThinkPad X1 Carbon 6th Gen, le portable lui-même a pu émuler n’importe quel périphérique USB, comme un clavier ou un périphérique de stockage
- L’indice était
/sys/class/usb_role/intel_xhci_usb_sw-role-switch, mais le seul changement de rôle xHCI ne suffisait pas : un UDC xDCI basé sur DWC3 distinct devait être exposé comme périphérique PCIe - L’image du BIOS contenait un réglage
xDCI Support, mais il était masqué dans l’interface Setup par défaut ; après activation, le xDCI8086:9d30et le pilotedwc3-pcisont apparus danslspci - La méthode qui a fonctionné a été le déverrouillage de la page BIOS Advanced et le patch de la NVRAM ; la reconfiguration des registres PCH s’est limitée à quelques changements côté PMC et a échoué à cause du verrouillage PSF
- Après activation du xDCI,
g_mass_storage, Raw Gadget, un reproducer syzkaller et un backend Facedancer ont fonctionné sans matériel externe, mais il faut un câble USB dont leVBUSest coupé et basculer le rôle endevice
L’indice du mode périphérique USB trouvé dans un ThinkPad
- Raw Gadget est un module noyau qui fournit une API en espace utilisateur au sous-système Linux USB Gadget, et peut être utilisé pour le fuzzing et l’exploitation d’hôtes USB en fournissant des descripteurs USB incorrects
- Les PC classiques n’ont généralement pas de USB Device Controller, c’est-à-dire d’UDC, contrairement aux ordinateurs monocartes comme le Raspberry Pi, où il est souvent intégré
- Les travaux précédents nécessitaient du matériel externe comme un Raspberry Pi ou un EC3380-AB basé sur USB 3380
- Sur le ThinkPad X1 Carbon 6th Gen,
intel_xhci_usb_sw-role-switcha été trouvé sous/sys/class/usb_role/sys/class/usb_roleest une interface qui fait basculer des composants USB matériels entre les modes host et device- Même en écrivant
devicedans le fichier role, aucun messagedmesgni entrée/sys/class/udc/n’apparaissait au départ
- xHCI est le HCD qui permet aux systèmes x86 de fonctionner comme hôte USB, tandis que xDCI est le nom employé par Intel pour l’interface côté périphérique USB
Architecture vérifiée dans le code du noyau et les listes de diffusion
- Dans le noyau Linux,
intel_xhci_usb_swapparaît à deux endroitsdrivers/usb/roles/intel-xhci-usb-role-switch.cimplémente le pilote USB Role Switch qui manipule les registres xHCI quanddeviceouhostest écritdrivers/usb/host/xhci-ext-caps.ccrée un périphérique de plateforme virtuelintel_xhci_usb_swlorsque le pilote xHCI définit le quirkXHCI_INTEL_USB_ROLE_SW
- L’identifiant de périphérique PCIe xHCI du ThinkPad était
0x9d2f, correspondant àPCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCIdans le noyau - Des discussions sur la liste de diffusion du noyau Linux ont confirmé que le xHCI et l’UDC DWC3 sont des périphériques distincts, avec un mux entre les deux
- Le role switch sert à commuter ce mux
- Si le DWC3 UDC lui-même n’apparaît pas comme périphérique PCI, il n’y a pas d’UDC utilisable en mode device
- DWC3 est l’IP Synopsys DesignWare Core SuperSpeed USB 3.0 Controller, utilisée dans les systèmes de plusieurs fournisseurs, dont Intel
- En vérifiant
lspcisur le ThinkPad, seul le xHCI8086:9d2fétait visible au départ, et l’identifiant de périphérique xDCI Sunrise Point-LP0x9d30défini dansdwc3-pci.cn’apparaissait pas
Traces de xDCI laissées dans l’ACPI et le BIOS
- La DSDT ACPI contenait
Device (XDCI)et une méthode_STA/sys/bus/acpi/devices/device:33/pathvalait\_SB_.PCI0.XDCI/sys/bus/acpi/devices/device:33/statusvalait15, ce qui signifie que le périphérique est enabled and functioning- Mais comme xDCI n’apparaissait pas dans
lspci, il n’était normal que du point de vue ACPI
- L’écran de Setup BIOS par défaut n’affichait aucun réglage lié à xDCI ou OTG
- L’image de mise à jour Lenovo BIOS Bootable CD a été téléchargée, le binaire BIOS
/mnt/bios/FLASH/N23ET86W/$0AN2300.FL1extrait, puis inspecté avec UEFITool - En recherchant des chaînes dans la
PE32 image sectiondu moduleSetup, les entrées suivantes sont apparuesxDCI SupportEnable/Disable xDCI (USB OTG Device).
- Le BIOS contient donc un réglage xDCI Support, mais il est masqué dans l’UI par défaut
Activer xDCI via la page BIOS Advanced
- La méthode documentée par le projet x1c6-hackintosh pour ouvrir la page BIOS Advanced cachée a été essayée
- Cette méthode nécessitait de reflasher la puce SPI contenant le BIOS
- Au lieu d’utiliser une pince SPI, la puce SPI a été remplacée par un socket afin de pouvoir la retirer et la remettre plusieurs fois pour les essais
- Un FTDI FT2232H Mini Module et
flashromont servi à dumper puis réécrire le contenu de la puce SPI
- Le patch BIOS se composait de deux étapes
- Avec
UEFIPatch, la référence de GUID de la page BIOSDate/Timeest remplacée par celle de la pageAdvanced - Un patch d’octets séparé force le TPM en
MFG Modeafin d’éviter que Boot Guard ne détecte la modification du BIOS
- Avec
- Sur le BIOS 1.37, appliquer seulement le premier patch faisait biper le portable et l’empêchait de démarrer ; après application du second patch aussi, la page Advanced est apparue
- En passant
xDCI SupportàEnableddansIntel Advanced Menu→PCI-IO Configuration→USB Configuration, xDCI a été exposé après le démarrage00:14.1 USB controller [8086:9d30]est apparu danslspci- Le noyau a chargé automatiquement le pilote
dwc3-pci dwc3.1.autoest apparu dans/sys/class/udc/
Port xDCI et contraintes de câble
- Pour trouver le port USB externe raccordé au xDCI, une clé USB a été branchée sur chaque port avec le rôle réglé sur
device- Sur un port donné, l’OS ne détectait pas la clé USB ; en repassant le rôle à
host, elle fonctionnait de nouveau - Ce port a été identifié comme le port raccordé au xDCI
- Sur un port donné, l’OS ne détectait pas la clé USB ; en repassant le rôle à
- Comme le port xDCI du ThinkPad était en USB Type-A, un câble Type-A vers Type-A mâle-mâle était nécessaire pour le connecter à un ordinateur host
- Comme le role switching ne coupait pas l’alimentation
VBUSdu port, un câble dont le VBUS est coupé a été utilisé pour éviter de relier directement lesVBUSdes deux appareils- Au départ, deux câbles USB 2.0 ont été découpés pour fabriquer un câble mâle-mâle avec
VBUScoupé - Ensuite, un PortaPow USB Power Blocker et un câble USB 2.0 mâle-mâle ont été utilisés
- Au départ, deux câbles USB 2.0 ont été découpés pour fabriquer un câble mâle-mâle avec
- En chargeant le gadget driver
g_zero, un périphérique USB de test a été correctement émulé depuis un autre portable - D’après la mise à jour du 11 juin 2024, le câble DataPro USB 3.0 Super-Speed A/A Debugging Cable coupe aussi les lignes USB 2.0
D-etD+, ce qui empêche l’établissement de la connexion High-Speed nécessaire à la connexion SuperSpeed- Le câble LogiLink CU0038 dont le
VBUSa été coupé manuellement fonctionne pour émuler un périphérique SuperSpeed
- Le câble LogiLink CU0038 dont le
Tentative d’activation logicielle via les registres PCH
- Pour comprendre comment le BIOS active xDCI, le fichier
Pch/Library/Private/PeiPchInitLib/PchXdci.cdu code source BIOS Kaby Lake a été examiné - Le chemin de désactivation xDCI du BIOS désactivait xDCI côté PMC et PSF
-
Changements PMC
- Effacer le bit #24
XDCI Function Disabledu registreNST_PG_FDIS_1offset0x628du PMC semblait pouvoir lever la coupure d’alimentation du xDCI - Un module noyau réutilisant le mapping
pmc_core_deviceetpmc->regbasedu noyau Linux a été écrit - Juste après le démarrage, le bit #31
ST_FDIS_LKdeST_PG_FDIS1était défini, ce qui empêchait de modifier la valeur deNST_PG_FDIS_1 - Après une mise en veille du portable puis un réveil, le bit de verrouillage n’était plus défini, et le bit
XDCI Function Disablea pu être effacé
- Effacer le bit #24
-
Changements PSF
- Le BIOS désactive xDCI en définissant le bit
USB Dual Role (OTG) Function Disabledans le PSF2 PCR du Port ID0xBBPID_PSF2 - L’adresse PCR est calculée à partir de
PCH_PCR_BASE_ADDRESS 0xFD000000, du Port ID et de l’offset - Dans le module noyau, le PSF2 PCR a été mappé avec
ioremap, mais la valeur lue était0xffffffffet ne changeait pas - Même en rendant P2SB visible, le résultat était identique
- Le
RemoveSidebandAccessdu BIOS détachePID_PSF2de l’IOSF-SB viaEPMASK5et le verrouille avecMASKLOCK, empêchant l’OS de reconfigurer le PSF - L’accès PCH a permis certains réglages PMC, mais l’échec de reconfiguration PSF en a fait une méthode inutilisable pour activer xDCI
- Le BIOS désactive xDCI en définissant le bit
Activation par patch NVRAM sans contournement de Boot Guard
- Comme les valeurs de configuration du BIOS sont stockées dans la zone NVRAM de la puce SPI, une méthode ne modifiant que la valeur
xDCI Support, sans ouvrir la page Advanced cachée, a été essayée - Les informations UEFI IFR du module
Setupont été extraites avec IFRExtractor-RS - Le réglage
xDCI Supportétait stocké dans la variable UEFIPchSetup- VarStore GUID:
4570B7F1-ADE8-4943-8DC3-406472842384 - VarStoreId:
0x5 - VarOffset:
0x40 - Plage de valeurs :
0x0ou0x1
- VarStore GUID:
- Dans
efivarfssous Linux,/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384a été vérifié- Les 4 premiers octets d’un fichier
efivarfssont un en-tête, donc la valeur réelle dexDCI Supportse trouve à l’offset0x44du fichier - Quand xDCI était désactivé, la valeur était
00; après activation via la page BIOS Advanced, elle passait à01
- Les 4 premiers octets d’un fichier
- En tentant d’écrire directement cette variable depuis l’espace utilisateur ou l’EFI Shell, une erreur
EFI_WRITE_PROTECTEDse produisait- Même en supprimant l’attribut immutable d’
efivarfs, une erreurRead-only file systemapparaissait - Modifier depuis l’EFI Shell avec chipsec produisait la même erreur
- Même en supprimant l’attribut immutable d’
- En retrouvant la séquence d’octets autour de
PchSetupdans l’image BIOS originale lue avec le programmateur SPI, puis en ne patchant que le bitxDCI Supportà01et en reflashant, xDCI a été activé - Cette méthode nécessite toujours de reflasher la puce SPI, mais elle n’a pas besoin du patch de la page Advanced ni d’un contournement de Boot Guard, et le TPM n’a pas été cassé
- Après patch de la NVRAM sur le BIOS 1.37 puis mise à jour vers 1.61, la valeur du réglage BIOS a été conservée, sans devoir réappliquer le patch
Émuler des périphériques USB avec xDCI
- Tous les exemples supposent que xDCI est activé dans le BIOS, que
intel_xhci_usb_sw-role-switcha été basculé endevice, et que le port xDCI est relié à un hôte USB avec un câble dontVBUSest coupé -
Legacy gadget drivers
- Les legacy gadget drivers du sous-système Linux USB Gadget émulent un périphérique d’une classe USB donnée lorsqu’un module est chargé
g_mass_storageexpose une image de système de fichiers comme périphérique USB mass storage- Après création d’une image FAT
disk.imget ajout deHi from xDCIdansfile.txt, le module est chargé avecsudo modprobe g_mass_storage file=./disk.img stall=0 - Sur l’hôte USB, le disque est monté automatiquement et le contenu du fichier est vérifié
-
Raw Gadget
- Raw Gadget a été exécuté avec xDCI pour essayer l’exemple de clavier USB
- Au départ, il restait bloqué pendant le traitement de
SET_CONFIGURATION - La cause était que
dwc3et quelques pilotes UDC supposent qu’ils peuvent acquitter immédiatement une control request de longueur 0 sans consulter le gadget driver - Après application du patch de contournement à Raw Gadget et d’une correction à GadgetFS, l’émulation du clavier a réussi
- Le comportement associé a été documenté dans ce commit
Utilisation avec syzkaller et Facedancer
- syzkaller peut utiliser Raw Gadget pour faire du fuzzing externe de la pile USB du noyau Linux
- Le fuzzing USB par défaut de syzkaller utilise Dummy HCD/UDC, qui relie en interne dans le noyau un périphérique USB virtuel et un contrôleur hôte
- Pour utiliser xDCI, le code de sélection d’UDC de syzkaller a été modifié pour utiliser
dwc3-gadget,dwc3.1.autoau lieu dedummy_udc - Le reproducer d’un bug
WARNING in smsusb_start_streaming/usb_submit_urbdécouvert par syzkaller a été exécuté avecsyz-execprog -enable=usb- Sur un portable avec un noyau Ubuntu
5.15.0-91-genericcomme hôte, l’avertissementusb_submit_urba été reproduit - Ce bug était un
WARNINGdû à l’absence de validation du type d’endpoint USB dans le pilotesmsusb, sans comportement dommageable
- Sur un portable avec un noyau Ubuntu
- Facedancer est un framework Python d’émulation de périphériques USB
- Le backend Facedancer basé sur Raw Gadget est encore un prototype et dépend de patchs Raw Gadget out-of-tree
- En définissant
BACKEND=rawgadget,RG_UDC_DRIVER=dwc3-gadget,RG_UDC_DEVICE=dwc3.1.autopuis en exécutant l’exemplerubber-ducky.py, il a fonctionné correctement
- Le USB Proxy basé sur Raw Gadget a aussi fonctionné avec xDCI, et xDCI permet d’utiliser le portable comme sniffer USB ou outil USB Man-in-the-Middle
Autres appareils et possibilité d’une méthode logicielle
- L’activation de xDCI pourrait être possible sur d’autres PC que le ThinkPad X1 Carbon 6th Gen
- Dans le cas le plus simple, il pourrait suffire d’activer xDCI dans les réglages du BIOS
- Le support ACPI et du role switching doit être présent, et le port xDCI doit être câblé vers un port externe
- Sur d’autres ThinkPad aussi, le réglage BIOS xDCI peut être masqué et protégé, ce qui peut nécessiter un reflashing de la puce SPI
- La méthode NVRAM peut être appliquée sans contournement de Boot Guard
- Les puces SPI de certains systèmes récents peuvent protéger le reflashing avec RPMC ; ces puces peuvent avoir un
Rdans leur nom, commeW25R128FW
- D’après une mise à jour, Shiny Quagsire avait déjà activé xDCI sur un XPS 13 et une Surface Go 1 en modifiant la variable
PchSetupavecgrub-mod-setup_var- Sur ces appareils, la variable
PchSetupn’était pas protégée, ce qui permettait une méthode entièrement logicielle
- Sur ces appareils, la variable
- D’autres approches logicielles pourraient consister à exploiter une vulnérabilité du BIOS pour modifier les variables NVRAM liées à xDCI, ou à attaquer le BIOS par DMA pendant le démarrage afin d’exécuter du code arbitraire
- Le “secret” du titre désigne plutôt une fonctionnalité non documentée qu’une dissimulation intentionnelle
1 commentaires
Avis Hacker News
Je me suis toujours demandé pourquoi la possibilité d’utiliser un ordinateur portable comme clavier et écran universels pour un autre ordinateur n’était pas plus courante.
Acheter un nouveau clavier et un nouvel écran pour maintenir une machine headless paraît étrange, alors qu’un ordinateur portable peut déjà remplir ce rôle.
La tablette Minisforum V3 qui arrive bientôt a aussi une entrée vidéo, ce qui permet de l’utiliser comme écran externe, mais il ne semble pas que le clavier et la souris puissent être partagés.
Ce serait vraiment bien que ce genre de fonction devienne plus courant.
La souris et le clavier peuvent être basculés vers un port externe et reliés par câble à une autre machine, et il y a deux ports HDMI sur le côté : l’un en sortie, l’autre en entrée.
Un interrupteur interne permet de choisir si la source de l’écran est la machine du deck elle-même ou l’entrée externe.
En gros, c’est une puce qui capture le signal HDMI de la machine headless et l’expose au portable via USB comme une webcam émulée ; l’électronique est assez petite pour tenir dans le câble.
Pour le clavier, je n’ai pas trouvé de meilleure solution qu’un clavier sans fil standard, avec trackpad intégré au cas où une souris serait parfois nécessaire.
D’après ce que j’ai entendu, USB 4 aurait un mode permettant cela.
https://web.archive.org/web/20180610141436/http://anselm.hoffmeister.be/computer/hidclient/index.html.en
https://github.com/benizi/hidclient
Cela me rappelle un exemple, il y a quelques années, du travail de Travis Goodspeed.
Une smart TV acceptait les mises à jour de firmware depuis des fichiers sur une clé USB ordinaire ; pour vérifier la signature numérique, la TV lisait le fichier du début à la fin, puis le relisait pour effectuer la mise à jour.
Un appareil se faisant passer pour un périphérique de stockage USB pouvait envoyer le firmware du constructeur à la première lecture, puis un firmware non officiel à la seconde.
https://en.m.wikipedia.org/wiki/Time-of-check_to_time-of-use
Vraiment fascinant. J’ai étudié des options similaires réalisables.
J’ai un serveur NAS puissant que je cherche sans cesse une bonne excuse d’utiliser, et j’ai aussi des connexions 40G et 10G un peu partout dans la maison.
La PS5 et la XBox utilisent des disques durs USB comme stockage supplémentaire.
J’ai regardé s’il était possible d’exposer le stockage du NAS à la PS5 et à la XBox, et c’est possible. Il suffit de monter un partage NAS en iSCSI ou NFS, puis d’émuler un périphérique de stockage USB avec le module g_mass_storage pour exposer ce stockage à l’hôte USB.
Pour l’instant, le principal obstacle, au-delà du temps et du coût, est la bande passante que fournirait ce système. Le gain ne serait pas énorme.
Le Raspberry Pi est connu pour prendre en charge l’USB-OTG, mais reste limité aux débits de l’USB 2.0, et la plupart des autres SBC de catégorie comparable que j’ai trouvés étaient dans le même cas. L’exception était le RockPi4 ; le RockPi a un port Ethernet gigabit, donc en saturant l’Ethernet, il peut fournir des débits de disque dur stables à la PS5 comme à la Xbox.
Si l’on créait une solution dépassant le 1GbE en branchant une carte réseau PCIe custom ou une carte Express, on pourrait vraiment saturer une interface USB 3.0, ce qui serait assez intéressant.
Il faut certes un client pour communiquer avec le serveur, mais cela semble plutôt bien fonctionner.
J’envisage d’avoir un « client USB léger » sur le bureau, d’y connecter des périphériques USB, puis de les attacher ou de les basculer vers l’hôte physique ou l’hôte VM voulu dans le labo.
Je suppose que c’est NAS → SBC → PS5 ; sinon, est-ce que le NAS est relié directement à la PS5 par un câble USB ?
Je me demande aussi comment se passe la lecture du contenu sur la PS5. Il me semble que le NVMe interne doit respecter une vitesse donnée ; cela ne s’applique pas aux disques externes ?
En fait, le NanoPi R6S possède deux ports Ethernet 2,5G en plus d’un port gigabit.
Merci pour cet article très détaillé. Il est de qualité.
Le fait que cela ait été possible donne l’espoir qu’une configuration façon Synergy / Mouse Without Borders sans réseau puisse être réalisable avec seulement un câble USB modifié.
Pour les personnes qui doivent contrôler plusieurs ordinateurs en même temps, c’est une très bonne piste.
Cela dit, l’approche proposée semble intéressante.
J’ai récemment exploré quelque chose de similaire : je voulais relier deux machines USB-C avec un seul câble USB-C pour avoir une communication à 10 Gbit/s.
Malheureusement, la plupart des cartes Ryzen n’ont toujours pas Thunderbolt, alors que Thunderbolt prend facilement en charge ce cas nativement.
Les contrôleurs USB « dual-role » étaient eux aussi assez rares avant l’USB 3.2/4.0 et, comme le montre cet article, même quand c’était possible, ce n’était souvent pas pris en charge.
Je trouve complètement étrange qu’il soit aussi difficile de mettre en réseau deux machines avec un câble USB-C sans Thunderbolt.
J’ai aussi aimé la partie où le bit de verrouillage est levé après une mise en veille. Ce genre de problème est vraiment courant. Par exemple, c’est aussi une méthode très fréquente pour sortir un périphérique SATA d’un état qui empêche l’effacement sécurisé.
La profondeur est vraiment impressionnante.
Pouvoir utiliser un PC comme périphérique USB ouvre beaucoup de possibilités intéressantes.
C’est un peu dommage que l’option xDCI nécessaire existe dans le matériel de cette machine, mais ne soit pas exposée, et qu’il faille hacker le firmware pour y accéder.
Le matériel le permet, mais le fabricant l’a simplement désactivé et a verrouillé les fonctions de contrôle.
Je me demande si Lenovo utilise ça comme moyen de déboguer un ThinkPad avec un autre ThinkPad.
https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/secure-coding/intel-debug-technology.html
Mise à jour : c’est probablement le cas.
https://www.youtube.com/watch?v=ExUvQa_jB7c
C’est une vidéo qui montre le débogage du firmware Intel avec DCI et USB 3.0.
Le passage « mais manipuler un Raspberry Pi, c’est pénible : brancher les câbles, démarrer la carte, se connecter au shell, etc. » aurait probablement pu être résolu en configurant USB OTG.
Il aurait sans doute été possible de l’alimenter depuis l’appareil branché, d’ouvrir un shell, puis de traiter le reste avec un script.
On aurait alors pu configurer les montages ou lancer des commandes via SSH, et probablement même monter le périphérique.
Cela dit, je recommande quand même cette démarche consistant à comprendre son propre matériel et à lire le noyau. C’est quelque chose qu’on a toujours envie de mieux faire, dans l’esprit « réparons nous-mêmes nos machines ».
J’ai essayé moi-même.
Ça rappelle très fortement la culture hacker des débuts d’Internet, au point d’en être nostalgique. C’est vraiment un excellent article.
Quand ESR parlait de ce que signifie devenir hacker, du hacker au sens de Hacker News, c’est exactement ce type de personne qu’il avait en tête.
La combinaison de curiosité, de persévérance et de compétence technique est extrêmement rare et très impressionnante.
J’ai un système basé sur Celeron N3350/Pentium N4200/Atom E3900, et le BIOS expose un commutateur xDCI.
Quand je l’active, quelques autres options apparaissent, et si je démarre sous Linux, je vois le périphérique PCI
USB controller: Intel Corporation Device 5aaa (rev 0b).Mais aucun nœud de périphérique UDC n’apparaît. Avec les indices de l’article original, je pense qu’il va falloir creuser un peu plus.