From 5bddb1e5481496a49a8ced22c4e0bb1fda796f47 Mon Sep 17 00:00:00 2001 From: Sam Blackshear Date: Thu, 26 Jan 2017 08:33:05 -0800 Subject: [PATCH] [quandary] allow sources to be specified in inferconfig Reviewed By: jberdine Differential Revision: D4448458 fbshipit-source-id: 5aa30c5 --- infer/src/base/Config.ml | 6 ++- infer/src/base/Config.mli | 1 + infer/src/checkers/Source.ml | 2 +- infer/src/quandary/JavaTrace.ml | 29 +++++++++++++-- infer/src/quandary/QuandaryConfig.ml | 32 ++++++++++++++++ infer/src/quandary/QuandaryConfig.mli | 20 ++++++++++ .../codetoanalyze/java/quandary/.inferconfig | 8 ++++ .../java/quandary/ExternalSpecs.java | 37 +++++++++++++++++++ .../codetoanalyze/java/quandary/issues.exp | 1 + 9 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 infer/src/quandary/QuandaryConfig.ml create mode 100644 infer/src/quandary/QuandaryConfig.mli create mode 100644 infer/tests/codetoanalyze/java/quandary/.inferconfig create mode 100644 infer/tests/codetoanalyze/java/quandary/ExternalSpecs.java diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 39fe3bc0d..995cd1d24 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -889,7 +889,7 @@ and load_average = and load_results = CLOpt.mk_path_opt ~deprecated:["load_results"] ~long:"load-results" - ~exes:CLOpt.[Print] + ~exes:CLOpt.[Analyze] ~meta:"file.iar" "Load analysis results from Infer Analysis Results file file.iar" (** name of the makefile to create with clusters and dependencies *) @@ -1006,6 +1006,9 @@ and progress_bar = ~exes:CLOpt.[Driver] "Show a progress bar" +and quandary_sources = + CLOpt.mk_json ~long:"quandary-sources" "Specify custom sources for Quandary" + and quiet = CLOpt.mk_bool ~long:"quiet" ~short:"q" ~default:(current_exe <> CLOpt.Print) ~exes:CLOpt.[Print] @@ -1475,6 +1478,7 @@ and print_using_diff = !print_using_diff and procs_csv = !procs_csv and procs_xml = !procs_xml and quandary = !quandary +and quandary_sources = !quandary_sources and quiet = !quiet and reactive_mode = !reactive and reactive_capture = !reactive_capture diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index e1257bbd2..2c89b2583 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -242,6 +242,7 @@ val procs_csv : string option val procs_xml : string option val project_root : string val quandary : bool +val quandary_sources : Yojson.Basic.json val quiet : bool val reactive_mode : bool val reactive_capture : bool diff --git a/infer/src/checkers/Source.ml b/infer/src/checkers/Source.ml index 6dd483968..7652a5240 100644 --- a/infer/src/checkers/Source.ml +++ b/infer/src/checkers/Source.ml @@ -46,7 +46,7 @@ module Make (Kind : Kind) = struct type kind = | Normal of Kind.t (** known source returned directly or transitively from a callee *) | Footprint of AccessPath.t (** unknown source read from the environment *) - [@@ deriving compare] + [@@deriving compare] let pp_kind fmt = function | Normal kind -> Kind.pp fmt kind diff --git a/infer/src/quandary/JavaTrace.ml b/infer/src/quandary/JavaTrace.ml index da052830a..40feddcd4 100644 --- a/infer/src/quandary/JavaTrace.ml +++ b/infer/src/quandary/JavaTrace.ml @@ -22,6 +22,13 @@ module SourceKind = struct let unknown = Unknown + let of_string = function + | "PrivateData" -> PrivateData + | "Intent" -> Intent + | _ -> Other + + let external_sources = QuandaryConfig.Source.of_json Config.quandary_sources + let get pname tenv = match pname with | Procname.Java pname -> begin @@ -49,10 +56,24 @@ module SourceKind = struct Some PrivateData | _ -> None in - PatternMatch.supertype_find_map_opt - tenv - taint_matching_supertype - (Typename.Java.from_string class_name) + let kind_opt = + PatternMatch.supertype_find_map_opt + tenv + taint_matching_supertype + (Typename.Java.from_string class_name) in + begin + match kind_opt with + | Some _ -> kind_opt + | None -> + (* check the list of externally specified sources *) + let procedure = class_name ^ "." ^ method_name in + IList.find_map_opt + (fun (source_spec : QuandaryConfig.Source.t) -> + if String.equal source_spec.procedure procedure + then Some (of_string source_spec.kind) + else None) + external_sources + end end | pname when BuiltinDecl.is_declared pname -> None | pname -> failwithf "Non-Java procname %a in Java analysis@." Procname.pp pname diff --git a/infer/src/quandary/QuandaryConfig.ml b/infer/src/quandary/QuandaryConfig.ml new file mode 100644 index 000000000..d7952f568 --- /dev/null +++ b/infer/src/quandary/QuandaryConfig.ml @@ -0,0 +1,32 @@ +(* + * Copyright (c) 2017 - 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. + *) + +open! IStd + +module F = Format + +(** utilities for importing JSON specifications of sources/sinks into Quandary*) + +module Source = struct + type t = { procedure : string; kind : string; } + + let of_json = function + | `List sources -> + let parse_source json = + let open Yojson.Basic.Util in + let procedure = json |> member "procedure" |> to_string in + let kind = json |> member "kind" |> to_string in + { procedure; kind; } in + IList.map parse_source sources + | _ -> + [] + + let pp fmt { procedure; kind; } = + F.fprintf fmt "Procedure: %s Kind: %s" procedure kind +end diff --git a/infer/src/quandary/QuandaryConfig.mli b/infer/src/quandary/QuandaryConfig.mli new file mode 100644 index 000000000..a0395d9bf --- /dev/null +++ b/infer/src/quandary/QuandaryConfig.mli @@ -0,0 +1,20 @@ +(* + * Copyright (c) 2016 - 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. + *) + +open! IStd + +(** utilities for importing JSON specifications of sources/sinks into Quandary*) + +module Source : sig + type t = { procedure : string; kind : string; } + + val of_json : [> `List of Yojson.Basic.json list ] -> t list + + val pp : Format.formatter -> t -> unit +end diff --git a/infer/tests/codetoanalyze/java/quandary/.inferconfig b/infer/tests/codetoanalyze/java/quandary/.inferconfig new file mode 100644 index 000000000..0822c7ec7 --- /dev/null +++ b/infer/tests/codetoanalyze/java/quandary/.inferconfig @@ -0,0 +1,8 @@ +{ + "quandary-sources": [ + { + "procedure": "codetoanalyze.java.quandary.ExternalSpecs.privateDataSource", + "kind": "PrivateData" + } + ] +} diff --git a/infer/tests/codetoanalyze/java/quandary/ExternalSpecs.java b/infer/tests/codetoanalyze/java/quandary/ExternalSpecs.java new file mode 100644 index 000000000..17bbc62ba --- /dev/null +++ b/infer/tests/codetoanalyze/java/quandary/ExternalSpecs.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 - 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 android.app.Activity; +import android.content.Intent; +import android.util.Log; + +import com.facebook.infer.builtins.InferTaint; + +/** Testing that sources and sinks specified in external JSON work correctly */ + +public class ExternalSpecs { + + // we specify this as a source with kind PrivateData in .inferconfig + private static Object privateDataSource() { + return new Object(); + } + + public static void logExternalSourceBad() { + Log.e("", (String) privateDataSource()); + } + + // we specified that this is a private data source, so passing it an intent sink like + // startActivity() is fine + public static void externalSourceAsIntentOk(Activity activity) { + activity.startActivity((Intent) privateDataSource()); + } + +} diff --git a/infer/tests/codetoanalyze/java/quandary/issues.exp b/infer/tests/codetoanalyze/java/quandary/issues.exp index f6138a0c1..47ca45bfc 100644 --- a/infer/tests/codetoanalyze/java/quandary/issues.exp +++ b/infer/tests/codetoanalyze/java/quandary/issues.exp @@ -43,6 +43,7 @@ codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInCatchBad2(), codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInFinallyBad1(), 5, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInFinallyBad2(), 6, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInFinallyBad3(), 7, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] +codetoanalyze/java/quandary/ExternalSpecs.java, void ExternalSpecs.logExternalSourceBad(), 1, QUANDARY_TAINT_ERROR, [return from Object ExternalSpecs.privateDataSource(),call to int Log.e(String,String)] codetoanalyze/java/quandary/Fields.java, void Fields.instanceFieldBad(), 2, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Fields.java, void Fields.staticFieldBad(), 2, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Fields.java, void Fields.viaFieldBad1(Fields$Obj), 2, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)]