{ 跳到内容 }

逐字块去重中的错误

发布于 2023 年 11 月 8 日,作者 Solidity 团队

安全警报

2023 年 10 月 24 日,Ori Pomerantz报告了一个错误,该错误影响了在 Yul 代码中使用verbatim 内置函数。经过调查,团队确认了问题并找到了问题根源。该错误存在于块去重优化器步骤中,该步骤会识别并合并等效的汇编块。被相同操作码包围的 verbatim 汇编项目被错误地视为相同并被合并。

该错误从 0.8.5 版本开始存在,该版本引入了 verbatim,并且只影响启用了优化的纯 Yul 编译。Solidity 代码或内联汇编块中使用的 Yul 不会触发该错误。

使用 verbatim 不常见,触发该错误的条件(两个或多个被相同操作码包围的 verbatim 项目)非常特殊。此外,根据团队的调查,没有证据表明这可以被用作漏洞或攻击向量。虽然该错误如果存在,其影响将非常严重,但其可能性非常低。考虑到这一点,团队为该错误分配了 的整体评分。

哪些合约受到影响?

可能触发该错误的条件如下

  1. 编译纯 Yul 代码。
  2. 对具有不同数据的 verbatim 内置函数进行多次调用。
  3. 块去重优化器步骤正在使用中。

请注意,当启用了优化器时,默认情况下会启用块去重器。

如果您的项目不包含用纯 Yul 编写的合约,或者不使用 verbatim,那么它就不存在被影响的风险。

技术细节

使用 verbatim 的 Yul 代码,例如以下示例,容易受到该错误的影响

verbatim.yul

{
    let special := 0xFFFFFFFFFFFF
    let input := sload(0)
    let output

    switch input
    case 0x00 {
        output := verbatim_1i_1o(hex"506000", special)
    }
    case 0x01 {
        output := 1
    }
    case 0x02 {
        output := verbatim_1i_1o(hex"506002", special)
    }
    case 0x03 {
        output := 3
    }

    sstore(0, output)
}

在这种情况下,块去重器错误地认为 0x000x02 的案例块相同,因此可以合并为一个块。

去重步骤是 基于操作码的优化器 的一部分,它对汇编代码进行操作。它将指令序列拆分为块,通常用 JUMPSJUMPDEST 分隔。对这些块进行分析,并执行一系列优化步骤。在去重步骤中,优化器会映射哪些标签可以互相替换,因为它们引用的是相同操作码序列的块。如果两个块具有相同顺序的相同操作码,则它们被认为是相同的。

块去重器会识别出顺序执行的汇编操作码块,直到遇到能够改变控制流的操作码,例如 JUMPRETURNREVERT。然后,优化器会检查是否存在两个由相同汇编操作码序列组成的块。如果存在这样的块,优化器会用另一个块的标签替换引用一个块的标签,这意味着后面一个块将不再使用,并且可以随后被删除。

当检查两个块是否相等时,该错误出现了。对 verbatim 汇编项目的比较错误地认为所有此类项目都是相同的,无论它们的数据如何。因此,如果具有不同数据的 verbatim 指令出现在其他方面完全相同的块中,即使 verbatim 数据不同,它们也会被去重。

例如,当编译之前显示的 Yul 代码片段 **没有** 优化时,它将包含下面显示的汇编代码片段

solc --strict-assembly verbatim.yul --asm
tag_2:
  dup4
  verbatimbytecode_506000
  swap2
  pop
  jump(tag_1)
tag_3:
  0x01
  swap2
  pop
  jump(tag_1)
tag_4:
  dup4
  verbatimbytecode_506002
  swap2
  pop
  jump(tag_1)

请注意,由 tag_2tag_4 引用的块几乎相同。由于该错误,优化器的去重步骤会认为 verbatim 项目相等,尽管它们的内容不同。然后,优化器会 错误地tag_4 映射为 tag_2 的替换项,这将进一步导致由 tag_2 引用的块在后面被删除。

该错误的结果可以在下面显示的优化代码的输出中看到

solc --strict-assembly verbatim.yul --asm --optimize
  0x00
  dup1
  sload
  dup1
  iszero
  tag_5
  jumpi
  dup1
  0x01
  eq
  tag_3
  jumpi
  dup1
  0x02
  eq
  tag_5
  jumpi
  0x03
  eq
  tag_7
  jumpi
  0x00
  sstore
  stop
tag_7:
  pop
  0x03
  0x00
  sstore
  stop
tag_5:
  pop
  pop
  0xaabbccddeeff
  verbatimbytecode_506002
  0x00
  sstore
  stop
tag_3:
  pop
  pop
  0x01
  0x00
  sstore
  stop

请注意,这两个跳转都指向从 tag_5 开始的块。该块替换了 verbatimbytecode 项目的两个实例,尽管它们的内容不同。

上一篇文章

下一篇文章

参与进来

GitHub

Twitter

Mastodon

Matrix

了解更多

博客文档用例贡献关于论坛

2024Solidity 团队

安全策略

行为准则