从模糊测试 Centrifuge 协议中学到的经验教训 第二部分

  • Recon
  • 发布于 2024-08-14 22:37
  • 阅读 25

本文讨论了Recon团队在与Centrifuge协议合作时如何应用安全设计思维和夹紧技术,以减少长时间运行Echidna模糊测试后出现的假阳性。文章详细介绍了如何通过手动审查代码和利用系统理解来优化测试套件,以辨别真正的错误和无效的属性测试。最后,强调了高代码覆盖率与高质量结果之间的关系。

介绍

在本系列的第一篇文章中,我们探讨了Recon团队实施的创新方法,以在与他们互动期间为Centrifuge协议构建的模糊测试套件中实现高代码覆盖率。

在这篇文章中,我们将讨论Recon团队在互动的第二部分中如何应用设计安全思维和夹紧技术,以减少长时间运行Echidna模糊测试后的虚假正例属性中断的数量。

减少虚假正例

在互动的后半部分,目标并不是改善模糊测试器对系统的行覆盖率,因为这一点在前半部分已经达成,而是要在被破坏的属性测试中分离信号与噪声。

对属性进行的长时间模糊运行导致15个属性中断,每个属性都需要解析并识别其中断源为真正的错误或根本无法达到的虚假正例(由于调用特权函数、错误配置等原因)。

为了方便对破坏属性的排序,使用了Recon的刮削工具将每个破坏的属性转换为独立的单元测试。

Recon的刮削工具允许你输入Echidna/Medusa日志,并将单元测试作为输出,以便你更轻松地调试破损属性的源头。

起初,花费了大量精力逐一调试破损的属性,以试图确定每个中断的根本原因。然而,这显得无果而终且耗时,因为许多属性因相同原因而失败,这表明测试套件本身存在更重大问题。

更多代码 != 有效代码

最终,解决与众多破损属性相关问题的方案并不在于引入更多代码,而在于更好地理解系统。这需要花时间手动审查代码,并利用有关系统功能的见解做出改进,如下所述,从而导致更高效、更有效的测试套件。

这些见解被用于通过实施更安全的设计和使用夹紧来简化测试套件,从而将模糊测试器的搜索空间减少到更现实的值。在互动的这一阶段,测试套件的一部分也进行了重构,以便作为通用库进行重用,以便与ERC7540标准的实现一起使用。

设计安全

利用这些额外理解所做的第一个优化是识别到handleExecutedCollectInvest函数作为requestDeposit函数(用于向系统提供流动性)的异步回调。换句话说,调用requestDeposit函数后,在Centifuge链上执行某些操作后,它通过handleExecutedCollectInvest回调到系统。

下面我们可以看到此调用序列的可视化表示:

创建Centifuge投资订单的请求/响应序列。

注意到handleExecutedCollectInvest函数接收一个输入值remainingInvestOrder,该值定义了用户的订单在被填充后剩余多少(由于Centifuge填充订单的方式,部分填充订单是可能的)。

这被识别为许多虚假正例破损属性的主要原因,因为以特权角色通过CryticTester合约调用handleExecutedCollectInvest的模糊测试器传入的remainingInvestOrder的随机值超出了最初请求的范围。

通常情况下,这是不可能的,因为在Centifuge链上的执行不会返回比订单本身更大的remainingInvestOrder值。然而,在该实现中这是未被严格禁止的,并且被模糊测试的目标函数未应用通常在对Centifuge链操作时会进行的输入验证,这暗示着只要Centifuge链始终返回有效值,系统就是安全的。

在认识到这些属性的破损是由于测试套件配置错误后,我们需要一种方法来过滤它们,以便更易于识别信号(有效的破损属性)。通常可以使用夹紧来限制传递给调用函数的输入值,但随着认识到系统永远不应处理超过请求金额的投资完成值,我们可以利用此点来重构系统逻辑以反映这一点,并确保任何对handleExecutedCollectInvest的调用(即使它们只能由特权用户进行)不会违反此规则。因此,这一重构将创建一个设计安全的系统。

这一重构通过将remainingInvestOrder变量(表示待完成订单的剩余数量)更改为fulfilledInvestOrder(表示订单已完成的数量)来实施,并在传递请求时设置pendingDepositRequest,以确保如果传入的值超过请求的存款金额,则会因下溢而回滚。

该重构实现还不得不考虑到Centifuge链的订单填充机制允许使用与创建订单的顺序不同的顺序填充订单。因此我们需要限制可能的投资完成量,以便如果模糊测试器试图使用超过此投资上限的输入值,则会回滚,而不会破坏检查请求金额是否被超过的属性。

我们可以看到实施所导致的变化及其与原始实现的比较:

这减少了必须实施的夹紧用例,并允许模糊运行以更高效地执行,浪费了更少的计算。

夹紧

夹紧是通过减少调用函数时模糊测试器可能使用的输入值数量的常见方法。

夹紧在模糊测试中通常适用于两种情况。第一种是减少由于算术错误等原因导致的回滚,从而防止模糊测试器无法实现对目标合约的有意义行覆盖率。第二种确保模糊测试器不会探索因特权调用而导致属性中断的输入值。

在此互动中,我们关注第二种情况,以减少由Centifuge链调用的回调处理函数的调用,这在实践中实际上永远不会被传入(在我们的案例中,它们只是因为Centifuge链的调用被模糊测试而出现,这在识别到模糊Centifuge系统会增加不必要复杂性时被认为是多余的)。

在“设计安全”部分中解释的变更帮助减少了对此类夹紧的需求,但如果不对测试套件设置做进一步更改,某些值仍需要进行限制,以确保只探索现实场景。

减少偏见

在任何给定系统中,如果我们不想让模糊测试器探索显然因某些原因导致的回滚路径,我们需要确保仍然允许模糊测试器探索用户可以执行的所有可能路径,而不是将输入值限制得太严格,以免导致对模糊测试器的偏见。

我们希望模糊测试器探索不在无趣路径集合中有效路径的子集(我们通过夹紧来避免的路径)。

因此,一个良好的方法通常是使用系统中的状态变量值来定义夹紧边界,这提高了模糊测试器探索所有有效路径的可能性。

handleExecutedCollectRedeem函数作为用户对系统提出的赎回请求的回调,用于将其层次代币(代表其在池中存入的流动性)兑换为基础资产。假设在Centifuge链上正确执行,则我们可以假设handleExecutedCollectRedeem接收的trancheTokenPayout输入值无法大于请求的金额。因此,我们可以通过将trancheTokenPayout值对pendingRedeemRequest取模,来对在我们的LiquidityPoolCallbacks目标合约中的函数调用进行夹紧。

然而,上述夹紧并未考虑在不同的层次代币价格下进行的多次赎回请求,这可能更真实地模拟系统的现实行为。这是应用夹紧中潜在的偏见来源,可能会遗漏某些行为,但由于时间限制,在这次互动中承认了这一风险,但未予考虑。

可重用属性库

在这次互动中,如果时间允许,计划实施的目标之一是为由Centrifuge团队创建的ERC7540保险库规范实现一个可重用属性库。这将允许任何实现ERC7540保险库的人轻松使用该库中的函数测试应该在其上保持的属性。

在此次互动中实施这样一个库的困难在于定义的属性中使用了幽灵变量。这将要求实现ERC7540属性的协议也实现相同的幽灵变量,以跟踪其系统中的状态变化。

因此,为了使库更具可重用性,测试属性的目标合约被变为一个值,作为传递给属性的参数,这样可以使用其接口直接访问合约的状态变量:

就可重用性而言,在互动中使用的初始实现中,定义的属性中有许多适用于ERC7540规范本身的实现,而其他则特定于Centrifuge为其使用案例开发的实现。

解决方案是创建一个通用库(ERC7540Properties),而任何实现特定的检查都在Centrifuge特定的属性合约(ERC7540CentrifugeProperties)中执行,该合约覆盖了ERC7540Properties中的通用属性,并在调用_centrifugeSpecificPreChecks函数时执行Centrifuge特定的检查:

这通过布尔属性目标函数调用,模糊测试器实际上要调用的函数来实现:

结果:真实的破损属性

上述简化让测试套件得以再次运行长时间作业,揭示了由于实际错误的系统行为而破损的属性,而非测试套件实现中的问题(如这个所示)。

奖杯 🏆

在进行上述更改后发现的一个真实属性破损与maxRedeem变量有关。在实现中,调用deposit后的最大接收金额向下取整,以防止发生通过取整在用户而非协议的情况下缓慢排空系统的场景。这也限制了用户可以存入的最大金额,但最大金额的计算是使用向下取整的金额进行的,从而允许用户通过多次交易来规避向下取整的功能。

结论

我们看到上述技术如何帮助Recon团队在模糊测试器识别的破损属性中分离信号与噪声。

这强调了不仅要侧重于实现整个系统模糊测试器的高行覆盖率的重要性,还要追求创造具有实质性结果的覆盖率,需正确设置。此外,处理任何破损属性的结果以理解它们是由于系统操作不正确还是指示测试套件本身更深层次问题的能力,是整个不变性测试过程的关键。


订阅Recon

启动于10个月前

Recon帮助你构建和运行不变测试

  • 原文链接: getrecon.substack.com/p/...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Recon
Recon
江湖只有他的大名,没有他的介绍。