Black Hat USA 2026:Pixel10零点击内核链
原创
Max Luo
Max Luo
白帽子罗棋琛
2026年8月16日 08:18
广东
在小说阅读器读本章
去阅读
从一段音频到 Pixel 10 内核:零点击漏洞链复盘
Black Hat USA 2026 议题《A 0-Click Exploit Chain for the Pixel 10》课件解读。本文依据公开课件、Project Zero 文章、Pixel 安全公告与 Dolby 公告整理,聚焦攻击面、漏洞组合和移动终端防守工程;不提供可直接运行的利用代码。
“零点击”容易被误解成一个能瞬间拿下整台手机的神奇漏洞。Pixel 10 这条链更接近真实世界:自动音频转写把不可信压缩数据送进 native 解码器,CVE-2025-54957 取得 mediacodec 进程内代码执行;随后,Pixel 10 新增的 VPU 驱动把过大的映射长度直接交给 remap_pfn_range(),CVE-2026-0106 再把受限媒体进程带到内核。
Pixel 9 的第二段并不相同。它使用 BigWave 驱动中的 CVE-2025-36934,由调度超时和对象生命周期错位造成 UAF。把两代设备放在一起看,结论比“又有三个 CVE”更重要:硬件迭代删除了旧驱动,却引入了一个更浅、更容易利用的新接口;媒体沙箱挡住了第一段,但沙箱可访问的设备节点决定了第二段还能走多远。
1、先把两条链分开:Pixel 9 不是 Pixel 10
课件开头列出三个 CVE,容易让人以为 Pixel 10 需要三段漏洞。实际是两条共享入口、后半段分叉的链:
text
不可信音频消息 └─ 自动转写/解码 └─ CVE-2025-54957:Dolby UDC,mediacodec RCE ├─ Pixel 9:CVE-2025-36934,BigWave driver UAF → kernel └─ Pixel 10:CVE-2026-0106,VPU mmap 越界 → kernel
官方信息也支持这种拆分。2025 年 12 月 Pixel 公告把 CVE-2025-54957 列为 Dolby 组件 Critical RCE,把 CVE-2025-36934 列为 BigWave 组件 High EoP;2026 年 2 月 Pixel 公告把 CVE-2026-0106 列为 VPU Driver 的 High EoP。Project Zero 进一步说明,Pixel 10 已不再提供 /dev/bigwave,因此不能直接移植 Pixel 9 的本地提权段,只能重新审计新 VPU 驱动。
这也是移动漏洞管理最常见的误区:CVE ID 相同不代表所有机型的可利用上下文相同;机型相同也不代表一个补丁级别覆盖 SoC、vendor driver 和闭源 codec 的全部风险。资产数据至少要精确到型号、build fingerprint、安全补丁级别和关键 vendor 组件版本。
2、零点击入口来自产品功能,不来自“打开附件”
Android 上的来信音频自动转写,会在用户播放之前解析音频。只要消息进入转写流水线,音频 codec 就从“用户主动打开的媒体文件解析器”变成远程零交互攻击面。
安全评审不能只列“App 接收哪些 MIME 类型”,还要追踪后台触发条件:
yaml
feature:incoming_audio_transcriptiontrigger:user_action_required:falseevents:-message_received-attachment_prefetchdata_path:-messaging_transport-container_demuxer-audio_decoder_native-transcription_modeltrust_boundaries:-remote_sender_to_app-app_to_mediacodec-mediacodec_to_kernel_drivercontrols_required:-format_allowlist-byte_and_frame_budget-isolated_decode_worker-syscall_and_device_allowlist-crash_telemetry-kill_switch
产品团队往往把自动转写视为 AI 功能,安全团队却应把它当成一个无人值守的解析服务:没有 UI 确认,输入由远端控制,执行频率可被攻击者放大,且 native codec 可能来自第三方二进制。威胁模型必须覆盖消息抵达后的所有隐式计算,而不是停在“用户没点播放”。
3、第一段:一个长度进位错误如何越过 Dolby UDC 堆边界
CVE-2025-54957 位于 Dolby Unified Decoder。DD+ syncframe 可以携带 EMDF 元数据;解码器把元数据写入并再次从 skip buffer 解析。课件展示的关键点是:攻击者可控制 payload_length,分配函数还会叠加 extra 并做对齐。
反编译代码里存在两类值得分别检查的整数问题:加法是否溢出,以及向 8 字节对齐时是否再次溢出。即便第一次 alloc_size + extra 做过检查,后续对齐计算仍不能使用有风险的余数表达式,也不能让“声明长度”和“实际复制长度”分离。
更稳妥的实现应把每一步都写成 checked arithmetic,并让复制循环由目标 buffer 大小而不是输入结束条件控制:
c
#include<stdbool.h>#include<stddef.h>#include<stdint.h>staticboolchecked_add_size(size_t a, size_t b, size_t *out) { if (b > SIZE_MAX - a) returnfalse; *out = a + b; returntrue; } staticboolchecked_align_up_8(size_t n, size_t *out) { size_t padding = (8u - (n & 7u)) & 7u; return checked_add_size(n, padding, out); } staticintcopy_payload(struct bitreader *br, struct heap *h, size_t payload_len, size_t extra) { size_t total, aligned; if (!checked_add_size(payload_len, extra, &total)) return ERR_RANGE; if (!checked_align_up_8(total, &aligned)) return ERR_RANGE; if (aligned > h->remaining) return ERR_NOMEM; uint8_t *dst = h->curr; for (size_t i = 0; i < payload_len; i++) { if (!read_u8(br, &dst[i])) return ERR_TRUNCATED; } h->curr += aligned; h->remaining -= aligned; return OK; }
Dolby 公告将受影响范围写为 UDC 4.5 至 4.13,漏洞类型为 Integer Overflow,影响为 Code Execution,CVSS 3.1 为 6.7、Medium;Pixel 公告在自己的设备上下文中则把它评为 Critical RCE。两者不矛盾:组件级评分考虑一般部署,设备级评分还要考虑后台自动处理和可串联的本地提权。企业不能只取供应链中最低的那一个严重度。
4、不是“溢出就等于执行”:从受控写到媒体进程 RCE
课件用多页内存布局解释了 evo heap、skip pointer、Scudo secondary header 和可写函数指针之间的关系。这里不复述偏移和调用序列,但可以保留利用工程对防守方最有价值的三点。
第一,专用 allocator 也需要与通用堆同等级的边界验证。evo heap 只是静态区域上的 bump allocator,remaining 被错误更新后,后续分配会把元数据当作合法空间。第二,guard page 能把某些越界变成崩溃,但攻击者会寻找能避开 guard 的布局。第三,控制流完整性不能只看“有没有 NX”;只要已有间接调用读取可写对象中的函数指针,数据破坏就可能转化为调用原语。
课件最终利用解码器内已有调用路径组织多次函数调用。对产品测试而言,与其复刻 exploit,不如把这条路径转化为内存安全回归:
cpp
extern\"C\"intLLVMFuzzerTestOneInput(constuint8_t *data, size_t size){ DecodeLimits limits{ .max_syncframes = 64, .max_emdf_payload = 64 * 1024, .max_total_alloc = 2 * 1024 * 1024, }; GuardedArena arena(/*redzone=*/4096, /*poison_on_free=*/true); Decoder decoder(arena, limits); DecodeResult result = decoder.Decode(data, size); CHECK(arena.RedzonesIntact()); CHECK(decoder.BytesConsumed() <= size); CHECK(decoder.BytesAllocated() <= limits.max_total_alloc); return0; }
该 harness 应同时跑 ASan/HWASan、UBSan integer、Scudo hardened 配置,并保留跨版本 corpus。闭源 codec 不能成为测试盲区:OEM 可以要求供应商提供可插桩构建、SBOM、fuzz 覆盖率和修复版本映射;做不到时,就应降低它在零点击路径上的权限与触发频率。
5、mediacodec 是沙箱,但它仍然是不可信执行域
Android 很早就把非安全媒体解码器放进 mediacodec 域,目的正是让 codec RCE 不直接等于系统接管。课件引用的 SELinux 说明也强调这个进程应当受约束。
风险出在审计习惯:很多工程师会优先盯 untrusted_app,却把系统域或媒体域默认当成可信。实际上,mediacodec、mediaextractor、浏览器 isolated process、baseband/Wi-Fi/Bluetooth 服务都直接解析外部输入。它们的 SELinux 域名不同,但威胁属性相似:输入不可信,必须假设进程会被拿到代码执行。
因此,SELinux 策略 review 的起点应是“进程失陷后能访问什么”。下面是一个设备节点最小权限测试思路:
python
EXPECTED = { \"u:r:mediacodec:s0\": { \"/dev/video-dec0\": {\"open\", \"read\", \"write\", \"ioctl\"}, } } deftest_device_acl(snapshot): for domain, devices in snapshot.items(): allowed = EXPECTED.get(domain, {}) for path, perms in devices.items(): assert path in allowed, f\"unexpected device exposed: {domain} -> {path}\"assert perms <= allowed[path], f\"excess permission: {domain} -> {path}: {perms}\"deftest_no_raw_physical_mapping(audit_log): assertnot audit_log.allowed( subject=\"u:r:mediacodec:s0\", operation=\"mmap\", target_type=\"raw_mmio_device\", length_gt=\"declared_resource_size\", )
策略回归还要验证 neverallow、真实设备文件标签、init 创建权限和 HAL 代理路径。只检查 .te 文件里有没有一条 allow 不够,因为最终暴露面由策略、ueventd、文件 mode、binder 服务和内核驱动共同决定。
6、Pixel 9:超时返回不等于后台任务已经放弃对象
BigWave 是 Pixel 9 上的视频解码驱动。CVE-2025-36934 的根因是一种典型的异步生命周期错误:ioctl 提交嵌在 bigo_inst 中的 job,调用线程等待最多 16 秒;worker 线程按队列处理 job。超时路径尝试清队列并返回,文件描述符随后可能关闭、释放 inst,但 worker 可能已经取走 job 并仍在使用它。
课件通过排队多个长任务,把目标 job 的处理时刻推到 ioctl 即将超时附近。问题不在“16 秒太长”,而在三方对所有权没有一致协议:队列、worker 和 file release 都认为自己可以推进对象生命周期。
驱动修复不能只增加锁或调整超时。更稳妥的模式是 job 自持引用,取消采用状态机,release 等待确定的完成事件;任何路径都不能在 worker 持有指针时释放容器对象。
c
enumjob_state { JOB_NEW, JOB_QUEUED, JOB_RUNNING, JOB_DONE, JOB_CANCELLED }; structbigo_job {refcount_t refs; structcompletionfinished;spinlock_t lock; enumjob_statestate;/* 不再依赖 file->private_data 的隐式生命周期 */ }; staticvoidjob_get(struct bigo_job *job) { refcount_inc(&job->refs); } staticvoidjob_put(struct bigo_job *job) { if (refcount_dec_and_test(&job->refs)) kfree(job); } staticintworker_take(struct bigo_job *job) { unsignedlong flags; spin_lock_irqsave(&job->lock, flags); if (job->state != JOB_QUEUED) { spin_unlock_irqrestore(&job->lock, flags); return -ECANCELED; } job->state = JOB_RUNNING; spin_unlock_irqrestore(&job->lock, flags); return0; } staticintcancel_or_join(struct bigo_job *job) { /* queued 可以取消;running 必须等待 worker 交还引用 */if (try_cancel_queued(job)) return0; return wait_for_completion_killable(&job->finished); }
测试时要系统化探索 enqueue / dequeue / timeout / close / interrupt / device reset 的排列,而不是只跑正常解码。KCSAN、KASAN、lockdep 与 fault injection 应在驱动 CI 中同时启用。
7、Pixel 10:mmap 长度没被资源大小约束
Pixel 10 更换 Tensor G5 后,BigWave 设备节点消失,mediacodec 可访问的新接口是 /dev/vpu。研究者在短时间审计中发现:vpu_mmap() 固定从 VPU 的物理地址起点开始映射,却直接使用用户 VMA 长度,没有确认映射范围落在 VPU MMIO resource 内。
这是一个无需复杂内核知识就应在 review 阶段拦住的错误。正确检查必须同时防长度为零、页偏移、加法溢出和末端越界:
c
staticintvpu_mmap(struct file *fp, struct vm_area_struct *vma) { structvpu_core *core = container_of(fp->f_inode->i_cdev, struct vpu_core, cdev); u64 map_len = vma->vm_end - vma->vm_start; u64 page_off = (u64)vma->vm_pgoff << PAGE_SHIFT; u64 resource_len = resource_size(core->regs); phys_addr_t phys; if (!map_len || !PAGE_ALIGNED(map_len)) return -EINVAL; if (vma->vm_pgoff > (U64_MAX >> PAGE_SHIFT)) return -EOVERFLOW; if (page_off > resource_len || map_len > resource_len - page_off) return -EINVAL; if (check_add_overflow(core->regs->start, page_off, &phys)) return -EOVERFLOW; vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); vma->vm_page_prot = pgprot_device(vma->vm_page_prot); return remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT, map_len, vma->vm_page_prot); }
如果 userspace 只需要提交命令和等待中断,更好的接口甚至不是暴露整段 MMIO:由内核验证结构化命令,通过窄 ioctl 或标准 V4L2 接口访问硬件,避免让媒体进程直接操纵寄存器。KISS 在这里不是“代码少”,而是“权限模型简单、可验证”。
课件还指出 Pixel 上的物理加载地址缺少足够随机化,使固定 MMIO 起点与 kernel image 的相对关系更容易预测。ASLR 是纵深措施,但不能替代长度检查;反过来,修好边界也不意味着启动链的物理地址随机化可以长期缺席。
8、补丁管理:检查 SPL,也要检查设备是否真的收到适用修复
Pixel 2025 年 12 月公告声明,安全补丁级别 2025-12-05 或更高覆盖该公告中的 CVE-2025-54957 与 CVE-2025-36934;Pixel 10 的 CVE-2026-0106 则进入 2026 年 2 月 Pixel 公告,基线为 2026-02-05。Project Zero 的 Pixel 10 文章也明确指出,更新后的 Dolby exploit 只适用于 SPL 2025 年 12 月或更早的未修补设备。
课件给出的修复周期值得单独记录:Dolby 漏洞在 Pixel 上用了 193 天,BigWave 用了 199 天;VPU 漏洞为 71 天。前两项在修复前已公开一段时间,且最初的单漏洞优先级没有充分反映组合能力。
企业移动设备管理不应只收一个日期字符串。建议把证明链完整保存:
json
{\"device_id\":\"managed-asset-7f2a\",\"manufacturer\":\"Google\",\"model\":\"Pixel 10\",\"build_fingerprint\":\"google/.../user/release-keys\",\"security_patch\":\"2026-02-05\",\"verified_boot_state\":\"green\",\"bootloader_locked\":true,\"last_attested_at\":\"2026-08-10T03:00:00Z\",\"required_controls\":{\"CVE-2025-54957\":\"security_patch>=2025-12-05\",\"CVE-2026-0106\":\"security_patch>=2026-02-05\"},\"source_bulletins\":[\"pixel/2025-12-01\",\"pixel/2026/2026-02-01\"]}
判定必须确认设备型号属于公告覆盖范围、系统 build 可信、Verified Boot 正常,且补丁字符串未被定制 ROM 虚报。BYOD 无法提供这些证明时,应限制其访问高价值应用,而不是仅弹一次升级提醒。
Dolby UDC 还是跨产品组件。Dolby 公告建议 OEM 与组件供应商获取最新 deliverable,因此企业内的 Android、Windows、ChromeOS、电视、车载与会议终端需要按 SBOM 查询实际嵌入版本,不能把“Pixel 已修”误当成组件风险关闭。
9、把零点击防线做成五道可测试的门
课件把防守方向归纳为 ASLR、SELinux、攻击面收缩、mitigation testing、快速补丁、托管语言和内存缓解。落到工程上,可以变成五个有验收条件的门禁。
第一道是触发门:后台处理默认只解析业务必要格式,限制消息大小、syncframe 数、解码时间和并发;高风险 codec 支持远程 kill switch。第二道是内存门:native parser 全量使用 checked arithmetic,在 HWASan/UBSan/Scudo 下跑持续 fuzz;能迁移的解析层使用内存安全语言。
第三道是沙箱门:把所有解析远程输入的域都视为不可信,最小化 binder 服务、syscall 与设备节点;CI 从编译后的 SELinux policy 反向枚举可达资源。第四道是驱动门:所有 mmap、ioctl、DMA buffer 和异步 job 统一走边界检查与显式所有权模板;新 SoC 驱动上线前做同族代码审计,不能因为删掉旧驱动就关闭历史问题。
第五道是交付门:严重度计算纳入可组合能力,组件修复与设备镜像同步推进;补丁发布后用 attestation 验证真实安装率,并为高风险未升级终端自动降权。
可以把 release gate 写成机器可执行的清单:
yaml
mobile_zero_click_release_gate:parser:checked_integer_arithmetic:requiredsanitizer_matrix: [hwasan, ubsan-integer, scudo] fuzz_hours_without_unique_crash:50000sandbox:compiled_selinux_policy_reviewed:trueunexpected_device_nodes:0syscall_profile_negative_tests_passed:truekernel_driver:mmap_resource_bounds_tested:trueasync_lifetime_fault_injection_passed:truekasan_kcsan_regression_passed:truedelivery:combined_chain_severity_reviewed:truesupported_devices_have_patch:truefleet_attestation_coverage_percent:98unpatched_high_value_access:blocked
课件还给了一个很有价值的对照:同一 Dolby UDC 问题在 iPhone 的一键上下文中,因为编译时启用了 -fbounds-safety,注入的边界检查阻止了该错误继续发展。这里不应推导成“某个平台天然安全”,但它证明了一件具体的事:编译期内存安全机制如果真正覆盖生产二进制,可以在漏洞进入复杂利用阶段之前截断链条。
这条 Pixel 10 链最终留下的不是一份偏移表,而是一种审计顺序:先找无人值守的 native 输入,再枚举沙箱可访问的内核设备,最后检查新硬件驱动是否遵守最基本的资源边界与对象生命周期。零点击并非无法防御,只是任何一层“默认应该安全”的假设,都会成为下一段链的接口。
资料:
- Black Hat 官方 Session 页面
- Black Hat USA 2026 Session
- Project Zero:A 0-click exploit chain for the Pixel 10
- Pixel Update Bulletin—December 2025
- Pixel Update Bulletin—February 2026
- Dolby Security Advisory:CVE-2025-54957
原始会议材料(仓库内)
- 演讲课件 PDF
开源资料与原始议题 PDF
本文对应的 Markdown 原稿、Black Hat 原始议题 PDF 与配图已整理到 GitHub,可按文章编号查找和下载。
https://github.com/cybermaxluo/black-hat-usa-2026-talks
也可以点击文末“阅读原文”进入仓库。欢迎 Star、提交 Issue 或参与勘误。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论