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.
226 lines
7.0 KiB
226 lines
7.0 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
|
|
|
|
module JavaSource = struct
|
|
|
|
module Kind = struct
|
|
type t =
|
|
| PrivateData (** private user or device-specific data *)
|
|
| Footprint of AccessPath.t (** source that was read from the environment. *)
|
|
| Intent
|
|
| Other (** for testing or uncategorized sources *)
|
|
|
|
let compare sk1 sk2 = match sk1, sk2 with
|
|
| PrivateData, PrivateData -> 0
|
|
| Footprint ap1, Footprint ap2 -> AccessPath.compare ap1 ap2
|
|
| _ -> tags_compare sk1 sk2
|
|
|
|
let pp fmt = function
|
|
| Intent -> F.fprintf fmt "Intent"
|
|
| PrivateData -> F.fprintf fmt "PrivateData"
|
|
| Footprint ap -> F.fprintf fmt "Footprint[%a]" AccessPath.pp ap
|
|
| Other -> F.fprintf fmt "Other"
|
|
end
|
|
|
|
type t =
|
|
{
|
|
kind : Kind.t;
|
|
site : CallSite.t;
|
|
}
|
|
|
|
let is_footprint t = match t.kind with
|
|
| Kind.Footprint _ -> true
|
|
| _ -> false
|
|
|
|
let get_footprint_access_path t = match t.kind with
|
|
| Kind.Footprint access_path -> Some access_path
|
|
| _ -> None
|
|
|
|
let call_site t =
|
|
t.site
|
|
|
|
let kind t =
|
|
t.kind
|
|
|
|
let make kind site =
|
|
{ site; kind; }
|
|
|
|
let make_footprint ap site =
|
|
{ kind = Kind.Footprint ap; site; }
|
|
|
|
let get site = match CallSite.pname site with
|
|
| Procname.Java pname ->
|
|
begin
|
|
match Procname.java_get_class_name pname, Procname.java_get_method pname with
|
|
| "android.content.Intent", ("parseUri" | "parseIntent") ->
|
|
Some (make Intent site)
|
|
| "android.content.SharedPreferences", "getString" ->
|
|
Some (make PrivateData site)
|
|
| "android.location.Location",
|
|
("getAltitude" | "getBearing" | "getLatitude" | "getLongitude" | "getSpeed") ->
|
|
Some (make PrivateData site)
|
|
| "android.telephony.TelephonyManager",
|
|
("getDeviceId" |
|
|
"getLine1Number" |
|
|
"getSimSerialNumber" |
|
|
"getSubscriberId" |
|
|
"getVoiceMailNumber") ->
|
|
Some (make PrivateData site)
|
|
| "com.facebook.infer.builtins.InferTaint", "inferSecretSource" ->
|
|
Some (make Other site)
|
|
| _ ->
|
|
None
|
|
end
|
|
| pname when BuiltinDecl.is_declared pname -> None
|
|
| pname -> failwithf "Non-Java procname %a in Java analysis@." Procname.pp pname
|
|
|
|
let to_callee t callee_site =
|
|
{ t with site = callee_site; }
|
|
|
|
let compare src1 src2 =
|
|
Kind.compare src1.kind src2.kind
|
|
|> next CallSite.compare src1.site src2.site
|
|
|
|
let pp fmt s =
|
|
F.fprintf fmt "%a(%a)" Kind.pp s.kind CallSite.pp s.site
|
|
|
|
module Set = PrettyPrintable.MakePPSet(struct
|
|
type nonrec t = t
|
|
let compare = compare
|
|
let pp_element = pp
|
|
end)
|
|
end
|
|
|
|
module JavaSink = struct
|
|
|
|
module Kind = struct
|
|
type t =
|
|
| Intent (** sink that trusts an Intent *)
|
|
| Logging (** sink that logs one or more of its arguments *)
|
|
| Other (** for testing or uncategorized sinks *)
|
|
|
|
let compare snk1 snk2 = tags_compare snk1 snk2
|
|
|
|
let pp fmt = function
|
|
| Intent -> F.fprintf fmt "Intent"
|
|
| Logging -> F.fprintf fmt "Logging"
|
|
| Other -> F.fprintf fmt "Other"
|
|
end
|
|
|
|
type t =
|
|
{
|
|
kind : Kind.t;
|
|
site : CallSite.t;
|
|
}
|
|
|
|
let kind t =
|
|
t.kind
|
|
|
|
let call_site t =
|
|
t.site
|
|
|
|
let make kind site =
|
|
{ kind; site; }
|
|
|
|
let get site _ =
|
|
(* taint all the inputs of [pname]. for non-static procedures, taints the "this" parameter only
|
|
if [taint_this] is true. *)
|
|
let taint_all ?(taint_this=false) pname kind site ~report_reachable =
|
|
let params =
|
|
let all_params = Procname.java_get_parameters pname in
|
|
if Procname.java_is_static (CallSite.pname site) || taint_this
|
|
then all_params
|
|
else IList.tl all_params in
|
|
IList.mapi
|
|
(fun param_num _ -> Sink.make_sink_param (make kind site) param_num ~report_reachable)
|
|
params in
|
|
(* taint the nth non-"this" parameter (0-indexed) *)
|
|
let taint_nth n kind site ~report_reachable =
|
|
let first_index = if Procname.java_is_static (CallSite.pname site) then n else n + 1 in
|
|
[Sink.make_sink_param (make kind site) first_index ~report_reachable] in
|
|
match CallSite.pname site with
|
|
| Procname.Java pname ->
|
|
begin
|
|
match Procname.java_get_class_name pname, Procname.java_get_method pname with
|
|
| ("android.app.Activity" | "android.content.ContextWrapper" | "android.content.Context"),
|
|
("bindService" |
|
|
"sendBroadcast" |
|
|
"sendBroadcastAsUser" |
|
|
"sendOrderedBroadcast" |
|
|
"sendStickyBroadcast" |
|
|
"sendStickyBroadcastAsUser" |
|
|
"sendStickyOrderedBroadcast" |
|
|
"sendStickyOrderedBroadcastAsUser" |
|
|
"startActivities" |
|
|
"startActivity" |
|
|
"startActivityForResult" |
|
|
"startActivityIfNeeded" |
|
|
"startNextMatchingActivity" |
|
|
"startService") ->
|
|
taint_nth 0 Intent site ~report_reachable:true
|
|
| "android.app.Activity", ("startActivityFromChild" | "startActivityFromFragment") ->
|
|
taint_nth 1 Intent site ~report_reachable:true
|
|
| "android.util.Log", ("e" | "println" | "w" | "wtf") ->
|
|
taint_all pname Logging site ~report_reachable:true
|
|
| "com.facebook.infer.builtins.InferTaint", "inferSensitiveSink" ->
|
|
[Sink.make_sink_param (make Other site) 0 ~report_reachable:false]
|
|
| _ ->
|
|
[]
|
|
end
|
|
| pname when BuiltinDecl.is_declared pname -> []
|
|
| pname -> failwithf "Non-Java procname %a in Java analysis@." Procname.pp pname
|
|
|
|
let to_callee t callee_site =
|
|
{ t with site = callee_site; }
|
|
|
|
let compare snk1 snk2 =
|
|
Kind.compare snk1.kind snk2.kind
|
|
|> next CallSite.compare snk1.site snk2.site
|
|
|
|
let pp fmt s =
|
|
F.fprintf fmt "%a(%a)" Kind.pp s.kind CallSite.pp s.site
|
|
|
|
module Set = PrettyPrintable.MakePPSet(struct
|
|
type nonrec t = t
|
|
let compare = compare
|
|
let pp_element = pp
|
|
end)
|
|
end
|
|
|
|
include
|
|
Trace.Make(struct
|
|
module Source = JavaSource
|
|
module Sink = JavaSink
|
|
|
|
let should_report source sink =
|
|
match Source.kind source, Sink.kind sink with
|
|
| Source.Kind.Other, Sink.Kind.Other
|
|
| Source.Kind.PrivateData, Sink.Kind.Logging ->
|
|
true
|
|
| Source.Kind.Intent, Sink.Kind.Intent ->
|
|
true
|
|
| _ ->
|
|
false
|
|
|
|
let get_reportable_exn source sink passthroughs =
|
|
let pp_error fmt () =
|
|
F.fprintf
|
|
fmt
|
|
"Error: %a -> %a via %a"
|
|
Source.pp source Sink.pp sink Passthrough.Set.pp passthroughs in
|
|
let msg = Localise.to_string Localise.quandary_taint_error in
|
|
let description = pp_to_string pp_error () in
|
|
Exceptions.Checkers (msg, Localise.verbatim_desc description)
|
|
end)
|