Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d77b60b

Browse files
committed
C#: Add preservesValue to NonLocalJumpNode.getAJumpSuccessor. Allow DataFlow::Configuration::isAdditionalFlowStep to jump between callables.
1 parent 7343e70 commit d77b60b

10 files changed

Lines changed: 51 additions & 37 deletions

File tree

change-notes/1.20/analysis-csharp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@
3333
* Support has been added for EntityFrameworkCore, including
3434
- Stored data flow sources
3535
- Sinks for SQL expressions
36-
- Dataflow through fields that are mapped to the database.
36+
- Data flow through fields that are mapped to the database.
3737

3838
## Changes to the autobuilder

csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ module DataFlow {
124124
*/
125125
abstract class NonLocalJumpNode extends Node {
126126
/** Gets a successor node that is potentially in another callable. */
127-
abstract Node getAJumpSuccessor();
127+
abstract Node getAJumpSuccessor(boolean preservesValue);
128128
}
129129

130130
/**
@@ -1099,8 +1099,10 @@ module DataFlow {
10991099
*/
11001100
bindingset[config]
11011101
predicate localFlowStep(Node pred, Node succ, Configuration config) {
1102-
localFlowStepNoConfig(pred, succ) or
1103-
config.isAdditionalFlowStep(pred, succ)
1102+
localFlowStepNoConfig(pred, succ)
1103+
or
1104+
config.isAdditionalFlowStep(pred, succ) and
1105+
pred.getEnclosingCallable() = succ.getEnclosingCallable()
11041106
}
11051107

11061108
/**
@@ -1111,7 +1113,7 @@ module DataFlow {
11111113
Pruning::nodeCand(node, config) and
11121114
(
11131115
config.isSource(node) or
1114-
jumpStep(_, node) or
1116+
additionalJumpStep(_, node, config) or
11151117
node instanceof ParameterNode or
11161118
node instanceof OutNode
11171119
)
@@ -1124,7 +1126,7 @@ module DataFlow {
11241126
predicate localFlowExit(Node node, Configuration config) {
11251127
Pruning::nodeCand(node, config) and
11261128
(
1127-
jumpStep(node, _) or
1129+
additionalJumpStep(node, _, config) or
11281130
node instanceof ArgumentNode or
11291131
node instanceof ReturnNode or
11301132
config.isSink(node)
@@ -1165,6 +1167,17 @@ module DataFlow {
11651167
}
11661168
}
11671169

1170+
1171+
/**
1172+
* Holds if the additional step from `node1` to `node2` jumps between callables.
1173+
*/
1174+
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
1175+
config.isAdditionalFlowStep(node1, node2) and
1176+
node1.getEnclosingCallable() != node2.getEnclosingCallable()
1177+
or
1178+
jumpStep(node1, node2)
1179+
}
1180+
11681181
/**
11691182
* Provides predicates for pruning the data flow graph, by only including
11701183
* nodes that may potentially be reached in flow from some source to some
@@ -1182,7 +1195,7 @@ module DataFlow {
11821195
or
11831196
exists(Node mid | nodeCandFwd1(mid, config) | LocalFlow::localFlowStep(mid, node, config))
11841197
or
1185-
exists(Node mid | nodeCandFwd1(mid, config) | jumpStep(mid, node))
1198+
exists(Node mid | nodeCandFwd1(mid, config) | additionalJumpStep(mid, node, config))
11861199
or
11871200
exists(ArgumentNode arg | nodeCandFwd1(arg, config) |
11881201
flowIntoCallableStep(_, arg, node, _, config)
@@ -1205,7 +1218,7 @@ module DataFlow {
12051218
or
12061219
exists(Node mid | nodeCand1(mid, config) | LocalFlow::localFlowStep(node, mid, config))
12071220
or
1208-
exists(Node mid | nodeCand1(mid, config) | jumpStep(node, mid))
1221+
exists(Node mid | nodeCand1(mid, config) | additionalJumpStep(node, mid, config))
12091222
or
12101223
exists(ParameterNode p | nodeCand1(p, config) |
12111224
flowIntoCallableStep(_, node, p, _, config)
@@ -1260,7 +1273,7 @@ module DataFlow {
12601273
pragma[noinline]
12611274
private predicate jumpStepCand1(Node pred, Node succ, Configuration config) {
12621275
nodeCand1(succ, config) and
1263-
jumpStep(pred, succ)
1276+
additionalJumpStep(mid, node, config)
12641277
}
12651278

12661279
pragma[noinline]
@@ -1349,7 +1362,7 @@ module DataFlow {
13491362
or
13501363
nodeCandFwd2(node, _, config) and
13511364
exists(Node mid | nodeCand2(mid, _, config) |
1352-
jumpStep(node, mid) and
1365+
additionalJumpStep(node, mid, config) and
13531366
isReturned = false
13541367
)
13551368
or
@@ -1408,7 +1421,7 @@ module DataFlow {
14081421
*/
14091422
cached
14101423
predicate jumpStep(ExprNode pred, ExprNode succ) {
1411-
pred.(NonLocalJumpNode).getAJumpSuccessor() = succ
1424+
pred.(NonLocalJumpNode).getAJumpSuccessor(true) = succ
14121425
}
14131426

14141427
/** A dataflow node that has field-like dataflow. */
@@ -1427,7 +1440,9 @@ module DataFlow {
14271440
hasNonlocalValue(flr)
14281441
}
14291442

1430-
override ExprNode getAJumpSuccessor() { result = succ }
1443+
override ExprNode getAJumpSuccessor(boolean preservesValue) {
1444+
result = succ and preservesValue = true
1445+
}
14311446
}
14321447

14331448
/**
@@ -1715,7 +1730,7 @@ module DataFlow {
17151730
ctx = mid.getContext() and
17161731
LocalFlow::localFlowBigStep(mid.getNode(), node, mid.getConfiguration())
17171732
or
1718-
jumpStep(mid.getNode(), node) and
1733+
additionalJumpStep(mid.getNode(), node, mid.getConfiguration()) and
17191734
ctx instanceof NoContext
17201735
or
17211736
flowIntoCallable(mid, node, ctx)

csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,13 @@ module TaintTracking {
8080
predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
8181

8282
final override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
83-
isAdditionalTaintStep(pred, succ) or
84-
localAdditionalTaintStep(pred, succ) or
83+
isAdditionalTaintStep(pred, succ)
84+
or
85+
localAdditionalTaintStep(pred, succ)
86+
or
8587
DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred, succ, false)
88+
or
89+
succ = pred.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false)
8690
}
8791

8892
final override predicate isAdditionalFlowStepIntoCall(

csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,9 @@ module EntityFramework {
185185

186186
MappedPropertyJumpNode() { this.asExpr() = property.getAnAssignedValue() }
187187

188-
override DataFlow::Node getAJumpSuccessor() {
189-
result.asExpr().(PropertyRead).getTarget() = property
188+
override DataFlow::Node getAJumpSuccessor(boolean preservesValue) {
189+
result.asExpr().(PropertyRead).getTarget() = property and
190+
preservesValue = false
190191
}
191192
}
192193
}

csharp/ql/test/library-tests/frameworks/EntityFramework/Dataflow.ql

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import csharp
22
import semmle.code.csharp.dataflow.TaintTracking
33

4-
class MyConfiguration extends TaintTracking::Configuration
5-
{
4+
class MyConfiguration extends TaintTracking::Configuration {
65
MyConfiguration() { this = "EntityFramework dataflow" }
7-
8-
override predicate isSource(DataFlow::Node node) {
9-
node.asExpr().getValue() = "tainted"
10-
}
11-
6+
7+
override predicate isSource(DataFlow::Node node) { node.asExpr().getValue() = "tainted" }
8+
129
override predicate isSink(DataFlow::Node node) {
1310
node.asExpr() = any(MethodCall c | c.getTarget().hasName("Sink")).getAnArgument()
1411
}

csharp/ql/test/library-tests/frameworks/EntityFramework/EntityFramework.cs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,23 @@ class MyContext : DbContext
2323
void FlowSources()
2424
{
2525
var p = new Person();
26-
var id = p.Id;
27-
var name = p.Name;
28-
var age = p.Age;
26+
var id = p.Id; // Remote flow source
27+
var name = p.Name; // Remote flow source
28+
var age = p.Age; // Not a remote flow source
2929
}
3030

3131
DbCommand command;
3232

3333
async void SqlSinks()
3434
{
3535
// System.Data.Common.DbCommand.set_CommandText
36-
command.CommandText = "";
37-
36+
command.CommandText = ""; // SqlExpr
37+
3838
// System.Data.SqlClient.SqlCommand.SqlCommand
39-
new System.Data.SqlClient.SqlCommand("");
40-
41-
this.Database.ExecuteSqlCommand("");
42-
await this.Database.ExecuteSqlCommandAsync("");
39+
new System.Data.SqlClient.SqlCommand(""); // SqlExpr
40+
41+
this.Database.ExecuteSqlCommand(""); // SqlExpr
42+
await this.Database.ExecuteSqlCommandAsync(""); // SqlExpr
4343
}
4444

4545
void TestDataFlow()
@@ -59,7 +59,6 @@ void TestDataFlow()
5959
void Sink(object @object)
6060
{
6161
}
62-
6362
}
6463

6564
}

csharp/ql/test/library-tests/frameworks/EntityFramework/MappedProperties.ql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ import semmle.code.csharp.frameworks.EntityFramework
33

44
from EntityFramework::MappedProperty property
55
select property
6-

csharp/ql/test/library-tests/frameworks/EntityFramework/SqlExprs.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ import csharp
22
import semmle.code.csharp.frameworks.Sql
33

44
from SqlExpr expr
5-
select expr
5+
select expr

csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSources.expected renamed to csharp/ql/test/library-tests/frameworks/EntityFramework/StoredFlowSources.expected

File renamed without changes.

csharp/ql/test/library-tests/frameworks/EntityFramework/FlowSources.ql renamed to csharp/ql/test/library-tests/frameworks/EntityFramework/StoredFlowSources.ql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import csharp
2-
32
import semmle.code.csharp.security.dataflow.flowsources.Stored
43

54
from StoredFlowSource source

0 commit comments

Comments
 (0)