[quandary] Allow sinks to have multiple taints

Reviewed By: jvillard

Differential Revision: D13163848

fbshipit-source-id: 929e4d0ea
master
Mehdi Bouaziz 6 years ago committed by Facebook Github Bot
parent 8de2b93cab
commit 8443cd73f6

@ -11,13 +11,13 @@ module F = Format
module type Kind = sig module type Kind = sig
include TraceElem.Kind include TraceElem.Kind
val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) option val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) list
end end
module type S = sig module type S = sig
include TraceElem.S include TraceElem.S
val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t option val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t list
val indexes : t -> IntSet.t val indexes : t -> IntSet.t
@ -38,11 +38,8 @@ module Make (Kind : Kind) = struct
let make ?(indexes = IntSet.empty) kind site = {kind; site; indexes} let make ?(indexes = IntSet.empty) kind site = {kind; site; indexes}
let get site actuals call_flags tenv = let get site actuals call_flags tenv =
match Kind.get (CallSite.pname site) actuals call_flags tenv with Kind.get (CallSite.pname site) actuals call_flags tenv
| Some (kind, indexes) -> |> List.rev_map ~f:(fun (kind, indexes) -> {kind; site; indexes})
Some {kind; site; indexes}
| None ->
None
let with_callsite t callee_site = {t with site= callee_site} let with_callsite t callee_site = {t with site= callee_site}

@ -10,14 +10,14 @@ open! IStd
module type Kind = sig module type Kind = sig
include TraceElem.Kind include TraceElem.Kind
val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) option val get : Typ.Procname.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> (t * IntSet.t) list
(** return Some kind if the given procname/actuals are a sink, None otherwise *) (** return Some kind if the given procname/actuals are a sink, None otherwise *)
end end
module type S = sig module type S = sig
include TraceElem.S include TraceElem.S
val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t option val get : CallSite.t -> HilExp.t list -> CallFlags.t -> Tenv.t -> t list
(** return Some sink if the given call site/actuals are a sink, None otherwise *) (** return Some sink if the given call site/actuals are a sink, None otherwise *)
val indexes : t -> IntSet.t val indexes : t -> IntSet.t

@ -32,7 +32,7 @@ end
module MakeSink (TraceElem : TraceElem.S) = struct module MakeSink (TraceElem : TraceElem.S) = struct
include TraceElem include TraceElem
let get _ _ _ _ = None let get _ _ _ _ = []
let indexes _ = IntSet.empty let indexes _ = IntSet.empty

@ -239,7 +239,7 @@ module SinkKind = struct
(* taint the nth parameter (0-indexed) *) (* taint the nth parameter (0-indexed) *)
let taint_nth n kind actuals = let taint_nth n kind actuals =
if n < List.length actuals then Some (kind, IntSet.singleton n) else None if n < List.length actuals then [(kind, IntSet.singleton n)] else []
(* taint all parameters after the nth (exclusive) *) (* taint all parameters after the nth (exclusive) *)
@ -248,13 +248,13 @@ module SinkKind = struct
List.filter_mapi ~f:(fun actual_num _ -> Option.some_if (actual_num > n) actual_num) actuals List.filter_mapi ~f:(fun actual_num _ -> Option.some_if (actual_num > n) actual_num) actuals
with with
| [] -> | [] ->
None []
| to_taint -> | to_taint ->
Some (kind, IntSet.of_list to_taint) [(kind, IntSet.of_list to_taint)]
let taint_all kind actuals = let taint_all kind actuals =
Some (kind, IntSet.of_list (List.mapi ~f:(fun actual_num _ -> actual_num) actuals)) [(kind, IntSet.of_list (List.mapi ~f:(fun actual_num _ -> actual_num) actuals))]
(* return Some(sink kind) if [procedure_name] is in the list of externally specified sinks *) (* return Some(sink kind) if [procedure_name] is in the list of externally specified sinks *)
@ -266,12 +266,14 @@ module SinkKind = struct
let kind = of_string kind in let kind = of_string kind in
try try
let n = int_of_string index in let n = int_of_string index in
taint_nth n kind actuals let taint = taint_nth n kind actuals in
Option.some_if (not (List.is_empty taint)) taint
with Failure _ -> with Failure _ ->
(* couldn't parse the index, just taint everything *) (* couldn't parse the index, just taint everything *)
taint_all kind actuals Some (taint_all kind actuals)
else None ) else None )
external_sinks external_sinks
|> Option.value ~default:[]
let get pname actuals _ _ = let get pname actuals _ _ =
@ -326,13 +328,13 @@ module SinkKind = struct
| Some (Const.Cint i) -> | Some (Const.Cint i) ->
(* check if the data kind might be CURLOPT_URL *) (* check if the data kind might be CURLOPT_URL *)
IntLit.to_int i IntLit.to_int i
|> Option.bind ~f:(fun n -> |> Option.value_map ~default:[] ~f:(fun n ->
if controls_request n then taint_after_nth 1 URL actuals else None ) if controls_request n then taint_after_nth 1 URL actuals else [] )
| _ -> | _ ->
(* can't statically resolve data kind; taint it just in case *) (* can't statically resolve data kind; taint it just in case *)
taint_after_nth 1 URL actuals ) taint_after_nth 1 URL actuals )
| None -> | None ->
None ) [] )
| "execl" | "execlp" | "execle" | "execv" | "execve" | "execvp" | "system" -> | "execl" | "execlp" | "execle" | "execv" | "execve" | "execvp" | "system" ->
taint_all ShellExec actuals taint_all ShellExec actuals
| "openat" -> | "openat" ->
@ -353,7 +355,7 @@ module SinkKind = struct
| _ -> | _ ->
get_external_sink pname actuals ) get_external_sink pname actuals )
| Typ.Procname.Block _ -> | Typ.Procname.Block _ ->
None []
| pname -> | pname ->
L.(die InternalError) "Non-C++ procname %a in C++ analysis" Typ.Procname.pp pname L.(die InternalError) "Non-C++ procname %a in C++ analysis" Typ.Procname.pp pname

@ -331,12 +331,12 @@ module SinkKind = struct
let indexes = let indexes =
IntSet.of_list (List.mapi ~f:(fun param_num _ -> param_num + offset) actuals_to_taint) IntSet.of_list (List.mapi ~f:(fun param_num _ -> param_num + offset) actuals_to_taint)
in in
Some (kind, indexes) Some [(kind, indexes)]
in in
(* taint the nth non-"this" parameter (0-indexed) *) (* taint the nth non-"this" parameter (0-indexed) *)
let taint_nth n kind = let taint_nth n kind =
let first_index = if Typ.Procname.Java.is_static java_pname then n else n + 1 in let first_index = if Typ.Procname.Java.is_static java_pname then n else n + 1 in
if first_index < List.length actuals then Some (kind, IntSet.singleton first_index) if first_index < List.length actuals then Some [(kind, IntSet.singleton first_index)]
else None else None
in in
let get_external_sink class_name method_name = let get_external_sink class_name method_name =
@ -444,8 +444,9 @@ module SinkKind = struct
in in
PatternMatch.supertype_find_map_opt tenv taint_matching_supertype PatternMatch.supertype_find_map_opt tenv taint_matching_supertype
(Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name java_pname)) (Typ.Name.Java.from_string (Typ.Procname.Java.get_class_name java_pname))
|> Option.value ~default:[]
| pname when BuiltinDecl.is_declared pname -> | pname when BuiltinDecl.is_declared pname ->
None []
| pname -> | pname ->
L.(die InternalError) "Non-Java procname %a in Java analysis" Typ.Procname.pp pname L.(die InternalError) "Non-Java procname %a in Java analysis" Typ.Procname.pp pname

@ -468,11 +468,8 @@ module Make (TaintSpecification : TaintSpec.S) = struct
proc_data.ProcData.tenv proc_data.ProcData.tenv
in in
let astate_acc_result = let astate_acc_result =
match sinks with List.fold sinks ~init:astate_acc ~f:(fun astate sink ->
| None -> add_sink sink dummy_actuals astate proc_data dummy_call_site )
astate_acc
| Some sink ->
add_sink sink dummy_actuals astate proc_data dummy_call_site
in in
add_sinks_for_access astate_acc_result ae add_sinks_for_access astate_acc_result ae
in in
@ -671,13 +668,11 @@ module Make (TaintSpecification : TaintSpec.S) = struct
let astate_with_sink = let astate_with_sink =
if List.is_empty actuals then astate if List.is_empty actuals then astate
else else
match let sinks =
TraceDomain.Sink.get call_site actuals call_flags proc_data.ProcData.tenv TraceDomain.Sink.get call_site actuals call_flags proc_data.ProcData.tenv
with in
| Some sink -> List.fold sinks ~init:astate ~f:(fun astate sink ->
add_sink sink actuals astate proc_data call_site add_sink sink actuals astate proc_data call_site )
| None ->
astate
in in
let astate_with_summary = let astate_with_summary =
let sources = TraceDomain.Source.get call_site actuals proc_data.tenv in let sources = TraceDomain.Source.get call_site actuals proc_data.tenv in

@ -32,8 +32,8 @@ module MockTrace = Trace.Make (struct
let get pname _ _ _ = let get pname _ _ _ =
if String.is_prefix ~prefix:"SINK" (Typ.Procname.to_string pname) then if String.is_prefix ~prefix:"SINK" (Typ.Procname.to_string pname) then
Some (CallSite.make pname Location.dummy, IntSet.singleton 0) [(CallSite.make pname Location.dummy, IntSet.singleton 0)]
else None else []
end) end)
module Sanitizer = Sanitizer.Dummy module Sanitizer = Sanitizer.Dummy

Loading…
Cancel
Save