Skip to content

Commit ea7af36

Browse files
arthaudfacebook-github-bot
authored andcommitted
Implement sanitizers as a proper abstract domain
Summary: Since sanitizers are part of the model, they should implement the abstract domain interface. It will also make it easier to implement sanitizers on attribute inside the abstract map domain. This patch moves the `Sanitize` module in `domains.ml` and implements the abstract domain interface for it. Reviewed By: fahndrich Differential Revision: D30741357 fbshipit-source-id: c027d77e4d24532c89065142565993f37e4f3d68
1 parent 8653ef7 commit ea7af36

File tree

17 files changed

+442
-246
lines changed

17 files changed

+442
-246
lines changed

source/interprocedural_analyses/taint/backwardAnalysis.ml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,9 +309,7 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
309309
BackwardTaint.leaf
310310
ByFilter
311311
~f:(fun sink ->
312-
Option.some_if
313-
(not (List.mem ~equal:Sinks.equal sanitized_tito_sinks sink))
314-
sink)
312+
Option.some_if (not (Sinks.Set.mem sink sanitized_tito_sinks)) sink)
315313
taint_in_taint_out
316314
|> Core.Map.Poly.fold
317315
~init:BackwardState.Tree.bottom
@@ -1143,13 +1141,13 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
11431141

11441142
let apply_attribute_sanitizers taint =
11451143
match Model.GlobalModel.get_sanitize global_model with
1146-
| { TaintResult.Sanitize.sinks = Some AllSinks; _ } -> BackwardState.Tree.empty
1147-
| { TaintResult.Sanitize.sinks = Some (SpecificSinks sanitized_sinks); _ } ->
1144+
| { Sanitize.sinks = Some AllSinks; _ } -> BackwardState.Tree.empty
1145+
| { Sanitize.sinks = Some (SpecificSinks sanitized_sinks); _ } ->
11481146
BackwardState.Tree.partition
11491147
BackwardTaint.leaf
11501148
ByFilter
11511149
~f:(fun sink ->
1152-
Option.some_if (not (List.mem ~equal:Sinks.equal sanitized_sinks sink)) sink)
1150+
Option.some_if (not (Sinks.Set.mem sink sanitized_sinks)) sink)
11531151
taint
11541152
|> Core.Map.Poly.fold
11551153
~init:BackwardState.Tree.bottom

source/interprocedural_analyses/taint/domains.ml

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,3 +739,159 @@ let local_return_taint =
739739
Part (Features.ReturnAccessPathSet.Element, []);
740740
Part (Features.SimpleSet.Self, Features.SimpleSet.empty);
741741
]
742+
743+
744+
module Sanitize = struct
745+
type sanitize_sources =
746+
| AllSources
747+
| SpecificSources of Sources.Set.t
748+
[@@deriving show, eq]
749+
750+
type sanitize_sinks =
751+
| AllSinks
752+
| SpecificSinks of Sinks.Set.t
753+
[@@deriving show, eq]
754+
755+
type sanitize_tito =
756+
| AllTito
757+
| SpecificTito of {
758+
sanitized_tito_sources: Sources.Set.t;
759+
sanitized_tito_sinks: Sinks.Set.t;
760+
}
761+
[@@deriving show, eq]
762+
763+
type sanitize = {
764+
sources: sanitize_sources option;
765+
sinks: sanitize_sinks option;
766+
tito: sanitize_tito option;
767+
}
768+
[@@deriving show, eq]
769+
770+
include Abstract.SimpleDomain.Make (struct
771+
type t = sanitize
772+
773+
let name = "sanitize"
774+
775+
let bottom = { sources = None; sinks = None; tito = None }
776+
777+
let less_or_equal ~left ~right =
778+
if phys_equal left right then
779+
true
780+
else
781+
(match left.sources, right.sources with
782+
| None, _ -> true
783+
| Some _, None -> false
784+
| Some AllSources, Some AllSources -> true
785+
| Some AllSources, Some (SpecificSources _) -> false
786+
| Some (SpecificSources _), Some AllSources -> true
787+
| Some (SpecificSources left), Some (SpecificSources right) -> Sources.Set.subset left right)
788+
&& (match left.sinks, right.sinks with
789+
| None, _ -> true
790+
| Some _, None -> false
791+
| Some AllSinks, Some AllSinks -> true
792+
| Some AllSinks, Some (SpecificSinks _) -> false
793+
| Some (SpecificSinks _), Some AllSinks -> true
794+
| Some (SpecificSinks left), Some (SpecificSinks right) -> Sinks.Set.subset left right)
795+
&&
796+
match left.tito, right.tito with
797+
| None, _ -> true
798+
| Some _, None -> false
799+
| Some AllTito, Some AllTito -> true
800+
| Some AllTito, Some (SpecificTito _) -> false
801+
| Some (SpecificTito _), Some AllTito -> true
802+
| Some (SpecificTito left), Some (SpecificTito right) ->
803+
Sources.Set.subset left.sanitized_tito_sources right.sanitized_tito_sources
804+
&& Sinks.Set.subset left.sanitized_tito_sinks right.sanitized_tito_sinks
805+
806+
807+
let join left right =
808+
if phys_equal left right then
809+
left
810+
else
811+
let sources =
812+
match left.sources, right.sources with
813+
| None, Some _ -> right.sources
814+
| Some _, None -> left.sources
815+
| Some AllSources, _
816+
| _, Some AllSources ->
817+
Some AllSources
818+
| Some (SpecificSources left_sources), Some (SpecificSources right_sources) ->
819+
Some (SpecificSources (Sources.Set.union left_sources right_sources))
820+
| None, None -> None
821+
in
822+
let sinks =
823+
match left.sinks, right.sinks with
824+
| None, Some _ -> right.sinks
825+
| Some _, None -> left.sinks
826+
| Some AllSinks, _
827+
| _, Some AllSinks ->
828+
Some AllSinks
829+
| Some (SpecificSinks left_sinks), Some (SpecificSinks right_sinks) ->
830+
Some (SpecificSinks (Sinks.Set.union left_sinks right_sinks))
831+
| None, None -> None
832+
in
833+
let tito =
834+
match left.tito, right.tito with
835+
| None, Some tito
836+
| Some tito, None ->
837+
Some tito
838+
| Some AllTito, _
839+
| _, Some AllTito ->
840+
Some AllTito
841+
| Some (SpecificTito left), Some (SpecificTito right) ->
842+
Some
843+
(SpecificTito
844+
{
845+
sanitized_tito_sources =
846+
Sources.Set.union left.sanitized_tito_sources right.sanitized_tito_sources;
847+
sanitized_tito_sinks =
848+
Sinks.Set.union left.sanitized_tito_sinks right.sanitized_tito_sinks;
849+
})
850+
| None, None -> None
851+
in
852+
{ sources; sinks; tito }
853+
854+
855+
let meet a b = if less_or_equal ~left:b ~right:a then b else a
856+
857+
let show = show_sanitize
858+
end)
859+
860+
let empty = bottom
861+
862+
let is_empty = is_bottom
863+
864+
let equal = equal_sanitize
865+
866+
let to_json { sources; sinks; tito } =
867+
let to_string name = `String name in
868+
let sources_to_json sources =
869+
`List (sources |> Sources.Set.elements |> List.map ~f:Sources.show |> List.map ~f:to_string)
870+
in
871+
let sinks_to_json sinks =
872+
`List (sinks |> Sinks.Set.elements |> List.map ~f:Sinks.show |> List.map ~f:to_string)
873+
in
874+
let sources_json =
875+
match sources with
876+
| Some AllSources -> ["sources", `String "All"]
877+
| Some (SpecificSources sources) -> ["sources", sources_to_json sources]
878+
| None -> []
879+
in
880+
let sinks_json =
881+
match sinks with
882+
| Some AllSinks -> ["sinks", `String "All"]
883+
| Some (SpecificSinks sinks) -> ["sinks", sinks_to_json sinks]
884+
| None -> []
885+
in
886+
let tito_json =
887+
match tito with
888+
| Some AllTito -> ["tito", `String "All"]
889+
| Some (SpecificTito { sanitized_tito_sources; sanitized_tito_sinks }) ->
890+
[
891+
"tito_sources", sources_to_json sanitized_tito_sources;
892+
"tito_sinks", sinks_to_json sanitized_tito_sinks;
893+
]
894+
| None -> []
895+
in
896+
`Assoc (sources_json @ sinks_json @ tito_json)
897+
end

source/interprocedural_analyses/taint/forwardAnalysis.ml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,7 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
184184
ForwardTaint.leaf
185185
ByFilter
186186
~f:(fun source ->
187-
Option.some_if
188-
(not (List.mem ~equal:Sources.equal sanitized_tito_sources source))
189-
source)
187+
Option.some_if (not (Sources.Set.mem source sanitized_tito_sources)) source)
190188
argument_taint
191189
|> Core.Map.Poly.fold
192190
~init:ForwardState.Tree.bottom
@@ -1113,13 +1111,13 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
11131111
in
11141112
let apply_attribute_sanitizers taint =
11151113
match Model.GlobalModel.get_sanitize global_model with
1116-
| { TaintResult.Sanitize.sources = Some AllSources; _ } -> ForwardState.Tree.empty
1117-
| { TaintResult.Sanitize.sources = Some (SpecificSources sanitized_sources); _ } ->
1114+
| { Sanitize.sources = Some AllSources; _ } -> ForwardState.Tree.empty
1115+
| { Sanitize.sources = Some (SpecificSources sanitized_sources); _ } ->
11181116
ForwardState.Tree.partition
11191117
ForwardTaint.leaf
11201118
ByFilter
11211119
~f:(fun source ->
1122-
Option.some_if (not (List.mem ~equal:Sources.equal sanitized_sources source)) source)
1120+
Option.some_if (not (Sources.Set.mem source sanitized_sources)) source)
11231121
taint
11241122
|> Core.Map.Poly.fold
11251123
~init:ForwardState.Tree.bottom

source/interprocedural_analyses/taint/model.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,9 @@ module GlobalModel = struct
327327
let is_sanitized_model { model = { TaintResult.sanitize; _ }; _ } =
328328
match sanitize with
329329
| {
330-
sources = Some TaintResult.Sanitize.AllSources;
331-
sinks = Some TaintResult.Sanitize.AllSinks;
332-
tito = Some TaintResult.Sanitize.AllTito;
330+
sources = Some Sanitize.AllSources;
331+
sinks = Some Sanitize.AllSinks;
332+
tito = Some Sanitize.AllTito;
333333
} ->
334334
true
335335
| _ -> false

source/interprocedural_analyses/taint/model.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module GlobalModel : sig
3333

3434
val get_tito : t -> Domains.BackwardState.Tree.t
3535

36-
val get_sanitize : t -> TaintResult.Sanitize.t
36+
val get_sanitize : t -> Domains.Sanitize.t
3737

3838
val get_modes : t -> TaintResult.ModeSet.t
3939

source/interprocedural_analyses/taint/modelParser.ml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ let introduce_sink_taint
735735
let should_keep_taint =
736736
match sinks_to_keep with
737737
| None -> true
738-
| Some sinks_to_keep -> Core.Set.mem sinks_to_keep taint_sink_kind
738+
| Some sinks_to_keep -> Sinks.Set.mem taint_sink_kind sinks_to_keep
739739
in
740740
if should_keep_taint then
741741
let backward =
@@ -830,7 +830,7 @@ let introduce_source_taint
830830
let should_keep_taint =
831831
match sources_to_keep with
832832
| None -> true
833-
| Some sources_to_keep -> Core.Set.mem sources_to_keep taint_source_kind
833+
| Some sources_to_keep -> Sources.Set.mem taint_source_kind sources_to_keep
834834
in
835835
if Sources.equal taint_source_kind Sources.Attach && List.is_empty breadcrumbs then
836836
Error "`Attach` must be accompanied by a list of features to attach."
@@ -1884,8 +1884,12 @@ let adjust_sanitize_and_modes_and_skipped_override
18841884
~callable_parameter_names_to_positions:None
18851885
value
18861886
>>= List.fold_result ~init:([], []) ~f:add_tito_annotation
1887-
>>| fun (sanitized_tito_sources, sanitized_tito_sinks) ->
1888-
Sanitize.SpecificTito { sanitized_tito_sources; sanitized_tito_sinks }
1887+
>>| fun (sources, sinks) ->
1888+
Sanitize.SpecificTito
1889+
{
1890+
sanitized_tito_sources = Sources.Set.of_list sources;
1891+
sanitized_tito_sinks = Sinks.Set.of_list sinks;
1892+
}
18891893
in
18901894
sanitize_tito
18911895
>>= fun sanitize_tito ->
@@ -1906,9 +1910,10 @@ let adjust_sanitize_and_modes_and_skipped_override
19061910
} ->
19071911
let sources =
19081912
match sources with
1909-
| None -> Some (Sanitize.SpecificSources [source])
1913+
| None ->
1914+
Some (Sanitize.SpecificSources (Sources.Set.singleton source))
19101915
| Some (Sanitize.SpecificSources sources) ->
1911-
Some (Sanitize.SpecificSources (source :: sources))
1916+
Some (Sanitize.SpecificSources (Sources.Set.add source sources))
19121917
| Some Sanitize.AllSources -> Some Sanitize.AllSources
19131918
in
19141919
Ok { Sanitize.sources; sinks; tito }
@@ -1922,9 +1927,9 @@ let adjust_sanitize_and_modes_and_skipped_override
19221927
} ->
19231928
let sinks =
19241929
match sinks with
1925-
| None -> Some (Sanitize.SpecificSinks [sink])
1930+
| None -> Some (Sanitize.SpecificSinks (Sinks.Set.singleton sink))
19261931
| Some (Sanitize.SpecificSinks sinks) ->
1927-
Some (Sanitize.SpecificSinks (sink :: sinks))
1932+
Some (Sanitize.SpecificSinks (Sinks.Set.add sink sinks))
19281933
| Some Sanitize.AllSinks -> Some Sanitize.AllSinks
19291934
in
19301935
Ok { Sanitize.sources; sinks; tito }
@@ -1954,8 +1959,7 @@ let adjust_sanitize_and_modes_and_skipped_override
19541959
List.fold arguments ~f:to_sanitize_kind ~init:(Ok Sanitize.empty)
19551960
in
19561961
sanitize_kind
1957-
>>| fun sanitize_kind ->
1958-
TaintResult.Sanitize.join sanitize sanitize_kind, modes, skipped_override
1962+
>>| fun sanitize_kind -> Sanitize.join sanitize sanitize_kind, modes, skipped_override
19591963
| "SkipAnalysis" -> Ok (sanitize, ModeSet.add SkipAnalysis modes, skipped_override)
19601964
| "SkipDecoratorWhenInlining" ->
19611965
Ok (sanitize, ModeSet.add SkipDecoratorWhenInlining modes, skipped_override)
@@ -1996,8 +2000,8 @@ let compute_sources_and_sinks_to_keep ~configuration ~rule_filter =
19962000
( Sources.Set.singleton Sources.Attach,
19972001
Sinks.Set.of_list [Sinks.AddFeatureToArgument; Sinks.Attach] )
19982002
~f:(fun (sources, sinks) (rule_sources, rule_sinks) ->
1999-
( Core.Set.union sources (Sources.Set.of_list rule_sources),
2000-
Core.Set.union sinks (Sinks.Set.of_list rule_sinks) ))
2003+
( Sources.Set.union sources (Sources.Set.of_list rule_sources),
2004+
Sinks.Set.union sinks (Sinks.Set.of_list rule_sinks) ))
20012005
in
20022006
Some sources_to_keep, Some sinks_to_keep
20032007

source/interprocedural_analyses/taint/sinks.ml

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,39 @@ module T = struct
2828
| AddFeatureToArgument
2929
(* Special marker to designate modifying the state the parameter passed in. *)
3030
[@@deriving compare, eq, sexp, hash]
31-
end
3231

33-
include T
32+
let pp formatter = function
33+
| Attach -> Format.fprintf formatter "Attach"
34+
| PartialSink { kind; label } -> Format.fprintf formatter "PartialSink[%s[%s]]" kind label
35+
| TriggeredPartialSink { kind; label } ->
36+
Format.fprintf formatter "TriggeredPartialSink[%s[%s]]" kind label
37+
| LocalReturn -> Format.fprintf formatter "LocalReturn"
38+
| NamedSink name -> Format.fprintf formatter "%s" name
39+
| ParametricSink { sink_name; subkind } -> Format.fprintf formatter "%s[%s]" sink_name subkind
40+
| ParameterUpdate index -> Format.fprintf formatter "ParameterUpdate%d" index
41+
| AddFeatureToArgument -> Format.fprintf formatter "AddFeatureToArgument"
3442

35-
let pp formatter = function
36-
| Attach -> Format.fprintf formatter "Attach"
37-
| PartialSink { kind; label } -> Format.fprintf formatter "PartialSink[%s[%s]]" kind label
38-
| TriggeredPartialSink { kind; label } ->
39-
Format.fprintf formatter "TriggeredPartialSink[%s[%s]]" kind label
40-
| LocalReturn -> Format.fprintf formatter "LocalReturn"
41-
| NamedSink name -> Format.fprintf formatter "%s" name
42-
| ParametricSink { sink_name; subkind } -> Format.fprintf formatter "%s[%s]" sink_name subkind
43-
| ParameterUpdate index -> Format.fprintf formatter "ParameterUpdate%d" index
44-
| AddFeatureToArgument -> Format.fprintf formatter "AddFeatureToArgument"
4543

44+
let show = Format.asprintf "%a" pp
45+
end
4646

47-
let show = Format.asprintf "%a" pp
47+
include T
4848

4949
let ignore_leaf_at_call = function
5050
| Attach -> true
5151
| _ -> false
5252

5353

54-
module Set = Set.Make (struct
55-
include T
56-
end)
54+
module Set = struct
55+
include Stdlib.Set.Make (struct
56+
include T
57+
end)
58+
59+
let show set =
60+
set |> elements |> List.map ~f:T.show |> String.concat ~sep:", " |> Format.asprintf "[%s]"
61+
62+
63+
let pp format set = Format.fprintf format "%s" (show set)
64+
end
5765

5866
let name = "sink"

source/interprocedural_analyses/taint/sinks.mli

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
* LICENSE file in the root directory of this source tree.
66
*)
77

8-
open Core
9-
108
type partial_sink = {
119
kind: string;
1210
label: string;
@@ -31,4 +29,10 @@ val name : string
3129

3230
val ignore_leaf_at_call : t -> bool
3331

34-
module Set : Set.S with type Elt.t = t
32+
module Set : sig
33+
include Stdlib.Set.S with type elt = t
34+
35+
val pp : Format.formatter -> t -> unit
36+
37+
val show : t -> string
38+
end

0 commit comments

Comments
 (0)