[quandary] support tainted formals

Summary:
We currently can only model the return values of functions as sources.
In order to model inputs of endpoints as sources, we need the capability to treat the formals of certain functions as sources too.
This diff adds that capability by adding a function for getting the tainted sources to the source module, then using that info in the analysis.

Reviewed By: jeremydubreil

Differential Revision: D4314738

fbshipit-source-id: dd7d423
master
Sam Blackshear 8 years ago committed by Facebook Github Bot
parent f3bd314c22
commit 06e0f6fbc9

@ -18,8 +18,9 @@ module type S = sig
val get_footprint_access_path: t -> AccessPath.t option val get_footprint_access_path: t -> AccessPath.t option
(** return Some (kind) if the call site is a taint source, None otherwise *)
val get : CallSite.t -> t option val get : CallSite.t -> t option
val get_tainted_formals : Procdesc.t -> (Mangled.t * Typ.t * t option) list
end end
module Dummy = struct module Dummy = struct
@ -37,8 +38,12 @@ module Dummy = struct
let make_footprint _ _ = assert false let make_footprint _ _ = assert false
let get_footprint_access_path _ = assert false let get_footprint_access_path _ = assert false
let get _ = None let get _ = None
let get_tainted_formals pdesc =
IList.map (fun (name, typ) -> name, typ, None) (Procdesc.get_formals pdesc)
module Kind = struct module Kind = struct
type nonrec t = t type nonrec t = t
let compare = compare let compare = compare

@ -18,8 +18,12 @@ module type S = sig
val get_footprint_access_path: t -> AccessPath.t option val get_footprint_access_path: t -> AccessPath.t option
(** return Some (kind) if the call site is a taint source, None otherwise *) (** return Some (source) if the call site is a taint source, None otherwise *)
val get : CallSite.t -> t option val get : CallSite.t -> t option
(** return each formal of the function paired with either Some(source) if the formal is a taint
source, or None if the formal is not a taint source *)
val get_tainted_formals : Procdesc.t -> (Mangled.t * Typ.t * t option) list
end end
module Dummy : S with type t = unit module Dummy : S with type t = unit

@ -79,6 +79,9 @@ module CppSource = struct
| pname -> | pname ->
failwithf "Non-C++ procname %a in C++ analysis@." Procname.pp pname failwithf "Non-C++ procname %a in C++ analysis@." Procname.pp pname
let get_tainted_formals pdesc =
IList.map (fun (name, typ) -> name, typ, None) (Procdesc.get_formals pdesc)
let with_callsite t callee_site = let with_callsite t callee_site =
{ t with site = callee_site; } { t with site = callee_site; }

@ -81,6 +81,41 @@ module JavaSource = struct
| pname when BuiltinDecl.is_declared pname -> None | pname when BuiltinDecl.is_declared pname -> None
| pname -> failwithf "Non-Java procname %a in Java analysis@." Procname.pp pname | pname -> failwithf "Non-Java procname %a in Java analysis@." Procname.pp pname
let get_tainted_formals pdesc =
let make_untainted (name, typ) =
name, typ, None in
let taint_formals_with_types type_strs kind pdesc formals =
let taint_formal_with_types ((formal_name, formal_typ) as formal) =
let matches_classname typ typ_str = match typ with
| Typ.Tptr (Tstruct typename, _) -> Typename.name typename = typ_str
| _ -> false in
if IList.mem matches_classname formal_typ type_strs
then
let site = CallSite.make (Procdesc.get_proc_name pdesc) (Procdesc.get_loc pdesc) in
formal_name, formal_typ, Some (make kind site)
else
make_untainted formal in
IList.map taint_formal_with_types formals in
let formals = Procdesc.get_formals pdesc in
match Procdesc.get_proc_name pdesc with
| Procname.Java java_pname ->
begin
match Procname.java_get_class_name java_pname, Procname.java_get_method java_pname with
| "codetoanalyze.java.quandary.TaintedFormals", "taintedContextBad" ->
taint_formals_with_types
["java.lang.Integer"; "java.lang.String"]
Other
pdesc
formals
| _ ->
IList.map make_untainted formals
end
| procname ->
failwithf
"Non-Java procedure %a where only Java procedures are expected"
Procname.pp procname
let with_callsite t callee_site = let with_callsite t callee_site =
{ t with site = callee_site; } { t with site = callee_site; }

@ -19,8 +19,8 @@ module Make (TaintSpecification : TaintSpec.S) = struct
module TaintDomain = TaintSpecification.AccessTree module TaintDomain = TaintSpecification.AccessTree
module IdMapDomain = IdAccessPathMapDomain module IdMapDomain = IdAccessPathMapDomain
(** map from formals to their position *) (** a map from a formal to its position and (optionally) whether we should treat it as a source *)
type formal_map = int AccessPath.BaseMap.t type formal_map = (int * TraceDomain.Source.t option) AccessPath.BaseMap.t
module Summary = Summary.Make(struct module Summary = Summary.Make(struct
type summary = QuandarySummary.t type summary = QuandarySummary.t
@ -90,13 +90,6 @@ module Make (TaintSpecification : TaintSpec.S) = struct
type extras = formal_map type extras = formal_map
let is_formal base formal_map =
AccessPath.BaseMap.mem base formal_map
let is_rooted_in_environment ap formal_map =
let root, _ = AccessPath.extract ap in
is_formal root formal_map || is_global root
let resolve_id id_map id = let resolve_id id_map id =
try Some (IdMapDomain.find id id_map) try Some (IdMapDomain.find id id_map)
with Not_found -> None with Not_found -> None
@ -116,8 +109,14 @@ module Make (TaintSpecification : TaintSpec.S) = struct
Some (TaintDomain.make_normal_leaf trace) in Some (TaintDomain.make_normal_leaf trace) in
let root, _ = AccessPath.extract access_path in let root, _ = AccessPath.extract access_path in
try try
let formal_num = AccessPath.BaseMap.find root proc_data.extras in let formal_num, taint_opt = AccessPath.BaseMap.find root proc_data.extras in
make_footprint_trace (make_footprint_access_path formal_num access_path) begin
match taint_opt with
| None ->
make_footprint_trace (make_footprint_access_path formal_num access_path)
| Some source ->
Some (TaintDomain.make_normal_leaf (TraceDomain.of_source source))
end
with Not_found -> with Not_found ->
if is_global root if is_global root
then make_footprint_trace access_path then make_footprint_trace access_path
@ -502,7 +501,7 @@ module Make (TaintSpecification : TaintSpec.S) = struct
(fun base node acc -> (fun base node acc ->
let base' = let base' =
try try
let formal_index = AccessPath.BaseMap.find base formal_map in let formal_index, _ = AccessPath.BaseMap.find base formal_map in
make_footprint_var formal_index, snd base make_footprint_var formal_index, snd base
with Not_found -> with Not_found ->
base in base in
@ -533,15 +532,15 @@ module Make (TaintSpecification : TaintSpec.S) = struct
let make_extras pdesc = let make_extras pdesc =
let pname = Procdesc.get_proc_name pdesc in let pname = Procdesc.get_proc_name pdesc in
let attrs = Procdesc.get_attributes pdesc in
let formals_with_nums = let formals_with_nums =
IList.mapi IList.mapi
(fun index (name, typ) -> (fun index (name, typ, taint_opt) ->
let pvar = Pvar.mk name pname in let pvar = Pvar.mk name pname in
AccessPath.base_of_pvar pvar typ, index) AccessPath.base_of_pvar pvar typ, index, taint_opt)
attrs.ProcAttributes.formals in (TraceDomain.Source.get_tainted_formals pdesc) in
IList.fold_left IList.fold_left
(fun formal_map (base, index) -> AccessPath.BaseMap.add base index formal_map) (fun formal_map (base, index, taint_opt) ->
AccessPath.BaseMap.add base (index, taint_opt) formal_map)
AccessPath.BaseMap.empty AccessPath.BaseMap.empty
formals_with_nums in formals_with_nums in

@ -45,6 +45,7 @@ module MockTrace = Trace.Make(struct
then Some site then Some site
else None else None
let get_tainted_formals _ = assert false
let is_footprint _ = false let is_footprint _ = false
let make_footprint _ = assert false let make_footprint _ = assert false
let get_footprint_access_path _ = assert false let get_footprint_access_path _ = assert false

@ -68,6 +68,7 @@ module MockSource = struct
let make_footprint _ _ = Footprint let make_footprint _ _ = Footprint
let get _ = assert false let get _ = assert false
let get_tainted_formals _ = []
let get_footprint_access_path _ = assert false let get_footprint_access_path _ = assert false
end end

@ -0,0 +1,56 @@
/*
* 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.
*/
package codetoanalyze.java.quandary;
import com.facebook.infer.builtins.InferTaint;
class Obj {
Object f;
}
public class TaintedFormals {
public void callSink(Object formal) {
InferTaint.inferSensitiveSink(formal);
}
// taintedFormal1 and taintedFormal2 were are modeled as tainted
public void taintedContextBad(String taintedFormal1, Boolean untaintedFormal, Integer taintedFormal2) {
InferTaint.inferSensitiveSink(taintedFormal1); // should report here
InferTaint.inferSensitiveSink(taintedFormal2); // should report here
callSink(taintedFormal1); // should report here
callSink(taintedFormal2); // should report here
InferTaint.inferSensitiveSink(untaintedFormal); // should not report here
}
public Object taintedContextBad(String taintedFormal) {
return taintedFormal;
}
public void callTaintedContextBad1(String formal) {
Object tainted = taintedContextBad(formal);
InferTaint.inferSensitiveSink(tainted);
}
public void callTaintedContextBad2() {
taintedContextBad(null, (Boolean) InferTaint.inferSecretSource(), null);
}
public void callTaintedContextOk1() {
taintedContextBad("foo", null, null);
}
// shouldn't report here, otherwise we will double report
public void callTaintedContextOk2() {
taintedContextBad(null, null, new Integer(1));
}
}

@ -175,4 +175,10 @@ codetoanalyze/java/quandary/Strings.java, void Strings.viaStringBufferIgnoreRetu
codetoanalyze/java/quandary/Strings.java, void Strings.viaStringBuilderBad(), 3, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Strings.java, void Strings.viaStringBuilderBad(), 3, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/Strings.java, void Strings.viaStringBuilderIgnoreReturnBad(), 5, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Strings.java, void Strings.viaStringBuilderIgnoreReturnBad(), 5, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/Strings.java, void Strings.viaStringBuilderSugarBad(), 2, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/Strings.java, void Strings.viaStringBuilderSugarBad(), 2, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/TaintedFormals.java, void TaintedFormals.callTaintedContextBad1(String), 2, QUANDARY_TAINT_ERROR, [return from Object TaintedFormals.taintedContextBad(String),return from Object TaintedFormals.taintedContextBad(String),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/TaintedFormals.java, void TaintedFormals.callTaintedContextBad2(), 1, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void TaintedFormals.taintedContextBad(String,Boolean,Integer),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/TaintedFormals.java, void TaintedFormals.taintedContextBad(String,Boolean,Integer), 1, QUANDARY_TAINT_ERROR, [return from void TaintedFormals.taintedContextBad(String,Boolean,Integer),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/TaintedFormals.java, void TaintedFormals.taintedContextBad(String,Boolean,Integer), 2, QUANDARY_TAINT_ERROR, [return from void TaintedFormals.taintedContextBad(String,Boolean,Integer),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/TaintedFormals.java, void TaintedFormals.taintedContextBad(String,Boolean,Integer), 3, QUANDARY_TAINT_ERROR, [return from void TaintedFormals.taintedContextBad(String,Boolean,Integer),call to void TaintedFormals.callSink(Object),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/TaintedFormals.java, void TaintedFormals.taintedContextBad(String,Boolean,Integer), 4, QUANDARY_TAINT_ERROR, [return from void TaintedFormals.taintedContextBad(String,Boolean,Integer),call to void TaintedFormals.callSink(Object),call to void InferTaint.inferSensitiveSink(Object)]
codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateViaUnknownConstructorBad(), 4, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)] codetoanalyze/java/quandary/UnknownCode.java, void UnknownCode.propagateViaUnknownConstructorBad(), 4, QUANDARY_TAINT_ERROR, [return from Object InferTaint.inferSecretSource(),call to void InferTaint.inferSensitiveSink(Object)]

Loading…
Cancel
Save