Skip to content

Commit afdb6f3

Browse files
First draft of TxOriginChecker with Taint check
1 parent 57db873 commit afdb6f3

File tree

5 files changed

+111
-9
lines changed

5 files changed

+111
-9
lines changed

evm-testcases/taint/example12/report.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
"files" : [ "report.json", "untyped_program.evm-testcases_taint_example12_example12.sol().json" ],
44
"info" : {
55
"cfgs" : "1",
6-
"duration" : "409ms",
7-
"end" : "2024-12-17T12:27:08.913+01:00",
6+
"duration" : "247ms",
7+
"end" : "2024-12-19T11:23:35.330+01:00",
88
"expressions" : "2",
99
"files" : "1",
1010
"globals" : "0",
1111
"members" : "1",
1212
"programs" : "1",
13-
"start" : "2024-12-17T12:27:08.504+01:00",
13+
"start" : "2024-12-19T11:23:35.083+01:00",
1414
"statements" : "9",
1515
"units" : "0",
1616
"version" : "0.1",

src/main/java/it/unipr/analysis/taint/TaintAbstractStack.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package it.unipr.analysis.taint;
22

3+
import it.unipr.analysis.StackElement;
34
import it.unive.lisa.analysis.BaseLattice;
45
import it.unive.lisa.analysis.Lattice;
56
import it.unive.lisa.analysis.ScopeToken;
@@ -1152,4 +1153,20 @@ public boolean equals(Object obj) {
11521153
public int hashCode() {
11531154
return java.util.Objects.hash(stack);
11541155
}
1156+
1157+
public TaintElement getSecondElement() {
1158+
if (isBottom())
1159+
return TaintElement.BOTTOM;
1160+
else if (isTop())
1161+
return TaintElement.TOP;
1162+
return this.stack.get(STACK_LIMIT - 2);
1163+
}
1164+
1165+
public TaintElement getFirstElement() {
1166+
if (isBottom())
1167+
return TaintElement.BOTTOM;
1168+
else if (isTop())
1169+
return TaintElement.TOP;
1170+
return this.stack.get(STACK_LIMIT - 1);
1171+
}
11551172
}

src/main/java/it/unipr/analysis/taint/TaintElement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ else if (isClean())
5757
*
5858
* @return {@code true} if this value is taint, {@code false} otherwise
5959
*/
60-
private boolean isTaint() {
60+
public boolean isTaint() {
6161
return this == TAINT;
6262
}
6363

src/main/java/it/unipr/cfg/EVMCFG.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,27 @@ public Set<Statement> getAllJumps() {
127127

128128
return jumpNodes;
129129
}
130+
131+
/**
132+
* Returns a set of all the JUMPI statements in the CFG.
133+
*
134+
* @return a set of all the JUMPI statements in the CFG
135+
*/
136+
public Set<Statement> getAllJumpI() {
137+
if (jumpNodes == null) {
138+
NodeList<CFG, Statement, Edge> cfgNodeList = this.getNodeList();
139+
Set<Statement> jumpStatements = new HashSet<>();
140+
141+
for (Statement statement : cfgNodeList.getNodes()) {
142+
if (statement instanceof Jumpi) {
143+
jumpStatements.add(statement);
144+
}
145+
}
146+
return jumpNodes = jumpStatements;
147+
}
148+
149+
return jumpNodes;
150+
}
130151

131152
public int getOpcodeCount() {
132153
// -1 for the return statement

src/main/java/it/unipr/checker/TxOriginChecker.java

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package it.unipr.checker;
22

3+
import it.unipr.analysis.AbstractStack;
34
import it.unipr.analysis.EVMAbstractState;
45
import it.unipr.analysis.MyCache;
6+
import it.unipr.analysis.StackElement;
7+
import it.unipr.analysis.taint.TaintAbstractStack;
8+
import it.unipr.analysis.taint.TaintElement;
59
import it.unipr.cfg.EVMCFG;
610
import it.unipr.cfg.Origin;
711
import it.unipr.cfg.ProgramCounterLocation;
12+
import it.unive.lisa.analysis.AnalysisState;
13+
import it.unive.lisa.analysis.AnalyzedCFG;
14+
import it.unive.lisa.analysis.SemanticException;
815
import it.unive.lisa.analysis.SimpleAbstractState;
916
import it.unive.lisa.analysis.heap.MonolithicHeap;
1017
import it.unive.lisa.analysis.nonrelational.value.TypeEnvironment;
@@ -18,22 +25,63 @@
1825
import org.apache.logging.log4j.Logger;
1926

2027
public class TxOriginChecker implements
21-
SemanticCheck<SimpleAbstractState<MonolithicHeap, EVMAbstractState, TypeEnvironment<InferredTypes>>> {
28+
SemanticCheck<SimpleAbstractState<MonolithicHeap, TaintAbstractStack, TypeEnvironment<InferredTypes>>> {
2229

2330
private static final Logger log = LogManager.getLogger(TxOriginChecker.class);
2431

2532
@Override
2633
public boolean visit(
2734
CheckToolWithAnalysisResults<
28-
SimpleAbstractState<MonolithicHeap, EVMAbstractState, TypeEnvironment<InferredTypes>>> tool,
35+
SimpleAbstractState<MonolithicHeap, TaintAbstractStack, TypeEnvironment<InferredTypes>>> tool,
2936
CFG graph, Statement node) {
3037

3138
if (node instanceof Origin) {
3239
EVMCFG cfg = ((EVMCFG) graph);
33-
Set<Statement> jumps = cfg.getAllJumps();
40+
Set<Statement> jumps = cfg.getAllJumpI();
3441
Statement origin = node;
3542

36-
for (Statement jump : jumps) {
43+
for (AnalyzedCFG<SimpleAbstractState<MonolithicHeap, TaintAbstractStack,
44+
TypeEnvironment<InferredTypes>>> result : tool.getResultOf(cfg)) {
45+
AnalysisState<SimpleAbstractState<MonolithicHeap, TaintAbstractStack,
46+
TypeEnvironment<InferredTypes>>> analysisResult = null;
47+
48+
for(Statement jump: jumps) {
49+
try {
50+
analysisResult = result.getAnalysisStateBefore(jump);
51+
} catch (SemanticException e1) {
52+
log.error("(TxOriginChecker): {}", e1.getMessage());
53+
}
54+
55+
// Retrieve the symbolic stack from the analysis result
56+
TaintAbstractStack taintedStack = analysisResult.getState().getValueState();
57+
58+
// If the stack is bottom, the jump is definitely
59+
// unreachable
60+
if (taintedStack.isBottom())
61+
// Nothing to do
62+
continue;
63+
else {
64+
TaintElement firstStackElement = taintedStack.getFirstElement();
65+
TaintElement secondStackElement = taintedStack.getSecondElement();
66+
if(secondStackElement.isBottom())
67+
// Nothing to do
68+
continue;
69+
else {
70+
// Checks if either first or second element in the stack is tainted
71+
if(firstStackElement.isTaint() || secondStackElement.isTaint()) {
72+
checkForTxOrigin(origin, jump, tool, cfg);
73+
}
74+
}
75+
}
76+
}
77+
78+
79+
80+
81+
82+
83+
}
84+
/*for (Statement jump : jumps) {
3785
if (cfg.reachableFrom(origin, jump)) {
3886
ProgramCounterLocation jumploc = (ProgramCounterLocation) jump.getLocation();
3987
@@ -54,10 +102,26 @@ public boolean visit(
54102
// contaminated value from the stack by origin opcode
55103
// (GENERICS)
56104
}
57-
}
105+
}*/
58106

59107
}
60108

61109
return true;
62110
}
111+
112+
private void checkForTxOrigin(Statement origin, Statement jump, CheckToolWithAnalysisResults<
113+
SimpleAbstractState<MonolithicHeap, TaintAbstractStack, TypeEnvironment<InferredTypes>>> tool, EVMCFG cfg) {
114+
if (cfg.reachableFrom(origin, jump)) {
115+
ProgramCounterLocation jumploc = (ProgramCounterLocation) jump.getLocation();
116+
117+
log.debug("Tx. Origin attack at {} at line no. {} coming from line {}", jumploc.getPc(),
118+
jumploc.getSourceCodeLine(),
119+
((ProgramCounterLocation) origin.getLocation()).getSourceCodeLine());
120+
121+
String warn = "TxOrigin attack at " + jumploc.getPc();
122+
tool.warn(warn);
123+
MyCache.getInstance().addTxOriginWarning(cfg.hashCode(), warn);
124+
125+
}
126+
}
63127
}

0 commit comments

Comments
 (0)