Skip to content

Commit 2b2fa6e

Browse files
committed
Add taint step for String.valueOf(Editable)
Kotlin inlines expr.toString() as String.valueOf(expr) when expr is nullable
1 parent edf0be0 commit 2b2fa6e

File tree

6 files changed

+43
-10
lines changed

6 files changed

+43
-10
lines changed

java/ql/lib/semmle/code/java/frameworks/android/Widget.qll

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,20 @@ private class DefaultAndroidWidgetSources extends RemoteFlowSource {
1818

1919
private class EditableToStringStep extends AdditionalTaintStep {
2020
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
21-
exists(MethodAccess toString |
22-
toString.getMethod().hasName("toString") and
23-
toString.getReceiverType().hasQualifiedName("android.text", "Editable")
24-
|
25-
n1.asExpr() = toString.getQualifier() and
26-
n2.asExpr() = toString
21+
exists(MethodAccess ma |
22+
ma.getMethod().hasName("toString") and
23+
ma.getReceiverType().getASourceSupertype*().hasQualifiedName("android.text", "Editable") and
24+
n1.asExpr() = ma.getQualifier() and
25+
n2.asExpr() = ma
26+
or
27+
ma.getMethod().hasQualifiedName("java.lang", "String", "valueOf") and
28+
ma.getArgument(0)
29+
.getType()
30+
.(RefType)
31+
.getASourceSupertype*()
32+
.hasQualifiedName("android.text", "Editable") and
33+
n1.asExpr() = ma.getArgument(0) and
34+
n2.asExpr() = ma
2735
)
2836
}
2937
}

java/ql/test/library-tests/frameworks/android/widget/TestWidget.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
public class TestWidget {
44

5+
private EditText source() {
6+
return null;
7+
}
8+
59
private void sink(Object sink) {}
610

7-
public void test(EditText t) {
8-
sink(t.getText().toString()); // $ hasTaintFlow
11+
public void test() {
12+
sink(source().getText().toString()); // $ hasTaintFlow
913
}
1014
}
1115

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import android.text.Editable
2+
3+
class TestWidget {
4+
5+
fun source() : Editable? { return null }
6+
fun sink(sink : String) {}
7+
8+
fun test() {
9+
val t = source()
10+
sink(t.toString()); // $ hasTaintFlow
11+
12+
val t2 : Any? = source()
13+
sink(t2.toString()); // $ MISSING: hasTaintFlow
14+
}
15+
}
16+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0
2+
//codeql-extractor-kotlin-options: ${testdir}/../../../../stubs/google-android-9.0.0
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
+failures
2+
+valueOf
3+
+| TestWidgetKt.kt:10:16:10:25 | valueOf(...) |
4+
+| TestWidgetKt.kt:13:17:13:26 | valueOf(...) |

java/ql/test/library-tests/frameworks/android/widget/test.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import java
22
import semmle.code.java.dataflow.FlowSources
33
import TestUtilities.InlineFlowTest
44

5-
class SourceTaintFlowConf extends DefaultTaintFlowConf {
6-
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
5+
query predicate valueOf(MethodAccess ma) {
6+
ma.getMethod().hasQualifiedName("java.lang", "String", "valueOf")
77
}

0 commit comments

Comments
 (0)