@@ -4,7 +4,12 @@ private import codeql.swift.dataflow.ExternalFlow
44private import codeql.swift.dataflow.FlowSources
55private import codeql.swift.dataflow.FlowSteps
66
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 {
813 override predicate row ( string row ) {
914 row = ";WKScriptMessageHandler;true;userContentController(_:didReceive:);;;Parameter[1];remote"
1015 }
@@ -27,3 +32,98 @@ private class WKScriptMessageBodyInheritsTaint extends TaintInheritingContent,
2732 )
2833 }
2934}
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