Skip to content

Commit a8c0108

Browse files
committed
Support for multiple pseudoconstants and fragment types
1 parent 8f488ff commit a8c0108

File tree

6 files changed

+126
-59
lines changed

6 files changed

+126
-59
lines changed

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

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.InputStreamReader;
1919
import java.io.Reader;
2020
import java.util.ArrayList;
21+
import java.util.Collections;
2122
import java.util.HashMap;
2223
import java.util.HashSet;
2324
import java.util.Iterator;
@@ -523,31 +524,27 @@ protected void analyzeMethodForFragmentTransaction(SootClass lifecycleElement, S
523524

524525
// first check if there is a Fragment manager, a fragment transaction
525526
// and a call to the add method which adds the fragment to the transaction
526-
boolean isFragmentManager = false;
527-
boolean isFragmentTransaction = false;
528-
boolean isAddTransaction = false;
527+
boolean isAddOrReplaceTransaction = false;
529528
for (Unit u : method.getActiveBody().getUnits()) {
530529
Stmt stmt = (Stmt) u;
531530
if (stmt.containsInvokeExpr()) {
532531
final String methodName = stmt.getInvokeExpr().getMethod().getName();
533-
if (methodName.equals("getFragmentManager") || methodName.equals("getSupportFragmentManager"))
534-
isFragmentManager = true;
535-
else if (methodName.equals("beginTransaction"))
536-
isFragmentTransaction = true;
537-
else if (methodName.equals("add") || methodName.equals("replace"))
538-
isAddTransaction = true;
532+
if (methodName.equals("add") || methodName.equals("replace"))
533+
isAddOrReplaceTransaction = true;
539534
else if (methodName.equals("inflate") && stmt.getInvokeExpr().getArgCount() > 1) {
540535
Value arg = stmt.getInvokeExpr().getArg(0);
541-
Integer fragmentID = valueProvider.getValue(method, stmt, arg, Integer.class);
542-
if (fragmentID != null)
543-
fragmentIDs.put(lifecycleElement, fragmentID);
536+
Set<Integer> fragmentID = valueProvider.getValue(method, stmt, arg, Integer.class);
537+
if (fragmentID != null) {
538+
for (int f : fragmentID)
539+
fragmentIDs.put(lifecycleElement, f);
540+
}
544541
}
545542
}
546543
}
547544

548545
// now get the fragment class from the second argument of the add method
549546
// from the transaction
550-
if (isFragmentManager && isFragmentTransaction && isAddTransaction)
547+
if (isAddOrReplaceTransaction)
551548
for (Unit u : method.getActiveBody().getUnits()) {
552549
Stmt stmt = (Stmt) u;
553550
if (stmt.containsInvokeExpr()) {
@@ -557,34 +554,56 @@ else if (methodName.equals("inflate") && stmt.getInvokeExpr().getArgCount() > 1)
557554

558555
// Make sure that we referring to the correct class and
559556
// method
560-
isFragmentTransaction = scFragmentTransaction != null && Scene.v().getFastHierarchy()
557+
boolean isFragmentTransaction = scFragmentTransaction != null && Scene.v().getFastHierarchy()
561558
.canStoreType(iinvExpr.getBase().getType(), scFragmentTransaction.getType());
562559
isFragmentTransaction |= scSupportFragmentTransaction != null && Scene.v().getFastHierarchy()
563560
.canStoreType(iinvExpr.getBase().getType(), scSupportFragmentTransaction.getType());
564561
isFragmentTransaction |= scAndroidXFragmentTransaction != null && Scene.v().getFastHierarchy()
565562
.canStoreType(iinvExpr.getBase().getType(), scAndroidXFragmentTransaction.getType());
566-
isAddTransaction = stmt.getInvokeExpr().getMethod().getName().equals("add")
563+
isAddOrReplaceTransaction = stmt.getInvokeExpr().getMethod().getName().equals("add")
567564
|| stmt.getInvokeExpr().getMethod().getName().equals("replace");
568565

569-
if (isFragmentTransaction && isAddTransaction) {
566+
if (isFragmentTransaction && isAddOrReplaceTransaction) {
570567
// We take all fragments passed to the method
571568
for (int i = 0; i < stmt.getInvokeExpr().getArgCount(); i++) {
572569
Value br = stmt.getInvokeExpr().getArg(i);
573570

574-
// Is this a fragment?
575-
if (br.getType() instanceof RefType) {
576-
RefType rt = (RefType) br.getType();
577-
if (br instanceof ClassConstant)
578-
rt = (RefType) ((ClassConstant) br).toSootType();
579-
580-
boolean addFragment = scFragment != null
581-
&& Scene.v().getFastHierarchy().canStoreType(rt, scFragment.getType());
582-
addFragment |= scSupportFragment != null && Scene.v().getFastHierarchy()
583-
.canStoreType(rt, scSupportFragment.getType());
584-
addFragment |= scAndroidXFragment != null && Scene.v().getFastHierarchy()
585-
.canStoreType(rt, scAndroidXFragment.getType());
586-
if (addFragment)
587-
checkAndAddFragment(method.getDeclaringClass(), rt.getSootClass());
571+
Type pt = stmt.getInvokeExpr().getMethodRef().getParameterType(i);
572+
if (pt instanceof RefType) {
573+
RefType rpt = (RefType) pt;
574+
//skip tag parameter
575+
if (rpt.getClassName().equals("java.lang.String"))
576+
continue;
577+
Set<Type> possibleTypes = Collections.emptySet();
578+
if (((RefType) pt).getSootClass().getName().equals("java.lang.Class")) {
579+
Set<ClassConstant> ct = valueProvider.getValue(method, stmt, br,
580+
ClassConstant.class);
581+
if (ct != null) {
582+
possibleTypes = new HashSet<>();
583+
for (ClassConstant p : ct) {
584+
possibleTypes.add((RefType) (p.toSootType()));
585+
}
586+
}
587+
588+
} else {
589+
possibleTypes = valueProvider.getType(method, stmt, br);
590+
}
591+
592+
for (Type t : possibleTypes) {
593+
if (t instanceof RefType) {
594+
RefType frt = (RefType) t;
595+
// Is this a fragment?
596+
boolean addFragment = scFragment != null && Scene.v().getFastHierarchy()
597+
.canStoreType(frt, scFragment.getType());
598+
addFragment |= scSupportFragment != null && Scene.v().getFastHierarchy()
599+
.canStoreType(frt, scSupportFragment.getType());
600+
addFragment |= scAndroidXFragment != null && Scene.v().getFastHierarchy()
601+
.canStoreType(frt, scAndroidXFragment.getType());
602+
if (addFragment)
603+
checkAndAddFragment(method.getDeclaringClass(), frt.getSootClass());
604+
}
605+
}
606+
588607
}
589608
}
590609
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -270,17 +270,19 @@ private void findClassLayoutMappings() {
270270
// the
271271
// fragments
272272
for (Value val : inv.getArgs()) {
273-
Integer intValue = valueProvider.getValue(sm, stmt, val, Integer.class);
274-
if (intValue != null) {
275-
this.layoutClasses.put(sm.getDeclaringClass(), intValue);
273+
Set<Integer> intValues = valueProvider.getValue(sm, stmt, val, Integer.class);
274+
if (intValues != null) {
275+
for (int iv : intValues)
276+
this.layoutClasses.put(sm.getDeclaringClass(), iv);
276277
}
277278

278279
}
279280
}
280281
if (invokesInflate(inv)) {
281-
Integer intValue = valueProvider.getValue(sm, stmt, inv.getArg(0), Integer.class);
282-
if (intValue != null) {
283-
this.layoutClasses.put(sm.getDeclaringClass(), intValue);
282+
Set<Integer> intValues = valueProvider.getValue(sm, stmt, inv.getArg(0), Integer.class);
283+
if (intValues != null) {
284+
for (int iv : intValues)
285+
this.layoutClasses.put(sm.getDeclaringClass(), iv);
284286
}
285287
}
286288
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ private void findClassLayoutMappings() {
7676
InvokeExpr inv = stmt.getInvokeExpr();
7777
if (invokesSetContentView(inv)) {
7878
for (Value val : inv.getArgs()) {
79-
Integer intValue = valueProvider.getValue(sm, stmt, val, Integer.class);
80-
if (intValue != null) {
81-
this.layoutClasses.put(sm.getDeclaringClass(), intValue);
79+
Set<Integer> intValues = valueProvider.getValue(sm, stmt, val, Integer.class);
80+
if (intValues != null) {
81+
for (int iv : intValues)
82+
this.layoutClasses.put(sm.getDeclaringClass(), iv);
8283
}
8384
}
8485
}

soot-infoflow-android/src/soot/jimple/infoflow/android/source/AndroidSourceSinkManager.java

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ private String findLastStringAssignment(Stmt stmt, Local local, BiDiInterprocedu
320320
* @return The layout control that is being accessed at the given statement, or
321321
* <code>null</code> if no such control could be found
322322
*/
323-
protected AndroidLayoutControl getLayoutControl(Stmt sCallSite, IInfoflowCFG cfg) {
323+
protected Set<AndroidLayoutControl> getLayoutControl(Stmt sCallSite, IInfoflowCFG cfg) {
324324
// If we don't have a layout control list, we cannot perform any
325325
// more specific checks
326326
if (this.layoutControls == null)
@@ -340,21 +340,27 @@ protected AndroidLayoutControl getLayoutControl(Stmt sCallSite, IInfoflowCFG cfg
340340
return null;
341341
}
342342

343-
Integer id = valueProvider.getValue(uiMethod, sCallSite, iexpr.getArg(0), Integer.class);
344-
if (id == null && iexpr.getArg(0) instanceof Local) {
345-
id = findLastResIDAssignment(sCallSite, (Local) iexpr.getArg(0), cfg,
343+
Set<Integer> ids = valueProvider.getValue(uiMethod, sCallSite, iexpr.getArg(0), Integer.class);
344+
if ((ids == null || ids.isEmpty()) && iexpr.getArg(0) instanceof Local) {
345+
Integer id = findLastResIDAssignment(sCallSite, (Local) iexpr.getArg(0), cfg,
346346
new HashSet<Stmt>(cfg.getMethodOf(sCallSite).getActiveBody().getUnits().size()));
347+
if (id != null)
348+
ids = Collections.singleton(id);
347349
}
348-
if (id == null) {
350+
if (ids == null || ids.isEmpty()) {
349351
logger.debug("Could not find assignment to local " + ((Local) iexpr.getArg(0)).getName() + " in method "
350352
+ cfg.getMethodOf(sCallSite).getSignature());
351353
return null;
352354
}
353355

354-
AndroidLayoutControl control = this.layoutControls.get(id);
355-
if (control == null)
356-
return null;
357-
return control;
356+
Set<AndroidLayoutControl> set = new HashSet<AndroidLayoutControl>();
357+
for (int id : ids) {
358+
AndroidLayoutControl control = this.layoutControls.get(id);
359+
if (control != null)
360+
set.add(control);
361+
}
362+
363+
return set;
358364
}
359365

360366
private boolean isResourceCall(SootMethod callee) {
@@ -403,11 +409,13 @@ protected ISourceSinkDefinition getUISourceDefinition(Stmt sCallSite, IInfoflowC
403409
return MethodSourceSinkDefinition.createReturnSource(CallType.MethodCall);
404410
}
405411

406-
AndroidLayoutControl control = getLayoutControl(sCallSite, cfg);
407-
if (control != null) {
408-
if (sourceSinkConfig.getLayoutMatchingMode() == LayoutMatchingMode.MatchSensitiveOnly
409-
&& control.isSensitive()) {
410-
return control.getSourceDefinition();
412+
Set<AndroidLayoutControl> control = getLayoutControl(sCallSite, cfg);
413+
if (control != null && !control.isEmpty()) {
414+
for (AndroidLayoutControl c : control) {
415+
if (sourceSinkConfig.getLayoutMatchingMode() == LayoutMatchingMode.MatchSensitiveOnly
416+
&& c.isSensitive()) {
417+
return c.getSourceDefinition();
418+
}
411419
}
412420
}
413421
}

soot-infoflow/src/soot/jimple/infoflow/values/IValueProvider.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package soot.jimple.infoflow.values;
22

3+
import java.util.Set;
4+
35
import soot.SootMethod;
6+
import soot.Type;
47
import soot.Value;
58
import soot.jimple.Stmt;
69

@@ -12,6 +15,24 @@
1215
*/
1316
public interface IValueProvider {
1417

15-
public <T> T getValue(SootMethod sm, Stmt stmt, Value value, Class<T> type);
18+
/**
19+
* Tries to find pseudo-constants for a given value at a given statement in a method
20+
* @param <T> the type the pseudo-constant should be
21+
* @param sm the method the statement is within
22+
* @param stmt the statement for which to inquire a value
23+
* @param value the value the analysis is interested in
24+
* @param type the type the pseudo-constant should be
25+
* @return the value as type <i>T</i> or null
26+
*/
27+
public <T> Set<T> getValue(SootMethod sm, Stmt stmt, Value value, Class<T> type);
28+
29+
/**
30+
* Tries to find a set of concrete types of a value
31+
* @param sm the method the statement is within
32+
* @param stmt the statement for which to inquire the type
33+
* @param value the value the analysis is interested in
34+
* @return a set of possible types for <i>value</i>
35+
*/
36+
public Set<Type> getType(SootMethod sm, Stmt stmt, Value value);
1637

1738
}

soot-infoflow/src/soot/jimple/infoflow/values/SimpleConstantValueProvider.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package soot.jimple.infoflow.values;
22

3+
import java.util.Collections;
4+
import java.util.HashSet;
35
import java.util.List;
6+
import java.util.Set;
47

58
import soot.Local;
69
import soot.SootField;
710
import soot.SootMethod;
11+
import soot.Type;
812
import soot.Unit;
913
import soot.Value;
1014
import soot.jimple.AssignStmt;
@@ -16,7 +20,6 @@
1620
import soot.jimple.LongConstant;
1721
import soot.jimple.Stmt;
1822
import soot.jimple.StringConstant;
19-
import soot.tagkit.ConstantValueTag;
2023
import soot.tagkit.DoubleConstantValueTag;
2124
import soot.tagkit.FloatConstantValueTag;
2225
import soot.tagkit.IntegerConstantValueTag;
@@ -37,14 +40,19 @@ public class SimpleConstantValueProvider implements IValueProvider {
3740

3841
@SuppressWarnings("unchecked")
3942
@Override
40-
public Object getValue(SootMethod sm, Stmt stmt, Value value, Class type) {
41-
if (value instanceof Constant)
42-
return getConstantOfType(value, type);
43+
public Set<Object> getValue(SootMethod sm, Stmt stmt, Value value, Class type) {
44+
if (value instanceof Constant) {
45+
Object c = getConstantOfType(value, type);
46+
if (c != null)
47+
return Collections.singleton(c);
48+
return null;
49+
}
4350

4451
if (value instanceof Local) {
4552
// Find the defs
4653
BriefUnitGraph ug = new BriefUnitGraph(sm.getActiveBody());
4754
SimpleLocalDefs du = new SimpleLocalDefs(ug);
55+
Set<Object> ret = new HashSet<>();
4856
List<Unit> defs = du.getDefsOfAt((Local) value, stmt);
4957
for (Unit def : defs) {
5058
if (!(def instanceof AssignStmt))
@@ -58,8 +66,9 @@ public Object getValue(SootMethod sm, Stmt stmt, Value value, Class type) {
5866
// Use the ConstantTag to retrieve the constant value
5967
Object constant = getConstantFromTag(((FieldRef) rightOp).getField(), type);
6068
if (constant != null)
61-
return constant;
69+
ret.add(constant);
6270
}
71+
return ret;
6372
}
6473

6574
return null;
@@ -82,6 +91,8 @@ private Object getConstantOfType(Value value, Class<?> type) {
8291
if (value instanceof StringConstant)
8392
return ((StringConstant) value).value;
8493
}
94+
if (type.isInstance(value))
95+
return value;
8596
return null;
8697
}
8798

@@ -104,4 +115,9 @@ private Object getConstantFromTag(SootField f, Class<?> type) {
104115
}
105116
return null;
106117
}
118+
119+
@Override
120+
public Set<Type> getType(SootMethod sm, Stmt stmt, Value value) {
121+
return Collections.singleton(value.getType());
122+
}
107123
}

0 commit comments

Comments
 (0)