Skip to content

Commit 4e05bb4

Browse files
committed
Merge branch 'develop' of github.com:secure-software-engineering/FlowDroid into develop
2 parents 36071aa + 8c7acde commit 4e05bb4

File tree

15 files changed

+329
-69
lines changed

15 files changed

+329
-69
lines changed

soot-infoflow-android/pom.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,12 @@
125125
<dependency>
126126
<groupId>org.slf4j</groupId>
127127
<artifactId>slf4j-simple</artifactId>
128-
<version>1.7.5</version>
128+
<version>1.7.32</version>
129129
</dependency>
130130
<dependency>
131131
<groupId>org.slf4j</groupId>
132132
<artifactId>slf4j-api</artifactId>
133-
<version>1.7.5</version>
133+
<version>1.7.32</version>
134134
</dependency>
135135
<dependency>
136136
<groupId>de.tud.sse</groupId>
@@ -140,7 +140,7 @@
140140
<dependency>
141141
<groupId>junit</groupId>
142142
<artifactId>junit</artifactId>
143-
<version>4.13.1</version>
143+
<version>4.13.2</version>
144144
<scope>test</scope>
145145
</dependency>
146146
<dependency>
@@ -163,12 +163,12 @@
163163
<dependency>
164164
<groupId>com.google.protobuf</groupId>
165165
<artifactId>protobuf-java</artifactId>
166-
<version>3.18.1</version>
166+
<version>3.19.2</version>
167167
</dependency>
168168
<dependency>
169169
<groupId>com.esotericsoftware</groupId>
170170
<artifactId>kryo</artifactId>
171-
<version>5.2.0</version>
171+
<version>5.2.1</version>
172172
</dependency>
173173
</dependencies>
174174

soot-infoflow-android/src/soot/jimple/infoflow/android/axml/AXmlNode.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,19 @@ public List<AXmlNode> getChildrenWithTag(String tag) {
198198
return children;
199199
}
200200

201+
/**
202+
* Removes an element from the attributes.
203+
*
204+
* @param key the key
205+
* @return the previously associated value or null
206+
*/
207+
public AXmlAttribute<?> removeAttribute(String key) {
208+
if (this.attributes == null)
209+
return null;
210+
return this.attributes.remove(key);
211+
}
212+
213+
201214
/**
202215
* Returns a map which contains all attributes. The keys match the attributes'
203216
* names.

soot-infoflow-android/src/soot/jimple/infoflow/android/axml/parsers/AXML20Parser.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public void attr(String ns, String name, int resourceId, int type, Object obj) {
7878
// Without a name, we cannot really carry on
7979
return;
8080
}
81+
if (tname == null)
82+
tname = String.valueOf(resourceId);
8183
}
8284
} else
8385
tname = name.trim();

soot-infoflow-android/src/soot/jimple/infoflow/android/callbacks/AbstractCallbackAnalyzer.java

Lines changed: 149 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,16 @@
2424
import java.util.List;
2525
import java.util.Map;
2626
import java.util.Set;
27+
import java.util.concurrent.ExecutionException;
2728

2829
import org.slf4j.Logger;
2930
import org.slf4j.LoggerFactory;
3031

32+
import com.google.common.cache.CacheBuilder;
33+
import com.google.common.cache.CacheLoader;
34+
import com.google.common.cache.LoadingCache;
35+
36+
import heros.solver.Pair;
3137
import soot.AnySubType;
3238
import soot.Body;
3339
import soot.FastHierarchy;
@@ -36,12 +42,17 @@
3642
import soot.RefType;
3743
import soot.Scene;
3844
import soot.SootClass;
45+
import soot.SootField;
3946
import soot.SootMethod;
4047
import soot.SootMethodRef;
4148
import soot.Type;
4249
import soot.Unit;
4350
import soot.Value;
51+
import soot.jimple.ArrayRef;
52+
import soot.jimple.AssignStmt;
53+
import soot.jimple.CastExpr;
4454
import soot.jimple.ClassConstant;
55+
import soot.jimple.FieldRef;
4556
import soot.jimple.IdentityStmt;
4657
import soot.jimple.InstanceInvokeExpr;
4758
import soot.jimple.InvokeExpr;
@@ -59,6 +70,9 @@
5970
import soot.jimple.infoflow.values.IValueProvider;
6071
import soot.jimple.infoflow.values.SimpleConstantValueProvider;
6172
import soot.jimple.toolkits.callgraph.Edge;
73+
import soot.toolkits.graph.ExceptionalUnitGraph;
74+
import soot.toolkits.graph.ExceptionalUnitGraphFactory;
75+
import soot.toolkits.scalar.SimpleLocalDefs;
6276
import soot.util.HashMultiMap;
6377
import soot.util.MultiMap;
6478

@@ -94,10 +108,16 @@ public abstract class AbstractCallbackAnalyzer {
94108

95109
protected final SootClass scSupportViewPager = Scene.v().getSootClassUnsafe("android.support.v4.view.ViewPager");
96110
protected final SootClass scAndroidXViewPager = Scene.v().getSootClassUnsafe("androidx.viewpager.widget.ViewPager");
111+
97112
protected final SootClass scFragmentStatePagerAdapter = Scene.v()
98113
.getSootClassUnsafe("android.support.v4.app.FragmentStatePagerAdapter");
114+
protected final SootClass scFragmentPagerAdapter = Scene.v()
115+
.getSootClassUnsafe("android.support.v4.app.FragmentPagerAdapter");
116+
99117
protected final SootClass scAndroidXFragmentStatePagerAdapter = Scene.v()
100118
.getSootClassUnsafe("androidx.fragment.app.FragmentStatePagerAdapter");
119+
protected final SootClass scAndroidXFragmentPagerAdapter = Scene.v()
120+
.getSootClassUnsafe("androidx.fragment.app.FragmentPagerAdapter");
101121

102122
protected final InfoflowAndroidConfiguration config;
103123
protected final Set<SootClass> entryPointClasses;
@@ -115,6 +135,69 @@ public abstract class AbstractCallbackAnalyzer {
115135

116136
protected IValueProvider valueProvider = new SimpleConstantValueProvider();
117137

138+
protected LoadingCache<SootField, List<Type>> arrayToContentTypes = CacheBuilder.newBuilder()
139+
.build(new CacheLoader<SootField, List<Type>>() {
140+
141+
@Override
142+
public List<Type> load(SootField field) throws Exception {
143+
// Find all assignments to this field
144+
List<Type> typeList = new ArrayList<>();
145+
field.getDeclaringClass().getMethods().stream().filter(m -> m.isConcrete())
146+
.map(m -> m.retrieveActiveBody()).forEach(b -> {
147+
// Find all locals that reference the field
148+
Set<Local> arrayLocals = new HashSet<>();
149+
for (Unit u : b.getUnits()) {
150+
if (u instanceof AssignStmt) {
151+
AssignStmt assignStmt = (AssignStmt) u;
152+
Value rop = assignStmt.getRightOp();
153+
Value lop = assignStmt.getLeftOp();
154+
if (rop instanceof FieldRef && ((FieldRef) rop).getField() == field) {
155+
arrayLocals.add((Local) lop);
156+
} else if (lop instanceof FieldRef && ((FieldRef) lop).getField() == field) {
157+
arrayLocals.add((Local) rop);
158+
}
159+
}
160+
}
161+
162+
// Find casts
163+
for (Unit u : b.getUnits()) {
164+
if (u instanceof AssignStmt) {
165+
AssignStmt assignStmt = (AssignStmt) u;
166+
Value rop = assignStmt.getRightOp();
167+
Value lop = assignStmt.getLeftOp();
168+
169+
if (rop instanceof CastExpr) {
170+
CastExpr ce = (CastExpr) rop;
171+
if (arrayLocals.contains(ce.getOp()))
172+
arrayLocals.add((Local) lop);
173+
else if (arrayLocals.contains(lop))
174+
arrayLocals.add((Local) ce.getOp());
175+
}
176+
}
177+
}
178+
179+
// Find the assignments to the array locals
180+
for (Unit u : b.getUnits()) {
181+
if (u instanceof AssignStmt) {
182+
AssignStmt assignStmt = (AssignStmt) u;
183+
Value rop = assignStmt.getRightOp();
184+
Value lop = assignStmt.getLeftOp();
185+
if (lop instanceof ArrayRef) {
186+
ArrayRef arrayRef = (ArrayRef) lop;
187+
if (arrayLocals.contains(arrayRef.getBase())) {
188+
Type t = rop.getType();
189+
if (t instanceof RefType)
190+
typeList.add(rop.getType());
191+
}
192+
}
193+
}
194+
}
195+
});
196+
return typeList;
197+
}
198+
199+
});
200+
118201
public AbstractCallbackAnalyzer(InfoflowAndroidConfiguration config, Set<SootClass> entryPointClasses)
119202
throws IOException {
120203
this(config, entryPointClasses, "AndroidCallbacks.txt");
@@ -488,15 +571,23 @@ else if (methodName.equals("inflate") && stmt.getInvokeExpr().getArgCount() > 1)
488571
* @author Julius Naeumann
489572
*/
490573
protected void analyzeMethodForViewPagers(SootClass clazz, SootMethod method) {
491-
if (scSupportViewPager == null || scFragmentStatePagerAdapter == null)
492-
if (scAndroidXViewPager == null || scAndroidXFragmentStatePagerAdapter == null)
493-
return;
574+
// We need at least one fragment base class
575+
if (scSupportViewPager == null && scAndroidXViewPager == null)
576+
return;
577+
// We need at least one class with a method to register a fragment
578+
if (scFragmentStatePagerAdapter == null && scAndroidXFragmentStatePagerAdapter == null
579+
&& scFragmentPagerAdapter == null && scAndroidXFragmentPagerAdapter == null)
580+
return;
494581

495582
if (!method.isConcrete())
496583
return;
497584

498585
Body body = method.retrieveActiveBody();
499586

587+
if (method.getDeclaringClass().getName().equals("org.liberty.android.fantastischmemo.ui.AnyMemo")
588+
&& method.getName().equals("initDrawer"))
589+
System.out.println("x");
590+
500591
// look for invocations of ViewPager.setAdapter
501592
for (Unit u : body.getUnits()) {
502593
Stmt stmt = (Stmt) u;
@@ -525,7 +616,8 @@ protected void analyzeMethodForViewPagers(SootClass clazz, SootMethod method) {
525616
RefType rt = (RefType) pa.getType();
526617

527618
// check whether argument is of type FragmentStatePagerAdapter
528-
if (!safeIsType(pa, scFragmentStatePagerAdapter) && !safeIsType(pa, scAndroidXFragmentStatePagerAdapter))
619+
if (!safeIsType(pa, scFragmentStatePagerAdapter) && !safeIsType(pa, scAndroidXFragmentStatePagerAdapter)
620+
&& !safeIsType(pa, scFragmentPagerAdapter) && !safeIsType(pa, scAndroidXFragmentPagerAdapter))
529621
continue;
530622

531623
// now analyze getItem() to find possible Fragments
@@ -546,7 +638,59 @@ protected void analyzeMethodForViewPagers(SootClass clazz, SootMethod method) {
546638
Value rv = rs.getOp();
547639
Type type = rv.getType();
548640
if (type instanceof RefType) {
549-
checkAndAddFragment(method.getDeclaringClass(), ((RefType) type).getSootClass());
641+
SootClass rtClass = ((RefType) type).getSootClass();
642+
if (rv instanceof Local && (rtClass.getName().startsWith("android.")
643+
|| rtClass.getName().startsWith("androidx.")))
644+
analyzeFragmentCandidates(rs, getItem, (Local) rv);
645+
else
646+
checkAndAddFragment(method.getDeclaringClass(), rtClass);
647+
}
648+
}
649+
}
650+
}
651+
}
652+
653+
/**
654+
* Attempts to find fragments that are not returned immediately, but that
655+
* require a more complex backward analysis. This analysis is best-effort, we do
656+
* not attempt to solve every possible case.
657+
*
658+
* @param s The statement at which the fragment is returned
659+
* @param m The method in which the fragment is returned
660+
* @param l The local that contains the fragment
661+
*/
662+
private void analyzeFragmentCandidates(Stmt s, SootMethod m, Local l) {
663+
ExceptionalUnitGraph g = ExceptionalUnitGraphFactory.createExceptionalUnitGraph(m.getActiveBody());
664+
SimpleLocalDefs lds = new SimpleLocalDefs(g);
665+
666+
List<Pair<Local, Stmt>> toSearch = new ArrayList<>();
667+
Set<Pair<Local, Stmt>> doneSet = new HashSet<>();
668+
toSearch.add(new Pair<>(l, s));
669+
670+
while (!toSearch.isEmpty()) {
671+
Pair<Local, Stmt> pair = toSearch.remove(0);
672+
if (doneSet.add(pair)) {
673+
List<Unit> defs = lds.getDefsOfAt(pair.getO1(), pair.getO2());
674+
for (Unit def : defs) {
675+
if (def instanceof AssignStmt) {
676+
AssignStmt assignStmt = (AssignStmt) def;
677+
Value rop = assignStmt.getRightOp();
678+
if (rop instanceof ArrayRef) {
679+
ArrayRef arrayRef = (ArrayRef) rop;
680+
681+
// Look for all assignments to the array
682+
toSearch.add(new Pair<>((Local) arrayRef.getBase(), assignStmt));
683+
} else if (rop instanceof FieldRef) {
684+
FieldRef fieldRef = (FieldRef) rop;
685+
try {
686+
List<Type> typeList = arrayToContentTypes.get(fieldRef.getField());
687+
typeList.stream().map(t -> ((RefType) t).getSootClass())
688+
.forEach(c -> checkAndAddFragment(m.getDeclaringClass(), c));
689+
} catch (ExecutionException e) {
690+
logger.error(String.format("Could not load potential types for field %s",
691+
fieldRef.getField().getSignature()), e);
692+
}
693+
}
550694
}
551695
}
552696
}

soot-infoflow-android/src/soot/jimple/infoflow/android/callbacks/DefaultCallbackAnalyzer.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,10 @@ protected void internalTransform(String phaseName, @SuppressWarnings("rawtypes")
115115
reachableChangedListener = Scene.v().getReachableMethods().listener();
116116
logger.info("Callback analysis done.");
117117
} else {
118-
// Incremental mode, only process the worklist
119-
logger.info(String.format("Running incremental callback analysis for %d components...",
120-
callbackWorklist.size()));
121118
// Find the mappings between classes and layouts
122119
findClassLayoutMappings();
123120

121+
// Add the methods that have become reachable in the views
124122
MultiMap<SootMethod, SootClass> reverseViewCallbacks = new HashMultiMap<>();
125123
for (Pair<SootClass, AndroidCallbackDefinition> i : viewCallbacks)
126124
reverseViewCallbacks.put(i.getO2().getTargetMethod(), i.getO1());
@@ -132,6 +130,10 @@ protected void internalTransform(String phaseName, @SuppressWarnings("rawtypes")
132130
}
133131
}
134132

133+
// Incremental mode, only process the worklist
134+
logger.info(String.format("Running incremental callback analysis for %d components...",
135+
callbackWorklist.size()));
136+
135137
MultiMap<SootClass, SootMethod> workList = new HashMultiMap<>(callbackWorklist);
136138
for (Iterator<SootClass> it = workList.keySet().iterator(); it.hasNext();) {
137139
// Check whether we're still running

soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/Main.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class Main {
4747
private static final String OPTION_CLASS_TIMEOUT = "ct";
4848
private static final String OPTION_ANALYZE_HASHCODE_EQUALS = "he";
4949
private static final String OPTION_ANDROID_PLATFORMS = "p";
50+
private static final String OPTION_IGNORE_DEFAULT_SUMMARIES = "is";
5051
private static final String OPTION_WRITE_JIMPLE_FILES = "wj";
5152

5253
public static void main(final String[] args) throws FileNotFoundException, XMLStreamException {
@@ -80,6 +81,8 @@ private void initializeCommandLineOptions() {
8081
"Also analyze hashCode() and equals() methods");
8182
options.addOption(OPTION_ANDROID_PLATFORMS, "platformsdir", true,
8283
"Path to the platforms directory from the Android SDK");
84+
options.addOption(OPTION_IGNORE_DEFAULT_SUMMARIES, "ignoresummaries", false,
85+
"Existing summaries from the default summary directory are ignored");
8386
options.addOption(OPTION_WRITE_JIMPLE_FILES, "writejimplefiles", false, "Write out the Jimple files");
8487
}
8588

@@ -203,6 +206,11 @@ protected void configureOptionalSettings(CommandLine cmd, SummaryGenerator gener
203206
String platformsDir = cmd.getOptionValue(OPTION_ANDROID_PLATFORMS);
204207
generator.getConfig().setAndroidPlatformDir(platformsDir);
205208
}
209+
{
210+
boolean ignoreDefaultSummaries = cmd.hasOption(OPTION_IGNORE_DEFAULT_SUMMARIES);
211+
if (ignoreDefaultSummaries)
212+
generator.getConfig().setUseDefaultSummaries(false);
213+
}
206214
{
207215
boolean writeJimpleFiles = cmd.hasOption(OPTION_WRITE_JIMPLE_FILES);
208216
if (writeJimpleFiles)

soot-infoflow-summaries/src/soot/jimple/infoflow/methodSummary/generator/SummaryGenerationTaintWrapper.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,19 +127,23 @@ protected Set<Abstraction> getTaintsForHashCodeEquals(Stmt stmt, Abstraction tai
127127
InstanceInvokeExpr iiexpr = (InstanceInvokeExpr) iexpr;
128128
AccessPath ap = taintedPath.getAccessPath();
129129

130+
final Set<Abstraction> taints = new HashSet<Abstraction>();
131+
132+
// We always keep the incoming taint
133+
taints.add(taintedPath);
134+
130135
// Check for hashCode()
131136
if (ref.getName().equals("hashCode") && ref.getParameterTypes().isEmpty()
132137
&& ref.getReturnType() instanceof IntType) {
133138
if (ap.getPlainValue() == iiexpr.getBase()) {
134139
// If the return value is used, we taint it
135140
if (stmt instanceof DefinitionStmt) {
136141
DefinitionStmt defStmt = (DefinitionStmt) stmt;
137-
return Collections.singleton(taintedPath.deriveNewAbstraction(
142+
taints.add(taintedPath.deriveNewAbstraction(
138143
manager.getAccessPathFactory().createAccessPath(defStmt.getLeftOp(), false), stmt));
139144
}
140145

141-
// The return value is apparently ignored
142-
return Collections.emptySet();
146+
return taints;
143147
}
144148
}
145149

@@ -150,12 +154,11 @@ protected Set<Abstraction> getTaintsForHashCodeEquals(Stmt stmt, Abstraction tai
150154
// If the return value is used, we taint it
151155
if (config.getImplicitFlowMode().trackControlFlowDependencies() && stmt instanceof DefinitionStmt) {
152156
DefinitionStmt defStmt = (DefinitionStmt) stmt;
153-
return Collections.singleton(taintedPath.deriveNewAbstraction(
157+
taints.add(taintedPath.deriveNewAbstraction(
154158
manager.getAccessPathFactory().createAccessPath(defStmt.getLeftOp(), false), stmt));
155159
}
156160

157-
// The return value is apparently ignored
158-
return Collections.emptySet();
161+
return taints;
159162
}
160163
}
161164

0 commit comments

Comments
 (0)