首页
/ Bitcoin Core 0.16.3 发布说明深度解析:CVE-2018-17144 拒绝服务漏洞修复与版本升级要点

Bitcoin Core 0.16.3 发布说明深度解析:CVE-2018-17144 拒绝服务漏洞修复与版本升级要点

2026-09-06 16:01:22作者:廉皓灿Ida

本文基于 Bitcoin Core 仓库中 release-notes-0.16.3.md 发布说明展开,覆盖 0.16.3 小版本发布的完整背景:面向矿工的拒绝服务漏洞(CVE-2018-17144)是如何被定位并修复的、0.16 系列的升级/降级注意事项与链状态(chainstate)格式兼容性问题,以及该版本全部四条变更记录(共识修复、signrawtransaction* 报错行为、bitcoinconsensus 库错误码、-prune 帮助文本)在当前代码库中的对应实现位置,读完可掌握一次安全小版本发布的完整技术脉络。

一、发布概览与定位

0.16.3 是 Bitcoin Core 0.16.x 系列中的一个新小版本(minor release),发布说明明确其定位是"包含若干 bug 修复的补丁版本"。它的核心驱动力是一个需要尽快修复的安全问题:在 0.14.0 至 0.16.2 版本间存在的、可被矿工利用的拒绝服务(Denial-of-Service)漏洞 CVE-2018-17144。发布说明给出的建议是——任何运行在受漏洞影响版本上的节点都应尽快升级到 0.16.3。

该版本共有 6 位贡献者直接参与(Anthony Towns、Hennadii Stepanov、Matt Corallo、Suhas Daftuar、Thomas Kerin、Wladimir J. van der Laan),安全问题的报告者为匿名。

二、如何升级(含链状态格式转换注意事项)

发布说明中"如何升级"一节给出了完整的操作路径,这里完整继承并说明其每一步的技术含义:

  1. 先关闭旧版本:如果正在运行更旧的版本,先将其关闭。
  2. 等待完全退出:旧版本完全退出可能需要几分钟(老版本尤其如此),必须等待进程真正终止,避免对链数据库的并发写入。
  3. 替换程序文件
    • Windows:运行安装包;
    • macOS:替换 /Applications/Bitcoin-Qt
    • Linux:替换 bitcoind / bitcoin-qt 可执行文件。
  4. 首次运行 0.15.0 或更新版本时的链状态转换:第一次运行 0.15.0 及以后版本时,chainstate 数据库会被转换为新格式,耗时从几分钟到半小时不等,取决于机器速度。因此从 0.14 及更早版本升级的用户,除了替换二进制之外,还要预留这次数据库迁移时间。
  5. 更老版本的不兼容边界:块数据库(block database)格式在 0.8.0 也发生过变化,不存在 0.8 之前版本到 0.15.0 及以上版本的自动升级代码。也就是说,从 0.7.x 及更早版本直接升级、且不重新下载区块链,是不受支持的;不过旧格式的钱包文件(wallet.dat)一如既往仍然受支持。

三、降级警告:0.16+ 钱包与旧版本不兼容

发布说明特别给出了"降级警告"小节,这一点在实际运维中容易被忽视:

  • 0.16 及以后版本创建的新钱包与 0.16 之前的版本不兼容。如果在旧版本中尝试使用新创建的钱包,将无法工作。
  • 用旧版本创建的已有钱包不受影响,降级后仍可正常使用。

因此,如果你计划长期停留在 0.16 之前的版本,不应在升级期间创建新钱包;或者干脆不要降级。

四、兼容性说明

发布说明"兼容性"一节给出 0.16.3 时代的支持矩阵:

  • 经过充分测试的操作系统:基于 Linux 内核的系统、macOS 10.8+、Windows Vista 及以后版本;
  • Windows XP 不受支持
  • 其他大多数类 Unix 系统上"应该也能工作",但没有被频繁测试。

需要注意的是,这是 0.16.3 发布时的兼容性描述。当前仓库(Bitcoin Core master)已经切换到 CMake 构建体系(见 CMakeLists.txt),其支持的构建平台由 ci/depends/ 下的交叉编译环境脚本共同覆盖(如 ci/test/00_setup_env_mac_native.shdepends/hosts/ 等),实际支持范围远大于当年的描述,两者不要混淆。

五、CVE-2018-17144:可被矿工利用的拒绝服务漏洞

5.1 漏洞机制

0.16.3 发布说明指出,CVE-2018-17144 存在于 0.14.0 至 0.16.2 的 Bitcoin Core 中,且可被矿工利用。其原理可以从当前源码中直接印证。

src/consensus/tx_check.cpp 中,CheckTransaction() 里有如下注释与检查代码:

// Check for duplicate inputs (see CVE-2018-17144)
// While Consensus::CheckTxInputs does check if all inputs of a tx are available, and UpdateCoins marks all inputs
// of a tx as spent, it does not check if the tx has duplicate inputs.
// Failure to run this check will result in either a crash or an inflation bug, depending on the implementation of
// the underlying coins database.
std::set<COutPoint> vInOutPoints;
for (const auto& txin : tx.vin) {
    if (!vInOutPoints.insert(txin.prevout).second)
        return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputs-duplicate");
}

要点拆解:

  • 漏洞根源Consensus::CheckTxInputs 只检查交易的所有输入是否"可用(available)",UpdateCoins 会把交易的所有输入标记为已花费,但两者都不检查交易内部是否存在重复输入
  • 后果:缺少这个检查时,"根据底层 coins 数据库的实现不同,结果要么是崩溃,要么是通胀 bug(inflation bug)"。对 0.16.3 之前的实际表现是崩溃,即拒绝服务。
  • 修复方式:在 CheckTransaction()(不依赖任何上下文的基础校验函数)中,用一个 std::set<COutPoint> 收集所有 txin.prevout,一旦 insert 失败(即同一个上一输出 prevout 出现两次),就以 TX_CONSENSUS 级别拒绝该交易,拒绝原因为 bad-txns-inputs-duplicate
  • 可被矿工利用的原因:只有矿工能通过打包交易把这样的恶意交易放进区块;攻击者只需挖出一个包含"重复输入交易"的区块,所有验证该区块的节点都会在连接区块时崩溃/断链,而攻击者自己可以停在旧高度或跳过该区块,从而获得相对优势。这就是发布说明中"exploitable by miners"的含义。

5.2 该检查在验证流程中的位置

从源码结构看,CheckTransaction() 是上下文无关(context-free)的基础交易校验,它在两条路径上被执行(见 src/consensus/tx_verify.cpp 中的注释):

  • 内存池路径MemPoolAccept::PreChecks 在更早阶段就会调用 CheckTransaction()
  • 区块连接路径Chainstate::ConnectBlock 通过 CheckBlock() 调用 CheckTransaction()

这意味着恶意交易无论走"广播进内存池"还是"直接打包进区块",都会在进入共识状态之前被以 bad-txns-inputs-duplicate 拒绝。另外,src/policy/packages.h 中的注释也明确将"同一 prevout 在一次交易中被引用多次"的冲突归口到 CheckTransaction() 处理(see bad-txns-inputs-duplicate in CheckTransaction()),并在 src/validation.cpp 附近有同样的引用,说明包(package)验证逻辑在设计上依赖这一共识级检查。

5.3 仓库中的可运行验证:重复输入基准测试

当前仓库自带一个专门针对该漏洞修复的基准测试 src/bench/duplicate_inputs.cpp。它的做法是:

  1. 构造一个合法 coinbase 交易,以及一个"naughty"(恶意)交易;
  2. 恶意交易填充约 ((MAX_BLOCK_SERIALIZED_SIZE / WITNESS_SCALE_FACTOR) - 两个交易已占用大小) / 41 - 100 个随机输入,并在最后一个输入上再追加一个与末尾输入完全相同的 prevoutnaughtyTx.vin.emplace_back(naughtyTx.vin.back()),见 src/bench/duplicate_inputs.cpp#L65),即人为制造重复输入,同时让区块逼近大小上限以检验攻击载荷的规模;
  3. 在基准循环中反复调用 CheckBlock(),并断言两个事实(见 src/bench/duplicate_inputs.cpp#L72-L76):
bench.run([&] {
    BlockValidationState cvstate{};
    assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
    assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
});
  • CheckBlock() 必须返回失败;
  • 拒绝原因必须精确等于 bad-txns-inputs-duplicate

这是"修复有效"的最直接证据:只要该断言通过,就说明 CVE-2018-17144 的攻击区块会在块校验阶段被确定性拒绝,而不是导致崩溃。

六、0.16.3 完整变更记录(Change Log)逐条解读

发布说明共列出 4 条变更,下面逐条给出其在当前仓库中的对应实现线索。

6.1 Consensus:修复交易内重复输入导致的崩溃(#14249)

  • 原始记录:#14249 696b936 Fix crash bug with duplicate inputs within a transaction (TheBlueMatt, sdaftuar)
  • 即第五节详细剖析的 CVE-2018-17144 修复。当前实现落在 src/consensus/tx_check.cpp 的重复输入检查中,配套验证见 src/bench/duplicate_inputs.cpp

6.2 RPC and other APIs:signrawtransaction* 缺少金额时给出错误(#13547)

  • 原始记录:#13547 212ef1f Make signrawtransaction* give an error when amount is needed but missing (ajtowns)
  • 背景:signrawtransaction / signrawtransactionwithkey 等 RPC 在签名时若缺少输出金额信息(例如 UTXO 数据不完整),0.16.3 之前的行为可能静默地部分签名;该修复让这类"需要金额却拿不到金额"的情形明确返回错误,避免用户误以为交易已完整签名。
  • 在当前仓库中,signrawtransaction* 系列 RPC 的实现位于 src/rpc/rawtransaction.cpp,客户端参数注册在 src/rpc/client.cpp,行为测试覆盖在 src/test/rpc_tests.cpp 与模糊测试 src/test/fuzz/rpc.cpp 中,可作为回归验证的入口。

6.3 Miscellaneous:bitcoinconsensus 库错误码修正(#13655)

  • 原始记录:#13655 1cdbea7 bitcoinconsensus: invalid flags error should be set to bitcoinconsensus_err (afk11)
  • 含义:bitcoinconsensus 是 Bitcoin Core 对外提供的轻量级共识校验 C 库(bitcoinconsensus_verify 系列接口),供不想链接完整 Core 的第三方做交易脚本/共识验证。该修复修正了一个错误处理 bug:当调用方传入了非法的验证标志(invalid flags)时,错误应正确设置到库的 bitcoinconsensus_err 错误槽位中,而不是丢失或置错。
  • 适用对象是使用 libbitcoinconsensus 的嵌入方:如果你在程序里调用了该库并依赖其错误码分支,升级时需注意错误信息的语义变化。当前仓库已重构为 libbitcoinkernel 体系(见 libbitcoinkernel.pc.indoc/design/libraries.md),但 0.16.3 这条记录反映的是当年独立 bitcoinconsensus 目标的行为修正。

6.4 Documentation:修正 -prune 的帮助输出(#13844)

  • 原始记录:#13844 11b9dbb correct the help output for -prune (hebasto)
  • 含义:-prune 是控制区块文件修剪(pruning)的启动参数,用于在保留 UTXO 集的同时释放区块链占用的磁盘空间。本修复纠正了 -prune 在帮助输出中的说明文本,使其与真实行为一致,避免用户按错误说明配置修剪值。
  • 仓库中与磁盘空间缩减相关的现行文档可参考 doc/reduce-memory.mddoc/reduce-traffic.md,配置文件示例见 share/examples/bitcoin.conf,可用于理解 prune= 在配置文件中的一般写法。

七、给运维者的操作核对清单

把发布说明整理成可执行的检查清单:

  1. 确认版本范围:若节点版本落在 0.14.0 ~ 0.16.2(含)区间,升级优先级为最高(CVE-2018-17144 可被矿工利用)。
  2. 升级前:停止旧节点并等待其完全退出;确认备份了 wallet.dat 等用户数据文件(发布说明未要求备份,但这是替换二进制前的通用安全习惯)。
  3. 升级中:按平台替换程序(Windows 安装包 / macOS 替换 Bitcoin-Qt / Linux 替换 bitcoindbitcoin-qt)。
  4. 升级后首次启动:预留 chainstate 数据库格式转换时间(几分钟至半小时)。
  5. 若计划降级:确认没有在 0.16+ 中新建钱包,否则新钱包在旧版本中不可用。
  6. 若使用 0.7.x 及更早的数据目录:0.16.3 不提供自动链数据库迁移,需重新同步区块链(钱包文件仍可继续使用)。

八、小结

0.16.3 是 0.16 系列中一次典型的"安全驱动"小版本发布:核心是 #14249 对交易内重复输入共识校验的补强,直接封堵了可被矿工利用、能导致节点崩溃的 CVE-2018-17144;配套三条变更分别改进了 signrawtransaction* 的错误反馈、libbitcoinconsensus 的错误码正确性与 -prune 的帮助文本。在当前仓库中,修复代码(src/consensus/tx_check.cpp)与回归基准(src/bench/duplicate_inputs.cpp)至今可查可跑,是理解"一条 release note 背后从漏洞机理到共识代码再到验证用例"完整链条的最佳样本。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388