You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
4.3 KiB

(*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! Utils
module F = Format
module L = Logging
(** Create a taint analysis from a trace domain *)
module Make (TraceDomain : Trace.S) = struct
module TaintDomain = AccessTree.Make (TraceDomain)
module IdMapDomain = IdAccessPathMapDomain
module Domain = struct
type astate =
{
access_tree : TaintDomain.astate; (* mapping of access paths to trace sets *)
id_map : IdMapDomain.astate; (* mapping of id's to access paths for normalization *)
}
let initial =
let access_tree = TaintDomain.initial in
let id_map = IdMapDomain.initial in
{ access_tree; id_map; }
let (<=) ~lhs ~rhs =
if lhs == rhs
then true
else
TaintDomain.(<=) ~lhs:lhs.access_tree ~rhs:rhs.access_tree &&
IdMapDomain.(<=) ~lhs:lhs.id_map ~rhs:rhs.id_map
let join astate1 astate2 =
if astate1 == astate2
then astate1
else
let access_tree = TaintDomain.join astate1.access_tree astate2.access_tree in
let id_map = IdMapDomain.join astate1.id_map astate2.id_map in
{ access_tree; id_map; }
let widen ~prev ~next ~num_iters =
if prev == next
then prev
else
let access_tree =
TaintDomain.widen ~prev:prev.access_tree ~next:next.access_tree ~num_iters in
let id_map = IdMapDomain.widen ~prev:prev.id_map ~next:next.id_map ~num_iters in
{ access_tree; id_map; }
let pp fmt { access_tree; id_map; } =
F.fprintf fmt "(%a, %a)" TaintDomain.pp access_tree IdMapDomain.pp id_map
end
module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG
module Domain = Domain
type formal_list = AccessPath.base list
type extras = formal_list
let add_source source ret_id ret_typ access_tree =
let trace = TraceDomain.of_source source in
let id_ap = AccessPath.Exact (AccessPath.of_id ret_id ret_typ) in
TaintDomain.add_trace id_ap trace access_tree
let exec_instr ({ Domain.access_tree; } as astate) proc_data _ instr =
match instr with
| Sil.Call (ret_ids, Const (Cfun callee_pname), _, callee_loc, _) ->
let call_site = CallSite.make callee_pname callee_loc in
let ret_typ =
match callee_pname with
| Procname.Java java_pname ->
let ret_typ_str = Procname.java_get_return_type java_pname in
Option.default
Typ.Tvoid
(Tenv.lookup_java_typ_from_string (proc_data.ProcData.tenv) ret_typ_str)
| Procname.C _ ->
Typ.Tvoid (* for tests only, since tests use C-style procnames *)
| _ ->
failwith "Unimp: looking up return type for non-Java procedure" in
let astate_with_source =
match TraceDomain.Source.get call_site, ret_ids with
| [(0, source)], [ret_id] ->
let access_tree' = add_source source ret_id ret_typ access_tree in
{ astate with Domain.access_tree = access_tree'; }
| [], _ | _, [] ->
astate
| _ ->
(* this is allowed by SIL, but not currently used in any frontends *)
failwith "Unimp: handling multiple return ids" in
astate_with_source
| Sil.Call _ ->
failwith "Unimp: non-pname call expressions"
| Sil.Letderef _ | Set _ ->
failwith "Unimp: assignment, load, and store"
| Sil.Prune _ | Remove_temps _ | Nullify _ | Abstract _ | Stackop _ | Declare_locals _ ->
astate
end
module Analyzer = AbstractInterpreter.Make
(ProcCfg.Normal)
(Scheduler.ReversePostorder)
(TransferFunctions)
let checker { Callbacks.proc_name; proc_desc; tenv; } =
let formals =
let attrs = Cfg.Procdesc.get_attributes proc_desc in
IList.map
(fun (name, typ) -> AccessPath.base_of_pvar (Pvar.mk name proc_name) typ)
attrs.formals in
let proc_data = ProcData.make proc_desc tenv formals in
ignore (Analyzer.compute_post proc_data)
end