@@ -4,7 +4,12 @@ private import codeql.swift.dataflow.ExternalFlow
4
4
private import codeql.swift.dataflow.FlowSources
5
5
private import codeql.swift.dataflow.FlowSteps
6
6
7
- private class WKScriptMessageSource extends SourceModelCsv {
7
+ /**
8
+ * A model for WKScriptMessage sources. Classes implementing the `WKScriptMessageHandler` protocol
9
+ * act as a bridge between JavaScript and native code. The messages sent from JavaScript code are
10
+ * stored in the `message` parameter of `userContentController`.
11
+ */
12
+ private class WKScriptMessageSources extends SourceModelCsv {
8
13
override predicate row ( string row ) {
9
14
row = ";WKScriptMessageHandler;true;userContentController(_:didReceive:);;;Parameter[1];remote"
10
15
}
@@ -27,3 +32,98 @@ private class WKScriptMessageBodyInheritsTaint extends TaintInheritingContent,
27
32
)
28
33
}
29
34
}
35
+
36
+ /**
37
+ * A model for `JSContext` sources. `JSContext` acts as a bridge between JavaScript and
38
+ * native code, so any object obtained from it has the potential of being tainted by a malicious
39
+ * website visited in the WebView.
40
+ */
41
+ private class JsContextSources extends SourceModelCsv {
42
+ override predicate row ( string row ) {
43
+ row =
44
+ [
45
+ ";JSContext;true;globalObject;;;;remote" ,
46
+ ";JSContext;true;objectAtIndexedSubscript(_:);;;ReturnValue;remote" ,
47
+ ";JSContext;true;objectForKeyedSubscript(_:);;;ReturnValue;remote"
48
+ ]
49
+ }
50
+ }
51
+
52
+ /**
53
+ * A model for `JSValue` summaries. If a `JSValue` is tainted, any object it is converted into
54
+ * is also tainted.
55
+ */
56
+ private class JsValueSummaries extends SummaryModelCsv {
57
+ override predicate row ( string row ) {
58
+ row =
59
+ [
60
+ ";JSValue;true;init(object:in:);;;Argument[0];ReturnValue;taint" ,
61
+ ";JSValue;true;init(bool:in:);;;Argument[0];ReturnValue;taint" ,
62
+ ";JSValue;true;init(double:in:);;;Argument[0];ReturnValue;taint" ,
63
+ ";JSValue;true;init(int32:in:);;;Argument[0];ReturnValue;taint" ,
64
+ ";JSValue;true;init(uInt32:in:);;;Argument[0];ReturnValue;taint" ,
65
+ ";JSValue;true;init(point:in:);;;Argument[0];ReturnValue;taint" ,
66
+ ";JSValue;true;init(range:in:);;;Argument[0];ReturnValue;taint" ,
67
+ ";JSValue;true;init(rect:in:);;;Argument[0];ReturnValue;taint" ,
68
+ ";JSValue;true;init(size:in:);;;Argument[0];ReturnValue;taint" ,
69
+ ";JSValue;true;toObject();;;Argument[-1];ReturnValue;taint" ,
70
+ ";JSValue;true;toObjectOf(_:);;;Argument[-1];ReturnValue;taint" ,
71
+ ";JSValue;true;toBool();;;Argument[-1];ReturnValue;taint" ,
72
+ ";JSValue;true;toDouble();;;Argument[-1];ReturnValue;taint" ,
73
+ ";JSValue;true;toInt32();;;Argument[-1];ReturnValue;taint" ,
74
+ ";JSValue;true;toUInt32();;;Argument[-1];ReturnValue;taint" ,
75
+ ";JSValue;true;toNumber();;;Argument[-1];ReturnValue;taint" ,
76
+ ";JSValue;true;toString();;;Argument[-1];ReturnValue;taint" ,
77
+ ";JSValue;true;toDate();;;Argument[-1];ReturnValue;taint" ,
78
+ ";JSValue;true;toArray();;;Argument[-1];ReturnValue;taint" ,
79
+ ";JSValue;true;toDictionary();;;Argument[-1];ReturnValue;taint" ,
80
+ ";JSValue;true;toPoint();;;Argument[-1];ReturnValue;taint" ,
81
+ ";JSValue;true;toRange();;;Argument[-1];ReturnValue;taint" ,
82
+ ";JSValue;true;toRect();;;Argument[-1];ReturnValue;taint" ,
83
+ ";JSValue;true;toSize();;;Argument[-1];ReturnValue;taint" ,
84
+ // TODO: These models could use content flow to be more precise
85
+ ";JSValue;true;atIndex(_:);;;Argument[-1];ReturnValue;taint" ,
86
+ ";JSValue;true;defineProperty(_:descriptor:);;;Argument[1];Argument[-1];taint" ,
87
+ ";JSValue;true;forProperty(_:);;;Argument[-1];ReturnValue;taint" ,
88
+ ";JSValue;true;setValue(_:at:);;;Argument[0];Argument[-1];taint" ,
89
+ ";JSValue;true;setValue(_:forProperty:);;;Argument[0];Argument[-1];taint"
90
+ ]
91
+ }
92
+ }
93
+
94
+ /** The class `JSContext`. */
95
+ private class JsContextDecl extends ClassDecl {
96
+ JsContextDecl ( ) { this .getName ( ) = "JSContext" }
97
+ }
98
+
99
+ /** The type of an object exposed to JavaScript through `JSContext.setObject`. */
100
+ private class TypeExposedThroughJsContext extends Type {
101
+ TypeExposedThroughJsContext ( ) {
102
+ exists ( ApplyExpr c , FuncDecl f |
103
+ c .getStaticTarget ( ) = f and
104
+ f .getEnclosingDecl ( ) instanceof JsContextDecl and
105
+ f .getName ( ) = "setObject(_:forKeyedSubscript)"
106
+ |
107
+ c .getArgument ( 0 ) .getExpr ( ) .getType ( ) = this
108
+ )
109
+ }
110
+ }
111
+
112
+ /**
113
+ * The members (fields and parameters of functions) of a class or struct
114
+ * an instance of which is exposed to JavaScript through `JSContext.setObject`.
115
+ */
116
+ private class ExposedThroughJsContextSource extends RemoteFlowSource {
117
+ ExposedThroughJsContextSource ( ) {
118
+ exists ( ParamDecl p | this .( DataFlow:: ParameterNode ) .getParameter ( ) = p |
119
+ p .getDeclaringFunction ( ) .getEnclosingDecl ( ) .( ClassOrStructDecl ) .getType ( ) instanceof
120
+ TypeExposedThroughJsContext
121
+ )
122
+ or
123
+ exists ( FieldDecl f | this .asDefinition ( ) .getSourceVariable ( ) = f |
124
+ f .getEnclosingDecl ( ) .( ClassOrStructDecl ) .getType ( ) instanceof TypeExposedThroughJsContext
125
+ )
126
+ }
127
+
128
+ override string getSourceType ( ) { result = "Member of a type exposed through JSContext" }
129
+ }
0 commit comments