diff --git a/infer/src/quandary/JavaTrace.ml b/infer/src/quandary/JavaTrace.ml index e7233996c..c7ccf7e6b 100644 --- a/infer/src/quandary/JavaTrace.ml +++ b/infer/src/quandary/JavaTrace.ml @@ -18,6 +18,7 @@ module JavaSource = struct type t = | SharedPreferences (** private data read from SharedPreferences *) | Footprint of AccessPath.t (** source that was read from the environment. *) + | Intent | Other (** for testing or uncategorized sources *) let compare sk1 sk2 = match sk1, sk2 with @@ -27,6 +28,9 @@ module JavaSource = struct | Footprint ap1, Footprint ap2 -> AccessPath.compare ap1 ap2 | Footprint _, _ -> (-1) | _, Footprint _ -> 1 + | Intent, Intent -> 0 + | Intent, _ -> (-1) + | _, Intent -> 1 | Other, Other -> 0 end @@ -62,6 +66,8 @@ module JavaSource = struct | Procname.Java pname -> begin match Procname.java_get_class_name pname, Procname.java_get_method pname with + | "android.content.Intent", ("parseUri" | "parseIntent") -> + [0, make Intent site] | "android.content.SharedPreferences", "getString" -> [0, make SharedPreferences site] | "com.facebook.infer.models.InferTaint", "inferSecretSource" -> @@ -84,6 +90,7 @@ module JavaSource = struct compare t1 t2 = 0 let pp_kind fmt (kind : kind) = match kind with + | Intent -> F.fprintf fmt "Intent" | SharedPreferences -> F.fprintf fmt "SharedPreferences" | Footprint ap -> F.fprintf fmt "Footprint[%a]" AccessPath.pp ap | Other -> F.fprintf fmt "Other" @@ -102,6 +109,7 @@ module JavaSink = struct module SinkKind = struct type t = + | Intent (** sink that trusts an Intent *) | Logging (** sink that logs one or more of its arguments *) | Other (** for testing or uncategorized sinks *) @@ -109,6 +117,9 @@ module JavaSink = struct | Logging, Logging -> 0 | Logging, _ -> (-1) | _, Logging -> 1 + | Intent, Intent -> 0 + | Intent, _ -> (-1) + | _, Intent -> 1 | Other, Other -> 0 end @@ -130,15 +141,43 @@ module JavaSink = struct { kind; site; } let get site = - (* taint all the inputs of [pname] *) - let taint_all pname kind site ~report_reachable = + (* taint all the inputs of [pname]. for non-static procedures, taints the "this" parameter only + if [taint_this] is true. *) + let taint_all ?(taint_this=false) pname kind site ~report_reachable = + let params = + let all_params = Procname.java_get_parameters pname in + if Procname.java_is_static (CallSite.pname site) || taint_this + then all_params + else IList.tl all_params in IList.mapi (fun param_num _ -> Sink.make_sink_param (make kind site) param_num ~report_reachable) - (Procname.java_get_parameters pname) in + params in + (* taint the nth non-"this" parameter (0-indexed) *) + let taint_nth n kind site ~report_reachable = + let first_index = if Procname.java_is_static (CallSite.pname site) then n else n + 1 in + [Sink.make_sink_param (make kind site) first_index ~report_reachable] in match CallSite.pname site with | Procname.Java pname -> begin match Procname.java_get_class_name pname, Procname.java_get_method pname with + | ("android.app.Activity" | "android.content.ContextWrapper" | "android.content.Context"), + ("bindService" | + "sendBroadcast" | + "sendBroadcastAsUser" | + "sendOrderedBroadcast" | + "sendStickyBroadcast" | + "sendStickyBroadcastAsUser" | + "sendStickyOrderedBroadcast" | + "sendStickyOrderedBroadcastAsUser" | + "startActivities" | + "startActivity" | + "startActivityForResult" | + "startActivityIfNeeded" | + "startNextMatchingActivity" | + "startService") -> + taint_nth 0 Intent site ~report_reachable:true + | "android.app.Activity", ("startActivityFromChild" | "startActivityFromFragment") -> + taint_nth 1 Intent site ~report_reachable:true | "android.util.Log", ("d" | "e" | "i" | "println" | "v" | "w" | "wtf") -> taint_all pname Logging site ~report_reachable:true | "com.facebook.infer.models.InferTaint", "inferSensitiveSink" -> @@ -160,6 +199,7 @@ module JavaSink = struct compare t1 t2 = 0 let pp_kind fmt (kind : kind) = match kind with + | Intent -> F.fprintf fmt "Intent" | Logging -> F.fprintf fmt "Logging" | Other -> F.fprintf fmt "Other" @@ -185,6 +225,8 @@ include | SourceKind.Other, SinkKind.Other | SourceKind.SharedPreferences, SinkKind.Logging -> true + | SourceKind.Intent, SinkKind.Intent -> + true | _ -> false diff --git a/infer/tests/codetoanalyze/java/quandary/Intents.java b/infer/tests/codetoanalyze/java/quandary/Intents.java new file mode 100644 index 000000000..926cd305d --- /dev/null +++ b/infer/tests/codetoanalyze/java/quandary/Intents.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package codetoanalyze.java.quandary; + +import java.io.IOException; +import java.net.URISyntaxException; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; + +import org.xmlpull.v1.XmlPullParserException; + +public class Intents { + + Activity activity; + + public void callAllSinks(Intent i) { + activity.bindService(i, null, 0); + activity.sendBroadcast(i); + activity.sendBroadcastAsUser(i, null); + activity.sendOrderedBroadcast(i, null); + activity.sendStickyBroadcast(i); + activity.sendStickyBroadcastAsUser(i, null); + activity.sendStickyOrderedBroadcast(i, null, null, 0, null, null); + activity.sendStickyOrderedBroadcastAsUser(i, null, null, null, 0, null, null); + activity.startActivities(new Intent[] { i }); + activity.startActivity(i); + activity.startActivityForResult(i, 0); + activity.startActivityIfNeeded(i, 0); + activity.startActivityFromChild(null, i, 0); + activity.startActivityFromFragment(null, i, 0); + activity.startService(i); + } + + private native int rand(); + + public Intent returnAllSources() throws + IOException, URISyntaxException, XmlPullParserException { + switch (rand()) { + case 1: + return Intent.parseUri(null, 0); + case 2: + return Intent.parseIntent(null, null, null); + } + return null; + } + + public void callAllSinksBad(String uri) throws + IOException, URISyntaxException, XmlPullParserException { + Intent intent = returnAllSources(); + callAllSinks(intent); + } + +} diff --git a/infer/tests/codetoanalyze/java/quandary/Makefile b/infer/tests/codetoanalyze/java/quandary/Makefile index bc6d07998..15247883b 100644 --- a/infer/tests/codetoanalyze/java/quandary/Makefile +++ b/infer/tests/codetoanalyze/java/quandary/Makefile @@ -15,6 +15,7 @@ FILES = \ Basics.java \ Exceptions.java \ Fields.java \ + Intents.java \ Interprocedural.java \ LoggingPrivateData.java \ Recursion.java \