- Ao ativar o controlador xDCI oculto no ThinkPad X1 Carbon 6th Gen, o próprio notebook passou a conseguir emular dispositivos USB arbitrários, como teclado ou armazenamento
- A pista era
/sys/class/usb_role/intel_xhci_usb_sw-role-switch, mas apenas a troca de papel do xHCI não bastava; um UDC xDCI baseado em DWC3 também precisava ser exposto como dispositivo PCIe - A imagem da BIOS tinha a configuração
xDCI Support, mas ela ficava oculta na interface padrão do Setup; após ativá-la, olspcipassou a mostrar o xDCI8086:9d30e o driverdwc3-pci - O método que funcionou foi desbloquear a página Advanced da BIOS e aplicar um patch na NVRAM; reconfigurar os registradores do PCH ficou limitado a algumas mudanças no PMC e falhou por causa do bloqueio do PSF
- Depois de ativar o xDCI,
g_mass_storage, Raw Gadget, reprodutores do syzkaller e o backend do Facedancer funcionaram sem hardware externo, mas foi preciso usar um cabo USB comVBUSdesconectado e alternar para o papeldevice
A pista do modo dispositivo USB encontrada no ThinkPad
- Raw Gadget é um módulo de kernel que fornece uma API de espaço de usuário para o subsistema USB Gadget do kernel Linux, e pode ser usado em fuzzing e exploração de hosts USB ao fornecer descritores USB malformados
- PCs comuns normalmente não têm um USB Device Controller, ou UDC, algo mais comum em computadores de placa única como o Raspberry Pi
- Trabalhos anteriores exigiam hardware externo, como um Raspberry Pi ou um EC3380-AB baseado em USB 3380
- No ThinkPad X1 Carbon 6th Gen, foi encontrado
intel_xhci_usb_sw-role-switchem/sys/class/usb_role/sys/class/usb_roleé a interface para alternar componentes USB de hardware entre os modos host e device- Mesmo escrevendo
deviceno arquivorole, no início não apareciam mensagens nodmesgnem entradas em/sys/class/udc/
- xHCI é o HCD que permite que sistemas x86 operem como host USB, e xDCI é o nome usado pela Intel para a interface do lado device do USB
Estrutura confirmada pelo código do kernel e pela mailing list
- No kernel Linux,
intel_xhci_usb_swaparece em dois lugaresdrivers/usb/roles/intel-xhci-usb-role-switch.cimplementa o driver USB Role Switch que manipula registradores do xHCI quandodeviceouhosté escritodrivers/usb/host/xhci-ext-caps.ccria o dispositivo de plataforma virtualintel_xhci_usb_swquando o driver xHCI define a quirkXHCI_INTEL_USB_ROLE_SW
- O ID do dispositivo PCIe xHCI do ThinkPad era
0x9d2f, correspondendo aPCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCIno kernel - Discussões na mailing list do kernel Linux confirmaram que xHCI e o UDC DWC3 são dispositivos separados, com um mux entre eles
- O role switch serve para trocar esse mux
- Se o próprio UDC DWC3 não aparece como dispositivo PCI, então não há UDC disponível para usar em modo device
- DWC3 é o IP DesignWare Core SuperSpeed USB 3.0 Controller da Synopsys, usado por vários fornecedores, incluindo a Intel
- Ao verificar o
lspcino ThinkPad, inicialmente só aparecia o xHCI8086:9d2f, e não o ID de dispositivo xDCI0x9d30do Sunrise Point-LP, citado emdwc3-pci.c
Vestígios do xDCI no ACPI e na BIOS
- No ACPI DSDT existiam
Device (XDCI)e o método_STA/sys/bus/acpi/devices/device:33/pathera\\_SB_.PCI0.XDCI/sys/bus/acpi/devices/device:33/statusera15, o que significa que o dispositivo estava enabled and functioning- Mas o xDCI não aparecia no
lspci, então ele parecia normal apenas do ponto de vista do ACPI
- Na tela padrão de Setup da BIOS não havia nenhuma configuração visível relacionada a xDCI ou OTG
- Foi baixada a imagem de atualização Lenovo BIOS Bootable CD, extraído o binário da BIOS
/mnt/bios/FLASH/N23ET86W/$0AN2300.FL1e examinado com UEFITool - Ao procurar strings na
PE32 image sectiondo móduloSetup, apareceram os itens abaixoxDCI SupportEnable/Disable xDCI (USB OTG Device).
- Ou seja, a BIOS continha a configuração xDCI Support, mas ela ficava oculta na interface padrão
Ativando o xDCI pela página Advanced da BIOS
- Seguindo a documentação do projeto x1c6-hackintosh, foi tentado o método para abrir a página Advanced da BIOS oculta
- Esse método exigia regravar o chip SPI onde a BIOS estava armazenada
- Em vez de usar um clipe SPI, o chip SPI foi trocado por um soquete para facilitar vários ciclos de remoção e reinserção durante os testes
- Um módulo FTDI FT2232H Mini e o
flashromforam usados para fazer dump e regravar o conteúdo do chip SPI
- O patch da BIOS era composto por duas etapas
- Com
UEFIPatch, a referência de GUID da página de BIOSDate/Timefoi alterada para apontar para a páginaAdvanced - Um patch de bytes separado forçava o TPM para
MFG Mode, para que o Boot Guard não detectasse a modificação da BIOS
- Com
- Na BIOS 1.37, aplicar só o primeiro patch fazia o notebook emitir bipes e não inicializar; depois de aplicar também o segundo patch, a página Advanced apareceu
- Ao alterar
xDCI SupportparaEnabledemIntel Advanced Menu→PCI-IO Configuration→USB Configuration, o xDCI passou a aparecer após o boot- O
lspcimostrava00:14.1 USB controller [8086:9d30] - O kernel carregava automaticamente o driver
dwc3-pci - Surgia
dwc3.1.autoem/sys/class/udc/
- O
Porta xDCI e requisitos do cabo
- Para descobrir a qual porta USB externa o xDCI estava ligado, foi deixado o papel em
devicee conectado um pendrive em cada porta para testar- Em uma porta específica, o sistema operacional não detectava o pendrive, e ele voltava a funcionar quando o papel era restaurado para
host - Essa porta foi considerada a porta ligada ao xDCI
- Em uma porta específica, o sistema operacional não detectava o pendrive, e ele voltava a funcionar quando o papel era restaurado para
- Como a porta xDCI do ThinkPad era USB Type-A, foi necessário um cabo Type-A para Type-A macho-macho para conectar a um computador host
- Como a troca de papel não desligava a alimentação
VBUSda porta, foi usado um cabo com oVBUSinterrompido para evitar que oVBUSdos dois dispositivos ficasse diretamente conectado- No início, foram cortados dois cabos USB 2.0 para montar manualmente um cabo macho-macho com o
VBUSinterrompido - Depois, foram usados um PortaPow USB Power Blocker e um cabo USB 2.0 macho-macho
- No início, foram cortados dois cabos USB 2.0 para montar manualmente um cabo macho-macho com o
- Ao carregar o driver gadget
g_zero, outro notebook reconheceu corretamente o dispositivo USB de teste emulado - Segundo a atualização de 11 de junho de 2024, o DataPro USB 3.0 Super-Speed A/A Debugging Cable também interrompe
D-eD+do USB 2.0, o que impede a conexão High-Speed necessária para estabelecer a conexão SuperSpeed- Um cabo LogiLink CU0038 com
VBUSinterrompido manualmente funcionou para emulação de dispositivos SuperSpeed
- Um cabo LogiLink CU0038 com
Tentativa de ativação por software com registradores do PCH
- Para entender como a BIOS ativava o xDCI, foi examinado
Pch/Library/Private/PeiPchInitLib/PchXdci.cno código-fonte da BIOS Kaby Lake - O caminho de desativação do xDCI na BIOS desabilitava o xDCI tanto no PMC quanto no PSF
-
Alteração no PMC
- A ideia era limpar o bit #24
XDCI Function Disableno registradorNST_PG_FDIS_1do PMC, offset0x628, para desfazer o power gating do xDCI - Foi escrito um módulo de kernel reutilizando o mapeamento de
pmc_core_deviceepmc->regbasedo kernel Linux - Logo após o boot, o bit
ST_FDIS_LK#31 deST_PG_FDIS1estava definido, impedindo a alteração deNST_PG_FDIS_1 - Depois de suspender e reativar o notebook, o lock bit já não estava definido, e foi possível limpar o bit
XDCI Function Disable
- A ideia era limpar o bit #24
-
Alteração no PSF
- A BIOS desabilitava o xDCI definindo o bit
USB Dual Role (OTG) Function Disableno PSF2 PCR do Port ID0xBB,PID_PSF2 - O endereço do PCR era calculado combinando
PCH_PCR_BASE_ADDRESS 0xFD000000, o Port ID e o offset - O módulo de kernel mapeou o PSF2 PCR com
ioremap, mas os valores lidos eram0xffffffffe não mudavam - Mesmo revelando o P2SB, o resultado foi o mesmo
- O
RemoveSidebandAccessda BIOS isolavaPID_PSF2do IOSF-SB comEPMASK5e travava isso comMASKLOCK, impedindo que o sistema operacional reconfigurasse o PSF - O acesso ao PCH até permitiu mudar parte das configurações do PMC, mas a falha na reconfiguração do PSF impediu que isso virasse um método de ativação do xDCI
- A BIOS desabilitava o xDCI definindo o bit
Ativação por patch na NVRAM sem contornar o Boot Guard
- Como os valores de configuração da BIOS são armazenados na área de NVRAM do chip SPI, foi tentada uma forma de alterar apenas
xDCI Supportsem abrir a página Advanced oculta - Foi usado IFRExtractor-RS para extrair as informações UEFI IFR do módulo
Setup - A configuração
xDCI Supportficava armazenada na variável UEFIPchSetup- GUID da VarStore:
4570B7F1-ADE8-4943-8DC3-406472842384 - VarStoreId:
0x5 - VarOffset:
0x40 - Faixa de valores:
0x0ou0x1
- GUID da VarStore:
- Em
efivarfsno Linux, foi verificado/sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384- Os 4 primeiros bytes do arquivo
efivarfssão cabeçalho, então o valor real dexDCI Supportfica no offset0x44 - Com o xDCI desativado, o valor era
00; após ativá-lo pela página Advanced da BIOS, mudava para01
- Os 4 primeiros bytes do arquivo
- Ao tentar escrever diretamente essa variável do espaço de usuário ou da EFI Shell, surgia o erro
EFI_WRITE_PROTECTED- Mesmo removendo o atributo immutable do
efivarfs, aparecia o erroRead-only file system - Alterar pela EFI Shell com chipsec produzia o mesmo erro
- Mesmo removendo o atributo immutable do
- Ao localizar no dump original da BIOS lido com o programador SPI a sequência de bytes próxima de
PchSetup, alterar apenas o bit dexDCI Supportpara01e regravar, o xDCI foi ativado - Esse método ainda exige regravar o chip SPI, mas não precisa de patch da página Advanced nem de contorno do Boot Guard, e também não quebra o TPM
- Na BIOS 1.37, depois do patch na NVRAM, a atualização para 1.61 preservou o valor da configuração da BIOS, sem necessidade de reaplicar o patch
Emulando dispositivos USB com xDCI
- Todos os exemplos assumem que o xDCI está ativado na BIOS, que
intel_xhci_usb_sw-role-switchfoi alternado paradevicee que a porta xDCI está conectada a um host USB por um cabo comVBUSinterrompido -
Drivers gadget legados
- Os drivers gadget legados do subsistema Linux USB Gadget emulam um dispositivo USB de uma classe específica quando o módulo é carregado
g_mass_storageexpõe uma imagem de sistema de arquivos como um dispositivo USB de armazenamento em massa- Foi criada uma imagem FAT
disk.img, colocadoHi from xDCIemfile.txte carregadosudo modprobe g_mass_storage file=./disk.img stall=0 - No host USB, a unidade foi montada automaticamente e o conteúdo do arquivo pôde ser verificado
-
Raw Gadget
- Raw Gadget foi executado com o xDCI para testar o exemplo de teclado USB
- No início, ele travava durante o tratamento de
SET_CONFIGURATION - A causa era que
dwc3e alguns drivers UDC presumem que podem reconhecer imediatamente uma control request de comprimento zero sem consultar o driver gadget - Após aplicar ao Raw Gadget o patch de contorno e também corrigir o GadgetFS, a emulação do teclado funcionou
- O comportamento relacionado foi documentado no commit de patch de documentação
Uso com syzkaller e Facedancer
- syzkaller pode usar o Raw Gadget para fazer fuzzing externo da pilha USB do kernel Linux
- O fuzzing USB padrão do syzkaller usa Dummy HCD/UDC para conectar internamente um dispositivo USB virtual a um controlador host
- Para usar o xDCI, o código do syzkaller que especifica o UDC foi alterado de
dummy_udcparadwc3-gadget,dwc3.1.auto - Foi executado com
syz-execprog -enable=usbum reproducer do bugWARNING in smsusb_start_streaming/usb_submit_urbencontrado pelo syzkaller- Em um notebook com kernel Ubuntu
5.15.0-91-genericatuando como host, o warning deusb_submit_urbfoi reproduzido - O bug era um
WARNINGcausado porque o driversmsusbnão validava o tipo de endpoint USB, sem comportamento prejudicial
- Em um notebook com kernel Ubuntu
- Facedancer é um framework em Python para emulação de dispositivos USB
- O backend do Facedancer baseado em Raw Gadget ainda é um protótipo e depende de patches out-of-tree do Raw Gadget
- Definindo
BACKEND=rawgadget,RG_UDC_DRIVER=dwc3-gadget,RG_UDC_DEVICE=dwc3.1.autoe executando o exemplorubber-ducky.py, tudo funcionou normalmente
- O USB Proxy baseado em Raw Gadget também rodou com xDCI, e o uso do xDCI permite transformar o notebook em uma ferramenta de sniffer USB ou USB Man-in-the-Middle
Possibilidades em outros dispositivos e por software
- Pode ser possível ativar xDCI em outros PCs além do ThinkPad X1 Carbon 6th Gen
- No caso mais simples, pode bastar ativar o xDCI nas configurações da BIOS
- Também é preciso haver suporte de ACPI e role switching, e a porta xDCI precisa estar ligada a uma porta externa
- Outros ThinkPads também podem ter a configuração de BIOS do xDCI oculta e protegida, exigindo regravação do chip SPI
- O método via NVRAM pode ser aplicado sem contornar o Boot Guard
- Em alguns sistemas mais novos, o chip SPI pode ser protegido contra regravação por RPMC, e esses chips podem ter um
Rno nome, comoW25R128FW
- Segundo a atualização, Shiny Quagsire já ativou xDCI em um XPS 13 e em um Surface Go 1 alterando a variável
PchSetupcomgrub-mod-setup_var- Nesses dispositivos, a variável
PchSetupnão era protegida, permitindo um método puramente por software
- Nesses dispositivos, a variável
- Outra abordagem por software pode ser explorar vulnerabilidades da BIOS para alterar variáveis de NVRAM relacionadas ao xDCI, ou atacar a BIOS por DMA durante o boot para executar código arbitrário
- O “secret” do título se refere menos a algo ocultado de propósito e mais a um recurso não documentado
1 comentários
Opiniões no Hacker News
Sempre me perguntei por que não é comum usar um notebook como teclado e monitor universais para outros computadores.
É estranho comprar um teclado e um monitor novos para fazer manutenção em máquinas headless, já que o notebook que você já tem poderia cumprir esse papel.
O tablet Minisforum V3, que deve sair em breve, também tem entrada de vídeo, então pode ser usado como monitor externo, mas parece que teclado e mouse não serão compartilhados.
Seria ótimo se esse tipo de recurso se tornasse mais comum.
Dá para alternar o mouse e o teclado para uma porta externa e conectá-los por cabo a outra máquina; na lateral há duas portas HDMI, uma de saída e uma de entrada.
Com uma chave interna, dá para escolher se a fonte do monitor será a própria máquina do deck ou a entrada externa.
Basicamente, é um chip que captura o sinal HDMI da máquina headless e o expõe ao notebook via USB como uma webcam emulada; os componentes eletrônicos são pequenos o suficiente para caber dentro do cabo.
Para o teclado, não encontrei nenhuma boa solução além de usar um teclado sem fio padrão e, para as raras vezes em que preciso de mouse, comprar um com trackpad embutido.
Pelo que ouvi, o USB 4 tem um modo que possibilita isso.
https://web.archive.org/web/20180610141436/http://anselm.hoffmeister.be/computer/hidclient/index.html.en
https://github.com/benizi/hidclient
Isso me lembra um caso de alguns anos atrás envolvendo algo que Travis Goodspeed fez.
Uma smart TV recebia atualizações de firmware por arquivos em um pendrive USB comum; a TV lia o arquivo do começo ao fim para verificar a assinatura digital e depois o lia novamente para fazer a atualização.
Um dispositivo fingindo ser armazenamento USB poderia enviar o arquivo de firmware do fabricante na primeira leitura e, na segunda, enviar um firmware não oficial.
https://en.m.wikipedia.org/wiki/Time-of-check_to_time-of-use
Muito interessante. Venho pesquisando opções parecidas que seriam viáveis.
Tenho um servidor NAS potente para o qual fico procurando desculpas de uso, e também tenho conexões de 40G e 10G espalhadas pela casa.
O PS5 e o XBox usam discos rígidos USB como armazenamento adicional.
Fui ver se seria possível expor o armazenamento do NAS ao PS5 e ao XBox, e é possível. Basta montar um compartilhamento do NAS via iSCSI ou NFS e então, com o módulo g_mass_storage, emular um dispositivo de armazenamento USB e expor esse armazenamento ao host USB.
No momento, além de tempo e custo, o grande obstáculo é a largura de banda que esse sistema entregaria. O ganho não é tão grande.
O Raspberry Pi é conhecido por suportar USB-OTG, mas fica limitado à velocidade do USB 2.0, e a maioria dos outros SBCs da mesma categoria que encontrei também era assim. A exceção foi o RockPi4; como o RockPi tem uma porta Ethernet gigabit, saturando a Ethernet seria possível fornecer velocidades estáveis de HDD tanto para o PS5 quanto para o Xbox.
Seria bem interessante criar uma solução capaz de passar de 1GbE usando uma placa de rede PCIe customizada ou uma placa ExpressCard, porque aí daria para saturar de verdade uma interface USB 3.0.
Ainda é preciso um cliente para se comunicar com o servidor, mas parece funcionar bem.
Estou pensando em manter um “cliente USB leve” na mesa, conectar os dispositivos USB nele e então anexá-los ou alterná-los para qualquer host físico ou host de VM desejado no laboratório.
Imagino que seja NAS → SBC → PS5; ou seria conectar o NAS diretamente ao PS5 com um cabo USB?
Também queria saber como fica a execução de conteúdo no PS5. Pelo que entendo, o NVMe interno precisa atender a uma determinada velocidade; isso não se aplica a unidades externas?
Na verdade, o NanoPi R6S tem, além de uma porta gigabit, duas portas Ethernet 2.5G.
Obrigado pelo texto tão detalhado. A qualidade é ótima.
O fato de isso ter sido possível me dá esperança de que talvez dê para montar algo como Synergy / Mouse Without Borders sem rede, usando apenas um cabo USB modificado.
Para quem precisa controlar vários computadores ao mesmo tempo, é um caminho muito bom.
Ainda assim, a abordagem proposta parece interessante.
Recentemente pesquisei algo parecido: eu queria conectar duas máquinas USB-C com um único cabo USB-C para ter comunicação a 10 Gbps
Infelizmente, a maioria das placas Ryzen ainda não tem Thunderbolt, e com Thunderbolt isso seria suportado nativamente com facilidade
Controladores USB de “dupla função” também eram bem raros antes de USB 3.2/4.0 e, como abordado neste texto, mesmo quando era possível, muitas vezes não havia suporte
Parece completamente estranho que seja tão difícil colocar duas máquinas em rede usando um cabo USB-C sem Thunderbolt
Também gostei da parte em que o bit de bloqueio é liberado depois da suspensão. Esse tipo de problema é muito comum. Por exemplo, é um método muito comum também para tirar dispositivos SATA de um estado que impede o secure erase
A profundidade é impressionante
Poder usar um PC como dispositivo USB abre muitas possibilidades interessantes
É um pouco lamentável que a opção xDCI necessária exista no hardware deste dispositivo, mas não esteja exposta, e que seja preciso hackear o firmware para acessá-la
O hardware permite, mas o fabricante simplesmente deixou desativado e bloqueou os controles
Fico me perguntando se a Lenovo usa isso como um caminho para depurar um ThinkPad a partir de outro ThinkPad
https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/secure-coding/intel-debug-technology.html
Atualização: provavelmente sim
https://www.youtube.com/watch?v=ExUvQa_jB7c
É um vídeo sobre depuração de firmware Intel com DCI e USB 3.0
A parte “Mas lidar com o Raspberry Pi é trabalhoso: conectar cabos, inicializar a placa, acessar o shell etc.” provavelmente poderia ter sido resolvida configurando USB OTG
Daria para fazer o dispositivo conectado fornecer energia, abrir o shell e então tratar tudo com um script
Assim seria possível configurar montagens ou executar comandos via SSH, e provavelmente até montar o dispositivo
Ainda assim, recomendo a tentativa de entender o próprio dispositivo e ler o kernel. É algo em que quero continuar melhorando, com aquela ideia de que nós mesmos devemos consertar nossos equipamentos
Eu mesmo já fiz isso
Isso me lembrou muito a cultura hacker do início da internet, a ponto de bater uma nostalgia. É um texto realmente excelente
Quando ESR falava sobre se tornar um hacker, sobre hackers no sentido de Hacker News, ele se referia exatamente a esse tipo de pessoa
A combinação de curiosidade, persistência e competência técnica é extremamente rara e muito impressionante
Tenho um sistema baseado em Celeron N3350/Pentium N4200/Atom E3900, e o BIOS expõe uma chave xDCI
Ao ativá-la, aparecem algumas outras opções e, ao inicializar no Linux, vejo o dispositivo PCI
USB controller: Intel Corporation Device 5aaa (rev 0b)Mas o nó de dispositivo UDC não aparece. Acho que vou investigar um pouco mais com as pistas do texto original