Cosmos报告#2914705 - 通过转发功能使传输v2通道无法升级
影响摘要
升级功能中存在特定检查HasInflightPackets
,它会查找通道的已提交数据包。如果存在任何数据包,则不会将通道设置为FLUSHCOMPLETE
状态(在handleFlushState
、WriteUpgradeAckChannel
和WriteUpgradeConfirmChannel
中)。如果通道不处于FLUSHCOMPLETE
状态,升级就无法完全完成(在ChanUpgradeOpen
中会报错,阻止进入WriteUpgradeOpenChannel
)。
数据包承诺可以通过两种方式删除:确认和超时。但转发功能在收到目标通道的确认之前,不会为转发的数据包写入确认。这导致合法通道可能依赖于恶意通道,而恶意通道可以选择不确认数据包,从而使合法通道无法进入FLUSHCOMPLETE
状态,最终无法完成当前或未来的升级。
重现步骤
- 首先创建合法的传输v2通道:ibc-0上的channel-0 <-> ibc-1上的channel-0(这部分由中继器处理)
- 在应用中打开另外两个通道:ibc-0上的channel-1 <-> 本地链 ibc-1 || 本地链 ibc-0 -> ibc-1上的channel-1
- 提交接收数据包,其结构包含转发信息:
|
|
数据包在ibc-0的channel-1上接收后,会通过channel-0转发到ibc-1的channel-0,然后再次转发到ibc-1的channel-1。由于这种转发机制,系统不会写入任何确认(但会写入收据),导致无法超时。最终结果是ibc-0上的合法channel-0将一直保持已提交(传输中)的数据包状态,直到恶意channel-1收到确认(这不会发生)。
技术细节
该漏洞的核心在于转发功能的实现方式:
- 转发功能等待目标通道的确认后才写入原始通道的确认
- 如果目标通道是恶意的且不发送确认,原始通道将永远保持未确认状态
- 这种设计意外引入了通道间的危险依赖关系
解决方案
Cosmos团队最终通过撤回传输v2功能并移除通道升级能力来解决此问题。虽然该漏洞被评定为低严重性,但仍获得了2000美元的漏洞赏金。
相关材料
- lock_upgrade.go - 漏洞验证代码
- upgrade.mov - 验证过程视频
- GitHub问题跟踪:#7947(撤回传输v2功能的问题)