Skip to content

Commit a221095

Browse files
committed
Swift: Uncontrolled format string query (initial version).
1 parent ace7146 commit a221095

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* @name Uncontrolled format string
3+
* @description TODO
4+
* @kind path-problem
5+
* @problem.severity TODO
6+
* @security-severity TODO
7+
* @precision TODO
8+
* @id swift/uncontrolled-format-string
9+
* @tags security
10+
* external/cwe/cwe-134
11+
*/
12+
13+
import swift
14+
import codeql.swift.dataflow.DataFlow
15+
import codeql.swift.dataflow.TaintTracking
16+
import codeql.swift.dataflow.FlowSources
17+
import DataFlow::PathGraph
18+
import swift
19+
20+
/**
21+
* A function that takes a `printf` style format argument.
22+
*/
23+
abstract class FormattingFunction extends AbstractFunctionDecl {
24+
/**
25+
* Gets the position of the format argument.
26+
*/
27+
abstract int getFormatParameterIndex();
28+
}
29+
30+
/**
31+
* An initializer for `String`, `NSString` or `NSMutableString` that takes a
32+
* `printf` style format argument.
33+
*/
34+
class StringInitWithFormat extends FormattingFunction, MethodDecl {
35+
StringInitWithFormat() {
36+
exists(string fName |
37+
this.hasQualifiedName(["String", "NSString", "NSMutableString"], fName) and
38+
fName.matches("init(format:%")
39+
)
40+
}
41+
42+
override int getFormatParameterIndex() { result = 0 }
43+
}
44+
45+
/**
46+
* The `localizedStringWithFormat` method of `String`, `NSString` and `NSMutableString`.
47+
*/
48+
class LocalizedStringWithFormat extends FormattingFunction, MethodDecl {
49+
LocalizedStringWithFormat() {
50+
this.hasQualifiedName(["String", "NSString", "NSMutableString"],
51+
"localizedStringWithFormat(_:_:)")
52+
}
53+
54+
override int getFormatParameterIndex() { result = 0 }
55+
}
56+
57+
/**
58+
* The functions `NSLog` and `NSLogv`.
59+
*/
60+
class NsLog extends FormattingFunction, FreeFunctionDecl {
61+
NsLog() { this.getName() = ["NSLog(_:_:)", "NSLogv(_:_:)"] }
62+
63+
override int getFormatParameterIndex() { result = 0 }
64+
}
65+
66+
/**
67+
* The `NSException.raise` method.
68+
*/
69+
class NsExceptionRaise extends FormattingFunction, MethodDecl {
70+
NsExceptionRaise() { this.hasQualifiedName("NSException", "raise(_:format:arguments:)") }
71+
72+
override int getFormatParameterIndex() { result = 1 }
73+
}
74+
75+
/**
76+
* A call to a function that takes a `printf` style format argument.
77+
*/
78+
class FormattingFunctionCall extends CallExpr {
79+
FormattingFunction target;
80+
81+
FormattingFunctionCall() { target = this.getStaticTarget() }
82+
83+
/**
84+
* Gets the format expression used in this call.
85+
*/
86+
Expr getFormat() { result = this.getArgument(target.getFormatParameterIndex()).getExpr() }
87+
}
88+
89+
/**
90+
* A taint configuration for tainted data that reaches a format string.
91+
*/
92+
class TaintedFormatConfiguration extends TaintTracking::Configuration {
93+
TaintedFormatConfiguration() { this = "TaintedFormatConfiguration" }
94+
95+
override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
96+
97+
override predicate isSink(DataFlow::Node node) {
98+
node.asExpr() = any(FormattingFunctionCall fc).getFormat()
99+
}
100+
}
101+
102+
from TaintedFormatConfiguration config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
103+
where config.hasFlowPath(sourceNode, sinkNode)
104+
select sinkNode.getNode(), sourceNode, sinkNode, "This format string is derived from a $@.",
105+
sourceNode.getNode(), "user-provided value"

0 commit comments

Comments
 (0)