BlackHalo logo
Published on

Tailscale 追踪到 SQLite 16 年历史的 WAL-Reset 漏洞

Authors
  • Name
    ropbear
    tailscale.com
SQLite 数据库文件与 WAL 日志文件示意图,展示检查点过程
头图来源: Picsum

引言

Tailscale 在 2025 年底至 2026 年初经历了多次服务不稳定,其状态页面显示频繁的停机事件。经过数月深入调查,他们发现这些问题的根源是一个存在于 SQLite 中长达 16 年的漏洞——WAL-Reset 数据竞争。该漏洞在特定条件下导致数据库损坏,影响了部分 tailnet 的控制平面可用性。Tailscale 与 SQLite 核心开发者合作,最终定位并修复了该漏洞,并在此过程中发现了另一个陈旧表达式索引漏洞。

Tailscale 的数据库架构

Tailscale 的控制平面由多个协调服务器(分片)组成,每个分片拥有一个 SQLite 数据库,存储该分片上所有 tailnet 的配置元数据。单个 Go 进程独占访问该数据库,遵循 SQLite 推荐的单写入者设计。自 2022 年起,Tailscale 将 SQLite 作为主数据库,因其可靠且广泛使用。备份流程为每几分钟拍摄完整快照并上传至 S3。

数据库损坏的出现

2025 年 8 月,一个读取 S3 备份的数据管道报告了数据库错误。运行 PRAGMA integrity_check 后确认数据库损坏。尽管修复了受影响的数据库并调查原因,但损坏事件反复发生。在六个月内,Tailscale 共遭遇 19 次数据库损坏。每次损坏导致该分片上的控制平面进程停止,影响 tailnet 的设备连接、管理控制台和 API 访问。虽然已在线设备之间的点对点连接不受影响,但新设备无法加入,网络变更无法同步。

艰难的排查过程

最初,Tailscale 团队检查了近期代码变更,但未发现相关修改。他们重新审查了所有与 SQLite 交互的低层代码,未找到明显错误。损坏事件没有共同模式:不限于特定分片、客户、功能、时间或负载。由于无法可靠触发,他们无法在测试环境中复现,只能依赖在生产环境部署被动诊断工具。

Tailscale 与 SQLite 开发者签订了专业支持合同,获得了直接访问其专业知识的渠道。双方提出了多种理论,包括 POSIX 锁在 close() 时失效、SQLite 内存管理错误、多线程使用 SQLite 时禁用线程安全等。每次事件后收集更多数据,逐步排除这些理论。

交易日志中的线索

在调查期间,Tailscale 构建了交易日志管道,记录所有修改数据库的 SQL 语句。由于 SQLite 是单写入者且事务可序列化,日志完全线性。回放日志应能将数据库恢复到最新状态。然而,有两次事件中日志回放失败:一个已提交的事务写入的数据对后续事务不可见。这违反了数据库的原子性和持久性保证。

WAL-Reset 漏洞的发现

SQLite 开发者正在开发一个新的调试工具,用于检查点过程的可视化。Tailscale 使用写入前日志(WAL)模式,新页面先写入 WAL 文件,再通过检查点复制回主数据库文件。Tailscale 手动控制检查点以实现快速一致备份。指标显示,在损坏事件中,SQLite 报告从 WAL 复制的页面数超过了 WAL 中实际存在的页面数。

SQLite 开发者创建了一个名为 tmstmpvfs 的虚拟文件系统包装器,记录文件系统层的详细跟踪信息。Tailscale 将其部署到生产环境后,下一次损坏事件提供了足够数据。最终定位到漏洞:在检查点过程中,如果写入事务发生在特定时间点,检查点会错误地认为某些页面已从 WAL 复制到主数据库,但实际上并未复制。这些页面随后被标记为已检查点,导致数据丢失。该漏洞自 2009 年引入,存在了 16 年。

修复与后续

SQLite 开发者修复了 WAL-Reset 漏洞,并在修复过程中发现了第二个陈旧表达式索引漏洞。Tailscale 升级了 SQLite 版本,并实施了自动化恢复流程,将停机时间缩短至一小时以内。他们强调,尽管数据库损坏令人担忧,但控制平面仅处理配置元数据,不涉及加密密钥或网络流量。此次经历也促使他们改进了监控和应急响应机制。

教训与反思

Tailscale 承认多次停机影响了客户信任,并为此道歉。他们指出,即使使用成熟稳定的技术(如 SQLite),在特定使用模式下仍可能触发隐藏的深层漏洞。与上游开发者紧密合作是解决问题的关键。同时,构建交易日志等辅助工具不仅帮助恢复,还提供了关键线索。最终,该漏洞的发现和修复使整个 SQLite 社区受益。

原标题:Tailscale Traces Database Corruption to 16y/o SQLite WAL-Reset Bug。 HN 原始发布时间:2026年8月12日星期三。当前记录为 796 分、141 条评论。

阅读原文 · 查看 HN 讨论