diff --git a/infer/src/quandary/JavaTrace.ml b/infer/src/quandary/JavaTrace.ml index 721ee5a22..0a2398644 100644 --- a/infer/src/quandary/JavaTrace.ml +++ b/infer/src/quandary/JavaTrace.ml @@ -130,18 +130,18 @@ module JavaSink = struct let get site = (* taint all the inputs of [pname] *) - let taint_all pname kind site = + let taint_all pname kind site ~report_reachable = IList.mapi - (fun param_num _ -> param_num,make kind site) + (fun param_num _ -> Sink.make_sink_param (make kind site) param_num ~report_reachable) (Procname.java_get_parameters pname) in match CallSite.pname site with | Procname.Java pname -> begin match Procname.java_get_class_name pname, Procname.java_get_method pname with | "android.util.Log", ("d" | "e" | "i" | "println" | "v" | "w" | "wtf") -> - taint_all pname Logging site + taint_all pname Logging site ~report_reachable:true | "com.facebook.infer.models.InferTaint", "inferSensitiveSink" -> - [0, make Other site] + [Sink.make_sink_param (make Other site) 0 ~report_reachable:false] | _ -> [] end diff --git a/infer/src/quandary/Sink.ml b/infer/src/quandary/Sink.ml index 0b4a0fa1d..c8354bf66 100644 --- a/infer/src/quandary/Sink.ml +++ b/infer/src/quandary/Sink.ml @@ -7,11 +7,23 @@ * of patent rights can be found in the PATENTS file in the same directory. *) +type 'a parameter = + { sink : 'a; + (** sink type of the parameter *) + index : int; + (** index of the parameter *) + report_reachable : bool; + (** if true, report if *any* value heap-reachable from the sink parameter is a source. + if false, report only if the value passed to the sink is itself a source *) + } + +let make_sink_param sink index ~report_reachable = + { sink; index; report_reachable; } + module type S = sig include TraceElem.S val to_callee : t -> CallSite.t -> t - (** ith param * ith source kind *) - val get : CallSite.t -> (int * t) list + val get : CallSite.t -> t parameter list end diff --git a/infer/src/quandary/TaintAnalysis.ml b/infer/src/quandary/TaintAnalysis.ml index b1288875c..40e4e08c4 100644 --- a/infer/src/quandary/TaintAnalysis.ml +++ b/infer/src/quandary/TaintAnalysis.ml @@ -124,16 +124,19 @@ module Make (TraceDomain : Trace.S) = struct let add_sinks sinks actuals ({ Domain.access_tree; id_map; } as astate) proc_data loc = let f_resolve_id = resolve_id id_map in (* add [sink] to the trace associated with the [formal_num]th actual *) - let add_sink_to_actual access_tree_acc (formal_num, sink) = - let actual_exp, actual_typ = IList.nth actuals formal_num in + let add_sink_to_actual access_tree_acc (sink_param : TraceDomain.Sink.t Sink.parameter) = + let actual_exp, actual_typ = IList.nth actuals sink_param.index in match AccessPath.of_exp actual_exp actual_typ ~f_resolve_id with | Some actual_ap -> - let actual_ap = AccessPath.Exact actual_ap in + let actual_ap = + if sink_param.report_reachable + then AccessPath.Abstracted actual_ap + else AccessPath.Exact actual_ap in begin match access_path_get_node actual_ap access_tree_acc proc_data loc with | Some (actual_trace, _) -> (* add callee_pname to actual trace as a sink *) - let actual_trace' = TraceDomain.add_sink sink actual_trace in + let actual_trace' = TraceDomain.add_sink sink_param.sink actual_trace in TraceDomain.log_reports actual_trace' (Cfg.Procdesc.get_proc_name proc_data.ProcData.pdesc) diff --git a/infer/src/unit/TaintTests.ml b/infer/src/unit/TaintTests.ml index 6e7ab29cd..f0333cad7 100644 --- a/infer/src/unit/TaintTests.ml +++ b/infer/src/unit/TaintTests.ml @@ -52,7 +52,7 @@ module MockTrace = Trace.Make(struct let get site = if string_is_prefix "SINK" (Procname.to_string (CallSite.pname site)) - then [(0, site)] + then [Sink.make_sink_param site 0 ~report_reachable:false] else [] end diff --git a/infer/tests/codetoanalyze/java/quandary/LoggingPrivateData.java b/infer/tests/codetoanalyze/java/quandary/LoggingPrivateData.java index 0ed581162..2e93896de 100644 --- a/infer/tests/codetoanalyze/java/quandary/LoggingPrivateData.java +++ b/infer/tests/codetoanalyze/java/quandary/LoggingPrivateData.java @@ -22,6 +22,21 @@ public class LoggingPrivateData { Log.d(prefs.getString("some", "data"), "value"); } + static class StringWrapper extends Throwable { + private String mStr; + + @Override + public String toString() { + return mStr; + } + } + + public void logSharedPreferencesDataIndirectBad(SharedPreferences prefs) { + StringWrapper wrapper = new StringWrapper(); + wrapper.mStr = prefs.getString("some", "data"); + Log.w("tag", wrapper); + } + public void logDataOk(SharedPreferences prefs) { Log.d("tag", "value"); } diff --git a/infer/tests/codetoanalyze/java/quandary/issues.exp b/infer/tests/codetoanalyze/java/quandary/issues.exp index d7699dbaf..28facd847 100644 --- a/infer/tests/codetoanalyze/java/quandary/issues.exp +++ b/infer/tests/codetoanalyze/java/quandary/issues.exp @@ -31,3 +31,4 @@ Fields.java:56: ERROR: QUANDARY_TAINT_ERROR Error: Other(Object InferTaint.infer Fields.java:63: ERROR: QUANDARY_TAINT_ERROR Error: Other(Object InferTaint.inferSecretSource() at [line 62]) -> Other(void InferTaint.inferSensitiveSink(Object) at [line 63]) via { } LoggingPrivateData.java:18: ERROR: QUANDARY_TAINT_ERROR Error: SharedPreferences(String SharedPreferences.getString(String,String) at [line 18]) -> Logging(int Log.d(String,String) at [line 18]) via { } LoggingPrivateData.java:22: ERROR: QUANDARY_TAINT_ERROR Error: SharedPreferences(String SharedPreferences.getString(String,String) at [line 22]) -> Logging(int Log.d(String,String) at [line 22]) via { } +LoggingPrivateData.java:37: ERROR: QUANDARY_TAINT_ERROR Error: SharedPreferences(String SharedPreferences.getString(String,String) at [line 36]) -> Logging(int Log.w(String,Throwable) at [line 37]) via { }