
GhostLock(CVE-2026-43499)は、ブートローダーがロックされたAndroidデバイス向けのカーネルエクスプロイトです。
ブートローダーがロックされたAndroidデバイス向けのカーネルエクスプロイト。ブートローダーのロック解除やbootイメージの変更なしに、一時的なroot権限の取得とKernelSUのインストールを実現します。実行時にカーネルバージョンを自動検出し、複数デバイス対応のオフセットテーブルを備えています。
CVE-2026-43499 — Futex PI (優先度継承) のUse-After-Free
Linuxカーネル5.7〜7.1に影響します。安定版6.1.175、6.6.140、6.12.86で修正済みです。2026年9月時点で、ほとんどのAndroidデバイスは未パッチのままです。
pselect6システムコールはfd_setデータをカーネルスタック上にコピーします。これがfutex PIのwaiter機構と組み合わさると、解放されたスタックフレームがrt_mutex_waiter構造体として再利用される可能性があります。その後、PIチェーン走査中のrb-treeの再平衡によって、制御された値が任意のカーネルアドレスに書き込まれます。
| デバイス | SoC | カーネル | GKIブランチ | SHIFT |
|---|---|---|---|---|
| OnePlus Ace 6T (PLR110) | SM8845 | 6.12.38 | android16-5 | 0 |
| OnePlus 15 (CPH2745/2747/2749) | SM8850 | 6.12.23 | android16-5 | 0 |
| OnePlus 15 (PLK110) | SM8850 | 6.12.58 | android16-6 | 0 |
| Xiaomi 17 (pudding) | SM8850 | 6.12.23 / 6.12.69 | android16-5 / android16-6 | 0 |
| OnePlus 13 (IN2060) | SM8750 | 6.6.89 | android15-8 | -2 |
| OPPO Pad 4 Pro | SM8750 | 6.6.89 | android15-8 | -2 |
| デバイス | SoC | カーネル | 備考 |
|---|---|---|---|
| OnePlus 15T (PLZ110) | SM8845 | 6.12.38 | Ace 6Tと同じカーネル |
| OPPO Reno10 Pro+ (CPH2521) | SM8475 | 5.10.236 | 5.10コンパクトwaiter、waiter word=0 |
| Sony Xperia 1 IV (nagara) | SM8450 | 5.10.218 | 5.10コンパクトwaiter、waiter word=0 |
| OPPO Find X9 Pro (PLG110) | D9400 | 6.12.23 | MediaTek、android16-5 |
| Vivo X200 Ultra (V2454A) | SM8750 | 6.6.89 | C ashmem、従来型フック |
| Vivo X Fold3 Pro (PD2337) | SM8650 | 6.1.124 | 6.1コンパクトwaiter、waiter word=3 |
| Vivo T4 | SM8650 | 6.1.145 | 6.1コンパクトwaiter、waiter word=3 |
pselectのスタックオーバーレイでは、解放されたrt_mutex_waiterがユーザー制御可能なstack_fds領域 (word 0〜14) 内に配置される必要があります。どこに配置されるかはカーネルバージョンではなく、コンパイラのPGO/LTOプロファイルによって決まります。スタックレイアウトを参照してください。
| デバイス | SoC | カーネル | 根本原因 |
|---|---|---|---|
| OPPO Find X9 Ultra | SM8750 | 6.12.58 | PGOがdo_futexを削除 → waiter word=14 |
| OnePlus 15 (PLK110) | SM8850 | 6.12.69 | PGOがdo_futexをインライン化 → waiter word=20 |
| OnePlus 12 | SM8650 | 6.1.141 | PGOがdo_futexをインライン化 → waiter word=13/19 |
| OnePlus 13R / Ace 5 | SM8650 | 6.1.x | OPLUS 6.1: waiter word=13 |
| realme RMX5070 | SM6650 | 6.1.141 | OPLUS 6.1: waiter word=13 |
| OPPO Pad 5 (OPD2502) | MT6878 | 6.1.134 | OPLUS 6.1: waiter word=13 |
| Motorola Edge 60 Fusion | MT6878 | 6.1.145 | 非OPLUS 6.1: 同じ結果 |
| iQOO Neo 10 CN | SM8650 | 6.1.84 | do_futexフレーム0xD0 → waiter word=-11 |
| OPPO PKW110 | — | 5.15.180 | do_futexフレーム0x140 → waiter word=-29 |
| iQOO Z9 5G | — | 5.15.178 | do_futexフレームが大きすぎる |
| CPH2763 (OPPO) | — | 6.1.115 | OPLUS 6.1: PGOインライン化、waiter word=24 |
| iQOO 12 | SM8650 | 6.1.145 | 6.1: waiter word=9、task/lockがゼロ領域内 |
6.1の実行可否に関する注記: OPLUS 6.1カーネルは、PGOが
do_futexをインライン化するため、一貫して実行不可です。ただし、一部の非OPLUS 6.1カーネル (vivo) は標準の呼び出しチェーンを維持しており、実行可能です (vivo T4、X Fold3 Pro)。実行可否はデバイスごとに確認する必要があります。
デバイスの機能に基づいて自動的に選択される、2つのroot取得パスがあります:
off_ashmem_misc_fops != 0が必要です (BSS内に静的miscdeviceを持つC ashmem)。
PI write (mode=4) → redirect miscdevice fops to fake fops
→ configfs r/w → pipe physrw (1-byte precise kernel r/w)
→ SELinux enforcing = 0 (single byte, no policycap corruption)
→ UMH: inject work_struct into system_unbound_wq
→ root script → ksud late-load → KSU installed
利用可能: OnePlus 13、OPPO Pad 4 Pro、5.10/6.1 C ashmem デバイス。 Rust ashmem (6.12 GKI) では利用不可 — ヒープ割り当ての miscdevice。
Write 1 (mode=1) → SELinux enforcing = 0 (8-byte write, corrupts adjacent bytes)
Write 2 (mode=2) → task->cred = init_cred (uid=0, all capabilities)
Root shell → ksud late-load → KSU → SELinux policy fix
W1+W2の後、エクスプロイトはSELinuxポリシーバイナリの設定フィールド(ANDROID_NETLINK_ROUTE + GETNEIGH に対して |= 0xC0000000)をパッチし、/sys/fs/selinux/load 経由でリロードしてネットワーク接続を復元します。
App (seccomp) → Write 1 → mini-adb TCP → adb shell: full exploit → root
起動時のランチャーは、別個の GhostLock Anchor アプリ によって提供されます。
NFDS=320 の場合、core_sys_select はカーネルスタック上に 256 バイトの stack_fds バッファを割り当てます:
stack_fds: 0 5 10 14 | 15 20 25 29
├─in─┤─out─┤─ex──┤ ├res_in┤res_out┤res_ex┤
◄── USER CONTROLLED ──►│◄── KERNEL ZEROED ──►
エクスプロイトは、fd_set 入力ビットマップに偽の waiter フィールド(task、lock)を配置します。6.12 のネストされた waiter(14 ワード)の場合:実現可能な最大 waiter ワード = 3。5.10/6.1 のコンパクトな waiter(10 ワード)の場合:実現可能な最大 waiter ワード = 7。
waiter の位置は呼び出しチェーンの深さに依存します:
| パターン | 呼び出しチェーン | 実現可能 |
|---|---|---|
| android16-5 (6.12) | sys_futex → do_futex → fwrpi | ✅ waiter word=2 |
| android16-6 (6.12.58) | sys_futex → do_futex → fwrpi | ✅ waiter word=2 |
| android16-6 (6.12.69 OPLUS) | sys_futex → fwrpi (PGO inlined) | ❌ waiter word=20 |
| android16-6 (X9 Ultra) | sys_futex → fwrpi (PGO inlined) | ❌ waiter word=14 |
| android15-8 (6.6) | sys_futex → do_futex → fwrpi | ✅ waiter word=2 (SHIFT=-2) |
| vivo 6.1 | sys_futex → do_futex → fwrpi | ✅ waiter word=3 |
| OPLUS 6.1 | sys_futex → fwrpi (PGO inlined) | ❌ waiter word=13+ |
| 5.10 OPLUS | sys_futex → do_futex → fwrpi | ✅ waiter word=0 |
すべてのカーネル書き込みはリニアマップのエイリアスを使用します。ブートローダーは kernel_phys_load を選択し、これは SoC ごとに異なります:
| SoC | kernel_phys_load |
|---|---|
| SM8845 (Ace 6T, 15T) | 0xa8000000 |
| SM8750 (OnePlus 13, OPPO Pad 4 Pro) | 0xa8000000 |
| SM8650 (vivo T4, X Fold3 Pro) | 0xa8000000 |
| SM8850 (OnePlus 15, Xiaomi 17) | 0xc7800000 |
誤った値はサイレントに失敗します。root 化された端末で読み取ります:
su -c 'grep -i "Kernel code" /proc/iomem' # c7810000-... → 0xc7800000
実行時にオーバーライド: KPHYS=0xc7800000 /data/local/tmp/a/e
/data/local/tmp/a/e # Default (shift=0)
PSELECT_SHIFT=-2 /data/local/tmp/a/e # OnePlus 13 (6.6)
5.10 カーネルは 0xffffffc008000000 を使用します(VA_BITS=39、6.x のデフォルト 0xffffffc080000000 とは異なります)。これはデバイスオフセットエントリの kimage_text_base フィールドを介して自動的に処理されます。
make NDK_ROOT=/path/to/android-ndk
Or directly:
NDK=/path/to/android-ndk
"$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android35-clang" \
-O2 -Wall -Isrc/core -Isrc/devices -DTARGET_CONFIG_H=\"target.h\" \
src/core/main.c src/core/util.c src/core/slide.c \
src/core/fops.c src/core/pipe_physrw.c src/core/root.c \
src/core/miniadb.c src/core/umh_root.c \
-o ./ghostlock -fPIE -pie -pthread
GhostLock は一時的な root を提供します。KernelSU のインストールには、各 KMI バージョン用の kernelsu.ko を同梱した ksud が必要です。
| 方法 | 手順 |
|---|---|
| ReSukiSU APK(推奨) | ReSukiSU またはこのフォークをインストールします。libksud.so を同梱しています。 |
| CI リリース | ReSukiSU CI からダウンロードします |
adb shell mkdir -p /data/local/tmp/a
adb push ./ghostlock /data/local/tmp/a/e
adb shell chmod 755 /data/local/tmp/a/e
adb shell /data/local/tmp/a/e
起動が完了し、ADB の準備ができてから実行します。
必要なのは boot.img のみです — root もデバイスへのアクセスも不要です。
完全なワークフローについては kallsyms ツールガイド を参照するか、以下を実行します:
python tools/extract_target.py --kallsyms kallsyms.txt
python tools/extract_btf.py kernel