Rootstock智能合约执行效率漏洞:CODESIZE实现低效导致1.5分钟延迟

本文详细分析了Rootstock平台中VM.doCODESIZE()方法的低效实现,该漏洞允许恶意构造的智能合约通过大量数据传输导致执行时间长达1.5分钟,并提供了完整的复现步骤和优化补丁。

crafted智能合约因低效CODESIZE实现导致执行时间达1.5分钟

摘要

TLDR: VM.doCODESIZE()效率低下可能导致执行缓慢。

VM.doCODESIZE()通过调用Program.getCode()获取代码大小,然后对返回值调用length属性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
protected void doCODESIZE() {
    if (computeGas) {
        if (op == OpCode.EXTCODESIZE) {
            gasCost = GasCost.EXT_CODE_SIZE;
        }
        spendOpCodeGas();
    }
    // 执行阶段
    DataWord codeLength;
    if (op == OpCode.CODESIZE) {
        codeLength = DataWord.valueOf(program.getCode().length); // 初始化期间返回初始化代码大小
    }
}

这意味着每次调用CODESIZE时,program.getCode()都会返回整个字节数组。这一特性可被利用,在Program.getCode()和VM.doCODESIZE()之间传输大量数据(如下复现示例中总计超过1TB),导致执行非常缓慢。

复现步骤

复现环境(在Linux x64上测试):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
wget -q https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz
tar zxf openjdk-11.0.2_linux-x64_bin.tar.gz
export JAVA_HOME=$(realpath jdk-11.0.2/)
git clone --depth 1 https://github.com/rsksmart/rskj.git
cd rskj/
echo "task testJar(type: Jar) {" >>rskj-core/build.gradle
echo "    from sourceSets.test.output" >>rskj-core/build.gradle
echo "    classifier = 'tests'" >>rskj-core/build.gradle
echo "}" >>rskj-core/build.gradle
echo "assemble.dependsOn(testJar)" >>rskj-core/build.gradle
./configure.sh
# 构建rskj
./gradlew assemble
# 构造复现程序
echo """
[POC代码内容]
""" >Poc.java
# 构建复现程序
$JAVA_HOME/bin/javac -cp rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-tests.jar:rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-all.jar Poc.java
# 运行复现程序
time $JAVA_HOME/bin/java -cp .:rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-tests.jar:rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-all.jar Poc

在我的机器上,运行耗时1分29.355秒。

此复现程序使用遗传算法构建,不一定代表字节复制数量的全局最大值(即可能构造出更慢的示例)。

解决方案

通过在Program中实现getCodeLength()方法,并从VM.doCODESIZE()调用此方法,可以轻松完全缓解此问题,这样只传输代码长度而不是整个代码数组。特此授予您将此补丁应用到存储库的权利。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
diff --git a/rskj-core/src/main/java/org/ethereum/vm/VM.java b/rskj-core/src/main/java/org/ethereum/vm/VM.java
index 2365d38..88eb90d 100644
--- a/rskj-core/src/main/java/org/ethereum/vm/VM.java
+++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java
@@ -775,7 +775,7 @@ public class VM {
         // EXECUTION PHASE
         DataWord codeLength;
         if (op == OpCode.CODESIZE) {
-            codeLength = DataWord.valueOf(program.getCode().length); // during initialization it will return the initialization code size
+            codeLength = DataWord.valueOf(program.getCodeLength()); // during initialization it will return the initialization code size
         } else {
             DataWord address = program.stackPop();
             codeLength = DataWord.valueOf(program.getCodeLengthAt(address));
diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java
index 5a79952..35885d5 100644
--- a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java
+++ b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java
@@ -960,6 +960,10 @@ public class Program {
         return Arrays.copyOf(ops, ops.length);
     }
 
+    public int getCodeLength() {
+        return ops.length;
+    }
+
     public Keccak256 getCodeHashAt(RskAddress addr, boolean standard) {
         if(standard) {
             return invoke.getRepository().getCodeHashStandard(addr);

应用此补丁后,构建并再次运行:

1
2
3
4
5
6
# 构建rskj
./gradlew assemble
# 构建复现程序
$JAVA_HOME/bin/javac -cp rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-tests.jar:rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-all.jar Poc.java
# 运行复现程序
time $JAVA_HOME/bin/java -cp .:rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-tests.jar:rskj-core/build/libs/rskj-core-6.2.0-SNAPSHOT-all.jar Poc

现在执行时间仅为0分0.755秒,速度提高了118倍以上。

此测试在Linux x64(Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz)上使用提交a61e9080ba353fcbb6f94cf4606986a88c3043e3的rskj进行。

影响

摘要: 可能导致网络停滞。

时间线

  • 2024年5月3日 20:23 UTC: guido向Rootstock Labs提交报告
  • 2024年5月5日 14:01 UTC: Rootstock Labs确认收到报告并正在审查
  • 2024年5月8日 15:54 UTC: 严重性从高调整为中
  • 2024年5月8日 15:55 UTC: 确认报告有效
  • 2024年5月13日 10:45 UTC: 请求推进奖励流程
  • 2024年5月14日 13:36 UTC: Rootstock Labs确认正在处理
  • 2024年5月29日 17:51 UTC: 确认补丁已合并,请求奖励
  • 2024年5月30日 14:18 UTC: 奖励流程已启动
  • 2024年6月12日 10:01 UTC: 询问奖励进展
  • 2024年6月13日 11:38 UTC: 奖励发放,报告标记为已解决
  • 2025年6月10日 15:14 UTC: 请求披露报告
  • 2025年6月12日 18:52 UTC: 同意披露,报告已公开

报告ID: #2489843
状态: 已解决
严重性: 中 (4 ~ 6.9)
弱点: 不受控制的资源消耗
CVE ID:

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计