[quandary] make it possible to report taint errors on footprint sources again

Reviewed By: jeremydubreil

Differential Revision: D5674384

fbshipit-source-id: b4778cb
master
Sam Blackshear 8 years ago committed by Facebook Github Bot
parent b1b7cc0b9d
commit 5d578cf196

@ -43,6 +43,8 @@ module Make (TraceElem : TraceElem.S) = struct
module Sink = MakeSink (TraceElem)
let should_report _ _ = true
let should_report_footprint _ _ = false
end)
type sink_path = Passthroughs.t * (Sink.t * Passthroughs.t) list

@ -17,8 +17,6 @@ let all_formals_untainted pdesc =
module type Kind = sig
include TraceElem.Kind
val unknown : t
val get : Typ.Procname.t -> HilExp.t list -> Tenv.t -> (t * int option) option
val get_tainted_formals : Procdesc.t -> Tenv.t -> (Mangled.t * Typ.t * t option) list

@ -15,9 +15,6 @@ val all_formals_untainted : Procdesc.t -> (Mangled.t * Typ.t * 'a option) list
module type Kind = sig
include TraceElem.Kind
val unknown : t
(** kind of an unknown source *)
val get : Typ.Procname.t -> HilExp.t list -> Tenv.t -> (t * int option) option
(** return Some (kind) if the procedure with the given actuals is a taint source, None otherwise *)

@ -18,6 +18,8 @@ module type Spec = sig
val should_report : Source.t -> Sink.t -> bool
(** should a flow originating at source and entering sink be reported? *)
val should_report_footprint : AccessPath.Abs.t -> Sink.t -> bool
end
module type S = sig
@ -54,10 +56,12 @@ module type S = sig
module Sinks = Sink.Set
module Passthroughs = Passthrough.Set
(** path from a source to a sink with passthroughs at each step in the call stack. the first set
of passthroughs are the ones in the "reporting" procedure that calls the first function in
both the source and sink stack *)
type path = Passthroughs.t * (Source.t * Passthroughs.t) list * (Sink.t * Passthroughs.t) list
type path_source = Known of Source.t | Footprint of AccessPath.Abs.t
type path_sink = Sink.t
type path =
Passthroughs.t * (path_source * Passthroughs.t) list * (path_sink * Passthroughs.t) list
val empty : t
@ -70,7 +74,7 @@ module type S = sig
val passthroughs : t -> Passthroughs.t
(** get the passthroughs of the trace *)
val get_reports : ?cur_site:CallSite.t -> t -> (Source.t * Sink.t * Passthroughs.t) list
val get_reports : ?cur_site:CallSite.t -> t -> (path_source * path_sink * Passthroughs.t) list
(** get the reportable source-sink flows in this trace. specifying [cur_site] restricts the
reported paths to ones introduced by the call at [cur_site] *)
@ -80,8 +84,8 @@ module type S = sig
[cur_site] restricts the reported paths to ones introduced by the call at [cur_site] *)
val to_loc_trace :
?desc_of_source:(Source.t -> string) -> ?source_should_nest:(Source.t -> bool)
-> ?desc_of_sink:(Sink.t -> string) -> ?sink_should_nest:(Sink.t -> bool) -> path
?desc_of_source:(path_source -> string) -> ?source_should_nest:(path_source -> bool)
-> ?desc_of_sink:(path_sink -> string) -> ?sink_should_nest:(path_sink -> bool) -> path
-> Errlog.loc_trace
(** create a loc_trace from a path; [source_should_nest s] should be true when we are going one
deeper into a call-chain, ie when lt_level should be bumper in the next loc_trace_elem, and
@ -115,6 +119,8 @@ module type S = sig
val pp_path : Typ.Procname.t -> F.formatter -> path -> unit
(** pretty-print a path in the context of the given procname *)
val pp_path_source : F.formatter -> path_source -> unit
end
(** Expand a trace element (i.e., a source or sink) into a list of trace elements bottoming out in
@ -224,12 +230,23 @@ module Make (Spec : Spec) = struct
type astate = t
type path = Passthroughs.t * (Source.t * Passthroughs.t) list * (Sink.t * Passthroughs.t) list
type path_source = Known of Source.t | Footprint of AccessPath.Abs.t
type path_sink = Sink.t
type path =
Passthroughs.t * (path_source * Passthroughs.t) list * (path_sink * Passthroughs.t) list
let pp fmt t =
F.fprintf fmt "%a -> %a via %a" Sources.pp t.sources Sinks.pp t.sinks Passthroughs.pp
t.passthroughs
let get_path_source_call_site = function
| Known source
-> Source.call_site source
| Footprint _
-> CallSite.dummy
let sources t = t.sources
let sinks t = t.sinks
@ -258,13 +275,28 @@ module Make (Spec : Spec) = struct
let report_source source sinks acc0 =
let report_one sink acc =
if Spec.should_report source sink && should_report_at_site source sink then
(source, sink, t.passthroughs) :: acc
(Known source, sink, t.passthroughs) :: acc
else acc
in
Sinks.fold report_one sinks acc0
in
let report_footprint acc0 footprint_access_path (is_mem, _) =
let report_one sink acc =
if is_mem && Spec.should_report_footprint footprint_access_path sink then
(Footprint footprint_access_path, sink, t.passthroughs) :: acc
else acc
in
Sinks.fold report_one t.sinks acc0
in
let report_sources source acc = report_source source t.sinks acc in
Sources.Known.fold report_sources t.sources.known []
|> Sources.Footprint.fold report_footprint t.sources.footprint
let pp_path_source fmt = function
| Known source
-> Source.pp fmt source
| Footprint access_path
-> AccessPath.Abs.pp fmt access_path
let pp_path cur_pname fmt (cur_passthroughs, sources_passthroughs, sinks_passthroughs) =
let pp_passthroughs fmt passthroughs =
@ -278,11 +310,11 @@ module Make (Spec : Spec) = struct
in
F.pp_print_list ~pp_sep pp_elem fmt elems_passthroughs
in
let pp_sources = pp_elems Source.call_site in
let pp_sources = pp_elems get_path_source_call_site in
let pp_sinks = pp_elems Sink.call_site in
let original_source = fst (List.hd_exn sources_passthroughs) in
let final_sink = fst (List.hd_exn sinks_passthroughs) in
F.fprintf fmt "Error: %a -> %a. Full trace:@.%a@.Current procedure %a %a@.%a" Source.pp
F.fprintf fmt "Error: %a -> %a. Full trace:@.%a@.Current procedure %a %a@.%a" pp_path_source
original_source Sink.pp final_sink pp_sources sources_passthroughs Typ.Procname.pp cur_pname
pp_passthroughs cur_passthroughs pp_sinks (List.rev sinks_passthroughs)
@ -312,41 +344,57 @@ module Make (Spec : Spec) = struct
in
Passthrough.Set.filter between_start_and_end passthroughs
in
let expand_path source sink =
let sources_of_pname pname =
let trace = trace_of_pname pname in
(Sources.Known.elements (sources trace).known, passthroughs trace)
in
let sinks_of_pname pname =
let trace = trace_of_pname pname in
(Sinks.elements (sinks trace), passthroughs trace)
in
let sources_passthroughs =
let filter_passthroughs = filter_passthroughs_ Source in
SourceExpander.expand source ~elems_passthroughs_of_pname:sources_of_pname
~filter_passthroughs
in
let sinks_passthroughs =
let filter_passthroughs = filter_passthroughs_ Sink in
SinkExpander.expand sink ~elems_passthroughs_of_pname:sinks_of_pname ~filter_passthroughs
in
(sources_passthroughs, sinks_passthroughs)
let expand_path path_source sink =
match path_source with
| Known source
-> let sources_of_pname pname =
let trace = trace_of_pname pname in
(Sources.Known.elements (sources trace).known, passthroughs trace)
in
let sinks_of_pname pname =
let trace = trace_of_pname pname in
(Sinks.elements (sinks trace), passthroughs trace)
in
let sources_passthroughs =
let filter_passthroughs = filter_passthroughs_ Source in
SourceExpander.expand source ~elems_passthroughs_of_pname:sources_of_pname
~filter_passthroughs
|> List.map ~f:(fun (source, passthrough) -> (Known source, passthrough))
in
let sinks_passthroughs =
let filter_passthroughs = filter_passthroughs_ Sink in
SinkExpander.expand sink ~elems_passthroughs_of_pname:sinks_of_pname
~filter_passthroughs
in
(sources_passthroughs, sinks_passthroughs)
| Footprint _
-> ([], [])
in
List.map
~f:(fun (source, sink, passthroughs) ->
let sources_passthroughs, sinks_passthroughs = expand_path source sink in
~f:(fun (path_source, sink, passthroughs) ->
let sources_passthroughs, sinks_passthroughs = expand_path path_source sink in
let filtered_passthroughs =
filter_passthroughs_ Top_level (Source.call_site source) (Sink.call_site sink)
passthroughs
let source_site =
match path_source with
| Known source
-> Source.call_site source
| Footprint _
-> Option.value ~default:CallSite.dummy cur_site
in
filter_passthroughs_ Top_level source_site (Sink.call_site sink) passthroughs
in
(filtered_passthroughs, sources_passthroughs, sinks_passthroughs))
(get_reports ?cur_site t)
let to_loc_trace
?(desc_of_source= fun source ->
let callsite = Source.call_site source in
Format.asprintf "return from %a" Typ.Procname.pp
(CallSite.pname callsite)) ?(source_should_nest= fun _ -> true)
?(desc_of_source= function
| Known source
-> let callsite = Source.call_site source in
Format.asprintf "return from %a" Typ.Procname.pp
(CallSite.pname callsite)
| Footprint access_path
-> Format.asprintf "read from %a" AccessPath.Abs.pp access_path)
?(source_should_nest= fun _ -> true)
?(desc_of_sink= fun sink ->
let callsite = Sink.call_site sink in
Format.asprintf "call to %a" Typ.Procname.pp (CallSite.pname callsite))
@ -389,7 +437,7 @@ module Make (Spec : Spec) = struct
trace_elem :: trace_elems_of_passthroughs lt_level passthroughs acc
in
let trace_elems_of_source =
trace_elems_of_path_elem Source.call_site desc_of_source ~is_source:true
trace_elems_of_path_elem get_path_source_call_site desc_of_source ~is_source:true
in
let trace_elems_of_sink =
trace_elems_of_path_elem Sink.call_site desc_of_sink ~is_source:false

@ -18,6 +18,10 @@ module type Spec = sig
val should_report : Source.t -> Sink.t -> bool
(** should a flow originating at source and entering sink be reported? *)
val should_report_footprint : AccessPath.Abs.t -> Sink.t -> bool
(** should a flow read from the environment via the given access path and entering sink be
reported? *)
end
module type S = sig
@ -56,10 +60,18 @@ module type S = sig
module Sinks = Sink.Set
module Passthroughs = Passthrough.Set
type path_source =
| Known of Source.t (** source originating from a called procedure *)
| Footprint of AccessPath.Abs.t
(** source read from an access path rooted in a parameter or global *)
type path_sink = Sink.t
(** path from a source to a sink with passthroughs at each step in the call stack. the first set
of passthroughs are the ones in the "reporting" procedure that calls the first function in
both the source and sink stack *)
type path = Passthroughs.t * (Source.t * Passthroughs.t) list * (Sink.t * Passthroughs.t) list
type path =
Passthroughs.t * (path_source * Passthroughs.t) list * (path_sink * Passthroughs.t) list
val empty : t
(** the empty trace *)
@ -73,7 +85,7 @@ module type S = sig
val passthroughs : t -> Passthroughs.t
(** get the passthroughs of the trace *)
val get_reports : ?cur_site:CallSite.t -> t -> (Source.t * Sink.t * Passthroughs.t) list
val get_reports : ?cur_site:CallSite.t -> t -> (path_source * path_sink * Passthroughs.t) list
(** get the reportable source-sink flows in this trace. specifying [cur_site] restricts the
reported paths to ones introduced by the call at [cur_site] *)
@ -83,8 +95,8 @@ module type S = sig
[cur_site] restricts the reported paths to ones introduced by the call at [cur_site] *)
val to_loc_trace :
?desc_of_source:(Source.t -> string) -> ?source_should_nest:(Source.t -> bool)
-> ?desc_of_sink:(Sink.t -> string) -> ?sink_should_nest:(Sink.t -> bool) -> path
?desc_of_source:(path_source -> string) -> ?source_should_nest:(path_source -> bool)
-> ?desc_of_sink:(path_sink -> string) -> ?sink_should_nest:(path_sink -> bool) -> path
-> Errlog.loc_trace
(** create a loc_trace from a path; [source_should_nest s] should be true when we are going one
deeper into a call-chain, ie when lt_level should be bumper in the next loc_trace_elem, and
@ -120,6 +132,8 @@ module type S = sig
val pp_path : Typ.Procname.t -> F.formatter -> path -> unit
(** pretty-print a path in the context of the given procname *)
val pp_path_source : F.formatter -> path_source -> unit
end
module Make (Spec : Spec) : S with module Source = Spec.Source and module Sink = Spec.Sink

@ -17,11 +17,8 @@ module SourceKind = struct
| EnvironmentVariable (** source that was read from an environment variable *)
| File (** source that was read from a file *)
| Other (** for testing or uncategorized sources *)
| Unknown
[@@deriving compare]
let unknown = Unknown
let of_string = function
| "Endpoint"
-> Endpoint (Mangled.from_string "NONE", Typ.Tvoid)
@ -111,9 +108,7 @@ module SourceKind = struct
| File
-> "File"
| Other
-> "Other"
| Unknown
-> "Unknown" )
-> "Other" )
end
module CppSource = Source.Make (SourceKind)
@ -257,6 +252,22 @@ include Trace.Make (struct
true
| _, Other
-> true
| Unknown, (Allocation | BufferAccess | ShellExec | SQL)
-> false
let should_report_footprint footprint_access_path sink =
(* is this var a command line flag created by the popular C++ gflags library for creating
command-line flags (https://github.com/gflags/gflags)? *)
let is_gflag access_path =
let pvar_is_gflag pvar =
String.is_substring ~substring:"FLAGS_" (Pvar.get_simplified_name pvar)
in
match AccessPath.Abs.extract access_path with
| (Var.ProgramVar pvar, _), _
-> Pvar.is_global pvar && pvar_is_gflag pvar
| _
-> false
in
match Sink.kind sink
with Allocation | BufferAccess | Other | ShellExec | SQL ->
(* gflags globals come from the environment; treat them as sources for everything *)
is_gflag footprint_access_path
end)

@ -18,11 +18,8 @@ module SourceKind = struct
| Other (** for testing or uncategorized sources *)
| PrivateData (** private user or device-specific data *)
| UserControlledURI (** resource locator controller by user *)
| Unknown
[@@deriving compare]
let unknown = Unknown
let of_string = function
| "Clipboard"
-> Clipboard
@ -166,9 +163,7 @@ module SourceKind = struct
| PrivateData
-> "PrivateData"
| Other
-> "Other"
| Unknown
-> "Unknown" )
-> "Other" )
end
module JavaSource = Source.Make (SourceKind)
@ -318,26 +313,28 @@ include Trace.Make (struct
let should_report source sink =
match (Source.kind source, Sink.kind sink) with
| PrivateData, Logging
(* logging private data issue *)
| Intent, StartComponent
(* intent reuse issue *)
| Intent, CreateIntent
(* intent configured with external values issue *)
| Intent, JavaScript
(* external data flows into JS: remote code execution risk *)
| PrivateData, JavaScript
(* leaking private data into JS *)
| UserControlledURI, (CreateIntent | StartComponent)
(* create intent/launch component from user-controlled URI *)
| UserControlledURI, CreateFile
(* create file from user-controller URI; potential path-traversal vulnerability *)
| Clipboard, (StartComponent | CreateIntent | JavaScript | CreateFile | HTML)
-> (* do something sensitive with user-controlled data from the clipboard *)
true
| Other, _ | _, Other
-> (* for testing purposes, Other matches everything *)
true
| _
-> false
| PrivateData, Logging
(* logging private data issue *)
| Intent, StartComponent
(* intent reuse issue *)
| Intent, CreateIntent
(* intent configured with external values issue *)
| Intent, JavaScript
(* external data flows into JS: remote code execution risk *)
| PrivateData, JavaScript
(* leaking private data into JS *)
| UserControlledURI, (CreateIntent | StartComponent)
(* create intent/launch component from user-controlled URI *)
| UserControlledURI, CreateFile
(* create file from user-controller URI; potential path-traversal vulnerability *)
| Clipboard, (StartComponent | CreateIntent | JavaScript | CreateFile | HTML)
-> (* do something sensitive with user-controlled data from the clipboard *)
true
| Other, _ | _, Other
-> (* for testing purposes, Other matches everything *)
true
| _
-> false
let should_report_footprint _ _ = false
end)

@ -94,11 +94,14 @@ module Make (TaintSpecification : TaintSpec.S) = struct
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 (Lazy.force endpoints) (Typ.Procname.java_get_class_name java_pname)
| _
let is_endpoint = function
| TraceDomain.Known source -> (
match CallSite.pname (TraceDomain.Source.call_site source) with
| Typ.Procname.Java java_pname
-> String.Set.mem (Lazy.force endpoints) (Typ.Procname.java_get_class_name java_pname)
| _
-> false )
| TraceDomain.Footprint _
-> false
(** log any new reportable source-sink flows in [trace] *)
@ -114,12 +117,12 @@ module Make (TaintSpecification : TaintSpec.S) = struct
| None
-> TaintDomain.empty
in
let get_short_trace_string original_source final_sink =
F.asprintf "%a -> %a%s" TraceDomain.Source.pp original_source TraceDomain.Sink.pp
let get_short_trace_string original_path_source final_sink =
F.asprintf "%a -> %a%s" TraceDomain.pp_path_source original_path_source TraceDomain.Sink.pp
final_sink
(if is_endpoint original_source then ". Note: source is an endpoint." else "")
(if is_endpoint original_path_source then ". Note: source is an endpoint." else "")
in
let report_one (source, sink, _) =
let report_one (path_source, sink, _) =
let open TraceDomain in
let rec expand_source source0 (report_acc, seen_acc as acc) =
let kind = Source.kind source0 in
@ -190,7 +193,14 @@ module Make (TaintSpecification : TaintSpec.S) = struct
| []
-> acc
in
let expanded_sources, _ = expand_source source ([(None, source)], CallSite.Set.empty) in
let expanded_sources, _ =
match path_source with
| Known source
-> let sources, calls = expand_source source ([(None, source)], CallSite.Set.empty) in
(List.map ~f:(fun (ap_opt, source) -> (ap_opt, Known source)) sources, calls)
| Footprint _
-> ([(None, path_source)], CallSite.Set.empty)
in
let expanded_sinks, _ = expand_sink sink sink_indexes ([sink], CallSite.Set.empty) in
let source_trace =
let pp_access_path_opt fmt = function
@ -205,13 +215,18 @@ module Make (TaintSpecification : TaintSpec.S) = struct
else access_path )
in
List.map
~f:(fun (access_path_opt, source) ->
let call_site = Source.call_site source in
let desc =
Format.asprintf "Return from %a%a" Typ.Procname.pp (CallSite.pname call_site)
pp_access_path_opt access_path_opt
~f:(fun (access_path_opt, path_source) ->
let desc, loc =
match path_source with
| Known source
-> let call_site = Source.call_site source in
( Format.asprintf "Return from %a%a" Typ.Procname.pp (CallSite.pname call_site)
pp_access_path_opt access_path_opt
, CallSite.loc call_site )
| Footprint access_path
-> (Format.asprintf "Read from %a" AccessPath.Abs.pp access_path, Location.dummy)
in
Errlog.make_trace_element 0 (CallSite.loc call_site) desc [])
Errlog.make_trace_element 0 loc desc [])
expanded_sources
in
let sink_trace =
@ -223,9 +238,9 @@ module Make (TaintSpecification : TaintSpec.S) = struct
expanded_sinks
in
let msg = IssueType.quandary_taint_error.unique_id in
let _, original_source = List.hd_exn expanded_sources in
let _, original_path_source = List.hd_exn expanded_sources in
let final_sink = List.hd_exn expanded_sinks in
let trace_str = get_short_trace_string original_source final_sink in
let trace_str = get_short_trace_string original_path_source final_sink in
let ltr = source_trace @ List.rev sink_trace in
let exn = Exceptions.Checkers (msg, Localise.verbatim_desc trace_str) in
Reporting.log_error proc_data.extras.summary ~loc:(CallSite.loc cur_site) ~ltr exn

@ -16,8 +16,6 @@ module MockTrace = Trace.Make (struct
module Source = Source.Make (struct
include MockTraceElem
let unknown = CallSite.dummy
let get pname _ _ =
if String.is_prefix ~prefix:"SOURCE" (Typ.Procname.to_string pname) then
Some (CallSite.make pname Location.dummy, None)
@ -36,6 +34,8 @@ module MockTrace = Trace.Make (struct
end)
let should_report _ _ = false
let should_report_footprint _ _ = false
end)
module MockTaintAnalysis = TaintAnalysis.Make (struct

@ -12,9 +12,7 @@ module L = Logging
module F = Format
module MockTraceElem = struct
type t = Kind1 | Kind2 | Footprint | Unknown [@@deriving compare]
let unknown = Unknown
type t = Kind1 | Kind2 | Footprint [@@deriving compare]
let call_site _ = CallSite.dummy
@ -29,8 +27,6 @@ module MockTraceElem = struct
-> F.fprintf fmt "Kind2"
| Footprint
-> F.fprintf fmt "Footprint"
| Unknown
-> F.fprintf fmt "Unknown"
module Kind = struct
type nonrec t = t
@ -81,10 +77,19 @@ module MockTrace = Trace.Make (struct
let should_report source sink =
[%compare.equal : MockTraceElem.t] (Source.kind source) (Sink.kind sink)
let should_report_footprint _ _ = false
end)
let trace_equal t1 t2 = MockTrace.( <= ) ~lhs:t1 ~rhs:t2 && MockTrace.( <= ) ~lhs:t2 ~rhs:t1
let source_equal path_source source =
match path_source with
| MockTrace.Known s
-> MockSource.equal s source
| MockTrace.Footprint _
-> false
let tests =
let source1 = MockSource.make MockTraceElem.Kind1 CallSite.dummy in
let source2 = MockSource.make MockTraceElem.Kind2 CallSite.dummy in
@ -101,13 +106,11 @@ let tests =
assert_equal (List.length reports) 2 ;
assert_bool "Reports should contain source1 -> sink1"
(List.exists
~f:(fun (source, sink, _) ->
MockSource.equal source source1 && MockSink.equal sink sink1)
~f:(fun (source, sink, _) -> source_equal source source1 && MockSink.equal sink sink1)
reports) ;
assert_bool "Reports should contain source2 -> sink2"
(List.exists
~f:(fun (source, sink, _) ->
MockSource.equal source source2 && MockSink.equal sink sink2)
~f:(fun (source, sink, _) -> source_equal source source2 && MockSink.equal sink sink2)
reports)
in
"get_reports" >:: get_reports_

@ -99,7 +99,7 @@ void customGetEnvOk() {
return execl(NULL, source);
}
void FN_exec_flag_bad() { execl(FLAGS_cli_string, NULL); }
void exec_flag_bad() { execl(FLAGS_cli_string, NULL); }
void sql_on_env_var_bad() {
std::string source = (std::string)std::getenv("ENV_VAR");

@ -54,6 +54,7 @@ codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 29, QUANDARY_TAINT_ERR
codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 31, QUANDARY_TAINT_ERROR, [Return from getenv,Call to execve]
codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 33, QUANDARY_TAINT_ERROR, [Return from getenv,Call to system]
codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 35, QUANDARY_TAINT_ERROR, [Return from getenv,Call to popen]
codetoanalyze/cpp/quandary/execs.cpp, execs::exec_flag_bad, 0, QUANDARY_TAINT_ERROR, [Read from &#GB<EXTERN>$execs::FLAGS_cli_string*,Call to execl]
codetoanalyze/cpp/quandary/execs.cpp, execs::sql_on_env_var_bad, 2, QUANDARY_TAINT_ERROR, [Return from getenv,Call to __infer_sql_sink]
codetoanalyze/cpp/quandary/files.cpp, files::read_file_call_exec_bad1, 5, QUANDARY_TAINT_ERROR, [Return from std::basic_istream<char,std::char_traits<char>>_read,Call to execle]
codetoanalyze/cpp/quandary/files.cpp, files::read_file_call_exec_bad2, 5, QUANDARY_TAINT_ERROR, [Return from std::basic_istream<char,std::char_traits<char>>_readsome,Call to execle]

Loading…
Cancel
Save