Skip to content

Commit f48d7c0

Browse files
authored
Merge pull request #612 from timll/injectTypeHierarchy
Streamline handling of type hierarchy provided by taint wrappers
2 parents eb1dc48 + 2b9417a commit f48d7c0

26 files changed

Lines changed: 276 additions & 575 deletions

File tree

soot-infoflow-android/src/soot/jimple/infoflow/android/SetupApplication.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,7 +1703,7 @@ public IMemoryManager<Abstraction, Unit> getMemoryManager(boolean tracingEnabled
17031703
info.setMemoryManagerFactory(null);
17041704

17051705
// Inject additional post-processors
1706-
info.setPostProcessors(Collections.singleton(new PostAnalysisHandler() {
1706+
info.addPostProcessor(new PostAnalysisHandler() {
17071707

17081708
@Override
17091709
public InfoflowResults onResultsAvailable(InfoflowResults results, IInfoflowCFG cfg) {
@@ -1717,7 +1717,7 @@ public InfoflowResults onResultsAvailable(InfoflowResults results, IInfoflowCFG
17171717
return results;
17181718
}
17191719

1720-
}));
1720+
});
17211721

17221722
return info;
17231723
}

soot-infoflow-cmd/src/soot/jimple/infoflow/cmd/MainClass.java

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,6 @@ public boolean accept(File dir, String name) {
355355
analyzer = createFlowDroidInstance(config);
356356
analyzer.setTaintWrapper(taintWrapper);
357357

358-
// We need to inject the StubDroid hierarchy
359-
if (taintWrapper instanceof SummaryTaintWrapper)
360-
injectStubDroidHierarchy((SummaryTaintWrapper) taintWrapper);
361-
362358
// Start the data flow analysis
363359
analyzer.runInfoflow();
364360

@@ -378,59 +374,6 @@ public boolean accept(File dir, String name) {
378374
}
379375
}
380376

381-
/**
382-
* Injects hierarchy data from StubDroid into Soot
383-
*
384-
* @param taintWrapper The StubDroid instance
385-
*/
386-
private void injectStubDroidHierarchy(final SummaryTaintWrapper taintWrapper) {
387-
final IMethodSummaryProvider provider = taintWrapper.getProvider();
388-
analyzer.addPreprocessor(new PreAnalysisHandler() {
389-
390-
@Override
391-
public void onBeforeCallgraphConstruction() {
392-
// Inject the hierarchy
393-
for (String className : provider.getAllClassesWithSummaries()) {
394-
SootClass sc = Scene.v().forceResolve(className, SootClass.SIGNATURES);
395-
if (sc.isPhantom()) {
396-
ClassMethodSummaries summaries = provider.getClassFlows(className);
397-
if (summaries != null) {
398-
// Some phantom classes are actually interfaces
399-
if (summaries.hasInterfaceInfo()) {
400-
if (summaries.isInterface())
401-
sc.setModifiers(sc.getModifiers() | Modifier.INTERFACE);
402-
else
403-
sc.setModifiers(sc.getModifiers() & ~Modifier.INTERFACE);
404-
}
405-
406-
// Set the correct superclass
407-
if (summaries.hasSuperclass()) {
408-
final String superclassName = summaries.getSuperClass();
409-
SootClass scSuperclass = Scene.v().forceResolve(superclassName, SootClass.SIGNATURES);
410-
sc.setSuperclass(scSuperclass);
411-
}
412-
413-
// Register the interfaces
414-
if (summaries.hasInterfaces()) {
415-
for (String intfName : summaries.getInterfaces()) {
416-
SootClass scIntf = Scene.v().forceResolve(intfName, SootClass.SIGNATURES);
417-
if (!sc.implementsInterface(intfName))
418-
sc.addInterface(scIntf);
419-
}
420-
}
421-
}
422-
}
423-
}
424-
}
425-
426-
@Override
427-
public void onAfterCallgraphConstruction() {
428-
//
429-
}
430-
431-
});
432-
}
433-
434377
/**
435378
* Creates an instance of the FlowDroid data flow solver tool for Android.
436379
* Derived classes can override this method to inject custom variants of

soot-infoflow-integration/res/AndroidRiverSourcesAndSinks.xml

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -494,48 +494,6 @@
494494
</additionalFlowCondition>
495495
</method>
496496

497-
<method signature="java.io.ObjectOutputStream: void write(byte[])">
498-
<param index="0" description="Output Data">
499-
<accessPath isSource="false" isSink="true" />
500-
</param>
501-
<additionalFlowCondition>
502-
<signatureOnPath signature="java.net.URLConnection: java.io.OutputStream getOutputStream()" />
503-
<signatureOnPath signature="android.content.Context: java.io.File getExternalCacheDir()" />
504-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalCacheDirs()" />
505-
<signatureOnPath signature="android.content.Context: java.io.File getExternalFilesDir(java.lang.String)" />
506-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalFilesDir(java.lang.String)" />
507-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalMediaDirs()" />
508-
<excludeClassName className="java.io.ByteArrayOutputStream" />
509-
</additionalFlowCondition>
510-
</method>
511-
<method signature="java.io.ObjectOutputStream: void write(byte[],int,int)">
512-
<param index="0" description="Output Data">
513-
<accessPath isSource="false" isSink="true" />
514-
</param>
515-
<additionalFlowCondition>
516-
<signatureOnPath signature="java.net.URLConnection: java.io.OutputStream getOutputStream()" />
517-
<signatureOnPath signature="android.content.Context: java.io.File getExternalCacheDir()" />
518-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalCacheDirs()" />
519-
<signatureOnPath signature="android.content.Context: java.io.File getExternalFilesDir(java.lang.String)" />
520-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalFilesDir(java.lang.String)" />
521-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalMediaDirs()" />
522-
<excludeClassName className="java.io.ByteArrayOutputStream" />
523-
</additionalFlowCondition>
524-
</method>
525-
<method signature="java.io.ObjectOutputStream: void write(int)">
526-
<param index="0" description="Output Data">
527-
<accessPath isSource="false" isSink="true" />
528-
</param>
529-
<additionalFlowCondition>
530-
<signatureOnPath signature="java.net.URLConnection: java.io.OutputStream getOutputStream()" />
531-
<signatureOnPath signature="android.content.Context: java.io.File getExternalCacheDir()" />
532-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalCacheDirs()" />
533-
<signatureOnPath signature="android.content.Context: java.io.File getExternalFilesDir(java.lang.String)" />
534-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalFilesDir(java.lang.String)" />
535-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalMediaDirs()" />
536-
<excludeClassName className="java.io.ByteArrayOutputStream" />
537-
</additionalFlowCondition>
538-
</method>
539497
<method signature="java.io.ObjectOutputStream: void writeBoolean(boolean)">
540498
<param index="0" description="Output Data">
541499
<accessPath isSource="false" isSink="true" />
@@ -719,62 +677,6 @@
719677
</additionalFlowCondition>
720678
</method>
721679

722-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(byte[])">
723-
<param index="0" description="Output Data">
724-
<accessPath isSource="false" isSink="true" />
725-
</param>
726-
<additionalFlowCondition>
727-
<signatureOnPath signature="java.net.URLConnection: java.io.OutputStream getOutputStream()" />
728-
<signatureOnPath signature="android.content.Context: java.io.File getExternalCacheDir()" />
729-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalCacheDirs()" />
730-
<signatureOnPath signature="android.content.Context: java.io.File getExternalFilesDir(java.lang.String)" />
731-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalFilesDir(java.lang.String)" />
732-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalMediaDirs()" />
733-
<excludeClassName className="java.io.ByteArrayOutputStream" />
734-
</additionalFlowCondition>
735-
</method>
736-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(byte[],int)">
737-
<param index="0" description="Output Data">
738-
<accessPath isSource="false" isSink="true" />
739-
</param>
740-
<additionalFlowCondition>
741-
<signatureOnPath signature="java.net.URLConnection: java.io.OutputStream getOutputStream()" />
742-
<signatureOnPath signature="android.content.Context: java.io.File getExternalCacheDir()" />
743-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalCacheDirs()" />
744-
<signatureOnPath signature="android.content.Context: java.io.File getExternalFilesDir(java.lang.String)" />
745-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalFilesDir(java.lang.String)" />
746-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalMediaDirs()" />
747-
<excludeClassName className="java.io.ByteArrayOutputStream" />
748-
</additionalFlowCondition>
749-
</method>
750-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(byte[],int,int)">
751-
<param index="0" description="Output Data">
752-
<accessPath isSource="false" isSink="true" />
753-
</param>
754-
<additionalFlowCondition>
755-
<signatureOnPath signature="java.net.URLConnection: java.io.OutputStream getOutputStream()" />
756-
<signatureOnPath signature="android.content.Context: java.io.File getExternalCacheDir()" />
757-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalCacheDirs()" />
758-
<signatureOnPath signature="android.content.Context: java.io.File getExternalFilesDir(java.lang.String)" />
759-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalFilesDir(java.lang.String)" />
760-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalMediaDirs()" />
761-
<excludeClassName className="java.io.ByteArrayOutputStream" />
762-
</additionalFlowCondition>
763-
</method>
764-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(int)">
765-
<param index="0" description="Output Data">
766-
<accessPath isSource="false" isSink="true" />
767-
</param>
768-
<additionalFlowCondition>
769-
<signatureOnPath signature="java.net.URLConnection: java.io.OutputStream getOutputStream()" />
770-
<signatureOnPath signature="android.content.Context: java.io.File getExternalCacheDir()" />
771-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalCacheDirs()" />
772-
<signatureOnPath signature="android.content.Context: java.io.File getExternalFilesDir(java.lang.String)" />
773-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalFilesDir(java.lang.String)" />
774-
<signatureOnPath signature="android.content.Context: java.io.File[] getExternalMediaDirs()" />
775-
<excludeClassName className="java.io.ByteArrayOutputStream" />
776-
</additionalFlowCondition>
777-
</method>
778680
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void writeAscii(java.lang.String)">
779681
<param index="0" description="Output Data">
780682
<accessPath isSource="false" isSink="true" />

soot-infoflow-integration/res/OutputStreamAndWriters.xml

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -443,30 +443,6 @@
443443
</additionalFlowCondition>
444444
</method>
445445

446-
<method signature="java.io.ObjectOutputStream: void write(byte[])">
447-
<param index="0" description="Output Data">
448-
<accessPath isSource="false" isSink="true" />
449-
</param>
450-
<additionalFlowCondition>
451-
<classNameOnPath className="java.net.URLConnection" />
452-
</additionalFlowCondition>
453-
</method>
454-
<method signature="java.io.ObjectOutputStream: void write(byte[],int,int)">
455-
<param index="0" description="Output Data">
456-
<accessPath isSource="false" isSink="true" />
457-
</param>
458-
<additionalFlowCondition>
459-
<classNameOnPath className="java.net.URLConnection" />
460-
</additionalFlowCondition>
461-
</method>
462-
<method signature="java.io.ObjectOutputStream: void write(int)">
463-
<param index="0" description="Output Data">
464-
<accessPath isSource="false" isSink="true" />
465-
</param>
466-
<additionalFlowCondition>
467-
<classNameOnPath className="java.net.URLConnection" />
468-
</additionalFlowCondition>
469-
</method>
470446
<method signature="java.io.ObjectOutputStream: void writeBoolean(boolean)">
471447
<param index="0" description="Output Data">
472448
<accessPath isSource="false" isSink="true" />
@@ -572,55 +548,6 @@
572548
</additionalFlowCondition>
573549
</method>
574550

575-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutputStream: void write(byte[],int,int)">
576-
<param index="0" description="Output Data">
577-
<accessPath isSource="false" isSink="true" />
578-
</param>
579-
<additionalFlowCondition>
580-
<classNameOnPath className="java.net.URLConnection" />
581-
</additionalFlowCondition>
582-
</method>
583-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutputStream: void write(int)">
584-
<param index="0" description="Output Data">
585-
<accessPath isSource="false" isSink="true" />
586-
</param>
587-
<additionalFlowCondition>
588-
<classNameOnPath className="java.net.URLConnection" />
589-
</additionalFlowCondition>
590-
</method>
591-
592-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(byte[])">
593-
<param index="0" description="Output Data">
594-
<accessPath isSource="false" isSink="true" />
595-
</param>
596-
<additionalFlowCondition>
597-
<classNameOnPath className="java.net.URLConnection" />
598-
</additionalFlowCondition>
599-
</method>
600-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(byte[],int)">
601-
<param index="0" description="Output Data">
602-
<accessPath isSource="false" isSink="true" />
603-
</param>
604-
<additionalFlowCondition>
605-
<classNameOnPath className="java.net.URLConnection" />
606-
</additionalFlowCondition>
607-
</method>
608-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(bytes[],int,int)">
609-
<param index="0" description="Output Data">
610-
<accessPath isSource="false" isSink="true" />
611-
</param>
612-
<additionalFlowCondition>
613-
<classNameOnPath className="java.net.URLConnection" />
614-
</additionalFlowCondition>
615-
</method>
616-
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void write(int)">
617-
<param index="0" description="Output Data">
618-
<accessPath isSource="false" isSink="true" />
619-
</param>
620-
<additionalFlowCondition>
621-
<classNameOnPath className="java.net.URLConnection" />
622-
</additionalFlowCondition>
623-
</method>
624551
<method signature="com.esotericsoftware.kryo.io.ByteBufferOutput: void writeAscii(java.lang.String)">
625552
<param index="0" description="Output Data">
626553
<accessPath isSource="false" isSink="true" />

soot-infoflow-integration/test/soot/jimple/infoflow/integration/test/OutputStreamTestCode.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ public void testByteArrayExcludedTest1() {
269269

270270

271271
public String externalLocation = "external/";
272+
272273
public String getExternalDirLoc() {
273274
return externalLocation;
274275
}
@@ -344,4 +345,10 @@ public void testFileWriter1() {
344345
throw new RuntimeException(e);
345346
}
346347
}
348+
349+
public void testCastWithSummaryTypeInformation1() throws IOException {
350+
OutputStream os = new FileOutputStream("myfile.txt");
351+
OutputStream bbo = (OutputStream) new ByteBufferOutput(os);
352+
bbo.write(1337);
353+
}
347354
}

soot-infoflow-integration/test/soot/jimple/infoflow/integration/test/junit/AndroidRegressionTests.java

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@
33
import org.junit.Assert;
44
import org.junit.Test;
55
import org.xmlpull.v1.XmlPullParserException;
6+
import soot.SootMethod;
67
import soot.jimple.infoflow.InfoflowConfiguration;
78
import soot.jimple.infoflow.android.SetupApplication;
8-
import soot.jimple.infoflow.methodSummary.data.provider.EagerSummaryProvider;
9-
import soot.jimple.infoflow.methodSummary.taintWrappers.SummaryTaintWrapper;
9+
import soot.jimple.infoflow.android.data.parsers.PermissionMethodParser;
1010
import soot.jimple.infoflow.methodSummary.taintWrappers.TaintWrapperFactory;
11+
import soot.jimple.infoflow.results.DataFlowResult;
1112
import soot.jimple.infoflow.results.InfoflowResults;
1213
import soot.jimple.infoflow.taintWrappers.ITaintPropagationWrapper;
1314

1415
import javax.xml.stream.XMLStreamException;
1516
import java.io.IOException;
16-
import java.net.URISyntaxException;
1717
import java.util.Collections;
18+
import java.util.*;
1819

1920
/**
2021
* Tests that uncovered a bug.
@@ -43,4 +44,48 @@ public void testFlowSensitivityWithOverwrite() throws XmlPullParserException, IO
4344
Assert.assertEquals(2, results.size());
4445
Assert.assertEquals(2, results.getResultSet().size());
4546
}
47+
48+
/**
49+
* Tests that StubDroid correctly narrows the type when the summary is in a superclass.
50+
* See also the comment in SummaryTaintWrapper#getSummaryDeclaringClass().
51+
*/
52+
@Test
53+
public void testTypeHierarchyFromSummary() throws XmlPullParserException, IOException {
54+
SetupApplication app = initApplication("testAPKs/TypeHierarchyTest.apk");
55+
InfoflowResults results = app.runInfoflow("../soot-infoflow-android/SourcesAndSinks.txt");
56+
Assert.assertEquals(1, results.size());
57+
Assert.assertEquals(1, results.getResultSet().size());
58+
}
59+
60+
/**
61+
* Tests an app that uses the kotlin collections.
62+
* Expects four leaks:
63+
* * From getDeviceId() in onCreate() to Log.d(String, String)
64+
* in listFlow(String), mapFlow(String) and setFlow(String).
65+
* * From new File in fileFlow() to Log.d(String, String) in fileFlow(String).
66+
*/
67+
@Test
68+
public void testKotlinAppWithCollections() throws IOException {
69+
SetupApplication app = initApplication("testAPKs/KotlinCollectionApp.apk");
70+
71+
// Make sure we find only one flow per method
72+
app.addResultsAvailableHandler((cfg, results) -> {
73+
Set<SootMethod> seenSet = new HashSet<>();
74+
for (DataFlowResult res : results.getResultSet()) {
75+
SootMethod sm = cfg.getMethodOf(res.getSink().getStmt());
76+
Assert.assertFalse(seenSet.contains(sm));
77+
seenSet.add(sm);
78+
}
79+
});
80+
81+
// Add the sources and sinks
82+
List<String> ssinks = new ArrayList<>();
83+
ssinks.add("<android.telephony.TelephonyManager: java.lang.String getDeviceId()> android.permission.READ_PHONE_STATE -> _SOURCE_");
84+
ssinks.add("<android.util.Log: int d(java.lang.String,java.lang.String)> -> _SINK_");
85+
ssinks.add("<kotlin.io.TextStreamsKt: java.util.List readLines(java.io.Reader)> -> _SOURCE_");
86+
87+
InfoflowResults results = app.runInfoflow(PermissionMethodParser.fromStringList(ssinks));
88+
Assert.assertEquals(4, results.size());
89+
Assert.assertEquals(4, results.getResultSet().size());
90+
}
4691
}

0 commit comments

Comments
 (0)