|
|
|
@ -357,6 +357,38 @@ module Make (TaintSpecification : TaintSpec.S) = struct
|
|
|
|
|
in
|
|
|
|
|
TaintDomain.trace_fold add_to_caller_tree summary caller_access_tree
|
|
|
|
|
|
|
|
|
|
let preprocess_exp exp =
|
|
|
|
|
(* hack: preprocessor for expressions to convert some literals into dummy field reads. needed in
|
|
|
|
|
Java when we want to us an R.id.whatever field as a source, but the compiler inlines the
|
|
|
|
|
field read because it's a static final constant *)
|
|
|
|
|
let convert_id_literal_to_read = function
|
|
|
|
|
| HilExp.Constant Const.Cint i as e
|
|
|
|
|
-> let int_value =
|
|
|
|
|
try IntLit.to_int i
|
|
|
|
|
with _ -> 0
|
|
|
|
|
in
|
|
|
|
|
(* heuristic to decide if this looks like a resource ID *)
|
|
|
|
|
if Int.abs int_value > 1000 then
|
|
|
|
|
(* convert this resource ID literal into a dummy field read *)
|
|
|
|
|
let dummy_pvar =
|
|
|
|
|
Pvar.mk_global
|
|
|
|
|
(Mangled.from_string
|
|
|
|
|
(F.sprintf "%s_%d" AndroidFramework.drawable_prefix int_value))
|
|
|
|
|
Pvar.TUExtern
|
|
|
|
|
in
|
|
|
|
|
HilExp.AccessPath ((Var.of_pvar dummy_pvar, Typ.mk (Typ.Tint Typ.IInt)), [])
|
|
|
|
|
else e
|
|
|
|
|
| e
|
|
|
|
|
-> e
|
|
|
|
|
in
|
|
|
|
|
convert_id_literal_to_read exp
|
|
|
|
|
|
|
|
|
|
(* avoid overhead of allocating new list in the (very) common case that preprocess is a no-op *)
|
|
|
|
|
let preprocess_exps exps =
|
|
|
|
|
if List.exists ~f:(fun exp -> not (phys_equal exp (preprocess_exp exp))) exps then
|
|
|
|
|
List.map ~f:preprocess_exp exps
|
|
|
|
|
else exps
|
|
|
|
|
|
|
|
|
|
let exec_instr (astate: Domain.astate) (proc_data: extras ProcData.t) _ (instr: HilInstr.t) =
|
|
|
|
|
(* not all sinks are function calls; we might want to treat an array or field access as a
|
|
|
|
|
sink too. do this by pretending an access is a call to a dummy function and using the
|
|
|
|
@ -382,13 +414,11 @@ module Make (TaintSpecification : TaintSpec.S) = struct
|
|
|
|
|
List.fold ~f:add_sinks_for_access ~init:astate accesses
|
|
|
|
|
in
|
|
|
|
|
let add_sources_for_access_path ((var, _), _ as ap) loc astate =
|
|
|
|
|
L.d_strln "adding sources for access path" ;
|
|
|
|
|
if Var.is_global var then
|
|
|
|
|
let dummy_call_site = CallSite.make BuiltinDecl.__global_access loc in
|
|
|
|
|
match TraceDomain.Source.get dummy_call_site [HilExp.AccessPath ap] proc_data.tenv with
|
|
|
|
|
| Some {TraceDomain.Source.source}
|
|
|
|
|
-> L.d_strln "Got source to add" ;
|
|
|
|
|
let access_path = AccessPath.Abs.Exact ap in
|
|
|
|
|
-> let access_path = AccessPath.Abs.Exact ap in
|
|
|
|
|
let trace, subtree =
|
|
|
|
|
Option.value ~default:TaintDomain.empty_node
|
|
|
|
|
(TaintDomain.get_node access_path astate)
|
|
|
|
@ -400,7 +430,6 @@ module Make (TaintSpecification : TaintSpec.S) = struct
|
|
|
|
|
else astate
|
|
|
|
|
in
|
|
|
|
|
let add_sources_sinks_for_exp exp loc astate =
|
|
|
|
|
L.d_strln "adding source/sinks" ;
|
|
|
|
|
match exp with
|
|
|
|
|
| HilExp.AccessPath access_path
|
|
|
|
|
-> add_sinks_for_access_path access_path loc astate
|
|
|
|
@ -428,12 +457,15 @@ module Make (TaintSpecification : TaintSpec.S) = struct
|
|
|
|
|
`return null` in a void function *)
|
|
|
|
|
astate
|
|
|
|
|
| Assign (lhs_access_path, rhs_exp, loc)
|
|
|
|
|
-> add_sources_sinks_for_exp rhs_exp loc astate
|
|
|
|
|
-> let rhs_exp = preprocess_exp rhs_exp in
|
|
|
|
|
add_sources_sinks_for_exp rhs_exp loc astate
|
|
|
|
|
|> add_sinks_for_access_path lhs_access_path loc |> exec_write lhs_access_path rhs_exp
|
|
|
|
|
| Assume (assume_exp, _, _, loc)
|
|
|
|
|
-> add_sources_sinks_for_exp assume_exp loc astate
|
|
|
|
|
-> let assume_exp = preprocess_exp assume_exp in
|
|
|
|
|
add_sources_sinks_for_exp assume_exp loc astate
|
|
|
|
|
| Call (ret_opt, Direct called_pname, actuals, call_flags, callee_loc)
|
|
|
|
|
-> let astate =
|
|
|
|
|
-> let actuals = preprocess_exps actuals in
|
|
|
|
|
let astate =
|
|
|
|
|
List.fold
|
|
|
|
|
~f:(fun acc exp -> add_sources_sinks_for_exp exp callee_loc acc)
|
|
|
|
|
actuals ~init:astate
|
|
|
|
|