Summary: Using a dedicated abstract domain, like Quandary does, is more suitable for taint analysis. Reviewed By: sblackshear Differential Revision: D5473794 fbshipit-source-id: c917417master
parent
fd4fbe163c
commit
f49d292c3b
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - 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 android.content;
|
|
||||||
|
|
||||||
import com.facebook.infer.builtins.InferBuiltins;
|
|
||||||
|
|
||||||
public class ContentValues {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We want to treat this as a sink for both privacy and security purposes.
|
|
||||||
*
|
|
||||||
* Privacy: The purpose of ContentValues is to feed information into a ContentProvider, a core
|
|
||||||
* Android component that can expose data for other Android applications to query. Thus, you do
|
|
||||||
* not want secret information to flow into ContentValues because you don't want to give other
|
|
||||||
* apps an interface that lets them query your secret information. There's a possibility for false
|
|
||||||
* positives here because ContentProviders can control access to information via permissions, but
|
|
||||||
* in general it's just a bad idea to let secret info into a ContentProvider.
|
|
||||||
*
|
|
||||||
* Security: You don't want untrusted external content to flow into ContentValues because it may
|
|
||||||
* be used to store data in a ContentProvider, potentially giving an external app control over
|
|
||||||
* what goes into the database backing the ContentProvider/giving them direct access to make
|
|
||||||
* queries on your content provider (rather than exposing a small set of trusted queries, which is
|
|
||||||
* what should be done). This could have any number of security implications depending on how the
|
|
||||||
* ContentProvider is used.
|
|
||||||
**/
|
|
||||||
public void put(String key, String value) {
|
|
||||||
InferBuiltins.__check_untainted(key);
|
|
||||||
InferBuiltins.__check_untainted(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - 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 javax.net;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
import com.facebook.infer.builtins.InferBuiltins;
|
|
||||||
|
|
||||||
public class SocketFactory {
|
|
||||||
|
|
||||||
// using recency abstraction to remember the last Socket created
|
|
||||||
private static Socket sLast;
|
|
||||||
|
|
||||||
public static Socket getLastSocket() {
|
|
||||||
return sLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
// proxy for Socket of undefined type
|
|
||||||
private native Socket genSocket();
|
|
||||||
|
|
||||||
private Socket returnAllocatedSocket() {
|
|
||||||
Socket socket = genSocket();
|
|
||||||
InferBuiltins.assume_allocated(socket);
|
|
||||||
sLast = socket;
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Socket createSocket() {
|
|
||||||
Socket socket = returnAllocatedSocket();
|
|
||||||
InferBuiltins.__set_taint_attribute(socket, "UnverifiedSSLSocket");
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the methods below are abstract methods in the actual Java class, but we need to implement it
|
|
||||||
// explicitly due to Infer's dynamic dispatch woes
|
|
||||||
public Socket createSocket(InetAddress addr, int i) throws IOException {
|
|
||||||
return this.createSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Socket createSocket(InetAddress addr1, int i, InetAddress addr2, int j)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
return this.createSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Socket createSocket(String s, int i) throws IOException {
|
|
||||||
return this.createSocket();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Socket createSocket(String s, int i, InetAddress addr, int j) throws IOException {
|
|
||||||
return this.createSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015 - 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 javax.net.ssl;
|
|
||||||
|
|
||||||
import java.net.Socket;
|
|
||||||
import javax.net.SocketFactory;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
|
|
||||||
import com.facebook.infer.builtins.InferBuiltins;
|
|
||||||
import com.facebook.infer.builtins.InferUndefined;
|
|
||||||
|
|
||||||
public class HostnameVerifier {
|
|
||||||
|
|
||||||
public boolean verify(
|
|
||||||
String hostname,
|
|
||||||
SSLSession session) {
|
|
||||||
|
|
||||||
Socket socket = SocketFactory.getLastSocket();
|
|
||||||
|
|
||||||
if (InferUndefined.boolean_undefined()) {
|
|
||||||
// verification succeeded; we can untaint the socket
|
|
||||||
InferBuiltins.__set_untaint_attribute(socket);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// verification failed; we can't untaint the socket
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,365 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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! IStd
|
|
||||||
module L = Logging
|
|
||||||
open PatternMatch
|
|
||||||
|
|
||||||
(* list of sources that return a tainted value *)
|
|
||||||
let sources0 =
|
|
||||||
[ (* for testing only *)
|
|
||||||
{ classname= "com.facebook.infer.builtins.InferTaint"
|
|
||||||
; method_name= "inferSecretSource"
|
|
||||||
; ret_type= "java.lang.Object"
|
|
||||||
; params= []
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Java }
|
|
||||||
; { classname= "com.facebook.infer.builtins.InferTaint"
|
|
||||||
; method_name= "inferSecretSourceUndefined"
|
|
||||||
; ret_type= "java.lang.Object"
|
|
||||||
; params= []
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Java }
|
|
||||||
; (* actual specs *)
|
|
||||||
{ classname= "android.content.SharedPreferences"
|
|
||||||
; method_name= "getString"
|
|
||||||
; ret_type= "java.lang.String"
|
|
||||||
; params= ["java.lang.String"; "java.lang.String"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_shared_preferences_data
|
|
||||||
; language= Config.Java }
|
|
||||||
; (* === iOS === *)
|
|
||||||
{ classname= "NSHTTPCookie"
|
|
||||||
; method_name= "value"
|
|
||||||
; ret_type= "NSString *"
|
|
||||||
; params= []
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Clang } ]
|
|
||||||
@ FbTaint.sources
|
|
||||||
|
|
||||||
(* list of (sensitive sinks, zero-indexed numbers of parameters that should not be tainted). note:
|
|
||||||
index 0 means "the first non-this/self argument"; we currently don't have a way to say "this/self
|
|
||||||
should not be tainted" with this form of specification *)
|
|
||||||
let sinks =
|
|
||||||
(* it's instance method *)
|
|
||||||
[ (* for testing only *)
|
|
||||||
( { classname= "com.facebook.infer.builtins.InferTaint"
|
|
||||||
; method_name= "inferSensitiveSink"
|
|
||||||
; ret_type= "void"
|
|
||||||
; params= ["java.lang.Object"]
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "com.facebook.infer.builtins.InferTaint"
|
|
||||||
; method_name= "inferSensitiveSinkUndefined"
|
|
||||||
; ret_type= "void"
|
|
||||||
; params= ["java.lang.Object"]
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; (* actual specs *)
|
|
||||||
( { classname= "android.util.Log"
|
|
||||||
; method_name= "d"
|
|
||||||
; ret_type= "int"
|
|
||||||
; params= ["java.lang.String"; "java.lang.String"]
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0; 1] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openInputStream"
|
|
||||||
; ret_type= "java.io.InputStream"
|
|
||||||
; params= ["android.net.Uri"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [1] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openOutputStream"
|
|
||||||
; ret_type= "java.io.OutputStream"
|
|
||||||
; params= ["android.net.Uri"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openOutputStream"
|
|
||||||
; ret_type= "java.io.OutputStream"
|
|
||||||
; params= ["android.net.Uri"; "java.lang.String"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openAssetFileDescriptor"
|
|
||||||
; ret_type= "android.content.res.AssetFileDescriptor"
|
|
||||||
; params= ["android.net.Uri"; "java.lang.String"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openAssetFileDescriptor"
|
|
||||||
; ret_type= "android.content.res.AssetFileDescriptor"
|
|
||||||
; params= ["android.net.Uri"; "java.lang.String"; "android.os.CancellationSignal"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openFileDescriptor"
|
|
||||||
; ret_type= "android.os.ParcelFileDescriptor"
|
|
||||||
; params= ["android.net.Uri"; "java.lang.String"; "android.os.CancellationSignal"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openFileDescriptor"
|
|
||||||
; ret_type= "android.os.ParcelFileDescriptor"
|
|
||||||
; params= ["android.net.Uri"; "java.lang.String"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openTypedAssetFileDescriptor"
|
|
||||||
; ret_type= "android.content.res.AssetFileDescriptor"
|
|
||||||
; params=
|
|
||||||
[ "android.net.Uri"
|
|
||||||
; "java.lang.String"
|
|
||||||
; "android.os.Bundle"
|
|
||||||
; "android.os.CancellationSignal" ]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; ( { classname= "android.content.ContentResolver"
|
|
||||||
; method_name= "openTypedAssetFileDescriptor"
|
|
||||||
; ret_type= "android.content.res.AssetFileDescriptor"
|
|
||||||
; params= ["android.net.Uri"; "java.lang.String"; "android.os.Bundle"]
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_privacy_annotation
|
|
||||||
; language= Config.Java }
|
|
||||||
, [0] )
|
|
||||||
; (* === iOS === *)
|
|
||||||
( { classname= "NSString"
|
|
||||||
; method_name= "stringWithFormat:"
|
|
||||||
; ret_type= "instancetype"
|
|
||||||
; params= []
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [-2] )
|
|
||||||
; ( { classname= "NSString"
|
|
||||||
; method_name= "stringWithUTF8String:"
|
|
||||||
; ret_type= "instancetype"
|
|
||||||
; params= []
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [-2] )
|
|
||||||
; ( { classname= "NSString"
|
|
||||||
; method_name= "localizedStringWithFormat:"
|
|
||||||
; ret_type= "instancetype"
|
|
||||||
; params= []
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [-2] )
|
|
||||||
; ( { classname= "NSString"
|
|
||||||
; method_name= "initWithFormat:"
|
|
||||||
; ret_type= "instancetype"
|
|
||||||
; params= []
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [-2] )
|
|
||||||
; ( { classname= "NSString"
|
|
||||||
; method_name= "stringWithString:"
|
|
||||||
; ret_type= "instancetype"
|
|
||||||
; params= []
|
|
||||||
; is_static= true
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [0] )
|
|
||||||
; (* ==== iOS for testing only ==== *)
|
|
||||||
( { classname= "ExampleViewController"
|
|
||||||
; method_name= "loadURL:trackingCodes:"
|
|
||||||
; ret_type= "void"
|
|
||||||
; params= []
|
|
||||||
; is_static= false
|
|
||||||
; taint_kind= Tk_unknown
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [1] ) ]
|
|
||||||
@ FbTaint.sinks
|
|
||||||
|
|
||||||
let functions_with_tainted_params =
|
|
||||||
[ (* ==== iOS for testing only ==== *)
|
|
||||||
( { classname= "ExampleDelegate"
|
|
||||||
; method_name= "application:openURL:sourceApplication:annotation:"
|
|
||||||
; ret_type= "BOOL"
|
|
||||||
; params= []
|
|
||||||
; is_static= false
|
|
||||||
; (* it's instance method *)
|
|
||||||
taint_kind= Tk_unknown
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [2] )
|
|
||||||
; (* actual specs *)
|
|
||||||
( { (* This method is a source in iOS as it get as parameter
|
|
||||||
a non trusted URL (openURL). The method the passes
|
|
||||||
it around and this URL may arrive unsanitized to
|
|
||||||
loadURL:trackingCodes: of FBWebViewController
|
|
||||||
which uses the URL. *)
|
|
||||||
classname= "AppDelegate"
|
|
||||||
; method_name= "application:openURL:sourceApplication:annotation:"
|
|
||||||
; ret_type= "BOOL"
|
|
||||||
; params= []
|
|
||||||
; is_static= false
|
|
||||||
; (* it's instance method *)
|
|
||||||
taint_kind= Tk_integrity_annotation
|
|
||||||
; language= Config.Clang }
|
|
||||||
, [2] ) ]
|
|
||||||
@ FbTaint.functions_with_tainted_params
|
|
||||||
|
|
||||||
(* turn string specificiation of Java method into a procname *)
|
|
||||||
let java_method_to_procname java_method =
|
|
||||||
Typ.Procname.Java
|
|
||||||
(Typ.Procname.java (Typ.Name.Java.from_string java_method.classname)
|
|
||||||
(Some (Typ.Procname.split_classname java_method.ret_type)) java_method.method_name
|
|
||||||
(List.map ~f:Typ.Procname.split_classname java_method.params)
|
|
||||||
(if java_method.is_static then Typ.Procname.Static else Typ.Procname.Non_Static))
|
|
||||||
|
|
||||||
(* turn string specificiation of an objc method into a procname *)
|
|
||||||
let objc_method_to_procname objc_method =
|
|
||||||
let method_kind = Typ.Procname.objc_method_kind_of_bool (not objc_method.is_static) in
|
|
||||||
let typename = Typ.Name.Objc.from_string objc_method.classname in
|
|
||||||
Typ.Procname.ObjC_Cpp
|
|
||||||
(Typ.Procname.objc_cpp typename objc_method.method_name method_kind Typ.NoTemplate
|
|
||||||
~is_generic_model:false)
|
|
||||||
|
|
||||||
let taint_spec_to_taint_info taint_spec =
|
|
||||||
let taint_source =
|
|
||||||
match taint_spec.language with
|
|
||||||
| Config.Clang
|
|
||||||
-> objc_method_to_procname taint_spec
|
|
||||||
| Config.Java
|
|
||||||
-> java_method_to_procname taint_spec
|
|
||||||
in
|
|
||||||
{PredSymb.taint_source= taint_source; taint_kind= taint_spec.taint_kind}
|
|
||||||
|
|
||||||
let sources = List.map ~f:taint_spec_to_taint_info sources0
|
|
||||||
|
|
||||||
let mk_pname_param_num methods =
|
|
||||||
List.map ~f:(fun (mname, param_num) -> (taint_spec_to_taint_info mname, param_num)) methods
|
|
||||||
|
|
||||||
let taint_sinks = mk_pname_param_num sinks
|
|
||||||
|
|
||||||
let func_with_tainted_params = mk_pname_param_num functions_with_tainted_params
|
|
||||||
|
|
||||||
let attrs_opt_get_annots = function
|
|
||||||
| Some attrs
|
|
||||||
-> attrs.ProcAttributes.method_annotation
|
|
||||||
| None
|
|
||||||
-> Annot.Method.empty
|
|
||||||
|
|
||||||
(* TODO: return a taint kind *)
|
|
||||||
|
|
||||||
(** returns true if [callee_pname] returns a tainted value *)
|
|
||||||
let returns_tainted callee_pname callee_attrs_opt =
|
|
||||||
let procname_matches taint_info =
|
|
||||||
Typ.Procname.equal taint_info.PredSymb.taint_source callee_pname
|
|
||||||
in
|
|
||||||
match List.find ~f:procname_matches sources with
|
|
||||||
| Some taint_info
|
|
||||||
-> Some taint_info.PredSymb.taint_kind
|
|
||||||
| None
|
|
||||||
-> let ret_annot, _ = attrs_opt_get_annots callee_attrs_opt in
|
|
||||||
if Annotations.ia_is_integrity_source ret_annot then Some PredSymb.Tk_integrity_annotation
|
|
||||||
else if Annotations.ia_is_privacy_source ret_annot then Some PredSymb.Tk_privacy_annotation
|
|
||||||
else None
|
|
||||||
|
|
||||||
let find_callee taint_infos callee_pname =
|
|
||||||
List.find
|
|
||||||
~f:(fun (taint_info, _) -> Typ.Procname.equal taint_info.PredSymb.taint_source callee_pname)
|
|
||||||
taint_infos
|
|
||||||
|
|
||||||
(** returns list of zero-indexed argument numbers of [callee_pname] that may be tainted *)
|
|
||||||
let accepts_sensitive_params callee_pname callee_attrs_opt =
|
|
||||||
match find_callee taint_sinks callee_pname with
|
|
||||||
| None
|
|
||||||
-> let _, param_annots = attrs_opt_get_annots callee_attrs_opt in
|
|
||||||
let offset = if Typ.Procname.java_is_static callee_pname then 0 else 1 in
|
|
||||||
let indices_and_annots =
|
|
||||||
List.mapi ~f:(fun param_num attr -> (param_num + offset, attr)) param_annots
|
|
||||||
in
|
|
||||||
let tag_tainted_indices acc (index, attr) =
|
|
||||||
if Annotations.ia_is_integrity_sink attr then (index, PredSymb.Tk_privacy_annotation)
|
|
||||||
:: acc
|
|
||||||
else if Annotations.ia_is_privacy_sink attr then (index, PredSymb.Tk_privacy_annotation)
|
|
||||||
:: acc
|
|
||||||
else acc
|
|
||||||
in
|
|
||||||
List.fold ~f:tag_tainted_indices ~init:[] indices_and_annots
|
|
||||||
| Some (taint_info, tainted_param_indices)
|
|
||||||
-> List.map
|
|
||||||
~f:(fun param_num -> (param_num, taint_info.PredSymb.taint_kind))
|
|
||||||
tainted_param_indices
|
|
||||||
|
|
||||||
(** returns list of zero-indexed parameter numbers of [callee_pname] that should be
|
|
||||||
considered tainted during symbolic execution *)
|
|
||||||
let tainted_params callee_pname =
|
|
||||||
match find_callee func_with_tainted_params callee_pname with
|
|
||||||
| Some (taint_info, tainted_param_indices)
|
|
||||||
-> List.map
|
|
||||||
~f:(fun param_num -> (param_num, taint_info.PredSymb.taint_kind))
|
|
||||||
tainted_param_indices
|
|
||||||
| None
|
|
||||||
-> []
|
|
||||||
|
|
||||||
let has_taint_annotation fieldname (struct_typ: Typ.Struct.t) =
|
|
||||||
let fld_has_taint_annot (fname, _, annot) =
|
|
||||||
Typ.Fieldname.equal fieldname fname
|
|
||||||
&& (Annotations.ia_is_privacy_source annot || Annotations.ia_is_integrity_source annot)
|
|
||||||
in
|
|
||||||
List.exists ~f:fld_has_taint_annot struct_typ.fields
|
|
||||||
|| List.exists ~f:fld_has_taint_annot struct_typ.statics
|
|
||||||
|
|
||||||
(* add tainting attributes to a list of paramenters *)
|
|
||||||
let get_params_to_taint tainted_param_nums formal_params =
|
|
||||||
let get_taint_kind index =
|
|
||||||
List.find ~f:(fun (taint_index, _) -> Int.equal index taint_index) tainted_param_nums
|
|
||||||
in
|
|
||||||
let collect_params_to_taint params_to_taint_acc (index, param) =
|
|
||||||
match get_taint_kind index with
|
|
||||||
| Some (_, taint_kind)
|
|
||||||
-> (param, taint_kind) :: params_to_taint_acc
|
|
||||||
| None
|
|
||||||
-> params_to_taint_acc
|
|
||||||
in
|
|
||||||
let numbered_params = List.mapi ~f:(fun i param -> (i, param)) formal_params in
|
|
||||||
List.fold ~f:collect_params_to_taint ~init:[] numbered_params
|
|
||||||
|
|
||||||
(* add tainting attribute to a pvar in a prop *)
|
|
||||||
let add_tainting_attribute tenv att pvar_param prop =
|
|
||||||
List.fold
|
|
||||||
~f:(fun prop_acc hpred ->
|
|
||||||
match hpred with
|
|
||||||
| Sil.Hpointsto (Exp.Lvar pvar, Sil.Eexp (rhs, _), _) when Pvar.equal pvar pvar_param
|
|
||||||
-> L.d_strln
|
|
||||||
("TAINT ANALYSIS: setting taint/untaint attribute of parameter " ^ Pvar.to_string pvar) ;
|
|
||||||
Attribute.add_or_replace tenv prop_acc (Apred (att, [rhs]))
|
|
||||||
| _
|
|
||||||
-> prop_acc)
|
|
||||||
~init:prop prop.Prop.sigma
|
|
@ -1,30 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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! IStd
|
|
||||||
|
|
||||||
val returns_tainted : Typ.Procname.t -> ProcAttributes.t option -> PredSymb.taint_kind option
|
|
||||||
(** returns true if [callee_pname] returns a tainted value *)
|
|
||||||
|
|
||||||
val accepts_sensitive_params :
|
|
||||||
Typ.Procname.t -> ProcAttributes.t option -> (int * PredSymb.taint_kind) list
|
|
||||||
(** returns list of zero-indexed argument numbers of [callee_pname] that may be tainted *)
|
|
||||||
|
|
||||||
val tainted_params : Typ.Procname.t -> (int * PredSymb.taint_kind) list
|
|
||||||
(** returns list of zero-indexed parameter numbers of [callee_pname] that should be
|
|
||||||
considered tainted during symbolic execution *)
|
|
||||||
|
|
||||||
val has_taint_annotation : Typ.Fieldname.t -> Typ.Struct.t -> bool
|
|
||||||
(** returns the taint_kind of [fieldname] if it has a taint source annotation *)
|
|
||||||
|
|
||||||
val add_tainting_attribute :
|
|
||||||
Tenv.t -> PredSymb.t -> Pvar.t -> Prop.normal Prop.t -> Prop.normal Prop.t
|
|
||||||
|
|
||||||
val get_params_to_taint :
|
|
||||||
(int * PredSymb.taint_kind) list -> Pvar.t list -> (Pvar.t * PredSymb.taint_kind) list
|
|
@ -1,16 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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! IStd
|
|
||||||
|
|
||||||
let sources = []
|
|
||||||
|
|
||||||
let sinks = []
|
|
||||||
|
|
||||||
let functions_with_tainted_params = []
|
|
@ -1,16 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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! IStd
|
|
||||||
|
|
||||||
val sources : PatternMatch.taint_spec list
|
|
||||||
|
|
||||||
val sinks : (PatternMatch.taint_spec * int list) list
|
|
||||||
|
|
||||||
val functions_with_tainted_params : (PatternMatch.taint_spec * int list) list
|
|
@ -1,267 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013 - 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.infer;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
|
||||||
import javax.net.ssl.SSLException;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
import com.facebook.infer.builtins.InferTaint;
|
|
||||||
import com.facebook.infer.annotation.IntegritySource;
|
|
||||||
import com.facebook.infer.annotation.IntegritySink;
|
|
||||||
import com.facebook.infer.annotation.PrivacySource;
|
|
||||||
import com.facebook.infer.annotation.PrivacySink;
|
|
||||||
|
|
||||||
public class TaintExample {
|
|
||||||
|
|
||||||
public InputStream socketNotVerifiedSimple(SSLSocketFactory f)
|
|
||||||
throws IOException {
|
|
||||||
Socket socket = f.createSocket();
|
|
||||||
return socket.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream socketVerifiedForgotToCheckRetval(SSLSocketFactory f,
|
|
||||||
HostnameVerifier v,
|
|
||||||
SSLSession session)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
Socket socket = f.createSocket();
|
|
||||||
v.verify("hostname", session);
|
|
||||||
return socket.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream socketVerifiedOk1(SSLSocketFactory f,
|
|
||||||
HostnameVerifier v,
|
|
||||||
SSLSession session)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
Socket socket = f.createSocket();
|
|
||||||
if (v.verify("hostname", session)) {
|
|
||||||
return socket.getInputStream();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HostnameVerifier mHostnameVerifier;
|
|
||||||
|
|
||||||
public void throwExceptionIfNoVerify(SSLSocket sslSocket, String host)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
if (!mHostnameVerifier.verify(host, sslSocket.getSession())) {
|
|
||||||
throw new SSLException("Couldn't verify!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream socketVerifiedOk2(SSLSocketFactory f) throws IOException {
|
|
||||||
SSLSocket s = (SSLSocket) f.createSocket();
|
|
||||||
throwExceptionIfNoVerify(s, "hostname");
|
|
||||||
return s.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream socketIgnoreExceptionNoVerify(SSLSocketFactory f)
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
SSLSocket s = (SSLSocket) f.createSocket();
|
|
||||||
try {
|
|
||||||
throwExceptionIfNoVerify(s, "hostname");
|
|
||||||
} catch (SSLException e) {
|
|
||||||
// ignore the fact that verifying the socket failed
|
|
||||||
}
|
|
||||||
return s.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream taintingShouldNotPreventInference1(SSLSocketFactory f) throws IOException {
|
|
||||||
socketNotVerifiedSimple(f).toString();
|
|
||||||
// failing to infer a post for socketNotVerifiedSimple will hide this error
|
|
||||||
Socket s = f.createSocket();
|
|
||||||
return s.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream readInputStream(Socket socket) throws IOException {
|
|
||||||
return socket.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're not careful, postcondition inference will fail for this function
|
|
||||||
Socket callReadInputStreamCauseTaintError(SSLSocketFactory f)
|
|
||||||
throws IOException {
|
|
||||||
Socket socket = f.createSocket();
|
|
||||||
InputStream s = readInputStream(socket);
|
|
||||||
s.toString(); // to avoid RETURN_VALUE_IGNORED warning
|
|
||||||
return f.createSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream taintingShouldNotPreventInference2(SSLSocketFactory f) throws IOException {
|
|
||||||
// if inference fails for this callee, we won't report an error here
|
|
||||||
Socket s = callReadInputStreamCauseTaintError(f);
|
|
||||||
return s.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void simpleTaintErrorWithModelMethods() {
|
|
||||||
Object o = InferTaint.inferSecretSource();
|
|
||||||
InferTaint.inferSensitiveSink(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object returnTaintedSourceModelMethods() {
|
|
||||||
return InferTaint.inferSecretSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void callSinkMethodModelMethods(Object o) {
|
|
||||||
InferTaint.inferSensitiveSink(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void interprocTaintErrorWithModelMethods1() {
|
|
||||||
InferTaint.inferSensitiveSink(returnTaintedSourceModelMethods());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void interprocTaintErrorWithModelMethods2() {
|
|
||||||
callSinkMethodModelMethods(InferTaint.inferSecretSource());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void interprocTaintErrorWithModelMethods3() {
|
|
||||||
callSinkMethodModelMethods(returnTaintedSourceModelMethods());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void simpleTaintErrorWithModelMethodsUndefined() {
|
|
||||||
Object o = InferTaint.inferSecretSourceUndefined();
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object returnTaintedSourceModelMethodsUndefined() {
|
|
||||||
return InferTaint.inferSecretSourceUndefined();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void callSinkMethodModelMethodsUndefined(Object o) {
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void interprocTaintErrorWithModelMethodsUndefined1() {
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(returnTaintedSourceModelMethodsUndefined());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void interprocTaintErrorWithModelMethodsUndefined2() {
|
|
||||||
callSinkMethodModelMethodsUndefined(InferTaint.inferSecretSourceUndefined());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void interprocTaintErrorWithModelMethodsUndefined3() {
|
|
||||||
callSinkMethodModelMethodsUndefined(returnTaintedSourceModelMethodsUndefined());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void contentValuesPutWithTaintedString(ContentValues values, SharedPreferences prefs,
|
|
||||||
String key, String value) {
|
|
||||||
values.put(key, prefs.getString(key, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void contentValuesPutOk(ContentValues values, String key, String value) {
|
|
||||||
values.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PrivacySource
|
|
||||||
public String privacySource() {
|
|
||||||
return "source";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPrivacySourceAnnot() {
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(privacySource()); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void instancePrivacySink(@PrivacySink String s1, String s2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void staticPrivacySink(@PrivacySink String s1, String s2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPrivacySinkAnnot1() {
|
|
||||||
String source = privacySource();
|
|
||||||
instancePrivacySink(source, ""); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPrivacySinkAnnot2() {
|
|
||||||
String source = privacySource();
|
|
||||||
instancePrivacySink("", source); // should not report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPrivacySinkAnnot3() {
|
|
||||||
String source = privacySource();
|
|
||||||
staticPrivacySink(source, ""); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPrivacySinkAnnot4() {
|
|
||||||
String source = privacySource();
|
|
||||||
staticPrivacySink("", source); // should not report
|
|
||||||
}
|
|
||||||
|
|
||||||
@PrivacySource String mPrivacySource;
|
|
||||||
|
|
||||||
@PrivacySource String sPrivacySource;
|
|
||||||
|
|
||||||
public void testPrivacySourceInstanceFieldAnnot() {
|
|
||||||
String source = mPrivacySource;
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(source); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPrivacySourceStaticFieldAnnot() {
|
|
||||||
String source = sPrivacySource;
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(source); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
String aFieldWithoutAnnotations;
|
|
||||||
|
|
||||||
public void testPrivacySourceFieldAnnotPropagation() {
|
|
||||||
aFieldWithoutAnnotations = mPrivacySource;
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(aFieldWithoutAnnotations); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
@IntegritySource
|
|
||||||
public String integritySource() {
|
|
||||||
return "source";
|
|
||||||
}
|
|
||||||
|
|
||||||
@IntegritySource String mIntegritySource;
|
|
||||||
|
|
||||||
@IntegritySource String sIntegritySource;
|
|
||||||
|
|
||||||
public void testIntegritySourceAnnot() {
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(integritySource()); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIntegritySourceInstanceFieldAnnot() {
|
|
||||||
String source = mIntegritySource;
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(source); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testIntegritySourceStaticFieldAnnot() {
|
|
||||||
String source = sIntegritySource;
|
|
||||||
InferTaint.inferSensitiveSinkUndefined(source); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
public void integritySink(@IntegritySink String s1, String s2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void testIntegritySinkAnnotReport(String s) {
|
|
||||||
integritySink(integritySource(), s); // should report
|
|
||||||
}
|
|
||||||
|
|
||||||
void testIntegritySinkAnnotNoReport(String s) {
|
|
||||||
integritySink(s, integritySource()); // should not report
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in new issue