diff --git a/infer/src/quandary/ClangTrace.ml b/infer/src/quandary/ClangTrace.ml index 1cb9854fd..8444a83f6 100644 --- a/infer/src/quandary/ClangTrace.ml +++ b/infer/src/quandary/ClangTrace.ml @@ -14,7 +14,7 @@ module L = Logging module SourceKind = struct type t = - | Endpoint of Mangled.t (** source originating from formal of an endpoint *) + | Endpoint of (Mangled.t * Typ.desc) (** source originating from formal of 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 *) @@ -24,7 +24,7 @@ module SourceKind = struct let unknown = Unknown let of_string = function - | "Endpoint" -> Endpoint (Mangled.from_string "NONE") + | "Endpoint" -> Endpoint (Mangled.from_string "NONE", Typ.Tvoid) | "EnvironmentVariable" -> EnvironmentVariable | "File" -> File | _ -> Other @@ -92,7 +92,7 @@ module SourceKind = struct if String.Set.mem endpoints qualified_pname then List.map - ~f:(fun (name, typ) -> name, typ, Some (Endpoint name)) + ~f:(fun (name, typ) -> name, typ, Some (Endpoint (name, typ.Typ.desc))) (Procdesc.get_formals pdesc) else Source.all_formals_untainted pdesc @@ -102,7 +102,7 @@ module SourceKind = struct let pp fmt kind = F.fprintf fmt "%s" (match kind with - | Endpoint formal_name -> F.sprintf "Endpoint[%s]" (Mangled.to_string formal_name) + | Endpoint (formal_name, _) -> F.sprintf "Endpoint[%s]" (Mangled.to_string formal_name) | EnvironmentVariable -> "EnvironmentVariable" | File -> "File" | Other -> "Other" @@ -195,9 +195,17 @@ include module Sink = CppSink let should_report source sink = + (* using this to match custom string wrappers such as folly::StringPiece *) + let is_stringy typ = + let lowercase_typ = String.lowercase (Typ.to_string (Typ.mk typ)) in + String.is_substring ~substring:"string" lowercase_typ || + String.is_substring ~substring:"char*" lowercase_typ in match Source.kind source, Sink.kind sink with - | (Endpoint _ | EnvironmentVariable | File), (ShellExec | SQL) -> - (* untrusted data flowing to exec/sql *) + | Endpoint (_, typ), (ShellExec | SQL) -> + (* untrusted string data flowing to shell exec/SQL *) + is_stringy typ + | (EnvironmentVariable | File), (ShellExec | SQL) -> + (* untrusted environment var or file data flowing to shell exec *) true | (Endpoint _ | EnvironmentVariable | File), Allocation -> (* untrusted data flowing to memory allocation *) diff --git a/infer/tests/codetoanalyze/cpp/quandary/.inferconfig b/infer/tests/codetoanalyze/cpp/quandary/.inferconfig index 2f1afbb05..2fdde237a 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/.inferconfig +++ b/infer/tests/codetoanalyze/cpp/quandary/.inferconfig @@ -71,6 +71,7 @@ } ], "quandary-endpoints": [ - "basics::Obj::endpoint" + "basics::Obj::endpoint", + "execs::Obj::endpoint" ] } diff --git a/infer/tests/codetoanalyze/cpp/quandary/execs.cpp b/infer/tests/codetoanalyze/cpp/quandary/execs.cpp index 4f5cef729..fdc7cf174 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/execs.cpp +++ b/infer/tests/codetoanalyze/cpp/quandary/execs.cpp @@ -13,7 +13,7 @@ extern int rand(); -extern void __infer_sql_sink(std::string query); +extern void __infer_sql_sink(std::string query, int i); namespace execs { @@ -99,6 +99,23 @@ void exec_flag_bad() { execl(FLAGS_cli_string, NULL); } void sql_on_env_var_bad() { std::string source = (std::string)std::getenv("ENV_VAR"); - __infer_sql_sink(source); + __infer_sql_sink(source, 0); } + +class Obj { + void endpoint(int i, + char c, + std::string s, + char* c_ptr, + char c_arr[], + std::string* s_ptr) { + __infer_sql_sink(nullptr, i); // don't report + __infer_sql_sink(nullptr, c); // don't report + + __infer_sql_sink(s, 0); // report + __infer_sql_sink(*s_ptr, 0); // report + __infer_sql_sink(c_ptr, 0); // report + __infer_sql_sink(c_arr, 0); // report + } +}; } diff --git a/infer/tests/codetoanalyze/cpp/quandary/issues.exp b/infer/tests/codetoanalyze/cpp/quandary/issues.exp index a1b715bfa..a9c8d1eb5 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/issues.exp +++ b/infer/tests/codetoanalyze/cpp/quandary/issues.exp @@ -21,6 +21,10 @@ codetoanalyze/cpp/quandary/basics.cpp, basics::via_field_bad1, 3, QUANDARY_TAINT codetoanalyze/cpp/quandary/basics.cpp, basics::via_field_bad2, 2, QUANDARY_TAINT_ERROR, [Return from basics::template_source_>,Call to basics::template_sink_>] codetoanalyze/cpp/quandary/basics.cpp, basics::via_passthrough_bad1, 4, QUANDARY_TAINT_ERROR, [Return from basics::Obj_string_source,Call to basics::Obj_string_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::via_passthrough_bad2, 3, QUANDARY_TAINT_ERROR, [Return from basics::Obj_string_source,Call to basics::Obj_string_sink] +codetoanalyze/cpp/quandary/execs.cpp, execs::Obj_endpoint, 9, QUANDARY_TAINT_ERROR, [Return from execs::Obj_endpoint,Call to __infer_sql_sink] +codetoanalyze/cpp/quandary/execs.cpp, execs::Obj_endpoint, 10, QUANDARY_TAINT_ERROR, [Return from execs::Obj_endpoint,Call to __infer_sql_sink] +codetoanalyze/cpp/quandary/execs.cpp, execs::Obj_endpoint, 11, QUANDARY_TAINT_ERROR, [Return from execs::Obj_endpoint,Call to __infer_sql_sink] +codetoanalyze/cpp/quandary/execs.cpp, execs::Obj_endpoint, 12, QUANDARY_TAINT_ERROR, [Return from execs::Obj_endpoint,Call to __infer_sql_sink] codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 6, QUANDARY_TAINT_ERROR, [Return from getenv,Call to execl] codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 8, QUANDARY_TAINT_ERROR, [Return from getenv,Call to execl] codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 11, QUANDARY_TAINT_ERROR, [Return from getenv,Call to execl]