Skip to content

Commit 1496310

Browse files
committed
Add full path reconstruction from RemoteFlowSource to sink
1 parent 445da1e commit 1496310

File tree

4 files changed

+65
-24
lines changed

4 files changed

+65
-24
lines changed

java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,32 @@ import semmle.code.java.dataflow.TaintTracking
66
import semmle.code.java.dataflow.TaintTracking2
77
import semmle.code.java.security.AndroidIntentRedirection
88

9+
/**
10+
* Holds if taint may flow from `source` to `sink` for `IntentRedirectionConfiguration`.
11+
*
12+
* It ensures that `ChangeIntentComponent` is an intermediate step in the flow.
13+
*/
14+
predicate hasIntentRedirectionFlowPath(DataFlow::PathNode source, DataFlow::PathNode sink) {
15+
exists(IntentRedirectionConfiguration conf, DataFlow::PathNode intermediate |
16+
intermediate.getNode().(ChangeIntentComponent).hasFlowFrom(source.getNode()) and
17+
conf.hasFlowPath(intermediate, sink)
18+
)
19+
}
20+
921
/**
1022
* A taint tracking configuration for tainted Intents being used to start Android components.
1123
*/
12-
class IntentRedirectionConfiguration extends TaintTracking::Configuration {
24+
private class IntentRedirectionConfiguration extends TaintTracking::Configuration {
1325
IntentRedirectionConfiguration() { this = "IntentRedirectionConfiguration" }
1426

15-
override predicate isSource(DataFlow::Node source) { source instanceof IntentRedirectionSource }
27+
override predicate isSource(DataFlow::Node source) {
28+
exists(ChangeIntentComponent c |
29+
c = source
30+
or
31+
// This is needed for PathGraph to be able to build the full flow
32+
c.hasFlowFrom(source)
33+
)
34+
}
1635

1736
override predicate isSink(DataFlow::Node sink) { sink instanceof IntentRedirectionSink }
1837

@@ -26,11 +45,16 @@ class IntentRedirectionConfiguration extends TaintTracking::Configuration {
2645
}
2746

2847
/** An expression modifying an `Intent` component with tainted data. */
29-
private class IntentRedirectionSource extends DataFlow::Node {
30-
IntentRedirectionSource() {
48+
private class ChangeIntentComponent extends DataFlow::Node {
49+
DataFlow::Node src;
50+
51+
ChangeIntentComponent() {
3152
changesIntentComponent(this.asExpr()) and
32-
exists(TaintedIntentComponentConf conf | conf.hasFlowTo(this))
53+
exists(TaintedIntentComponentConf conf | conf.hasFlow(src, this))
3354
}
55+
56+
/** Holds if `source` flows to `this`. */
57+
predicate hasFlowFrom(DataFlow::Node source) { source = src }
3458
}
3559

3660
/**
@@ -46,7 +70,7 @@ private class TaintedIntentComponentConf extends TaintTracking2::Configuration {
4670

4771
/** Holds if `expr` modifies the component of an `Intent`. */
4872
private predicate changesIntentComponent(Expr expr) {
49-
any(IntentGetParcelableExtra igpe).getQualifier() = expr or
73+
any(IntentGetParcelableExtra igpe) = expr or
5074
any(IntentSetComponent isc).getSink() = expr
5175
}
5276

java/ql/src/Security/CWE/CWE-940/AndroidIntentRedirection.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import semmle.code.java.dataflow.DataFlow
1818
import semmle.code.java.security.AndroidIntentRedirectionQuery
1919
import DataFlow::PathGraph
2020

21-
from DataFlow::PathNode source, DataFlow::PathNode sink, IntentRedirectionConfiguration conf
22-
where conf.hasFlowPath(source, sink)
21+
from DataFlow::PathNode source, DataFlow::PathNode sink
22+
where hasIntentRedirectionFlowPath(source, sink)
2323
select sink.getNode(), source, sink,
2424
"Arbitrary Android activities or services can be started from $@.", source.getNode(),
2525
"this user input"

java/ql/test/query-tests/security/CWE-940/AndroidIntentRedirectionTest.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,6 @@ public class AndroidIntentRedirectionTest extends Activity {
1111
public void onCreate(Bundle savedInstanceState) {
1212
Intent intent = (Intent) getIntent().getParcelableExtra("forward_intent");
1313

14-
if (intent.getComponent().getPackageName().equals("something")) {
15-
startActivity(intent); // Safe - sanitized
16-
} else {
17-
startActivity(intent); // $ hasAndroidIntentRedirection
18-
}
19-
if (intent.getComponent().getClassName().equals("something")) {
20-
startActivity(intent); // Safe - sanitized
21-
} else {
22-
startActivity(intent); // $ hasAndroidIntentRedirection
23-
}
24-
25-
startActivity(getIntent()); // Safe - not an intent obtained from the Extras
26-
2714
// @formatter:off
2815
startActivities(new Intent[] {intent}); // $ hasAndroidIntentRedirection
2916
startActivities(new Intent[] {intent}, null); // $ hasAndroidIntentRedirection
@@ -56,6 +43,17 @@ public void onCreate(Bundle savedInstanceState) {
5643
sendStickyOrderedBroadcastAsUser(intent, null, null, null, 0, null, null); // $ hasAndroidIntentRedirection
5744
// @formatter:on
5845

46+
if (intent.getComponent().getPackageName().equals("something")) {
47+
startActivity(intent); // Safe - sanitized
48+
} else {
49+
startActivity(intent); // $ hasAndroidIntentRedirection
50+
}
51+
if (intent.getComponent().getClassName().equals("something")) {
52+
startActivity(intent); // Safe - sanitized
53+
} else {
54+
startActivity(intent); // $ hasAndroidIntentRedirection
55+
}
56+
5957
try {
6058
{
6159
Intent fwdIntent = new Intent();
@@ -134,6 +132,25 @@ public void onCreate(Bundle savedInstanceState) {
134132
fwdIntent.setComponent(component);
135133
startActivity(fwdIntent); // $ hasAndroidIntentRedirection
136134
}
135+
{
136+
Intent originalIntent = getIntent();
137+
Intent fwdIntent = (Intent) originalIntent.getParcelableExtra("forward_intent");
138+
startActivity(originalIntent); // Safe - not an Intent obtained from the Extras
139+
}
140+
{
141+
Intent originalIntent = getIntent();
142+
ComponentName cp = new ComponentName(originalIntent.getStringExtra("packageName"),
143+
originalIntent.getStringExtra("className"));
144+
Intent anotherIntent = new Intent();
145+
anotherIntent.setComponent(cp);
146+
startActivity(originalIntent); // Safe - not a tainted Intent
147+
}
148+
{
149+
// Delayed cast
150+
Object obj = getIntent().getParcelableExtra("forward_intent");
151+
Intent fwdIntent = (Intent) obj;
152+
startActivity(fwdIntent); // $ hasAndroidIntentRedirection
153+
}
137154
} catch (Exception e) {
138155
}
139156
}

java/ql/test/query-tests/security/CWE-940/AndroidIntentRedirectionTest.ql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ class HasAndroidIntentRedirectionTest extends InlineExpectationsTest {
99

1010
override predicate hasActualResult(Location location, string element, string tag, string value) {
1111
tag = "hasAndroidIntentRedirection" and
12-
exists(DataFlow::Node src, DataFlow::Node sink, IntentRedirectionConfiguration conf |
13-
conf.hasFlow(src, sink)
12+
exists(DataFlow::PathNode src, DataFlow::PathNode sink |
13+
hasIntentRedirectionFlowPath(src, sink)
1414
|
15-
sink.getLocation() = location and
15+
sink.getNode().getLocation() = location and
1616
element = sink.toString() and
1717
value = ""
1818
)

0 commit comments

Comments
 (0)