
Prova de conceito demonstrando um vazamento de dados microarquitetural nos processadores Loongson LA464/LA664 através de bits superiores indefinidos dos registradores vetoriais LASX, semelhante ao ZenBleed.
LoongBleed é uma vulnerabilidade de hardware, conceitualmente semelhante ao ZenBleed (CVE-2023-20593) — afetando processadores Loongson LA464/LA664 que implementam tanto LSX (SIMD de 128 bits) quanto LASX (SIMD de 256 bits).
No LoongArch, os registradores LSX $vr (128 bits) são alias da metade inferior dos registradores LASX
$xr (256 bits). As instruções LSX e as operações básicas de ponto flutuante
são definidas apenas para operar sobre os 128 bits inferiores (ou um subconjunto destes); os
bits superiores do registrador $xr correspondente são indefinidos. No entanto, devido
a uma falha microarquitetural, essas operações podem vazar dados através dos
128 bits superiores de $xr, expondo dados sensíveis através de fronteiras de privilégio ou
entre irmãos SMT.
Nota sobre descoberta independente — A mesma falha de hardware subjacente foi descoberta e publicada de forma independente por pesquisadores do CISPA Helmholtz Center for Information Security como LoongLeak (https://loongleakattack.com/), apresentada na USENIX Security 2026 como "LoongLeak: Architectural Cross-Privilege-Boundary Data Leakage on LoongArch CPUs". Nosso trabalho foi desenvolvido independentemente da equipe LoongLeak; ambos os grupos chegaram à mesma conclusão de que os processadores Loongson LA464/LA664 vazam dados através dos bits superiores indefinidos dos registradores LASX
$xr. Observe que as instruções que usamos para acionar o vazamento não são idênticas às relatadas no artigo do LoongLeak: nosso PoC depende de um conjunto diferente de gadgets (vor.v,vld,fld.d,fld.s) para reproduzir a mesma falha de hardware subjacente. Além disso, como o vazamento pode ser acionado por instruções puras de registrador-registrador comovor.v(sem carregamento de memória envolvido), nossa análise sugere que a causa raiz é provavelmente a reutilização de registradores físicos: os bits superiores de um registrador físico reutilizado não são limpos, vazando dados obsoletos de um ocupante anterior do registrador. Isso difere da análise do artigo do LoongLeak, que atribui os dados vazados ao cache de dados L1.
A prova de conceito funciona da seguinte forma:
$xrN via xvld.xvst.O PoC executa esse gadget repetidamente em 16 registradores vetoriais arquiteturais
($xr0–$xr15) em threads fixadas a núcleos físicos. Valores diferentes de zero que
aparecem após a instrução indicam que a microarquitetura propagou dados obsoletos ou
de contexto cruzado para o estado do registrador arquitetural.
O PoC suporta múltiplas instruções de teste, selecionáveis via --gadget:
Em LA664, todos os quatro gadgets expõem o vazamento, vazando no máximo 192 bits por
vetor. Em LA464, vld, fld.d e fld.s vazam (no máximo 224 bits por
vetor); o gadget padrão vor.v não vaza em LA464.
Usage: ./loongbleed_poc [OPTIONS]
Options:
-a, --all Launch one thread pinned to each physical core.
By default only thread on CPU 0 is launched.
-g, --gadget [vor|vld|fld.d|fld.s]
Use different instructions for testing.
-h, --help Show this help and exit.
# Single-thread mode on CPU 0
./run.sh
# Single-thread mode with vld gadget (required for LA464)
./run.sh --gadget vld
# All physical cores, default gadget
./run.sh -a
# All cores with fld.d gadget
./run.sh --all --gadget fld.d
Uma thread vítima processa dados sensíveis em uma CPU lógica enquanto o PoC sonda registradores em seu irmão SMT. A thread espiã pode observar fragmentos dos dados da vítima nos bits superiores vazados.
# Terminal 1 — start LoongBleed on CPU 0
./run.sh
# Terminal 2 — victim workload on the SMT sibling (CPU 1)
while true; do numactl -C 1 sort < /etc/shadow > /dev/null; done
Para uma configuração automatizada, use o script fornecido:
./poc_la664.sh
Isso gera uma carga de trabalho sort na CPU 1 (o irmão SMT da CPU 0) e inicia
o LoongBleed na CPU 0 com o gadget padrão.
Uma thread vítima processa dados sensíveis em uma CPU enquanto o PoC sonda
registradores no mesmo núcleo. Requer --gadget vld, pois o gadget padrão vor.v
não vaza em LA464.
# Terminal 1 — start LoongBleed on CPU 0
./run.sh --gadget vld
# Terminal 2 — victim workload on the same core
while true; do numactl -C 0 sort < /etc/shadow > /dev/null; done
Para uma configuração automatizada:
./poc_la464.sh
Isso gera uma carga de trabalho sort na CPU 0 e inicia o LoongBleed com --gadget vld.
O PoC é um programa C++ de arquivo único sem dependências externas.
g++ -std=c++11 -O2 -march=native -pthread -o loongbleed_poc loongbleed_poc.cpp
Ou use o script fornecido:
./run.sh
# or, on LA464:
./run.sh --gadget vld
Quando um vazamento é detectado e os bytes vazados contêm uma sequência de pelo menos 8 caracteres ASCII imprimíveis contíguos (0x20–0x7e), o PoC imprime:
[cpu 0] LEAK chunk=14 data=0x7461646e756f4620_6572617774666f53_0000000000000000_0000000000000000 ascii=............Software Foundat
$xr0–$xr15) foi acionado$xrN após a
instrução, exibido como data3_data2_data1_data0 onde:
data0 = bits [63:0] (64 bits mais baixos do resultado)data1 = bits [127:64] (64 bits superiores da metade inferior de 128 bits)data2 = bits [191:128] (64 bits inferiores da metade superior de 128 bits)data3 = bits [255:192] (64 bits superiores da metade superior de 128 bits)..Qualquer valor diferente de zero nos 128 bits superiores (data2 ou data3) indica um
vazamento de dados microarquitetural.
A vulnerabilidade foi descoberta durante a leitura do artigo do Chips and Cheese "Loongson's LSX and LASX Vector Extensions". O artigo observou que instruções vetoriais podem deixar para trás algum resíduo de dados aleatórios. Isso nos levou a hipotetizar que o renomeamento de registradores pode não limpar os registradores — um mecanismo semelhante ao ZenBleed — o que, em teoria, permitiria vazar dados do espaço do kernel. Em seguida, realizamos experimentos para verificar essa hipótese; o vazamento de fato ocorre e se reproduz tanto no Loongson 3A5000 quanto no 3A6000.
Este projeto é fornecido apenas para fins educacionais e de pesquisa em segurança.
| Gadget | Instrução | Descrição | Vaza em LA664 | Vaza em LA464 |
|---|
vor | vor.v $vrN, $vrN, $vrN | OR bit a bit de $vrN com ele mesmo | Sim | Não |
vld | vld $vrN, … | Carregamento de 128 bits da memória para $vrN | Sim | Sim |
fld.d | fld.d $fN, … | Carregamento de ponto flutuante de 64 bits para $fN (alias dos 64 bits inferiores de $vrN) | Sim | Sim |
fld.s | fld.s $fN, … | Carregamento de ponto flutuante de 32 bits para $fN (alias dos 32 bits inferiores de $vrN) | Sim | Sim |