source/interprocedural_analyses/taint/globalModel.ml (131 lines of code) (raw):
(*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open Core
open Ast
open Analysis
open Expression
open Pyre
open Domains
module CallGraph = Interprocedural.CallGraph
type t = {
models: Model.WithCallTarget.t list;
resolution: Resolution.t;
location: Location.WithModule.t;
interval: Interprocedural.ClassInterval.t;
}
let get_global_targets ~call_graph ~expression =
match Node.value expression with
| Expression.Name (Name.Identifier identifier) ->
CallGraph.DefineCallGraph.resolve_identifier
call_graph
~location:(Node.location expression)
~identifier
>>| (fun { global_targets } -> global_targets)
|> Option.value ~default:[]
| Expression.Name (Name.Attribute { attribute; _ }) ->
CallGraph.DefineCallGraph.resolve_attribute_access
call_graph
~location:(Node.location expression)
~attribute
>>| (fun { global_targets; _ } -> global_targets)
|> Option.value ~default:[]
| _ -> []
let from_expression ~resolution ~call_graph ~qualifier ~expression ~interval =
let fetch_model ({ CallGraph.CallTarget.target; _ } as call_target) =
let model = CallModel.at_callsite ~resolution ~call_target:target ~arguments:[] in
{ Model.WithCallTarget.model; call_target }
in
let models = get_global_targets ~call_graph ~expression |> List.map ~f:fetch_model in
let location = Node.location expression |> Location.with_module ~module_reference:qualifier in
{ models; resolution; location; interval }
let global_root =
AccessPath.Root.PositionalParameter { position = 0; name = "$global"; positional_only = false }
let get_source { models; resolution; location; interval } =
let to_source
existing
{
Model.WithCallTarget.call_target = { target; _ };
model = { Model.forward = { Model.Forward.source_taint }; _ };
_;
}
=
ForwardState.read ~root:AccessPath.Root.LocalResult ~path:[] source_taint
|> ForwardState.Tree.apply_call
~resolution
~location
~callee:(Some target)
~arguments:[]
~port:AccessPath.Root.LocalResult
~is_self_call:false
~caller_class_interval:interval
~receiver_class_interval:Interprocedural.ClassInterval.top
|> ForwardState.Tree.join existing
in
List.fold ~init:ForwardState.Tree.bottom ~f:to_source models
let get_sinks { models; resolution; location; interval } =
let to_sink_tree_with_identifier
{
Model.WithCallTarget.call_target = { target; _ } as call_target;
model = { Model.backward = { Model.Backward.sink_taint; _ }; _ };
_;
}
=
let sink_tree =
BackwardState.read ~root:global_root ~path:[] sink_taint
|> BackwardState.Tree.apply_call
~resolution
~location
~callee:(Some target)
~arguments:[]
~port:AccessPath.Root.LocalResult
~is_self_call:false
~caller_class_interval:interval
~receiver_class_interval:Interprocedural.ClassInterval.top
in
{ Issue.SinkTreeWithHandle.sink_tree; handle = Issue.SinkHandle.make_global ~call_target }
in
List.map ~f:to_sink_tree_with_identifier models |> Issue.SinkTreeWithHandle.filter_bottom
let get_tito { models; _ } =
let to_tito
existing
{
Model.WithCallTarget.model =
{ Model.backward = { Model.Backward.taint_in_taint_out; _ }; _ };
_;
}
=
BackwardState.read ~root:global_root ~path:[] taint_in_taint_out
|> BackwardState.Tree.join existing
in
List.fold ~init:BackwardState.Tree.bottom ~f:to_tito models
let get_sanitize { models; _ } =
let get_sanitize
existing
{ Model.WithCallTarget.model = { Model.sanitizers = { global = sanitize; _ }; _ }; _ }
=
Sanitize.join sanitize existing
in
List.fold ~init:Sanitize.empty ~f:get_sanitize models
let get_modes { models; _ } =
let get_modes existing { Model.WithCallTarget.model = { Model.modes; _ }; _ } =
Model.ModeSet.join modes existing
in
List.fold ~init:Model.ModeSet.empty ~f:get_modes models
let is_sanitized { models; _ } =
let is_sanitized_model
{ Model.WithCallTarget.model = { Model.sanitizers = { global = sanitize; _ }; _ }; _ }
=
match sanitize with
| {
sources = Some SanitizeSources.All;
sinks = Some SanitizeSinks.All;
tito = Some SanitizeTito.All;
} ->
true
| _ -> false
in
List.exists ~f:is_sanitized_model models