
このリポジトリは、FatFs における確認済みの6件のセキュリティ脆弱性と、テストハーネス、ファザー、およびスタンドアロンのエクスプロイトディスクイメージ生成ツールを文書化したものです。
元のFatFsソースコードは、FatFs-R0.16 ディレクトリにあります。
このプロジェクトは、2017年に実施したセキュリティ評価への回帰です。その当時、手動監査と数日間にわたるファジングによって、FatFsドライバの基本的ではあるが興味深くないバグがいくつか特定されました。9年後の2026年3月、私たちはVisual Studio Code、GitHub Copilotの「auto」モード、およびいくつかの基本的なプロンプトを使用して、特定のループ、ハーネス、スキルを一切使わずにこのプロジェクトを再訪しました。結果は驚くべきものでした。手動監査で見落とされていたバグが、LLMを使って新しい入力を伴うファザーを自動的に構築することで、簡単に見つかるようになったのです。この取り組みでは興味深いバグが見つかっただけでなく、さまざまな組み込み開発シナリオにわたって悪用可能性を検証するプロセスも自動化されました。
詳細なメモについては、以下のファイルを参照してください:
FatFsは、ChaN (elm-chan.org) によってCで書かれた、移植可能でロイヤリティフリーのFAT/exFATファイルシステムライブラリです。OSに依存せず、リソースが制約された組み込みシステム向けに設計されており、通常はファームウェアに直接コンパイルされます。FAT12、FAT16、FAT32、exFATに加え、オプションのLFN(長いファイル名)およびGPTパーティションサポートをサポートしています。
FatFsは小さく、自己完結型であり、寛容なライセンスであるため、マイクロコントローラファームウェアにおける事実上の標準FAT実装となっています。このライブラリは、公式SDK、RTOS、ブートローダー、アプリケーションフレームワークにそのままベンダリングされています。つまり、単一の上流の脆弱性が、ff.cをコピーしたすべての下流プロジェクトに伝播するということです。
以下のプロジェクトは、脆弱性のあるバージョンのFatFsを同梱していることが確認されています。完全な分析、プロジェクトごとの伝播経路、およびセキュリティ連絡先情報については、02_CRITICAL.md を参照してください。
FatFsにはCVEの履歴がなく、セキュリティメーリングリストもなければ、パッチ通知の仕組みもありません。ff.cをベンダリングしているすべての下流プロジェクトは、通常は影響を受けていることを知らないまま、これらの脆弱性を独自に発見し、トリアージし、パッチを当てる必要があります。つまり、公表から広範な修正までの期間は、日単位ではなく年単位になるでしょう。したがって、実際の攻撃対象は1つのソフトウェアアプリケーションやサービスではなく、数十の独立したコードベースにわたる数千万台のデバイスであり、その多くは決してパッチを受け取ることはありません。
典型的な悪用シナリオは悪意のあるSDカードです。数秒の物理アクセスを持つ攻撃者が、民生用カメラからドローン、3Dプリンタ、その他数千もの製品ファミリーに至るデバイスのストレージメディアを交換します。この一連の脆弱性はすべて、細工されたFATイメージをマウントするだけでトリガーでき、それはほとんどの場合、ユーザーの操作を必要とせず挿入時に自動的に発生します。とはいえ、物理アクセスだけが経路ではありません。
FAT形式のアップデートパッケージをネットワークソースから取り込むデバイス(OTAアップデートフレームワークやドラッグアンドドロップのブートローダーアップデートなど)は、アップデートパイプラインに悪意のあるイメージを届けられるあらゆる攻撃者によって悪用可能です。サプライチェーンへの侵害、平文HTTPアップデートフィードへのAitMインジェクション、またはホビーファームウェア配布ポータルに投稿された悪意のあるイメージなどが該当します。OTA経路は、FatFsでマウントする前にアップデートコンテナのエンドツーエンドの認証付き完全性検証を行わないすべてのデバイスにおいて、完全にリモートで攻撃可能です。
CVE-2026-6682 - 攻撃者が制御する読み取り長につながる整数オーバーフロー
特定のフィールドをオーバーフローさせるように設定したFAT32ボリュームを細工することで、攻撃者は被害デバイスに対して、攻撃者が選択したバイト数を固定バッファに読み込ませることができます。これはコード実行への直接的な経路です。ベアメタルの組み込みターゲットでは、このエクスプロイトは決定的であり、ヒープスプレー、ブルートフォース、情報漏えいを前提条件として必要としません。
攻撃者は、ターゲットがマウントするFATボリュームを制御する必要があります。ほとんどのデバイスでは、SDカードを交換するための物理アクセスを意味します。ネットワーク経由でファームウェアアップデートを受け入れるデバイスや、FatFsが解析した後でのみアップデートパッケージの完全性を信頼するデバイスは、リモートで悪用可能です。
CVE-2026-6683 - exFAT同期におけるゼロ除算
R0.16より前のFatFsを実行しているデバイスに、細工されたexFATボリュームを届けられる攻撃者は、その後の任意の書き込みでクラッシュを保証できます。FatFs R0.16は、書き込みが発生する前に細工されたボリュームを拒否する可能性のある、マウント時の部分的なガードを追加しましたが、根本的な算術欠陥は完全には修正されていません。FAT形式のメディアへの書き込みによってOTAファームウェアアップデートを適用するデバイスに対しては、トリガーが成功すると一撃のリモート文鎮化になります。アップデートプロセスが書き込み途中でクラッシュし、ハードウェアデバッガへの物理アクセスなしにはデバイスを復旧できない可能性があります。
攻撃者は、標的のデバイスに自身が制御するexFATボリュームをマウントさせ、その後何らかの書き込みまたは同期操作を実行させる必要があります。悪意のあるSDカードのシナリオはほとんどの組み込みデバイスをカバーします。リモート悪用の場合、標的のOTAパイプラインが、完全性を最初に検証することなく、攻撃者が提供したイメージを受け入れてマウントする必要があります。
CVE-2026-6684 - GPTパーティションスキャンにおける無限ループ
単一のフィールドを最大値に設定したGPTディスクイメージを配信すると、標的は電源が切られるまでディスクセクタの読み取りをループし続けます。ウォッチドッグなしで動作するブートローダーやベアメタルファームウェアに対しては、これは恒久的な文鎮化です。デバイスは二度とブートを完了できません。この脆弱性はFatFs R0.16で修正されているため、影響を受けるのは古いリリースをベンダリングしているデバイスだけです。
攻撃者は、標的に自身が制御するGPTフォーマットのディスクをマウントさせる必要があり、標的は64ビットLBAサポートを有効にしたR0.16より前のFatFsビルドを実行している必要があります。ブートローダーがここで最も魅力的なターゲットとなるのは、まさにウォッチドッグや復旧経路を持たない傾向があるからです。
CVE-2026-6686 - EOFを超えたシーク後に古いクラスタデータが読み取り可能
ファイルの終端を超えてシークしてファイルを拡張しても、FatFsは新しく割り当てられたストレージをゼロで埋めません。削除されたファイルによって以前にそれらのセクタに書き込まれたデータは、拡張されたファイルを次に開いたプロセスによって読み取られます。OTAステージング領域でファームウェアイメージを循環させるデバイスや、ブートローダーとアプリケーションの間でSDカードを共有するデバイスでは、以前のファームウェアブロブ、キー、その他の機密コンテンツが、権限の低い読み取り側に露出する可能性があります。
攻撃者は、標的のFATボリューム上で、シーク操作によって拡張されたファイルへの読み取りアクセスが必要です。これは主にローカルまたは物理アクセスのシナリオです。
CVE-2026-6687 - exFATボリュームラベルによるスタックオーバーフロー
過大なラベルを持つexFATボリュームを供給すると、アプリケーションがf_getlabel()を呼び出したときに、FatFsが呼び出し元のラベルバッファをオーバーフローさせます。STのSTM32CubeMXコードジェネレータは、生成するすべてのFatFs対応プロジェクトで脆弱なバッファサイズを出力するため、この脆弱性は、膨大でほとんどカタログ化されていない商用STM32ファームウェア群に存在します。スタッククッキーやASLRがないベアメタルのCortex-Mデバイス(一般的なケース)では、これは一撃のコード実行プリミティブです。
攻撃者は、標的に自身が制御するexFATボリュームをマウントさせ、その後f_getlabel()を呼び出させる必要があります。FatFsライブラリはこれを内部的に呼び出しません。アプリケーションが明示的に呼び出す必要があります。ほとんどのプロジェクトは、独自のマウント時初期化の一部としてこれを行うため、実際にはそれらのプロジェクトでは攻撃者のさらなる操作は不要です。
CVE-2026-6688 - ディレクトリ一覧における長いLFNファイル名によるバッファオーバーフロー
FATディレクトリに長い名前のファイルを置くことで、攻撃者は、ディレクトリを反復処理する際にその名前を格納するために呼び出し側アプリケーションが使用するバッファをオーバーフローさせることができます。オーバーフローはファイル名の長さに比例し、最大255バイトになります。この脆弱性はFatFs自体ではなく呼び出し側コードに存在するため、影響はターゲットによって異なります。ただし、ディレクトリを反復処理し、長さを確認せずにファイル名を固定サイズのバッファにコピーするアプリケーションはすべて影響を受けます。
攻撃者は、標的に自身が制御するFATボリューム上のディレクトリを走査させる必要があります。exFATは不要で、FAT12、FAT16、FAT32で機能します。FatFs設定で長いファイル名サポートが有効になっている必要がありますが、これはすべての主要ディストリビューションでデフォルトかつ推奨される設定です。
FatFs R0.16およびそれ以前のバージョンで、6つの異なるバグが特定されました。
mount_volume() 内のFAT32整数オーバーフロー → 攻撃者が制御する finfo.fsize場所: ff.c mount_volume() - fasize *= fs->n_fats
BPB_FATSz32が大きな値を生成するように細工されると、DWORD乗算オーバーフローが発生します。BPB_FATSz32 = 0x80000001かつNumFATs = 2の場合:```c
fasize = 0x80000001;
fasize *= 2; // DWORD overflow → 0x00000002
切り詰められた `fasize` により、`fs->database`(データ領域の先頭)が FAT 領域内に配置されてしまいます。ディスクイメージを制御できる攻撃者は、重複するセクタに偽のディレクトリエントリを配置し、`f_stat()` に攻撃者が制御した `finfo.fsize` を返させることができます。その後に `f_read(fp, buf, finfo.fsize, &br)` を呼び出すアプリケーションが、そのカウントを `sizeof(buf)` と比較して制限していない場合、宛先バッファは完全に攻撃者が制御するバイト列であふれ、RCE への直接的な経路になります。
**最悪の影響:** FatFs からファイルサイズを読み取り、それを読み取り長として使用する任意の組み込みデバイス上でのリモートコード実行(ヒープまたはスタックオーバーフロー)。
---
### CVE-2026-6683 - `sync_fs()` におけるゼロ除算 (exFAT)
**場所:** `ff.c` `sync_fs()` - `(n_fatent - 2 - free_clst) * 100 / (n_fatent - 2)`
`BPB_NumClusEx = 0` の場合、`n_fatent = 2` となり、除数 `(n_fatent - 2)` は `0` になります。これは、細工された exFAT ボリュームに対する任意の書き込みまたは同期操作で発生し、SIGFPE / ハードフォールトを引き起こしてターゲットをクラッシュさせます。
FatFs R0.16 は、マウント時にこの問題を部分的に防ぎます(`NumClusEx = 0` の場合、ビットマップクラスタの検証が失敗します)。古いバージョン(R0.14b(ArduPilot、Mbed OS)、R0.15(RIOT OS、STM32)、R0.13c(MicroPython))にはそのような保護がなく、無条件にクラッシュします。
**最悪の影響:** 細工された exFAT ボリュームへの任意の書き込みにおけるサービス拒否 / システムクラッシュ。OTA アップデート中はデバイスをブリックさせる可能性があります。
---
### CVE-2026-6684 - `find_volume()` における無制限の GPT パーティション走査ループ (pre-R0.16)
**場所:** `ff.c` `find_volume()` - `for (i = 0; i < n_ent; i++) disk_read()`
`FF_LBA64 = 1` の場合、`find_volume()` は FAT パーティションを検索するためにすべての GPT パーティションエントリを反復処理します。pre-R0.16 ビルドでは、ループ回数は上限なしでディスク上の `GPTH_PtNum` フィールド(0–0xFFFFFFFF)から直接取得されます。`GPTH_PtNum = 0xFFFFFFFF` を設定した細工済み GPT イメージは、関数が「not found」を返すまでにおよそ 10 億回のディスク読み取りを引き起こし、システムを永久にハングさせます。
R0.16 では、ループに入る前に CRC32 を検証し、`PtNum ≤ 128` を強制する `test_gpt_header()` が導入されました。
**最悪の影響:** マウント時の永続的なサービス拒否。ウォッチドッグのないデバイス(ブートローダー、ベアメタル FPGA ブート ROM)では、これによりシステムが完全に文鎮化(ブリック)します。
### CVE-2026-6686 - EOF を超えた `f_lseek()` による未初期化クラスタデータ
**場所:** `ff.c` `f_lseek()`:```c
if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) {
fp->obj.objsize = fp->fptr; // extend, but never zero-fill
fp->flag |= FA_MODIFIED;
}
EOF を超えるシークにより create_chain() が呼び出され、新しいクラスタが割り当てられますが、それらのセクタは決してゼロにされません。その後の拡張領域の読み取りでは、再利用されたクラスタ内に残存する、以前に削除されたファイルの内容という生の古いデータが返されます。
最悪の影響: 削除されたファイルの内容(古いファームウェアイメージ、秘密鍵、センサーデータ)が、権限の低い読み取り元や接続されたインターフェース経由で情報漏洩します。
XDIR_NumLabel 経由の f_getlabel() 内スタックバッファオーバーフロー場所: ff.c f_getlabel():```c
for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) {
wc = ld_16(dj.dir + XDIR_Label + si * 2);
nw = put_utf((DWORD)hs << 16 | wc, &label[di], 4);
di += nw;
}
exFAT仕様では `XDIR_NumLabel` は11文字に制限されています。 FatFs は
これを検証なしの生の `BYTE` (0–255) として読み取ります。 細工されたボリュームで
`XDIR_NumLabel = 128` の場合、`f_getlabel` は128文字を呼び出し元のバッファ
- 通常 STM32CubeMX によって生成される `char label[12]` または `char label[24]` -
に書き込み、スタックを最大244バイトあふれさせます。
**最悪の場合の影響:** exFATボリューム上の `f_getlabel()` を呼び出すすべての呼び出し元で、
スタックバッファオーバーフローが発生します。 典型的な脆弱性パターン (`char label[12]`) は
STM32CubeMX、AN3224、UM1721 によって生成されるすべてのプロジェクトに存在します。
---
### CVE-2026-6688 - 長いLFNファイル名による呼び出し元のスタック/ヒープオーバーフロー
**根本原因:** `FF_USE_LFN` が有効な場合、`f_readdir()` は `fno.fname` に
完全なLong File Name - 最大 `FF_LFN_BUF` (255) 文字。 呼び出し元は
SFN専用動作向けに書かれており、固定サイズのパスまたは名前バッファ (例:
`char path[16]`、`char name[14]`) を使用し、境界チェックなしで `fno.fname` を
コピーします。
複数のプロジェクトで見られる一般的な脆弱性パターン:```c
strcpy(entry->name, fno.fname); // Zephyr: entry->name[14]
sprintf(path, "0:/%s", fno.fname); // NodeMCU, ChibiOS demo, StarryPilot
sprintf(&cur_path[n], "/%s", fn); // Samsung TizenRT
最悪の影響: 細工されたFATボリューム上の任意のディレクトリ走査において、LFN長(最大255バイト)に比例したスタックまたはヒープのオーバーフローが発生します。entry->name[14] を241バイトあふれさせる細工されたSDカードは、Zephyrスケジューラのスタックフレームを確実に破壊します。
├── harness/ Security test harness and exploit tools
│ ├── Makefile Build system (see targets below)
│ ├── test_ffconf.h FatFs config for the harness (LFN+exFAT+LBA64)
│ ├── diskio_ramdisk.c/h In-memory block device (2 MiB RAM disk)
│ ├── ffunicode_stub.c Minimal Unicode stub (CP437 pass-through)
│ ├── test_harness.c Deterministic per-bug test suite (CVE-2026-6682 through CVE-2026-6688)
│ ├── rce_demo.c Standalone CVE-2026-6682 RCE demo: OTA struct-pointer overwrite
│ ├── libfuzzer_harness.c libFuzzer / AFL++ entry point
│ ├── exploit_disks.c Standalone disk-image generator (see below)
│ ├── build/ Compiled binaries
│ └── img/ Generated exploit disk images (*.img)
│
├── fuzzer/ Go corpus generator and structural fuzzer
│ ├── main.go Corpus builder + Go native fuzz targets
│ ├── fat_image.go FAT12/16/32/exFAT/GPT image construction helpers
│ └── corpus/ Seed corpus written by make corpus
---
## ハーネスのビルドターゲット
すべてのターゲットは `harness/` ディレクトリから実行します。 `clang` が必要です(または `CC=gcc` を設定)。
macOS で `afl` ターゲットをビルドするには、`brew install afl++` を実行し、その後 `sudo afl-system-config` を実行してシステムを準備します。
| ターゲット | 説明 |
|--------|-------------|
| `make` / `make test` | ASan + UBSan で決定論的テストスイートをビルドして実行します |
| `make rce_demo` | CVE-2026-6682 RCE デモをビルドして実行します(サニタイザなし、スタックプロテクタなし) |
| `make exploit_disks` | 14 個すべてのエクスプロイトディスクイメージをビルドして `harness/img/` に生成します |
| `make fuzz_asan` | libFuzzer バイナリ(`build/fuzz_fatfs`)をビルドします |
| `make afl` | AFL++ ターゲットをビルドします(`PATH` に `afl-clang-fast` が必要です) |
| `make corpus` | Go ジェネレータを使ってシードコーパスを `harness/corpus/` に生成します |
| `make clean` | `build/` と `img/` を削除します |
### クイックスタート```sh
# Run the full deterministic test suite
cd harness && make
# Run the CVE-2026-6682 RCE demo
make rce_demo
# Generate all exploit disk images
make exploit_disks
# Fuzz with libFuzzer (requires clang)
make fuzz_asan
build/fuzz_fatfs -max_len=2097152 corpus/
# Fuzz with AFL++
make corpus afl
afl-fuzz -i corpus/ -o findings/ -- build/afl_fatfs @@
make exploit_disks は harness/img/ に14個のRAWディスクイメージを生成します。
プロジェクト/脆弱性の組み合わせごとに1つです。 各イメージは生成時にバンドルされた FatFs で
マウントしてセルフテストされます。 イメージは物理的な SD カードに
書き込むことができます:```sh
dd if=harness/img/exploit_bug1_espidf.img of=/dev/sdX bs=512
| Image | Bug | Target project(s) | Effect |
|-------|-----|------------------|--------|
| `exploit_bug1_fat32.img` | CVE-2026-6682 | Generic | `f_read` 経由でポインタサイズのペイロードを配信します |
| `exploit_bug1_espidf.img` | CVE-2026-6682 | espressif/esp-idf | `finfo.fsize=16 MB` → `malloc`/`fread` ヒープオーバーフロー |
| `exploit_bug1_stm32.img` | CVE-2026-6682 | STMicro stm32-mw-fatfs | `finfo.fsize=1 MB` → 1 KB ファームウェアバッファのオーバーフロー |
| `exploit_bug1_keystone3.img` | CVE-2026-6682 | KeystoneHQ wallet | `finfo.fsize=512 KB` → OTA バッファのオーバーフロー |
| `exploit_bug1_ardupilot.img` | CVE-2026-6682 | ArduPilot / Mbed OS / RIOT / MicroPython | `finfo.fsize=2 MB` → ログ読み取りバッファのオーバーフロー |
| `exploit_bug2_exfat.img` | CVE-2026-6683 | ArduPilot / Mbed OS / MicroPython / RIOT | `BPB_NumClusEx=0` → `sync_fs` ゼロ除算 (R0.16 より前では SIGFPE) |
| `exploit_bug3_gpt.img` | CVE-2026-6684 | vivado-risc-v / tinyuf2 / circle | `GPTH_PtNum=0xFFFFFFFF` → 起動時に無限ループ (R0.16 より前) |
| `exploit_bug5_stale.img` | CVE-2026-6686 | RT-Thread / tinyuf2 / ArduPilot / RIOT | `f_lseek` の拡張により `0xAA` でシードされた削除済みクラスタのデータが露出 |
| `exploit_bug6_stm32.img` | CVE-2026-6687 | STMicro stm32-mw-fatfs | `XDIR_NumLabel=128` → CubeMX の `label[12]` に対して 117 バイトのオーバーフロー |
| `exploit_bug6_zephyr.img` | CVE-2026-6687 | Zephyr / ArduPilot / RIOT / MicroPython | `XDIR_NumLabel=255` → `label[24]` に対して 216 バイトのオーバーフロー |
| `exploit_bug7_max255.img` | CVE-2026-6688 | NodeMCU / ChibiOS / StarryPilot / TizenRT | 255 文字の LFN は 255 バイト未満の固定バッファをオーバーフローさせる |
| `exploit_bug7_zephyr.img` | CVE-2026-6688 | Zephyr | 14 文字の LFN → `entry->name[14]` に対して 1 バイトの NUL オーバーフロー |
| `exploit_bug7_grblhal.img` | CVE-2026-6688 | grblHAL | 1 バイト過剰: ガードが前のエントリをチェック; 11 文字の LFN が `dirent.name[12]` を NUL 1 バイト分オーバーフローさせる |
---
## 決定論的テストスイート (`test_harness.c`)
テストハーネスは、メモリ内に構築した手作りのディスクイメージで 6 つのバグを実行し、脆弱なコードパスに到達したことを確認します:
- **CVE-2026-6682** - `BPB_FATSz32=0x80000001` の FAT32 イメージを構築してマウントし、
`fs.database` が FAT 領域内に収まることを確認; 次に完全な
RCE チェーン (偽のディレクトリエントリ → 仕込まれた関数ポインタの `f_read` →
`rce_proof_of_execution()` の呼び出し) を実行します。
- **CVE-2026-6683** - `(n_fatent-2)` の除数を文書化し、算術パスを確認;
R0.16 がマウント時にイメージを拒否することをチェックします。
- **CVE-2026-6684** - `GPTH_PtNum=0xFFFFFFFF` の GPT イメージを構築し、
`test_gpt_header()` 経由で R0.16 がディスク読み取り 3 回以内にそれを拒否することを確認します。
- **CVE-2026-6686** - すべてのデータクラスタを `0xAA` で事前シードし、短いファイルを書き込み、
`f_lseek` で拡張してから読み戻し、古いバイトが可視であることを確認します。
- **CVE-2026-6687** - `XDIR_NumLabel=128` の exFAT イメージを構築し、
プローブバッファに対して `f_getlabel` を呼び出し、バイト 24 を超えるオーバーフローを数えます。
- **CVE-2026-6688** - 50 文字の LFN を持つ FAT16 ディレクトリを構築し、
`f_readdir` で読み取り、`fno.fname` の長さが一般的な呼び出し元バッファを超えることを確認します。
---
## CVE-2026-6682 RCE デモ (`rce_demo.c`)
CVE-2026-6682 の悪用チェーンを、組み込み OTA ファームウェア更新コードをモデルにした、自己完結型で現実的なデモです。 固定サイズのヘッダバッファの直後に関数ポインタコールバックが続く struct が宣言されています:```c
typedef struct {
uint8_t fw_header[128]; // buffer the developer reads into
uint32_t crc32;
uint32_t version;
void (*on_apply)(void); // callback - attacker target
} ota_ctx_t;
このデモは、DIR_FileSize = sizeof(ota_ctx_t) となるように細工したディスクイメージを構築し、
ペイロードセクタ内の正しいバイトオフセットに rce_win() のアドレスを配置し、
その後OTAチェッカーを実行する。 f_read は fw_header を越えて on_apply に書き込み、
その後の ctx.on_apply() 呼び出しが rce_win() を実行し、
rce_canary = 0xDEAD を設定する。
ビルドと実行: cd harness && make rce_demo
fuzzer/)Goファザーには2つのモードがある:
コーパス生成器 (go run . -out ./corpus または make corpus): 18個の構造化シードイメージを書き出す。
6つのバグクラス、3つのFATバリエーションすべて、
正常および不正なGPT、有効なFAT32イメージに対する50個のランダムな1バイト変異を
網羅する。
Goネイティブファザー (go test -fuzz=FuzzFAT32BPB): 構造的ファジングを
Go組み込みファザーでBPBフィールド値に対して行い、フィールド
間の関係がCを呼び出さずに成立することを検証する。
シードコーパスは、libFuzzerバイナリ (build/fuzz_fatfs) と
AFL++ターゲット (build/afl_fatfs) の両方に供給される。
このリポジトリには、Espressif QEMU ESP32エミュレータ内のESP-IDFファームウェア上でFatFs ディレクトリトラバーサルを利用した、ESP32関連のCVE-2026-6688呼び出し元オーバーフロー パターンを実証する自己完結型のDockerテストケースが含まれている。
現在のPoCイメージは意図的にハイブリッドになっている:
readdir() によって返される長いVFATファイル名を埋め込む。strcpy / strcat
パス組み立て) を模倣し、長いファイル名を固定32バイトバッファにコピーする。この最終的なコピーがCVE-2026-6688スタイルの条件である: 長いファイル名の無制限な使用による呼び出し元側オーバーフロー。``` cd esp32-qemu-test ./run.sh
または、あるいは:```
docker build -t fatfs-esp32-vuln-test esp32-qemu-test/
docker run --rm fatfs-esp32-vuln-test
f_readdir()は、最大255文字の長い名前(LFN)を返すことができます。実際の
組み込み呼び出し元は、依然として名前をより小さな固定バッファにコピーしています。公開されているESP32の
例には、次と同等のパターンが含まれています:```
strcpy(fn, entry->d_name);
strcat(path, "/");
strcat(path, entry->d_name);
細工されたFATイメージに長いファイル名が含まれていると、これらのコピーは呼び出し元のバッファをオーバーフローさせます。
### このリポジトリ内のPoCチェーン
| Step | 説明 | マーカー |
|------|------|---------|
| 1 | 細工されたストレージイメージがマウントされ、攻撃者が制御するディレクトリエントリが返される | (mount succeeds) |
| 2 | 長いファイル名が、公開パターンの安全でないコピーパスを介して `char name[32]` にコピーされる | `[VULN-BUG7-CONFIRMED]` |
| 3 | ガード破壊がログに記録され、続いてQEMUで制御データのクラッシュが発生する | `guard=0x61616161`, `Guru Meditation Error` |
このPoCは、コンテキストとマーカー出力(`PWNED-UART`)のために、レガシーなCVE-2026-6682形式のOTAコールバック上書きパスを依然として保持していますが、ここでのバグ固有の証明は、上記の長いファイル名による呼び出し元オーバーフローマーカーです。
代表的な出力:```
I (...) fatfs_vuln: PoC: CVE-2026-6688 long-LFN caller overflow probe (ESP32 public-pattern copy path)
...
PWNED-UART
E (...) fatfs_vuln: [VULN-BUG7-CONFIRMED] guard corrupted after filename copy
E (...) fatfs_vuln: entry='esp32_lfn_trigger_aaaa...aaaa.bin' len=78 guard=0x61616161
Guru Meditation Error: Core 0 panic'ed (...)
この調査中に、符号なし減算の動作が以前に指摘され報告されていましたが、その後 CVE コーパスから削除されました。そのため、このリポジトリのアクティブな CVE セットからは意図的にその撤回済みレコードを除外しているため、番号に抜けがあることに気付くでしょう。CVE プログラムは未公開レコードへの参照について少々うるさいことがあるため、これにより相互リンクの煩わしさを避けつつ、履歴の正確性を保っています。非常に興味がある方は、このリポジトリの git 履歴を調べると、その発見の詳細を確認できます。
論争のあったレポートに注意を向けてくれた David Brown に感謝します。アップストリームの状況とパッチの指針については、ChaN の公式 FatFs パッチページをご覧ください: https://elm-chan.org/fsw/ff/patches.html
| プロジェクト | スター数 | FatFsバージョン | 脆弱性 |
|---|
| espressif/esp-idf | 17,655 | R0.16 | CVE-2026-6682 |
| STMicroelectronics/stm32-mw-fatfs | すべてのSTM32Cube | R0.15 w/p2 | CVE-2026-6682, CVE-2026-6683, CVE-2026-6686, CVE-2026-6687 |
| zephyrproject-rtos/zephyr | 14,820 | R0.16 | CVE-2026-6683, CVE-2026-6687, CVE-2026-6688 |
| micropython/micropython | 21,583 | R0.13c (2019) | CVE-2026-6682, CVE-2026-6683, CVE-2026-6684, CVE-2026-6686, CVE-2026-6687 |
| ArduPilot/ardupilot | 14,743 | R0.14b | CVE-2026-6682, CVE-2026-6683, CVE-2026-6686, CVE-2026-6687 |
| RT-Thread/rt-thread | 11,862 | R0.16 | CVE-2026-6683, CVE-2026-6686 |
| nodemcu/nodemcu-firmware | 7,903 | 様々 | CVE-2026-6688 |
| RIOT-OS/RIOT | 5,701 | R0.15 | CVE-2026-6682, CVE-2026-6683, CVE-2026-6686, CVE-2026-6687 |
| ARMmbed/mbed-os | 4,837 | R0.14b | CVE-2026-6682, CVE-2026-6683, CVE-2026-6686 |
| sbabic/swupdate | 1,780 | R0.16 | CVE-2026-6683 |
| rsta2/circle | 2,222 | 未定 | CVE-2026-6684 |
| hugen79/NanoVNA-H | 695 | R0.15 | CVE-2026-6683 |
| ChibiOS/ChibiOS | 833 | 様々 | CVE-2026-6688 |
| Samsung/TizenRT | 643 | R0.16 | CVE-2026-6683, CVE-2026-6688 |
| adafruit/tinyuf2 | 447 | 未定 | CVE-2026-6684, CVE-2026-6686 |
| grblHAL/Plugin_SD_card | 475 | R0.16 | CVE-2026-6688 |
| JcZou/StarryPilot | 315 | R0.16 | CVE-2026-6688 |
| KeystoneHQ/keystone3-firmware | 199 | R0.16 | CVE-2026-6682 |
| flysight/flysight | 44 | 様々 | CVE-2026-6682, CVE-2026-6688 |
| eugene-tarassov/vivado-risc-v | 1,061 | 未定 | CVE-2026-6684 |
| CVE ID | 概要 | CWE |
|---|
| CVE-2026-6682 | FAT32ボリュームマウントにおける整数オーバーフロー | CWE-190: Integer Overflow or Wraparound |
| CVE-2026-6683 | exFAT同期におけるゼロ除算 | CWE-369: Divide By Zero |
| CVE-2026-6684 | GPTパーティションスキャンにおける無限ループ | CWE-835: Loop with Unreachable Exit Condition |
| CVE-2026-6686 | EOFを超えたシーク後に未初期化クラスタを使用 | CWE-908: Use of Uninitialized Resource |
| CVE-2026-6687 | 無制限のexFATラベル長によるスタックバッファオーバーフロー | CWE-121: Stack-based Buffer Overflow |
| CVE-2026-6688 | 無制限のLFNファイル名コピーによるバッファオーバーフロー | CWE-120: Buffer Copy without Checking Size of Input |