[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) module Sink = MakeSink (TraceElem)
let should_report _ _ = true let should_report _ _ = true
let should_report_footprint _ _ = false
end) end)
type sink_path = Passthroughs.t * (Sink.t * Passthroughs.t) list type sink_path = Passthroughs.t * (Sink.t * Passthroughs.t) list

@ -17,8 +17,6 @@ let all_formals_untainted pdesc =
module type Kind = sig module type Kind = sig
include TraceElem.Kind include TraceElem.Kind
val unknown : t
val get : Typ.Procname.t -> HilExp.t list -> Tenv.t -> (t * int option) option 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 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 module type Kind = sig
include TraceElem.Kind 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 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 *) (** 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 val should_report : Source.t -> Sink.t -> bool
(** should a flow originating at source and entering sink be reported? *) (** should a flow originating at source and entering sink be reported? *)
val should_report_footprint : AccessPath.Abs.t -> Sink.t -> bool
end end
module type S = sig module type S = sig
@ -54,10 +56,12 @@ module type S = sig
module Sinks = Sink.Set module Sinks = Sink.Set
module Passthroughs = Passthrough.Set module Passthroughs = Passthrough.Set
(** path from a source to a sink with passthroughs at each step in the call stack. the first set type path_source = Known of Source.t | Footprint of AccessPath.Abs.t
of passthroughs are the ones in the "reporting" procedure that calls the first function in
both the source and sink stack *) type path_sink = Sink.t
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 val empty : t
@ -70,7 +74,7 @@ module type S = sig
val passthroughs : t -> Passthroughs.t val passthroughs : t -> Passthroughs.t
(** get the passthroughs of the trace *) (** 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 (** 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] *) 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] *) [cur_site] restricts the reported paths to ones introduced by the call at [cur_site] *)
val to_loc_trace : val to_loc_trace :
?desc_of_source:(Source.t -> string) -> ?source_should_nest:(Source.t -> bool) ?desc_of_source:(path_source -> string) -> ?source_should_nest:(path_source -> bool)
-> ?desc_of_sink:(Sink.t -> string) -> ?sink_should_nest:(Sink.t -> bool) -> path -> ?desc_of_sink:(path_sink -> string) -> ?sink_should_nest:(path_sink -> bool) -> path
-> Errlog.loc_trace -> Errlog.loc_trace
(** create a loc_trace from a path; [source_should_nest s] should be true when we are going one (** 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 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 val pp_path : Typ.Procname.t -> F.formatter -> path -> unit
(** pretty-print a path in the context of the given procname *) (** pretty-print a path in the context of the given procname *)
val pp_path_source : F.formatter -> path_source -> unit
end end
(** Expand a trace element (i.e., a source or sink) into a list of trace elements bottoming out in (** 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 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 = let pp fmt t =
F.fprintf fmt "%a -> %a via %a" Sources.pp t.sources Sinks.pp t.sinks Passthroughs.pp F.fprintf fmt "%a -> %a via %a" Sources.pp t.sources Sinks.pp t.sinks Passthroughs.pp
t.passthroughs t.passthroughs
let get_path_source_call_site = function
| Known source
-> Source.call_site source
| Footprint _
-> CallSite.dummy
let sources t = t.sources let sources t = t.sources
let sinks t = t.sinks let sinks t = t.sinks
@ -258,13 +275,28 @@ module Make (Spec : Spec) = struct
let report_source source sinks acc0 = let report_source source sinks acc0 =
let report_one sink acc = let report_one sink acc =
if Spec.should_report source sink && should_report_at_site source sink then 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 else acc
in in
Sinks.fold report_one sinks acc0 Sinks.fold report_one sinks acc0
in 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 let report_sources source acc = report_source source t.sinks acc in
Sources.Known.fold report_sources t.sources.known [] 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_path cur_pname fmt (cur_passthroughs, sources_passthroughs, sinks_passthroughs) =
let pp_passthroughs fmt passthroughs = let pp_passthroughs fmt passthroughs =
@ -278,11 +310,11 @@ module Make (Spec : Spec) = struct
in in
F.pp_print_list ~pp_sep pp_elem fmt elems_passthroughs F.pp_print_list ~pp_sep pp_elem fmt elems_passthroughs
in 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 pp_sinks = pp_elems Sink.call_site in
let original_source = fst (List.hd_exn sources_passthroughs) in let original_source = fst (List.hd_exn sources_passthroughs) in
let final_sink = fst (List.hd_exn sinks_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 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) pp_passthroughs cur_passthroughs pp_sinks (List.rev sinks_passthroughs)
@ -312,41 +344,57 @@ module Make (Spec : Spec) = struct
in in
Passthrough.Set.filter between_start_and_end passthroughs Passthrough.Set.filter between_start_and_end passthroughs
in in
let expand_path source sink = let expand_path path_source sink =
let sources_of_pname pname = match path_source with
let trace = trace_of_pname pname in | Known source
(Sources.Known.elements (sources trace).known, passthroughs trace) -> let sources_of_pname pname =
in let trace = trace_of_pname pname in
let sinks_of_pname pname = (Sources.Known.elements (sources trace).known, passthroughs trace)
let trace = trace_of_pname pname in in
(Sinks.elements (sinks trace), passthroughs trace) let sinks_of_pname pname =
in let trace = trace_of_pname pname in
let sources_passthroughs = (Sinks.elements (sinks trace), passthroughs trace)
let filter_passthroughs = filter_passthroughs_ Source in in
SourceExpander.expand source ~elems_passthroughs_of_pname:sources_of_pname let sources_passthroughs =
~filter_passthroughs let filter_passthroughs = filter_passthroughs_ Source in
in SourceExpander.expand source ~elems_passthroughs_of_pname:sources_of_pname
let sinks_passthroughs = ~filter_passthroughs
let filter_passthroughs = filter_passthroughs_ Sink in |> List.map ~f:(fun (source, passthrough) -> (Known source, passthrough))
SinkExpander.expand sink ~elems_passthroughs_of_pname:sinks_of_pname ~filter_passthroughs in
in let sinks_passthroughs =
(sources_passthroughs, 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 in
List.map List.map
~f:(fun (source, sink, passthroughs) -> ~f:(fun (path_source, sink, passthroughs) ->
let sources_passthroughs, sinks_passthroughs = expand_path source sink in let sources_passthroughs, sinks_passthroughs = expand_path path_source sink in
let filtered_passthroughs = let filtered_passthroughs =
filter_passthroughs_ Top_level (Source.call_site source) (Sink.call_site sink) let source_site =
passthroughs 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 in
(filtered_passthroughs, sources_passthroughs, sinks_passthroughs)) (filtered_passthroughs, sources_passthroughs, sinks_passthroughs))
(get_reports ?cur_site t) (get_reports ?cur_site t)
let to_loc_trace let to_loc_trace
?(desc_of_source= fun source -> ?(desc_of_source= function
let callsite = Source.call_site source in | Known source
Format.asprintf "return from %a" Typ.Procname.pp -> let callsite = Source.call_site source in
(CallSite.pname callsite)) ?(source_should_nest= fun _ -> true) 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 -> ?(desc_of_sink= fun sink ->
let callsite = Sink.call_site sink in let callsite = Sink.call_site sink in
Format.asprintf "call to %a" Typ.Procname.pp (CallSite.pname callsite)) 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 trace_elem :: trace_elems_of_passthroughs lt_level passthroughs acc
in in
let trace_elems_of_source = 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 in
let trace_elems_of_sink = let trace_elems_of_sink =
trace_elems_of_path_elem Sink.call_site desc_of_sink ~is_source:false 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 val should_report : Source.t -> Sink.t -> bool
(** should a flow originating at source and entering sink be reported? *) (** 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 end
module type S = sig module type S = sig
@ -56,10 +60,18 @@ module type S = sig
module Sinks = Sink.Set module Sinks = Sink.Set
module Passthroughs = Passthrough.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 (** 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 of passthroughs are the ones in the "reporting" procedure that calls the first function in
both the source and sink stack *) 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 val empty : t
(** the empty trace *) (** the empty trace *)
@ -73,7 +85,7 @@ module type S = sig
val passthroughs : t -> Passthroughs.t val passthroughs : t -> Passthroughs.t
(** get the passthroughs of the trace *) (** 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 (** 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] *) 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] *) [cur_site] restricts the reported paths to ones introduced by the call at [cur_site] *)
val to_loc_trace : val to_loc_trace :
?desc_of_source:(Source.t -> string) -> ?source_should_nest:(Source.t -> bool) ?desc_of_source:(path_source -> string) -> ?source_should_nest:(path_source -> bool)
-> ?desc_of_sink:(Sink.t -> string) -> ?sink_should_nest:(Sink.t -> bool) -> path -> ?desc_of_sink:(path_sink -> string) -> ?sink_should_nest:(path_sink -> bool) -> path
-> Errlog.loc_trace -> Errlog.loc_trace
(** create a loc_trace from a path; [source_should_nest s] should be true when we are going one (** 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 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 val pp_path : Typ.Procname.t -> F.formatter -> path -> unit
(** pretty-print a path in the context of the given procname *) (** pretty-print a path in the context of the given procname *)
val pp_path_source : F.formatter -> path_source -> unit
end end
module Make (Spec : Spec) : S with module Source = Spec.Source and module Sink = Spec.Sink 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 *) | EnvironmentVariable (** source that was read from an environment variable *)
| File (** source that was read from a file *) | File (** source that was read from a file *)
| Other (** for testing or uncategorized sources *) | Other (** for testing or uncategorized sources *)
| Unknown
[@@deriving compare] [@@deriving compare]
let unknown = Unknown
let of_string = function let of_string = function
| "Endpoint" | "Endpoint"
-> Endpoint (Mangled.from_string "NONE", Typ.Tvoid) -> Endpoint (Mangled.from_string "NONE", Typ.Tvoid)
@ -111,9 +108,7 @@ module SourceKind = struct
| File | File
-> "File" -> "File"
| Other | Other
-> "Other" -> "Other" )
| Unknown
-> "Unknown" )
end end
module CppSource = Source.Make (SourceKind) module CppSource = Source.Make (SourceKind)
@ -257,6 +252,22 @@ include Trace.Make (struct
true true
| _, Other | _, Other
-> true -> 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) end)

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

@ -94,11 +94,14 @@ module Make (TaintSpecification : TaintSpec.S) = struct
let endpoints = let endpoints =
(lazy (String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints))) (lazy (String.Set.of_list (QuandaryConfig.Endpoint.of_json Config.quandary_endpoints)))
let is_endpoint source = let is_endpoint = function
match CallSite.pname (TraceDomain.Source.call_site source) with | TraceDomain.Known source -> (
| Typ.Procname.Java java_pname match CallSite.pname (TraceDomain.Source.call_site source) with
-> String.Set.mem (Lazy.force endpoints) (Typ.Procname.java_get_class_name java_pname) | Typ.Procname.Java java_pname
| _ -> String.Set.mem (Lazy.force endpoints) (Typ.Procname.java_get_class_name java_pname)
| _
-> false )
| TraceDomain.Footprint _
-> false -> false
(** log any new reportable source-sink flows in [trace] *) (** log any new reportable source-sink flows in [trace] *)
@ -114,12 +117,12 @@ module Make (TaintSpecification : TaintSpec.S) = struct
| None | None
-> TaintDomain.empty -> TaintDomain.empty
in in
let get_short_trace_string original_source final_sink = let get_short_trace_string original_path_source final_sink =
F.asprintf "%a -> %a%s" TraceDomain.Source.pp original_source TraceDomain.Sink.pp F.asprintf "%a -> %a%s" TraceDomain.pp_path_source original_path_source TraceDomain.Sink.pp
final_sink 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 in
let report_one (source, sink, _) = let report_one (path_source, sink, _) =
let open TraceDomain in let open TraceDomain in
let rec expand_source source0 (report_acc, seen_acc as acc) = let rec expand_source source0 (report_acc, seen_acc as acc) =
let kind = Source.kind source0 in let kind = Source.kind source0 in
@ -190,7 +193,14 @@ module Make (TaintSpecification : TaintSpec.S) = struct
| [] | []
-> acc -> acc
in 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 expanded_sinks, _ = expand_sink sink sink_indexes ([sink], CallSite.Set.empty) in
let source_trace = let source_trace =
let pp_access_path_opt fmt = function let pp_access_path_opt fmt = function
@ -205,13 +215,18 @@ module Make (TaintSpecification : TaintSpec.S) = struct
else access_path ) else access_path )
in in
List.map List.map
~f:(fun (access_path_opt, source) -> ~f:(fun (access_path_opt, path_source) ->
let call_site = Source.call_site source in let desc, loc =
let desc = match path_source with
Format.asprintf "Return from %a%a" Typ.Procname.pp (CallSite.pname call_site) | Known source
pp_access_path_opt access_path_opt -> 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 in
Errlog.make_trace_element 0 (CallSite.loc call_site) desc []) Errlog.make_trace_element 0 loc desc [])
expanded_sources expanded_sources
in in
let sink_trace = let sink_trace =
@ -223,9 +238,9 @@ module Make (TaintSpecification : TaintSpec.S) = struct
expanded_sinks expanded_sinks
in in
let msg = IssueType.quandary_taint_error.unique_id 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 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 ltr = source_trace @ List.rev sink_trace in
let exn = Exceptions.Checkers (msg, Localise.verbatim_desc trace_str) 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 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 module Source = Source.Make (struct
include MockTraceElem include MockTraceElem
let unknown = CallSite.dummy
let get pname _ _ = let get pname _ _ =
if String.is_prefix ~prefix:"SOURCE" (Typ.Procname.to_string pname) then if String.is_prefix ~prefix:"SOURCE" (Typ.Procname.to_string pname) then
Some (CallSite.make pname Location.dummy, None) Some (CallSite.make pname Location.dummy, None)
@ -36,6 +34,8 @@ module MockTrace = Trace.Make (struct
end) end)
let should_report _ _ = false let should_report _ _ = false
let should_report_footprint _ _ = false
end) end)
module MockTaintAnalysis = TaintAnalysis.Make (struct module MockTaintAnalysis = TaintAnalysis.Make (struct

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

@ -99,7 +99,7 @@ void customGetEnvOk() {
return execl(NULL, source); 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() { void sql_on_env_var_bad() {
std::string source = (std::string)std::getenv("ENV_VAR"); 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, 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, 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::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/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_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] 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