Skip to content

Commit c6b4ba6

Browse files
arthaudfacebook-github-bot
authored andcommitted
Add a data structure for parameter and return sanitizers
Summary: This patch adds parameter and return sanitizers in our model representation. The follow-up diffs will update the model parser to properly parse those, and finally the analysis itself to take those into account. Reviewed By: dkgi Differential Revision: D30744484 fbshipit-source-id: 6f419af0d9aab17aea3fac3891d7b35fa2ec8ea3
1 parent ea7af36 commit c6b4ba6

File tree

14 files changed

+211
-104
lines changed

14 files changed

+211
-104
lines changed

source/interprocedural_analyses/taint/backwardAnalysis.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
159159
(Node.create_with_default_location call_expression)
160160
Model.pp
161161
taint_model;
162-
let { TaintResult.backward; sanitize; modes; _ } = taint_model.model in
162+
let { TaintResult.backward; sanitizers; modes; _ } = taint_model.model in
163163
let sink_taint = BackwardState.join backward.sink_taint triggered_taint in
164164
let sink_argument_matches =
165165
BackwardState.roots sink_taint |> AccessPath.match_actuals_to_formals arguments
@@ -302,7 +302,7 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
302302
|> BackwardState.Tree.join taint_in_taint_out
303303
in
304304
let taint_in_taint_out =
305-
match sanitize with
305+
match sanitizers.global with
306306
| { tito = Some AllTito; _ } -> BackwardState.Tree.bottom
307307
| { tito = Some (SpecificTito { sanitized_tito_sinks; _ }); _ } ->
308308
BackwardState.Tree.partition

source/interprocedural_analyses/taint/domains.ml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,3 +895,26 @@ module Sanitize = struct
895895
in
896896
`Assoc (sources_json @ sinks_json @ tito_json)
897897
end
898+
899+
(** Map from parameters or return value to a sanitizer. *)
900+
module SanitizeRootMap = struct
901+
include
902+
Abstract.MapDomain.Make
903+
(struct
904+
let name = "sanitize"
905+
906+
include AccessPath.Root
907+
908+
let absence_implicitly_maps_to_bottom = true
909+
end)
910+
(Sanitize)
911+
912+
let to_json map =
913+
map
914+
|> to_alist
915+
|> List.map ~f:(fun (root, sanitize) ->
916+
let (`Assoc fields) = Sanitize.to_json sanitize in
917+
let port = AccessPath.create root [] |> AccessPath.to_json in
918+
`Assoc (("port", port) :: fields))
919+
|> fun elements -> `List elements
920+
end

source/interprocedural_analyses/taint/forwardAnalysis.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
132132
sinks at the end. *)
133133
let triggered_sinks = String.Hash_set.create () in
134134
let apply_call_target state arguments_taint call_target =
135-
let ({ Model.model = { TaintResult.forward; backward; sanitize; modes }; _ } as taint_model)
135+
let ({ Model.model = { TaintResult.forward; backward; sanitizers; modes }; _ } as
136+
taint_model)
136137
=
137138
Model.get_callsite_model ~resolution ~call_target ~arguments
138139
in
@@ -177,7 +178,7 @@ module AnalysisInstance (FunctionContext : FUNCTION_CONTEXT) = struct
177178
(argument_taint, ((argument, sink_matches), (_dup, tito_matches)))
178179
=
179180
let taint_to_propagate =
180-
match sanitize with
181+
match sanitizers.global with
181182
| { tito = Some AllTito; _ } -> ForwardState.Tree.bottom
182183
| { tito = Some (SpecificTito { sanitized_tito_sources; _ }); _ } ->
183184
ForwardState.Tree.partition

source/interprocedural_analyses/taint/model.ml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ let register_unknown_callee_model callable =
107107
{
108108
TaintResult.forward = Forward.empty;
109109
backward = { sink_taint; taint_in_taint_out };
110-
sanitize = Sanitize.empty;
110+
sanitizers = Sanitizers.empty;
111111
modes = ModeSet.singleton Mode.SkipAnalysis;
112112
})
113113

@@ -121,7 +121,7 @@ let get_callsite_model ~resolution ~call_target ~arguments =
121121
{
122122
forward = { source_taint };
123123
backward = { sink_taint; taint_in_taint_out };
124-
sanitize;
124+
sanitizers;
125125
modes;
126126
}
127127
=
@@ -176,7 +176,7 @@ let get_callsite_model ~resolution ~call_target ~arguments =
176176
{
177177
forward = { source_taint };
178178
backward = { sink_taint; taint_in_taint_out };
179-
sanitize;
179+
sanitizers;
180180
modes;
181181
}
182182
in
@@ -312,7 +312,10 @@ module GlobalModel = struct
312312

313313

314314
let get_sanitize { models; _ } =
315-
let get_sanitize existing { model = { TaintResult.sanitize; _ }; _ } =
315+
let get_sanitize
316+
existing
317+
{ model = { TaintResult.sanitizers = { global = sanitize; _ }; _ }; _ }
318+
=
316319
Sanitize.join sanitize existing
317320
in
318321
List.fold ~init:Sanitize.empty ~f:get_sanitize models
@@ -324,7 +327,7 @@ module GlobalModel = struct
324327

325328

326329
let is_sanitized { models; _ } =
327-
let is_sanitized_model { model = { TaintResult.sanitize; _ }; _ } =
330+
let is_sanitized_model { model = { TaintResult.sanitizers = { global = sanitize; _ }; _ }; _ } =
328331
match sanitize with
329332
| {
330333
sources = Some Sanitize.AllSources;
@@ -395,7 +398,7 @@ let infer_class_models ~environment =
395398
List.foldi ~f:fold_taint ~init:BackwardState.empty attributes;
396399
sink_taint = BackwardState.empty;
397400
};
398-
sanitize = Sanitize.empty;
401+
sanitizers = Sanitizers.empty;
399402
modes = ModeSet.empty;
400403
}
401404
in
@@ -422,7 +425,7 @@ let infer_class_models ~environment =
422425
List.foldi ~f:fold_taint ~init:BackwardState.empty attributes;
423426
sink_taint = BackwardState.empty;
424427
};
425-
sanitize = Sanitize.empty;
428+
sanitizers = Sanitizers.empty;
426429
modes = ModeSet.empty;
427430
}
428431
in

source/interprocedural_analyses/taint/modelParser.ml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,10 +1967,15 @@ let adjust_sanitize_and_modes_and_skipped_override
19671967
| "SkipObscure" -> Ok (sanitize, ModeSet.remove Obscure modes, Some define_name)
19681968
| _ -> Ok (sanitize, modes, skipped_override)
19691969
in
1970-
List.fold_result top_level_decorators ~f:adjust ~init:(model.sanitize, model.modes, None)
1970+
List.fold_result
1971+
top_level_decorators
1972+
~f:adjust
1973+
~init:(model.sanitizers.global, model.modes, None)
19711974
in
19721975
sanitize_and_modes_and_skipped_override
1973-
>>| fun (sanitize, modes, skipped_override) -> { model with sanitize; modes }, skipped_override
1976+
>>| fun (sanitize, modes, skipped_override) ->
1977+
let sanitizers = { model.sanitizers with global = sanitize } in
1978+
{ model with sanitizers; modes }, skipped_override
19741979

19751980

19761981
let compute_sources_and_sinks_to_keep ~configuration ~rule_filter =

source/interprocedural_analyses/taint/taintAnalysis.ml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ include Taint.Result.Register (struct
303303
Interprocedural.AnalysisResult.InitializedModels.create get_taint_models
304304

305305

306-
let analyze ~environment ~callable ~qualifier ~define ~sanitize ~modes existing_model =
306+
let analyze ~environment ~callable ~qualifier ~define ~sanitizers ~modes existing_model =
307307
let call_graph_of_define =
308308
Interprocedural.CallGraph.SharedMemory.get_or_compute
309309
~callable
@@ -331,7 +331,7 @@ include Taint.Result.Register (struct
331331
let model =
332332
let open Domains in
333333
let forward =
334-
match sanitize.Sanitize.sources with
334+
match sanitizers.Sanitizers.global.sources with
335335
| Some Sanitize.AllSources -> empty_model.forward
336336
| Some (Sanitize.SpecificSources sanitized_sources) ->
337337
let { Forward.source_taint } = forward in
@@ -348,12 +348,12 @@ include Taint.Result.Register (struct
348348
| None -> forward
349349
in
350350
let taint_in_taint_out =
351-
match sanitize.Sanitize.tito with
351+
match sanitizers.Sanitizers.global.tito with
352352
| Some AllTito -> empty_model.backward.taint_in_taint_out
353353
| _ -> backward.taint_in_taint_out
354354
in
355355
let sink_taint =
356-
match sanitize.Sanitize.sinks with
356+
match sanitizers.Sanitizers.global.sinks with
357357
| Some Sanitize.AllSinks -> empty_model.backward.sink_taint
358358
| Some (Sanitize.SpecificSinks sanitized_sinks) ->
359359
let { Backward.sink_taint; _ } = backward in
@@ -367,7 +367,7 @@ include Taint.Result.Register (struct
367367
~f:(fun ~key:_ ~data:source_state state -> BackwardState.join source_state state)
368368
| None -> backward.sink_taint
369369
in
370-
{ forward; backward = { sink_taint; taint_in_taint_out }; sanitize; modes }
370+
{ forward; backward = { sink_taint; taint_in_taint_out }; sanitizers; modes }
371371
in
372372
result, model
373373

@@ -397,15 +397,15 @@ include Taint.Result.Register (struct
397397
| Some ({ modes; _ } as model) when ModeSet.contains Mode.SkipAnalysis modes ->
398398
let () = Log.info "Skipping taint analysis of %a" Target.pretty_print callable in
399399
[], model
400-
| Some ({ sanitize; modes; _ } as model) ->
401-
analyze ~callable ~environment ~qualifier ~define ~sanitize ~modes model
400+
| Some ({ sanitizers; modes; _ } as model) ->
401+
analyze ~callable ~environment ~qualifier ~define ~sanitizers ~modes model
402402
| None ->
403403
analyze
404404
~callable
405405
~environment
406406
~qualifier
407407
~define
408-
~sanitize:Domains.Sanitize.empty
408+
~sanitizers:Sanitizers.empty
409409
~modes:ModeSet.empty
410410
empty_model
411411

source/interprocedural_analyses/taint/taintResult.ml

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,41 @@ module Backward = struct
109109
&& BackwardState.less_or_equal ~left:tito_next ~right:tito_previous
110110
end
111111

112+
module Sanitizers = struct
113+
type model = {
114+
(* Sanitizers applying to all parameters and the return value. *)
115+
global: Sanitize.t;
116+
(* Map from parameter or return value to sanitizers. *)
117+
roots: SanitizeRootMap.t;
118+
}
119+
120+
let pp_model formatter { global; roots } =
121+
Format.fprintf
122+
formatter
123+
" Global Sanitizer: %s\n Sanitizers: %s"
124+
(json_to_string ~indent:" " (Sanitize.to_json global))
125+
(json_to_string ~indent:" " (SanitizeRootMap.to_json roots))
126+
127+
128+
let show_model = Format.asprintf "%a" pp_model
129+
130+
let empty = { global = Sanitize.empty; roots = SanitizeRootMap.bottom }
131+
132+
let is_empty_model { global; roots } = Sanitize.is_empty global && SanitizeRootMap.is_bottom roots
133+
134+
let join
135+
{ global = global_left; roots = roots_left }
136+
{ global = global_right; roots = roots_right }
137+
=
138+
{
139+
global = Sanitize.join global_left global_right;
140+
roots = SanitizeRootMap.join roots_left roots_right;
141+
}
142+
143+
144+
let widen ~iteration:_ ~previous ~next = join previous next
145+
end
146+
112147
module Mode = struct
113148
let name = "modes"
114149

@@ -150,19 +185,20 @@ end
150185
type call_model = {
151186
forward: Forward.model;
152187
backward: Backward.model;
153-
sanitize: Sanitize.t;
188+
sanitizers: Sanitizers.model;
154189
modes: ModeSet.t;
155190
}
156191

157-
let pp_call_model formatter { forward; backward; sanitize; modes } =
192+
let pp_call_model formatter { forward; backward; sanitizers; modes } =
158193
Format.fprintf
159194
formatter
160-
"%a\n%a\n Sanitize: %s\n%a"
195+
"%a\n%a\n%a\n%a"
161196
Forward.pp_model
162197
forward
163198
Backward.pp_model
164199
backward
165-
(Sanitize.to_json sanitize |> json_to_string ~indent:" ")
200+
Sanitizers.pp_model
201+
sanitizers
166202
ModeSet.pp_model
167203
modes
168204

@@ -175,7 +211,7 @@ let empty_skip_model =
175211
{
176212
forward = Forward.empty;
177213
backward = Backward.empty;
178-
sanitize = Sanitize.empty;
214+
sanitizers = Sanitizers.empty;
179215
modes = ModeSet.singleton SkipAnalysis;
180216
}
181217

@@ -195,7 +231,7 @@ module ResultArgument = struct
195231
{
196232
forward = Forward.obscure;
197233
backward = Backward.obscure;
198-
sanitize = Sanitize.empty;
234+
sanitizers = Sanitizers.empty;
199235
modes = ModeSet.singleton Obscure;
200236
}
201237

@@ -204,29 +240,29 @@ module ResultArgument = struct
204240
{
205241
forward = Forward.empty;
206242
backward = Backward.empty;
207-
sanitize = Sanitize.empty;
243+
sanitizers = Sanitizers.empty;
208244
modes = ModeSet.empty;
209245
}
210246

211247

212-
let is_empty_model ~with_modes { forward; backward; sanitize; modes } =
248+
let is_empty_model ~with_modes { forward; backward; sanitizers; modes } =
213249
Forward.is_empty_model forward
214250
&& Backward.is_empty_model backward
215-
&& Sanitize.is_empty sanitize
251+
&& Sanitizers.is_empty_model sanitizers
216252
&& ModeSet.equal with_modes modes
217253

218254

219-
let should_externalize_model { forward; backward; sanitize; _ } =
255+
let should_externalize_model { forward; backward; sanitizers; _ } =
220256
(not (Forward.is_empty_model forward))
221257
|| (not (Backward.is_empty_model backward))
222-
|| not (Sanitize.is_empty sanitize)
258+
|| not (Sanitizers.is_empty_model sanitizers)
223259

224260

225261
let join ~iteration:_ left right =
226262
{
227263
forward = Forward.join left.forward right.forward;
228264
backward = Backward.join left.backward right.backward;
229-
sanitize = Sanitize.join left.sanitize right.sanitize;
265+
sanitizers = Sanitizers.join left.sanitizers right.sanitizers;
230266
modes = ModeSet.join left.modes right.modes;
231267
}
232268

@@ -235,7 +271,7 @@ module ResultArgument = struct
235271
{
236272
forward = Forward.widen ~iteration ~previous:previous.forward ~next:next.forward;
237273
backward = Backward.widen ~iteration ~previous:previous.backward ~next:next.backward;
238-
sanitize = Sanitize.join previous.sanitize next.sanitize;
274+
sanitizers = Sanitizers.widen ~iteration ~previous:previous.sanitizers ~next:next.sanitizers;
239275
modes = ModeSet.widen ~iteration ~prev:previous.modes ~next:next.modes;
240276
}
241277

@@ -246,7 +282,12 @@ module ResultArgument = struct
246282

247283

248284
let strip_for_callsite
249-
{ forward = { source_taint }; backward = { sink_taint; taint_in_taint_out }; sanitize; modes }
285+
{
286+
forward = { source_taint };
287+
backward = { sink_taint; taint_in_taint_out };
288+
sanitizers;
289+
modes;
290+
}
250291
=
251292
(* Remove positions and other info that are not needed at call site *)
252293
let source_taint =
@@ -279,13 +320,18 @@ module ResultArgument = struct
279320
Map
280321
~f:Domains.TraceInfo.strip_for_callsite
281322
in
282-
{ forward = { source_taint }; backward = { sink_taint; taint_in_taint_out }; sanitize; modes }
323+
{ forward = { source_taint }; backward = { sink_taint; taint_in_taint_out }; sanitizers; modes }
283324

284325

285326
let model_to_json
286327
~filename_lookup
287328
callable
288-
{ forward = { source_taint }; backward = { sink_taint; taint_in_taint_out }; sanitize; modes }
329+
{
330+
forward = { source_taint };
331+
backward = { sink_taint; taint_in_taint_out };
332+
sanitizers = { global = global_sanitizer; roots = root_sanitizers };
333+
modes;
334+
}
289335
=
290336
let callable_name = Interprocedural.Target.external_target_name callable in
291337
let model_json = ["callable", `String callable_name] in
@@ -308,8 +354,14 @@ module ResultArgument = struct
308354
model_json
309355
in
310356
let model_json =
311-
if not (Sanitize.is_empty sanitize) then
312-
model_json @ ["sanitize", Sanitize.to_json sanitize]
357+
if not (Sanitize.is_empty global_sanitizer) then
358+
model_json @ ["global_sanitizer", Sanitize.to_json global_sanitizer]
359+
else
360+
model_json
361+
in
362+
let model_json =
363+
if not (SanitizeRootMap.is_bottom root_sanitizers) then
364+
model_json @ ["sanitizers", SanitizeRootMap.to_json root_sanitizers]
313365
else
314366
model_json
315367
in

0 commit comments

Comments
 (0)