Skip to content

Commit 5ba2894

Browse files
committed
C#: Address review comments.
1 parent e32fd75 commit 5ba2894

File tree

3 files changed

+29
-60
lines changed

3 files changed

+29
-60
lines changed

csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ private import semmle.code.csharp.commons.Collections
77
private import semmle.code.csharp.frameworks.System
88
private import semmle.code.csharp.frameworks.system.Text
99

10-
/** A method that formats a string, for example `string.Format()`. */
10+
/** A method that formats a string (or parses a format string), for example `string.Format()` */
1111
abstract private class FormatMethodImpl extends Method {
1212
/**
1313
* Gets the argument containing the format string. For example, the argument of
@@ -124,6 +124,17 @@ private class SystemDiagnosticsFormatMethods extends FormatMethodImpl {
124124
override int getFormatArgument() { result = 0 }
125125
}
126126

127+
/**
128+
* The `System.Text.CompositeFormat.Parse` method.
129+
*
130+
* Note that this method is not an ordinary format method, but it parses the format argument.
131+
*/
132+
class CompositeFormatParseMethod extends FormatMethodImpl {
133+
CompositeFormatParseMethod() { this = any(SystemTextCompositeFormatClass x).getParseMethod() }
134+
135+
override int getFormatArgument() { result = 0 }
136+
}
137+
127138
pragma[nomagic]
128139
private predicate parameterReadPostDominatesEntry(ParameterRead pr) {
129140
pr.getAControlFlowNode().postDominates(pr.getEnclosingCallable().getEntryPoint()) and
@@ -289,31 +300,3 @@ class FormatCall extends MethodCall {
289300
result = this.getArgument(this.getFirstArgument() + index)
290301
}
291302
}
292-
293-
/**
294-
* A method call to a method that parses a format string, for example a call
295-
* to `string.Format()`.
296-
*/
297-
abstract private class FormatStringParseCallImpl extends MethodCall {
298-
/**
299-
* Gets the expression used as the format string.
300-
*/
301-
abstract Expr getFormatExpr();
302-
}
303-
304-
final class FormatStringParseCall = FormatStringParseCallImpl;
305-
306-
private class OrdinaryFormatCall extends FormatStringParseCallImpl instanceof FormatCall {
307-
override Expr getFormatExpr() { result = FormatCall.super.getFormatExpr() }
308-
}
309-
310-
/**
311-
* A method call to `System.Text.CompositeFormat.Parse`.
312-
*/
313-
class ParseFormatStringCall extends FormatStringParseCallImpl {
314-
ParseFormatStringCall() {
315-
this.getTarget() = any(SystemTextCompositeFormatClass x).getParseMethod()
316-
}
317-
318-
override Expr getFormatExpr() { result = this.getArgument(0) }
319-
}

csharp/ql/src/API Abuse/FormatInvalid.ql

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,13 @@ import semmle.code.csharp.frameworks.system.Text
1515
import semmle.code.csharp.frameworks.Format
1616
import FormatFlow::PathGraph
1717

18-
module FormatInvalidConfig implements DataFlow::ConfigSig {
19-
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
20-
21-
predicate isSink(DataFlow::Node n) {
22-
exists(FormatStringParseCall c | n.asExpr() = c.getFormatExpr())
23-
}
24-
}
25-
26-
module FormatInvalid = DataFlow::Global<FormatInvalidConfig>;
27-
28-
module FormatLiteralConfig implements DataFlow::ConfigSig {
18+
module FormatFlowConfig implements DataFlow::ConfigSig {
2919
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
3020

3121
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
3222
// Add flow via `System.Text.CompositeFormat.Parse`.
33-
exists(ParseFormatStringCall call |
23+
exists(FormatCall call |
24+
call.getTarget() instanceof CompositeFormatParseMethod and
3425
pred.asExpr() = call.getFormatExpr() and
3526
succ.asExpr() = call
3627
)
@@ -39,31 +30,28 @@ module FormatLiteralConfig implements DataFlow::ConfigSig {
3930
predicate isSink(DataFlow::Node n) { exists(FormatCall c | n.asExpr() = c.getFormatExpr()) }
4031
}
4132

42-
module FormatLiteral = DataFlow::Global<FormatLiteralConfig>;
43-
44-
module FormatFlow =
45-
DataFlow::MergePathGraph<FormatInvalid::PathNode, FormatLiteral::PathNode,
46-
FormatInvalid::PathGraph, FormatLiteral::PathGraph>;
33+
module FormatFlow = DataFlow::Global<FormatFlowConfig>;
4734

4835
private predicate invalidFormatString(
49-
InvalidFormatString src, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
50-
FormatStringParseCall call, string callString
36+
InvalidFormatString src, FormatFlow::PathNode source, FormatFlow::PathNode sink, string msg,
37+
FormatCall call, string callString
5138
) {
5239
source.getNode().asExpr() = src and
5340
sink.getNode().asExpr() = call.getFormatExpr() and
54-
FormatInvalid::flowPath(source, sink) and
41+
FormatFlow::flowPath(source, sink) and
5542
msg = "Invalid format string used in $@ formatting call." and
5643
callString = "this"
5744
}
5845

5946
private predicate unusedArgument(
60-
FormatCall call, FormatLiteral::PathNode source, FormatLiteral::PathNode sink, string msg,
47+
FormatCall call, FormatFlow::PathNode source, FormatFlow::PathNode sink, string msg,
6148
ValidFormatString src, string srcString, Expr unusedExpr, string unusedString
6249
) {
6350
exists(int unused |
6451
source.getNode().asExpr() = src and
6552
sink.getNode().asExpr() = call.getFormatExpr() and
66-
FormatLiteral::flowPath(source, sink) and
53+
not call.getTarget() instanceof CompositeFormatParseMethod and
54+
FormatFlow::flowPath(source, sink) and
6755
unused = call.getASuppliedArgument() and
6856
not unused = src.getAnInsert() and
6957
not src.getValue() = "" and
@@ -75,13 +63,14 @@ private predicate unusedArgument(
7563
}
7664

7765
private predicate missingArgument(
78-
FormatCall call, FormatLiteral::PathNode source, FormatLiteral::PathNode sink, string msg,
66+
FormatCall call, FormatFlow::PathNode source, FormatFlow::PathNode sink, string msg,
7967
ValidFormatString src, string srcString
8068
) {
8169
exists(int used, int supplied |
8270
source.getNode().asExpr() = src and
8371
sink.getNode().asExpr() = call.getFormatExpr() and
84-
FormatLiteral::flowPath(source, sink) and
72+
not call.getTarget() instanceof CompositeFormatParseMethod and
73+
FormatFlow::flowPath(source, sink) and
8574
used = src.getAnInsert() and
8675
supplied = call.getSuppliedArguments() and
8776
used >= supplied and
@@ -94,14 +83,13 @@ from
9483
Element alert, FormatFlow::PathNode source, FormatFlow::PathNode sink, string msg, Element extra1,
9584
string extra1String, Element extra2, string extra2String
9685
where
97-
invalidFormatString(alert, source.asPathNode1(), sink.asPathNode1(), msg, extra1, extra1String) and
86+
invalidFormatString(alert, source, sink, msg, extra1, extra1String) and
9887
extra2 = extra1 and
9988
extra2String = extra1String
10089
or
101-
unusedArgument(alert, source.asPathNode2(), sink.asPathNode2(), msg, extra1, extra1String, extra2,
102-
extra2String)
90+
unusedArgument(alert, source, sink, msg, extra1, extra1String, extra2, extra2String)
10391
or
104-
missingArgument(alert, source.asPathNode2(), sink.asPathNode2(), msg, extra1, extra1String) and
92+
missingArgument(alert, source, sink, msg, extra1, extra1String) and
10593
extra2 = extra1 and
10694
extra2String = extra1String
10795
select alert, source, sink, msg, extra1, extra1String, extra2, extra2String

csharp/ql/src/Security Features/CWE-134/UncontrolledFormatString.ql

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import FormatString::PathGraph
1919
module FormatStringConfig implements DataFlow::ConfigSig {
2020
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
2121

22-
predicate isSink(DataFlow::Node sink) {
23-
sink.asExpr() = any(FormatStringParseCall call).getFormatExpr()
24-
}
22+
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(FormatCall call).getFormatExpr() }
2523
}
2624

2725
module FormatString = TaintTracking::Global<FormatStringConfig>;

0 commit comments

Comments
 (0)