2021年3月20日,我们团队在solidity 字节码优化器发现了一个Bug。
危害等级为中危,影响版本为 version < 0.8.3
字节码优化器会重用内联汇编中的keccak256哈希结果。
solidity的字节码优化器有一个优化步骤: 如果keccak256的哈希结果在余下的编译过程中用到了,则直接使用缓存结果。但这个步骤有一个bug,相同内容但长度不同的message,会被认为有相同的keccak256哈希结果。
下面的代码是一个小例子:
**contract** C {
**function** bug() **public** **returns** (**uint** a, **uint** b) {
**assembly** {
mstore(0, 0)
** a **:=** keccak256(0, 32)
** b **:=** keccak256(0, 23)
}
}
}
在上面的代码中,编译时会计算keccak256
下面的代码在编译过程中不会计算keccak256
。但效果都一样,都会被优化器判为相等哈希。
**contract** C {
**function** bug(**string** **memory** s) **public** **returns** (**bool** ret) {
**assembly** {
**let** a **:=** keccak256(s, 32)
**let** b **:=** keccak256(s, 8)
** ret **:=** eq(a, b)
}
}
}
**contract** C {
**function** bug() **public** **view** **returns** (**bool** ret) {
**assembly** {
**let** x **:=** calldataload(0)
mstore(0, x)
mstore(0x20, x)
**let** a **:=** keccak256(0, 4)
** **let** b **:=** keccak256(0x20, 8)
** ret **:=** eq(a, b)
}
}
}
如果 length1
和 length2
做四舍五入后相等,则keccak256(mpos, length1)
和 keccak256(mpos, length2)
相等。
以下特征的代码,不会受影响:
keccak256
keccak256
keccak256
中夹一个特定指令:
jumpi
, jump
etc.mstore
外的内存写入指令,例如call
, returndatacopy
, etc.注意,除了手写keccak256
,编译器还会自动生成一些keccak256
,比如
abi.encodeWithSignature