Skip to content

Commit ca2959c

Browse files
authored
Merge pull request #8537 from atorralba/atorralba/unsafe_android_access_improvs
Java: Improvements to UnsafeAndroidAccess
2 parents 6169ac6 + 8601137 commit ca2959c

File tree

14 files changed

+123
-490
lines changed

14 files changed

+123
-490
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,76 @@
11
import java
22

3+
/** The class `android.webkit.WebView`. */
34
class TypeWebView extends Class {
45
TypeWebView() { this.hasQualifiedName("android.webkit", "WebView") }
56
}
67

8+
/** The class `android.webkit.WebViewClient`. */
79
class TypeWebViewClient extends Class {
810
TypeWebViewClient() { this.hasQualifiedName("android.webkit", "WebViewClient") }
911
}
1012

13+
/** The class `android.webkit.WebSettings`. */
1114
class TypeWebSettings extends Class {
1215
TypeWebSettings() { this.hasQualifiedName("android.webkit", "WebSettings") }
1316
}
1417

18+
/** The method `getSettings` of the class `android.webkit.WebView`. */
1519
class WebViewGetSettingsMethod extends Method {
1620
WebViewGetSettingsMethod() {
1721
this.hasName("getSettings") and
1822
this.getDeclaringType() instanceof TypeWebView
1923
}
2024
}
2125

26+
/** The method `loadUrl` or `postUrl` of the class `android.webkit.WebView`. */
2227
class WebViewLoadUrlMethod extends Method {
2328
WebViewLoadUrlMethod() {
2429
this.getDeclaringType() instanceof TypeWebView and
2530
(this.hasName("loadUrl") or this.hasName("postUrl"))
2631
}
2732
}
2833

34+
/** The method `getUrl` or `getOriginalUrl` of the class `android.webkit.WebView`. */
2935
class WebViewGetUrlMethod extends Method {
3036
WebViewGetUrlMethod() {
3137
this.getDeclaringType() instanceof TypeWebView and
3238
(this.getName() = "getUrl" or this.getName() = "getOriginalUrl")
3339
}
3440
}
41+
42+
/**
43+
* A method allowing any-local-file and cross-origin access in the class `android.webkit.WebSettings`.
44+
*/
45+
class CrossOriginAccessMethod extends Method {
46+
CrossOriginAccessMethod() {
47+
this.getDeclaringType() instanceof TypeWebSettings and
48+
this.hasName(["setAllowUniversalAccessFromFileURLs", "setAllowFileAccessFromFileURLs"])
49+
}
50+
}
51+
52+
/**
53+
* The method `setJavaScriptEnabled` of the class `android.webkit.WebSettings`.
54+
*/
55+
class AllowJavaScriptMethod extends Method {
56+
AllowJavaScriptMethod() {
57+
this.getDeclaringType() instanceof TypeWebSettings and
58+
this.hasName("setJavaScriptEnabled")
59+
}
60+
}
61+
62+
/** The method `setWebViewClient` of the class `android.webkit.WebView`. */
63+
class WebViewSetWebViewClientMethod extends Method {
64+
WebViewSetWebViewClientMethod() {
65+
this.getDeclaringType() instanceof TypeWebView and
66+
this.hasName("setWebViewClient")
67+
}
68+
}
69+
70+
/** The method `shouldOverrideUrlLoading` of the class `android.webkit.WebViewClient`. */
71+
class ShouldOverrideUrlLoading extends Method {
72+
ShouldOverrideUrlLoading() {
73+
this.getDeclaringType().getASupertype*() instanceof TypeWebViewClient and
74+
this.hasName("shouldOverrideUrlLoading")
75+
}
76+
}

java/ql/lib/semmle/code/java/security/UnsafeAndroidAccess.qll

Lines changed: 76 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
*/
44

55
import java
6-
private import semmle.code.java.frameworks.android.WebView
76
private import semmle.code.java.dataflow.DataFlow
8-
private import semmle.code.java.dataflow.ExternalFlow
7+
private import semmle.code.java.frameworks.android.WebView
98

109
/**
1110
* A sink that represents a method that fetches a web resource in Android.
@@ -26,11 +25,9 @@ abstract class UrlResourceSink extends DataFlow::Node {
2625
*/
2726
private class CrossOriginUrlResourceSink extends JavaScriptEnabledUrlResourceSink {
2827
CrossOriginUrlResourceSink() {
29-
exists(Variable settings, MethodAccess ma |
30-
webViewLoadUrl(this.asExpr(), settings) and
31-
ma.getMethod() instanceof CrossOriginAccessMethod and
32-
ma.getArgument(0).(BooleanLiteral).getBooleanValue() = true and
33-
ma.getQualifier() = settings.getAnAccess()
28+
exists(WebViewRef webview |
29+
webViewLoadUrl(this.asExpr(), webview) and
30+
isAllowFileAccessEnabled(webview)
3431
)
3532
}
3633

@@ -44,57 +41,96 @@ private class CrossOriginUrlResourceSink extends JavaScriptEnabledUrlResourceSin
4441
*/
4542
private class JavaScriptEnabledUrlResourceSink extends UrlResourceSink {
4643
JavaScriptEnabledUrlResourceSink() {
47-
exists(Variable settings |
48-
webViewLoadUrl(this.asExpr(), settings) and
49-
isJSEnabled(settings)
44+
exists(WebViewRef webview |
45+
webViewLoadUrl(this.asExpr(), webview) and
46+
isJSEnabled(webview)
5047
)
5148
}
5249

5350
override string getSinkType() { result = "user input vulnerable to XSS attacks" }
5451
}
5552

53+
private class WebViewRef extends Element {
54+
WebViewRef() {
55+
this.(RefType).getASourceSupertype*() instanceof TypeWebView or
56+
this.(Variable).getType().(RefType).getASourceSupertype*() instanceof TypeWebView
57+
}
58+
59+
/** Gets an access to this WebView as a data flow node. */
60+
DataFlow::Node getAnAccess() {
61+
exists(DataFlow::InstanceAccessNode t | t.getType() = this and result = t |
62+
t.isOwnInstanceAccess() or t.getInstanceAccess().isEnclosingInstanceAccess(this)
63+
)
64+
or
65+
result = DataFlow::exprNode(this.(Variable).getAnAccess())
66+
}
67+
}
68+
5669
/**
57-
* Holds if a `WebViewLoadUrlMethod` method is called with the given `urlArg` on a
58-
* WebView with settings stored in `settings`.
70+
* Holds if a `WebViewLoadUrlMethod` is called on an access of `webview`
71+
* with `urlArg` as its first argument.
5972
*/
60-
private predicate webViewLoadUrl(Expr urlArg, Variable settings) {
61-
exists(MethodAccess loadUrl, Variable webview, MethodAccess getSettings |
73+
private predicate webViewLoadUrl(Argument urlArg, WebViewRef webview) {
74+
exists(MethodAccess loadUrl |
6275
loadUrl.getArgument(0) = urlArg and
63-
loadUrl.getMethod() instanceof WebViewLoadUrlMethod and
64-
loadUrl.getQualifier() = webview.getAnAccess() and
65-
getSettings.getMethod() instanceof WebViewGetSettingsMethod and
66-
webview.getAnAccess() = getSettings.getQualifier() and
67-
settings.getAnAssignedValue() = getSettings
76+
loadUrl.getMethod() instanceof WebViewLoadUrlMethod
77+
|
78+
webview.getAnAccess() = DataFlow::getInstanceArgument(loadUrl)
79+
or
80+
// `webview` is received as a parameter of an event method in a custom `WebViewClient`,
81+
// so we need to find `WebViews` that use that specific `WebViewClient`.
82+
exists(WebViewClientEventMethod eventMethod, MethodAccess setWebClient |
83+
setWebClient.getMethod() instanceof WebViewSetWebViewClientMethod and
84+
setWebClient.getArgument(0).getType() = eventMethod.getDeclaringType() and
85+
loadUrl.getQualifier() = eventMethod.getWebViewParameter().getAnAccess()
86+
|
87+
webview.getAnAccess() = DataFlow::getInstanceArgument(setWebClient)
88+
)
6889
)
6990
}
7091

7192
/**
72-
* A method allowing any-local-file and cross-origin access in the WebSettings class.
93+
* Holds if `webview`'s option `setJavascriptEnabled`
94+
* has been set to `true` via a `WebSettings` object obtained from it.
7395
*/
74-
private class CrossOriginAccessMethod extends Method {
75-
CrossOriginAccessMethod() {
76-
this.getDeclaringType() instanceof TypeWebSettings and
77-
this.hasName(["setAllowUniversalAccessFromFileURLs", "setAllowFileAccessFromFileURLs"])
78-
}
96+
private predicate isJSEnabled(WebViewRef webview) {
97+
exists(MethodAccess allowJs, MethodAccess settings |
98+
allowJs.getMethod() instanceof AllowJavaScriptMethod and
99+
allowJs.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() = true and
100+
settings.getMethod() instanceof WebViewGetSettingsMethod and
101+
DataFlow::localExprFlow(settings, allowJs.getQualifier()) and
102+
DataFlow::localFlow(webview.getAnAccess(), DataFlow::getInstanceArgument(settings))
103+
)
79104
}
80105

81106
/**
82-
* The `setJavaScriptEnabled` method for the webview.
107+
* Holds if `webview`'s options `setAllowUniversalAccessFromFileURLs` or
108+
* `setAllowFileAccessFromFileURLs` have been set to `true` via a `WebSettings` object
109+
* obtained from it.
83110
*/
84-
private class AllowJavaScriptMethod extends Method {
85-
AllowJavaScriptMethod() {
86-
this.getDeclaringType() instanceof TypeWebSettings and
87-
this.hasName("setJavaScriptEnabled")
88-
}
111+
private predicate isAllowFileAccessEnabled(WebViewRef webview) {
112+
exists(MethodAccess allowFileAccess, MethodAccess settings |
113+
allowFileAccess.getMethod() instanceof CrossOriginAccessMethod and
114+
allowFileAccess.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() = true and
115+
settings.getMethod() instanceof WebViewGetSettingsMethod and
116+
DataFlow::localExprFlow(settings, allowFileAccess.getQualifier()) and
117+
DataFlow::localFlow(webview.getAnAccess(), DataFlow::getInstanceArgument(settings))
118+
)
89119
}
90120

91-
/**
92-
* Holds if a call to `v.setJavaScriptEnabled(true)` exists.
93-
*/
94-
private predicate isJSEnabled(Variable v) {
95-
exists(MethodAccess jsa |
96-
v.getAnAccess() = jsa.getQualifier() and
97-
jsa.getMethod() instanceof AllowJavaScriptMethod and
98-
jsa.getArgument(0).(BooleanLiteral).getBooleanValue() = true
99-
)
121+
/** A method of the class `WebViewClient` that handles an event. */
122+
private class WebViewClientEventMethod extends Method {
123+
WebViewClientEventMethod() {
124+
this.getDeclaringType().getASupertype*() instanceof TypeWebViewClient and
125+
this.hasName([
126+
"shouldOverrideUrlLoading", "shouldInterceptRequest", "onPageStarted", "onPageFinished",
127+
"onLoadResource", "onPageCommitVisible", "onTooManyRedirects"
128+
])
129+
}
130+
131+
/** Gets a `WebView` parameter of this method. */
132+
Parameter getWebViewParameter() {
133+
result = this.getAParameter() and
134+
result.getType() instanceof TypeWebView
135+
}
100136
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The logic to detect `WebView`s with JavaScript (and optionally file access) enabled in the query `java/android/unsafe-android-webview-fetch` has been improved.
5+

java/ql/test/stubs/google-android-9.0.0/android/app/RemoteAction.java

Lines changed: 0 additions & 30 deletions
This file was deleted.

java/ql/test/stubs/google-android-9.0.0/android/view/textclassifier/ConversationAction.java

Lines changed: 0 additions & 31 deletions
This file was deleted.

java/ql/test/stubs/google-android-9.0.0/android/view/textclassifier/ConversationActions.java

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)