
Loongson LA464/LA664プロセッサにおいて、LASXベクトルレジスタの未定義上位ビットを介したマイクロアーキテクチャデータリークを実証する概念実証。ZenBleedに類似。
LoongBleed はハードウェア脆弱性であり、概念的には ZenBleed (CVE-2023-20593) に類似しています — LSX (128ビット SIMD) と LASX (256ビット SIMD) の両方を実装した Loongson LA464/LA664 プロセッサに影響を与えます。
LoongArch では、LSX の $vr レジスタ (128ビット) は LASX の $xr レジスタ (256ビット) の下半分とエイリアスしています。LSX 命令と基本的な浮動小数点演算は、下位 128 ビット (またはその一部) のみを操作するように定義されており、対応する $xr レジスタの上位ビットは未定義です。しかし、マイクロアーキテクチャ上の欠陥により、これらの操作は $xr の上位 128 ビットを通じてデータを漏洩させる可能性があり、特権境界を越えたり SMT 兄弟スレッド間で機密データを露出させます。
独立発見に関する注記 — 同じ根本的なハードウェア欠陥は、CISPA Helmholtz Center for Information Security の研究者らによって LoongLeak として独立に発見・公開されました (https://loongleakattack.com/)。これは USENIX Security 2026 において「LoongLeak: Architectural Cross-Privilege-Boundary Data Leakage on LoongArch CPUs」として発表されました。我々の研究は LoongLeak チームとは独立に開発されましたが、両グループは Loongson LA464/LA664 プロセッサが LASX
$xrレジスタの未定義の上位ビットを通じてデータを漏洩させるという同じ結論に達しました。なお、我々が漏洩を引き起こすために使用する命令は、LoongLeak 論文で報告されているものと同一ではありません。我々の PoC は、同じ根本的なハードウェア欠陥を再現するために異なるガジェット群 (vor.v、vld、fld.d、fld.s) に依存しています。さらに、漏洩はvor.vのような純粋なレジスタ間命令 (メモリロードを伴わない) によって引き起こされる可能性があるため、我々の分析では根本原因は物理レジスタの再利用である可能性が高いと示唆されています。再利用された物理レジスタの上位ビットがクリアされず、以前のレジスタ占有者からの古いデータが漏洩するのです。これは、漏洩データを L1 データキャッシュに帰属させる LoongLeak 論文の分析とは異なります。
概念実証 (PoC) は次のように動作します:
xvld を介して全ゼロデータを $xrN レジスタにロードします。xvst を介して完全な 256 ビットレジスタをストアして戻します。PoC はこのガジェットを、物理コアに固定されたスレッド上で 16 個のアーキテクチャベクトルレジスタ ($xr0–$xr15) にわたって繰り返し実行します。命令の後に現れる非ゼロ値は、マイクロアーキテクチャが古いデータまたはクロスコンテキストのデータをアーキテクチャレジスタ状態に伝播させたことを示します。
PoC は複数のテスト命令をサポートしており、--gadget で選択できます:
LA664 では、4 つのガジェットすべてが漏洩を露呈し、ベクトルあたり最大 192 ビットを漏洩します。LA464 では、vld、fld.d、fld.s が漏洩し (ベクトルあたり最大 224 ビット)、デフォルトの vor.v ガジェットは 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
被害者スレッドが 1 つの論理 CPU 上で機密データを処理している間、PoC はその SMT 兄弟上でレジスタをプローブします。スヌーピングスレッドは、漏洩した上位ビットの中に被害者のデータの断片を観察できます。
# 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
自動セットアップには、提供されているスクリプトを使用します:
./poc_la664.sh
これは CPU 1 (CPU 0 の SMT 兄弟) 上で sort ワークロードを起動し、CPU 0 上でデフォルトガジェットを使って LoongBleed を起動します。
被害者スレッドが 1 つの CPU 上で機密データを処理している間、PoC は同じコア上でレジスタをプローブします。デフォルトの vor.v ガジェットは LA464 では漏洩しないため、--gadget vld が必要です。
# 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
自動セットアップには:
./poc_la464.sh
これは CPU 0 上で sort ワークロードを起動し、--gadget vld を指定して LoongBleed を起動します。
PoC は外部依存のない単一ファイルの C++ プログラムです。
g++ -std=c++11 -O2 -march=native -pthread -o loongbleed_poc loongbleed_poc.cpp
または、提供されているスクリプトを使用します:
./run.sh
# or, on LA464:
./run.sh --gadget vld
漏洩が検出され、漏洩したバイトに少なくとも 8 文字の連続した印刷可能 ASCII 文字 (0x20–0x7e) が含まれる場合、PoC は次を出力します:
[cpu 0] LEAK chunk=14 data=0x7461646e756f4620_6572617774666f53_0000000000000000_0000000000000000 ascii=............Software Foundat
$xr0–$xr15) のうちどれがトリガーしたか$xrN から読み戻された完全な 256 ビット値。data3_data2_data1_data0 として表示され、ここで:
data0 = ビット [63:0] (結果の最下位 64 ビット)data1 = ビット [127:64] (下位 128 ビット半分の上位 64 ビット)data2 = ビット [191:128] (上位 128 ビット半分の下位 64 ビット)data3 = ビット [255:192] (上位 128 ビット半分の上位 64 ビット). として表示されます。上位 128 ビット (data2 または data3) に非ゼロ値があれば、マイクロアーキテクチャのデータ漏洩を示します。
この脆弱性は、Chips and Cheese の記事 「Loongson's LSX and LASX Vector Extensions」を読んでいる際に発見されました。この記事は、ベクトル命令がランダムなデータの残留物を残す可能性があると指摘していました。これにより、レジスタリネーミングがレジスタをクリアしない可能性があるという仮説 — ZenBleed に類似したメカニズム — を立てるに至り、理論上はカーネル空間のデータを漏洩させることが可能になります。その後、この仮説を検証する実験を行い、漏洩は実際に発生し、Loongson 3A5000 と 3A6000 の両方で再現しました。
このプロジェクトは教育およびセキュリティ研究目的のみで提供されています。
| ガジェット | 命令 | 説明 | LA664 で漏洩 | LA464 で漏洩 |
|---|
vor | vor.v $vrN, $vrN, $vrN | $vrN と自身のビット単位 OR | はい | いいえ |
vld | vld $vrN, … | メモリから $vrN への 128 ビットロード | はい | はい |
fld.d | fld.d $fN, … | $fN への 64 ビット浮動小数点ロード ($vrN 下位 64 ビットのエイリアス) | はい | はい |
fld.s | fld.s $fN, … | $fN への 32 ビット浮動小数点ロード ($vrN 下位 32 ビットのエイリアス) | はい | はい |