diff --git a/infer/src/base/IssueType.ml b/infer/src/base/IssueType.ml index c332b820b..d29909d6c 100644 --- a/infer/src/base/IssueType.ml +++ b/infer/src/base/IssueType.ml @@ -120,6 +120,8 @@ let class_cast_exception = from_string ~enabled:false "CLASS_CAST_EXCEPTION" let cluster_callback = from_string "CLUSTER_CALLBACK" +let create_intent_from_uri = from_string "CREATE_INTENT_FROM_URI" + let codequery = from_string "Codequery" let comparing_floats_for_equality = from_string "COMPARING_FLOAT_FOR_EQUALITY" diff --git a/infer/src/base/IssueType.mli b/infer/src/base/IssueType.mli index cd745acd6..c3a74bb9e 100644 --- a/infer/src/base/IssueType.mli +++ b/infer/src/base/IssueType.mli @@ -71,6 +71,8 @@ val class_cast_exception : t val cluster_callback : t +val create_intent_from_uri : t + val codequery : t val comparing_floats_for_equality : t diff --git a/infer/src/quandary/JavaTrace.ml b/infer/src/quandary/JavaTrace.ml index cdaf11e89..5b1963047 100644 --- a/infer/src/quandary/JavaTrace.ml +++ b/infer/src/quandary/JavaTrace.ml @@ -15,10 +15,11 @@ module SourceKind = struct type t = | DrawableResource of Pvar.t (** Drawable resource ID read from a global *) | Intent (** external Intent or a value read from one *) + | IntentFromURI (** Intent created from a URI *) | Other (** for testing or uncategorized sources *) | PrivateData (** private user or device-specific data *) | UserControlledString (** data read from a text box or the clipboard service *) - | UserControlledURI (** resource locator from the browser bar *) + | UserControlledURI (** resource locator originating from the browser bar *) [@@deriving compare] let matches ~caller ~callee = Int.equal 0 (compare caller callee) @@ -26,6 +27,8 @@ module SourceKind = struct let of_string = function | "Intent" -> Intent + | "IntentFromURI" -> + IntentFromURI | "PrivateData" -> PrivateData | "UserControlledURI" -> @@ -47,6 +50,13 @@ module SourceKind = struct match pname with | Typ.Procname.Java pname -> ( match (Typ.Procname.java_get_class_name pname, Typ.Procname.java_get_method pname) with + | "android.content.Intent", "" when List.length actuals > 2 -> + (* taint the [this] parameter passed to the constructor *) + Some (IntentFromURI, Some 0) + | ( "android.content.Intent" + , ( "parseUri" | "setData" | "setDataAndNormalize" | "setDataAndType" + | "setDataAndTypeAndNormalize" ) ) -> + Some (IntentFromURI, return) | ( "android.location.Location" , ("getAltitude" | "getBearing" | "getLatitude" | "getLongitude" | "getSpeed") ) -> Some (PrivateData, return) @@ -179,6 +189,8 @@ module SourceKind = struct Pvar.to_string pvar | Intent -> "Intent" + | IntentFromURI -> + "IntentFromURI" | Other -> "Other" | PrivateData -> @@ -385,7 +397,7 @@ include Trace.Make (struct match (Source.kind source, Sink.kind sink) with | _ when not (List.is_empty sanitizers) -> (* assume any sanitizer clears all forms of taint *) - L.d_strln "non-empty sanitizers!" ; None + None | PrivateData, Logging (* logging private data issue *) | Intent, StartComponent @@ -395,8 +407,6 @@ include Trace.Make (struct | Intent, JavaScript (* external data flows into JS: remote code execution risk *) | PrivateData, JavaScript - (* leaking private data into JS *) - | UserControlledURI, (CreateIntent | StartComponent) (* create intent/launch component from user-controlled URI *) | UserControlledURI, CreateFile (* create file from user-controller URI; potential path-traversal vulnerability *) @@ -409,8 +419,11 @@ include Trace.Make (struct | DrawableResource _, OpenDrawableResource -> (* not a security issue, but useful for debugging flows from resource IDs to inflation *) Some IssueType.quandary_taint_error + | IntentFromURI, StartComponent -> + (* create an intent/start a component using a (possibly user-controlled) URI. may or may not + be an issue; depends on where the URI comes from *) + Some IssueType.create_intent_from_uri | Other, _ | _, Other -> - L.d_strln (F.asprintf "have %d sanitizers" (List.length sanitizers)) ; (* for testing purposes, Other matches everything *) Some IssueType.quandary_taint_error | _ -> diff --git a/infer/tests/codetoanalyze/java/quandary/Intents.java b/infer/tests/codetoanalyze/java/quandary/Intents.java index bd8b04967..c8467ccdf 100644 --- a/infer/tests/codetoanalyze/java/quandary/Intents.java +++ b/infer/tests/codetoanalyze/java/quandary/Intents.java @@ -66,11 +66,10 @@ class MyActivity extends Activity { @Override public void onResume() { - FN_startServiceWithTaintedIntent(); + startServiceWithTaintedIntent(); } - // need to understand the lifecycle to get this - void FN_startServiceWithTaintedIntent() { + void startServiceWithTaintedIntent() { Intent taintedIntent = new Intent("", mUri); startService(taintedIntent); } diff --git a/infer/tests/codetoanalyze/java/quandary/WebViews.java b/infer/tests/codetoanalyze/java/quandary/WebViews.java index de63f73c6..0f253dbf9 100644 --- a/infer/tests/codetoanalyze/java/quandary/WebViews.java +++ b/infer/tests/codetoanalyze/java/quandary/WebViews.java @@ -55,7 +55,8 @@ public class WebViews { @Override public void onLoadResource(WebView w, String url) { try { - Intent.parseUri(url, 0); // should report + Intent i = Intent.parseUri(url, 0); + mActivity.startActivity(i); // should report } catch (URISyntaxException e) { } } @@ -69,7 +70,8 @@ public class WebViews { @Override public boolean shouldOverrideUrlLoading(WebView w, String url) { try { - Intent.parseUri(url, 0); // should report + Intent i = Intent.parseUri(url, 0); + mActivity.startActivity(i); // should report } catch (URISyntaxException e) { } return false; @@ -81,7 +83,8 @@ public class WebViews { @Override public boolean onJsAlert(WebView w, String url, String message, JsResult result) { try { - Intent.parseUri(url, 0); // should report + Intent i = Intent.parseUri(url, 0); + mActivity.startActivity(i); } catch (URISyntaxException e) { } return false; @@ -90,7 +93,8 @@ public class WebViews { @Override public boolean onJsBeforeUnload(WebView w, String url, String m, JsResult result) { try { - Intent.parseUri(url, 0); // should report + Intent i = Intent.parseUri(url, 0); + mActivity.startActivity(i); } catch (URISyntaxException e) { } return false; @@ -99,7 +103,8 @@ public class WebViews { @Override public boolean onJsConfirm(WebView w, String url, String m, JsResult result) { try { - Intent.parseUri(url, 0); // should report + Intent i = Intent.parseUri(url, 0); + mActivity.startActivity(i); } catch (URISyntaxException e) { } return false; @@ -108,7 +113,8 @@ public class WebViews { @Override public boolean onJsPrompt(WebView w, String url, String m, String s, JsPromptResult result) { try { - Intent.parseUri(url, 0); // should report + Intent i = Intent.parseUri(url, 0); + mActivity.startActivity(i); } catch (URISyntaxException e) { } return false; diff --git a/infer/tests/codetoanalyze/java/quandary/issues.exp b/infer/tests/codetoanalyze/java/quandary/issues.exp index ca5a6eca6..17da3afc3 100644 --- a/infer/tests/codetoanalyze/java/quandary/issues.exp +++ b/infer/tests/codetoanalyze/java/quandary/issues.exp @@ -103,6 +103,7 @@ codetoanalyze/java/quandary/Intents.java, void Intents.reuseIntentBad(Activity), codetoanalyze/java/quandary/Intents.java, void Intents.subclassCallBad(IntentSubclass,ContextSubclass), 3, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void Context.startActivity(Intent)] codetoanalyze/java/quandary/Intents.java, void MyActivity.onActivityResult(int,int,Intent), 1, QUANDARY_TAINT_ERROR, [Return from void MyActivity.onActivityResult(int,int,Intent),Call to ComponentName ContextWrapper.startService(Intent)] codetoanalyze/java/quandary/Intents.java, void MyActivity.onNewIntent(Intent), 1, QUANDARY_TAINT_ERROR, [Return from void MyActivity.onNewIntent(Intent),Call to ComponentName ContextWrapper.startService(Intent)] +codetoanalyze/java/quandary/Intents.java, void MyActivity.startServiceWithTaintedIntent(), 2, CREATE_INTENT_FROM_URI, [Return from Intent.(String,Uri),Call to ComponentName ContextWrapper.startService(Intent)] codetoanalyze/java/quandary/Intents.java, void MyBroadcastReceiver.onReceive(Context,Intent), 1, QUANDARY_TAINT_ERROR, [Return from void MyBroadcastReceiver.onReceive(Context,Intent),Call to ComponentName ContextWrapper.startService(Intent)] codetoanalyze/java/quandary/Intents.java, void MyService.onRebind(Intent), 1, QUANDARY_TAINT_ERROR, [Return from void MyService.onRebind(Intent),Call to ComponentName ContextWrapper.startService(Intent)] codetoanalyze/java/quandary/Intents.java, void MyService.onStart(Intent,int), 1, QUANDARY_TAINT_ERROR, [Return from void MyService.onStart(Intent,int),Call to ComponentName ContextWrapper.startService(Intent)] @@ -216,13 +217,13 @@ codetoanalyze/java/quandary/UserControlledStrings.java, void UserControlledStrin codetoanalyze/java/quandary/UserControlledStrings.java, void UserControlledStrings.readClipboardSourcesBad(), 3, QUANDARY_TAINT_ERROR, [Return from ClipData ClipboardManager.getPrimaryClip(),Call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UserControlledStrings.java, void UserControlledStrings.readClipboardSourcesBad(), 4, QUANDARY_TAINT_ERROR, [Return from ClipData ClipboardManager.getPrimaryClip(),Call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UserControlledStrings.java, void UserControlledStrings.readClipboardSourcesBad(), 5, QUANDARY_TAINT_ERROR, [Return from ClipData ClipboardManager.getPrimaryClip(),Call to void InferTaint.inferSensitiveSink(Object)] -codetoanalyze/java/quandary/WebViews.java, WebResourceResponse WebViews$MyWebViewClient.shouldInterceptRequest(WebView,WebResourceRequest), 1, QUANDARY_TAINT_ERROR, [Return from WebResourceResponse WebViews$MyWebViewClient.shouldInterceptRequest(WebView,WebResourceRequest),Call to void Activity.startActivity(Intent)] -codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsAlert(WebView,String,String,JsResult), 2, QUANDARY_TAINT_ERROR, [Return from boolean WebViews$MyWebChromeClient.onJsAlert(WebView,String,String,JsResult),Call to Intent Intent.parseUri(String,int)] -codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsBeforeUnload(WebView,String,String,JsResult), 2, QUANDARY_TAINT_ERROR, [Return from boolean WebViews$MyWebChromeClient.onJsBeforeUnload(WebView,String,String,JsResult),Call to Intent Intent.parseUri(String,int)] -codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsConfirm(WebView,String,String,JsResult), 2, QUANDARY_TAINT_ERROR, [Return from boolean WebViews$MyWebChromeClient.onJsConfirm(WebView,String,String,JsResult),Call to Intent Intent.parseUri(String,int)] -codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsPrompt(WebView,String,String,String,JsPromptResult), 2, QUANDARY_TAINT_ERROR, [Return from boolean WebViews$MyWebChromeClient.onJsPrompt(WebView,String,String,String,JsPromptResult),Call to Intent Intent.parseUri(String,int)] -codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebViewClient.shouldOverrideUrlLoading(WebView,String), 2, QUANDARY_TAINT_ERROR, [Return from boolean WebViews$MyWebViewClient.shouldOverrideUrlLoading(WebView,String),Call to Intent Intent.parseUri(String,int)] -codetoanalyze/java/quandary/WebViews.java, void WebViews$MyWebViewClient.onLoadResource(WebView,String), 2, QUANDARY_TAINT_ERROR, [Return from void WebViews$MyWebViewClient.onLoadResource(WebView,String),Call to Intent Intent.parseUri(String,int)] +codetoanalyze/java/quandary/WebViews.java, WebResourceResponse WebViews$MyWebViewClient.shouldInterceptRequest(WebView,WebResourceRequest), 1, CREATE_INTENT_FROM_URI, [Return from Intent.(String,Uri),Call to void Activity.startActivity(Intent)] +codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsAlert(WebView,String,String,JsResult), 3, CREATE_INTENT_FROM_URI, [Return from Intent Intent.parseUri(String,int),Call to void Activity.startActivity(Intent)] +codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsBeforeUnload(WebView,String,String,JsResult), 3, CREATE_INTENT_FROM_URI, [Return from Intent Intent.parseUri(String,int),Call to void Activity.startActivity(Intent)] +codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsConfirm(WebView,String,String,JsResult), 3, CREATE_INTENT_FROM_URI, [Return from Intent Intent.parseUri(String,int),Call to void Activity.startActivity(Intent)] +codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebChromeClient.onJsPrompt(WebView,String,String,String,JsPromptResult), 3, CREATE_INTENT_FROM_URI, [Return from Intent Intent.parseUri(String,int),Call to void Activity.startActivity(Intent)] +codetoanalyze/java/quandary/WebViews.java, boolean WebViews$MyWebViewClient.shouldOverrideUrlLoading(WebView,String), 3, CREATE_INTENT_FROM_URI, [Return from Intent Intent.parseUri(String,int),Call to void Activity.startActivity(Intent)] +codetoanalyze/java/quandary/WebViews.java, void WebViews$MyWebViewClient.onLoadResource(WebView,String), 3, CREATE_INTENT_FROM_URI, [Return from Intent Intent.parseUri(String,int),Call to void Activity.startActivity(Intent)] codetoanalyze/java/quandary/WebViews.java, void WebViews.callWebviewSinks(WebView), 3, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void WebView.evaluateJavascript(String,ValueCallback)] codetoanalyze/java/quandary/WebViews.java, void WebViews.callWebviewSinks(WebView), 4, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void WebView.loadData(String,String,String)] codetoanalyze/java/quandary/WebViews.java, void WebViews.callWebviewSinks(WebView), 5, QUANDARY_TAINT_ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void WebView.loadDataWithBaseURL(String,String,String,String,String)]