Skip to content

Commit 470eb13

Browse files
committed
Added cross-chain policy support and refactored Bridge initialization
1 parent 48c7c34 commit 470eb13

File tree

5 files changed

+179
-53
lines changed

5 files changed

+179
-53
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"policy": [
3+
{
4+
"event": "Deposit",
5+
"function": "deposit"
6+
},
7+
{
8+
"event": "Deposit",
9+
"function": "depositWithExpiry"
10+
},
11+
{
12+
"event": "TransferOut",
13+
"function": "transferOut"
14+
},
15+
{
16+
"event": "TransferOut",
17+
"function": "batchTransferOut"
18+
},
19+
{
20+
"event": "TransferAllowance",
21+
"function": "transferAllowance"
22+
},
23+
{
24+
"event": "VaultTransfer",
25+
"function": "returnVaultAssets"
26+
},
27+
{
28+
"event": "TransferOutAndCall",
29+
"function": "transferOutAndCall"
30+
},
31+
{
32+
"event": "Outbound",
33+
"function": "transferOut"
34+
},
35+
{
36+
"event": "Deposited",
37+
"function": "depositIncentives"
38+
},
39+
{
40+
"event": "Deposited",
41+
"function": "depositBatchIncentives"
42+
},
43+
{
44+
"event": "Deposited",
45+
"function": "_depositAndSync"
46+
},
47+
{
48+
"event": "Transfer",
49+
"function": "_transfer"
50+
},
51+
{
52+
"event": "Transfer",
53+
"function": "_mint"
54+
},
55+
{
56+
"event": "Transfer",
57+
"function": "_burn"
58+
},
59+
{
60+
"event": "Approval",
61+
"function": "_approve"
62+
},
63+
{
64+
"event": "OwnershipTransferred",
65+
"function": "constructor"
66+
},
67+
{
68+
"event": "OwnershipTransferred",
69+
"function": "renounceOwnership"
70+
},
71+
{
72+
"event": "OwnershipTransferred",
73+
"function": "transferOwnership"
74+
}
75+
]
76+
}

src/main/java/it/unipr/EVMLiSA.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,14 @@ private void go(String[] args) {
192192
if (cmd.hasOption("cross-chain-analysis")
193193
&& cmd.hasOption("bytecode-directory-path")
194194
&& cmd.hasOption("abi-directory-path")) {
195+
Path policyPath = null;
196+
if (cmd.hasOption("cross-chain-policy"))
197+
policyPath = Path.of(cmd.getOptionValue("cross-chain-policy"));
198+
195199
xEVMLiSA.runAnalysis(
196200
Path.of(cmd.getOptionValue("bytecode-directory-path")),
197-
Path.of(cmd.getOptionValue("abi-directory-path")));
201+
Path.of(cmd.getOptionValue("abi-directory-path")),
202+
policyPath);
198203
return;
199204
}
200205

@@ -969,6 +974,13 @@ private Options getOptions() {
969974
.hasArg(false)
970975
.build();
971976

977+
Option crossChainPolicyOption = Option.builder()
978+
.longOpt("cross-chain-policy")
979+
.desc("Import a cross-chain policy.")
980+
.required(false)
981+
.hasArg(true)
982+
.build();
983+
972984
Option crossChainBytecodeDirectoryPathOption = Option.builder()
973985
.longOpt("bytecode-directory-path")
974986
.desc("Directory path of bytecode files.")
@@ -1013,6 +1025,7 @@ private Options getOptions() {
10131025
options.addOption(enableCrossChainAnalysisOption);
10141026
options.addOption(crossChainBytecodeDirectoryPathOption);
10151027
options.addOption(crossChainAbiDirectoryPathOption);
1028+
options.addOption(crossChainPolicyOption);
10161029

10171030
return options;
10181031
}

src/main/java/it/unipr/crosschain/Bridge.java

Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.nio.file.Path;
1717
import java.util.*;
1818
import org.apache.commons.io.FilenameUtils;
19+
import org.apache.commons.lang3.tuple.Pair;
1920
import org.apache.logging.log4j.LogManager;
2021
import org.apache.logging.log4j.Logger;
2122
import org.json.JSONArray;
@@ -29,42 +30,28 @@ public class Bridge implements Iterable<SmartContract> {
2930

3031
private EVMCFG xCFG;
3132

33+
private final List<Pair<String, String>> policy;
34+
3235
/** Detected vulnerabilities in the bridge. */
3336
private VulnerabilitiesObject _vulnerabilities;
3437

3538
public Bridge(String name) {
36-
this.name = name;
37-
this.contracts = new ArrayList<>();
39+
this(null, null, null, name);
40+
}
41+
42+
public Bridge(Path bytecodeDirectoryPath, Path abiDirectoryPath, Path policyPath) {
43+
this(bytecodeDirectoryPath, abiDirectoryPath, policyPath, "unknown_bridge_" + System.currentTimeMillis());
3844
}
3945

40-
/**
41-
* Initializes the bridge by mapping and matching smart contracts from the
42-
* ABI and bytecode directories. It creates `SmartContract` objects for each
43-
* contract that has both an ABI and a bytecode file.
44-
*
45-
* @param bytecodeDirectoryPath the path to the directory containing
46-
* bytecode files
47-
* @param abiDirectoryPath the path to the directory containing ABI
48-
* files
49-
*/
5046
public Bridge(Path bytecodeDirectoryPath, Path abiDirectoryPath) {
51-
this(bytecodeDirectoryPath, abiDirectoryPath, "unknown_bridge_" + System.currentTimeMillis());
47+
this(bytecodeDirectoryPath, abiDirectoryPath, null, "unknown_bridge_" + System.currentTimeMillis());
5248
}
5349

54-
/**
55-
* Constructs a Bridge object, initializing its fields and mapping smart
56-
* contracts from the specified ABI and bytecode directories. It creates
57-
* `SmartContract` objects for any contracts that have matching ABI and
58-
* bytecode files.
59-
*
60-
* @param bytecodeDirectoryPath the path to the directory containing
61-
* bytecode files
62-
* @param abiDirectoryPath the path to the directory containing ABI
63-
* files
64-
* @param name the name of the bridge
65-
*/
66-
public Bridge(Path bytecodeDirectoryPath, Path abiDirectoryPath, String name) {
67-
this(name);
50+
public Bridge(Path bytecodeDirectoryPath, Path abiDirectoryPath, Path policyPath, String name) {
51+
this.name = name;
52+
this.contracts = new ArrayList<>();
53+
this.policy = new ArrayList<>();
54+
6855
Map<String, Path> abiFiles = mapFilesByName(abiDirectoryPath, ".abi");
6956
Map<String, Path> bytecodeFiles = mapFilesByName(bytecodeDirectoryPath, ".bytecode");
7057

@@ -76,6 +63,12 @@ public Bridge(Path bytecodeDirectoryPath, Path abiDirectoryPath, String name) {
7663
}
7764
}
7865
log.info("Created bridge {} with {} contracts.", name, contracts.size());
66+
67+
if (policyPath != null)
68+
loadPolicy(policyPath);
69+
else
70+
log.info("Created bridge without policy. Using default policy");
71+
7972
}
8073

8174
public String getName() {
@@ -104,6 +97,24 @@ public EVMCFG getXCFG() {
10497
return xCFG;
10598
}
10699

100+
public List<Pair<String, String>> getPolicy() {
101+
return policy;
102+
}
103+
104+
public boolean hasEventFunctionMapping(String event) {
105+
for (Pair<String, String> pair : policy)
106+
if (pair.getLeft().equals(event))
107+
return true;
108+
return false;
109+
}
110+
111+
public String getFunctionForEvent(String event) {
112+
for (Pair<String, String> pair : policy)
113+
if (pair.getLeft().equals(event))
114+
return pair.getRight();
115+
return null;
116+
}
117+
107118
public void addEdges(Set<Edge> edges) {
108119
for (Edge edge : edges)
109120
addEdge(edge);
@@ -165,6 +176,34 @@ public EVMCFG buildPartialXCFG() {
165176
return xCFG;
166177
}
167178

179+
private void loadPolicy(Path policyPath) {
180+
try {
181+
log.info("Loading policy from: {}", policyPath);
182+
String content = Files.readString(policyPath);
183+
JSONObject policyJson = new JSONObject(content);
184+
185+
if (policyJson.has("policy")) {
186+
JSONArray eventFunctionPairs = policyJson.getJSONArray("policy");
187+
188+
for (int i = 0; i < eventFunctionPairs.length(); i++) {
189+
JSONObject pair = eventFunctionPairs.getJSONObject(i);
190+
String event = pair.getString("event");
191+
String function = pair.getString("function");
192+
policy.add(Pair.of(event, function));
193+
}
194+
195+
log.info("Loaded {} event-function pairs from policy.", policy.size());
196+
log.debug("Policy: {}", policy);
197+
} else {
198+
log.warn("Policy file does not contain 'policy' array.");
199+
}
200+
} catch (IOException e) {
201+
log.error("Error reading policy file: {}", e.getMessage());
202+
} catch (Exception e) {
203+
log.error("Error parsing policy JSON: {}", e.getMessage());
204+
}
205+
}
206+
168207
/**
169208
* Scans a directory for files with a given extension and maps them by their
170209
* base name. The base name is derived from the file name without its
@@ -204,8 +243,14 @@ public JSONObject toJson() {
204243
contractsArray.put(contract.toJson());
205244
}
206245

246+
JSONObject policyJson = new JSONObject();
247+
for (Pair<String, String> pair : policy) {
248+
policyJson.put(pair.getLeft(), pair.getRight());
249+
}
250+
207251
json.put("name", name);
208252
json.put("smart_contracts", contractsArray);
253+
json.put("policy", policyJson);
209254
json.put("bridge_vulnerabilities", _vulnerabilities != null ? _vulnerabilities.toJson() : new JSONArray());
210255
return json;
211256
}

src/main/java/it/unipr/crosschain/xEVMLiSA.java

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.nio.file.Path;
2727
import java.util.*;
2828
import java.util.concurrent.Future;
29+
import org.apache.commons.lang3.tuple.Pair;
2930
import org.apache.logging.log4j.LogManager;
3031
import org.apache.logging.log4j.Logger;
3132
import org.json.JSONArray;
@@ -34,21 +35,11 @@
3435
public class xEVMLiSA {
3536
private static final Logger log = LogManager.getLogger(xEVMLiSA.class);
3637

37-
/**
38-
* Runs analysis by initializing a bridge using the specified bytecode
39-
* directory path and ABI directory path, and then invoking the
40-
* analyzeBridge method on the bridge.
41-
*
42-
* @param bytecodeDirectoryPath The path to the directory containing the
43-
* smart contract bytecode files.
44-
* @param abiDirectoryPath The path to the directory containing the ABI
45-
* (Application Binary Interface) files.
46-
*/
47-
public static void runAnalysis(Path bytecodeDirectoryPath, Path abiDirectoryPath) {
38+
public static void runAnalysis(Path bytecodeDirectoryPath, Path abiDirectoryPath, Path policyPath) {
4839
EVMLiSA.setLinkUnsoundJumpsToAllJumpdest();
4940
EVMLiSA.setCores(Runtime.getRuntime().availableProcessors() - 1);
5041

51-
Bridge bridge = new Bridge(bytecodeDirectoryPath, abiDirectoryPath);
42+
Bridge bridge = new Bridge(bytecodeDirectoryPath, abiDirectoryPath, policyPath);
5243

5344
analyzeBridge(bridge);
5445

@@ -102,7 +93,7 @@ public static Set<Edge> getCrossChainEdgesUsingEventsAndFunctionsEntrypoint(Brid
10293
for (Signature event : contractSource.getEventsSignature()) {
10394
for (Signature function : contractDestination.getFunctionsSignature()) {
10495

105-
if (xEVMLiSA.defaultPolicy(event, function)) {
96+
if (xEVMLiSA.applyPolicy(bridge.getPolicy(), event, function)) {
10697
functionsUsed.add(function.getFullSignature());
10798
eventUsed.add(event.getFullSignature());
10899

@@ -139,17 +130,18 @@ public static Set<Edge> getCrossChainEdgesUsingEventsAndFunctionsEntrypoint(Brid
139130
return crossChainEdges;
140131
}
141132

142-
/**
143-
* Matches events and functions by name.
144-
*
145-
* @param event The event signature to compare with the function's name.
146-
* @param function The function signature whose name will be compared with
147-
* the event's name.
148-
*
149-
* @return True if the names match, false otherwise.
150-
*/
151-
public static boolean defaultPolicy(Signature event, Signature function) {
152-
return event.getName().equalsIgnoreCase(function.getName());
133+
public static boolean applyPolicy(List<Pair<String, String>> policy, Signature event, Signature function) {
134+
if (policy == null || policy.isEmpty())
135+
return event.getName().equalsIgnoreCase(function.getName());
136+
137+
for (Pair<String, String> pair : policy) {
138+
String eventPolicy = pair.getLeft();
139+
String functionPolicy = pair.getRight();
140+
if (eventPolicy.equalsIgnoreCase(event.getName())
141+
&& functionPolicy.equalsIgnoreCase(function.getName()))
142+
return true;
143+
}
144+
return false;
153145
}
154146

155147
/**

src/test/java/it/unipr/analysis/cron/SmartaxeBenchmark.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ private void runBenchmark() {
5555
String name = dir.getFileName().toString();
5656

5757
EVMLiSA.setWorkingDirectory(workingDirectory.resolve(name));
58-
bridges.add(new Bridge(bytecodeDirectoryPath, abiDirectoryPath, name));
58+
bridges.add(new Bridge(bytecodeDirectoryPath, abiDirectoryPath, null, name));
5959
}
6060
}
6161
} catch (IOException e) {

0 commit comments

Comments
 (0)