diff --git a/infer/src/quandary/ClangTrace.ml b/infer/src/quandary/ClangTrace.ml index 11a6a44eb..788b1918a 100644 --- a/infer/src/quandary/ClangTrace.ml +++ b/infer/src/quandary/ClangTrace.ml @@ -14,6 +14,7 @@ module L = Logging module SourceKind = struct type t = + | Endpoint (** source originating from an endpoint *) | EnvironmentVariable (** source that was read from an environment variable *) | File (** source that was read from a file *) | Other (** for testing or uncategorized sources *) @@ -23,6 +24,7 @@ module SourceKind = struct let unknown = Unknown let of_string = function + | "Endpoint" -> Endpoint | "EnvironmentVariable" -> EnvironmentVariable | "File" -> File | _ -> Other @@ -33,6 +35,8 @@ module SourceKind = struct QualifiedCppName.Match.of_fuzzy_qual_names [procedure], kind, index) (QuandaryConfig.Source.of_json Config.quandary_sources) + let endpoints = String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints) + (* return Some(source kind) if [procedure_name] is in the list of externally specified sources *) let get_external_source qualified_pname = let return = None in @@ -79,11 +83,22 @@ module SourceKind = struct failwithf "Non-C++ procname %a in C++ analysis@." Typ.Procname.pp pname let get_tainted_formals pdesc _ = - Source.all_formals_untainted pdesc + match Procdesc.get_proc_name pdesc with + | (Typ.Procname.ObjC_Cpp objc) as pname -> + let qualified_pname = + F.sprintf "%s::%s" + (Typ.Procname.objc_cpp_get_class_name objc) + (Typ.Procname.get_method pname) in + if String.Set.mem endpoints qualified_pname + then List.map ~f:(fun (name, typ) -> name, typ, Some Endpoint) (Procdesc.get_formals pdesc) + else Source.all_formals_untainted pdesc + | _ -> + Source.all_formals_untainted pdesc let pp fmt kind = F.fprintf fmt (match kind with + | Endpoint -> "Endpoint" | EnvironmentVariable -> "EnvironmentVariable" | File -> "File" | Other -> "Other" @@ -176,10 +191,10 @@ include let should_report source sink = match Source.kind source, Sink.kind sink with - | (EnvironmentVariable | File), ShellExec -> + | (Endpoint | EnvironmentVariable | File), ShellExec -> (* untrusted data flowing to exec *) true - | (EnvironmentVariable | File), Allocation -> + | (Endpoint | EnvironmentVariable | File), Allocation -> (* untrusted data flowing to memory allocation *) true | _, (Allocation | Other | ShellExec) when Source.is_footprint source -> diff --git a/infer/src/quandary/TaintAnalysis.ml b/infer/src/quandary/TaintAnalysis.ml index ab742e802..5e58f7768 100644 --- a/infer/src/quandary/TaintAnalysis.ml +++ b/infer/src/quandary/TaintAnalysis.ml @@ -112,12 +112,13 @@ module Make (TaintSpecification : TaintSpec.S) = struct | exception (Failure _) -> failwithf "Bad source specification: index %d out of bounds" index - let endpoints = String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints) + let endpoints = + lazy (String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints)) let is_endpoint source = match CallSite.pname (TraceDomain.Source.call_site source) with | Typ.Procname.Java java_pname -> - String.Set.mem endpoints (Typ.Procname.java_get_class_name java_pname) + String.Set.mem (Lazy.force endpoints) (Typ.Procname.java_get_class_name java_pname) | _ -> false diff --git a/infer/tests/codetoanalyze/cpp/quandary/.inferconfig b/infer/tests/codetoanalyze/cpp/quandary/.inferconfig index 8be6e13ae..378189339 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/.inferconfig +++ b/infer/tests/codetoanalyze/cpp/quandary/.inferconfig @@ -56,5 +56,8 @@ "kind": "Other", "index": "1" } + ], + "quandary-endpoints": [ + "basics::Obj::endpoint" ] } diff --git a/infer/tests/codetoanalyze/cpp/quandary/basics.cpp b/infer/tests/codetoanalyze/cpp/quandary/basics.cpp index cb73904e0..a2eb779c3 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/basics.cpp +++ b/infer/tests/codetoanalyze/cpp/quandary/basics.cpp @@ -25,6 +25,11 @@ class Obj { void string_sink(std::string) {} std::string field1; std::string field2; + + void endpoint(std::string source1, void* source2) { + this->string_sink(source1); + __infer_taint_sink(source2); + } }; void* returnSource() { return __infer_taint_source(); } diff --git a/infer/tests/codetoanalyze/cpp/quandary/issues.exp b/infer/tests/codetoanalyze/cpp/quandary/issues.exp index 18ba6fc2f..c041a38a8 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/issues.exp +++ b/infer/tests/codetoanalyze/cpp/quandary/issues.exp @@ -5,6 +5,8 @@ codetoanalyze/cpp/quandary/allocs.cpp, allocs::untrusted_malloc_bad, 0, QUANDARY codetoanalyze/cpp/quandary/allocs.cpp, allocs::untrusted_reaalloc_bad1, 0, QUANDARY_TAINT_ERROR, [return from allocs::allocation_source,call to realloc] codetoanalyze/cpp/quandary/allocs.cpp, allocs::untrusted_reaalloc_bad2, 0, QUANDARY_TAINT_ERROR, [return from allocs::allocation_source,call to realloc] codetoanalyze/cpp/quandary/allocs.cpp, allocs::untrusted_sbrk_bad, 0, QUANDARY_TAINT_ERROR, [return from allocs::allocation_source,call to sbrk] +codetoanalyze/cpp/quandary/basics.cpp, basics::Obj_endpoint, 1, QUANDARY_TAINT_ERROR, [return from basics::Obj_endpoint,call to basics::Obj_string_sink] +codetoanalyze/cpp/quandary/basics.cpp, basics::Obj_endpoint, 2, QUANDARY_TAINT_ERROR, [return from basics::Obj_endpoint,call to __infer_taint_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::object_source_sink_bad, 2, QUANDARY_TAINT_ERROR, [return from basics::Obj_method_source,call to basics::Obj_method_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::propagateBad, 3, QUANDARY_TAINT_ERROR, [return from __infer_taint_source,flow through basics::id,call to basics::callSink,call to __infer_taint_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::returnSourceToSinkBad, 2, QUANDARY_TAINT_ERROR, [return from __infer_taint_source,return from basics::returnSource,call to __infer_taint_sink]