[quandary] only treat overrides of service methods as endpoints

Reviewed By: mbouaziz

Differential Revision: D8010176

fbshipit-source-id: 14a4b32
master
Sam Blackshear 7 years ago committed by Facebook Github Bot
parent 1263bfa899
commit 370f5c80e6

@ -278,7 +278,7 @@ let proc_calls resolve_attributes pdesc filter : (Typ.Procname.t * ProcAttribute
List.rev !res List.rev !res
let override_exists f tenv proc_name = let override_exists ?(check_current_type= true) f tenv proc_name =
let method_name = Typ.Procname.get_method proc_name in let method_name = Typ.Procname.get_method proc_name in
let rec super_type_exists_ tenv super_class_name = let rec super_type_exists_ tenv super_class_name =
match Tenv.lookup tenv super_class_name with match Tenv.lookup tenv super_class_name with
@ -297,7 +297,7 @@ let override_exists f tenv proc_name =
List.exists ~f:(super_type_exists_ tenv) List.exists ~f:(super_type_exists_ tenv)
(type_get_direct_supertypes tenv (Typ.mk (Tstruct type_name))) (type_get_direct_supertypes tenv (Typ.mk (Tstruct type_name)))
in in
f proc_name (check_current_type && f proc_name)
|| ||
match proc_name with match proc_name with
| Typ.Procname.Java proc_name_java -> | Typ.Procname.Java proc_name_java ->

@ -50,9 +50,9 @@ val proc_calls :
-> (Typ.Procname.t -> ProcAttributes.t -> bool) -> (Typ.Procname.t * ProcAttributes.t) list -> (Typ.Procname.t -> ProcAttributes.t -> bool) -> (Typ.Procname.t * ProcAttributes.t) list
(** Return the callees that satisfy [filter]. *) (** Return the callees that satisfy [filter]. *)
val override_exists : (Typ.Procname.t -> bool) -> Tenv.t -> Typ.Procname.t -> bool val override_exists :
(** Return true if applying the given predicate to an override of [procname] or [procname] itself ?check_current_type:bool -> (Typ.Procname.t -> bool) -> Tenv.t -> Typ.Procname.t -> bool
returns true. For the moment, this only works for Java *) (** Return true if applying the given predicate to an override of [procname] (including [procname] itself when [check_current_type] is true, which it is by default) returns true. *)
val override_iter : (Typ.Procname.t -> unit) -> Tenv.t -> Typ.Procname.t -> unit val override_iter : (Typ.Procname.t -> unit) -> Tenv.t -> Typ.Procname.t -> unit
(** Apply the given predicate to procname and each override of [procname]. For the moment, this only (** Apply the given predicate to procname and each override of [procname]. For the moment, this only

@ -171,7 +171,7 @@ module SourceKind = struct
in in
let formals = Procdesc.get_formals pdesc in let formals = Procdesc.get_formals pdesc in
match Procdesc.get_proc_name pdesc with match Procdesc.get_proc_name pdesc with
| Typ.Procname.Java java_pname | Typ.Procname.Java java_pname as pname
-> ( -> (
let method_name = Typ.Procname.Java.get_method java_pname in let method_name = Typ.Procname.Java.get_method java_pname in
let taint_matching_supertype typename = let taint_matching_supertype typename =
@ -217,7 +217,10 @@ module SourceKind = struct
| Some typ -> | Some typ ->
if if
Annotations.struct_typ_has_annot typ Annotations.ia_is_thrift_service Annotations.struct_typ_has_annot typ Annotations.ia_is_thrift_service
&& PredSymb.equal_access (Procdesc.get_access pdesc) PredSymb.Public && PatternMatch.override_exists ~check_current_type:false
(fun superclass_pname ->
String.equal (Typ.Procname.get_method superclass_pname) method_name )
tenv pname
then then
(* assume every non-this formal of a Thrift service is tainted *) (* assume every non-this formal of a Thrift service is tainted *)
(* TODO: may not want to taint numbers or Enum's *) (* TODO: may not want to taint numbers or Enum's *)

@ -20,72 +20,78 @@ class Services {
} }
// classes annotated with @ThriftService are servers (sources), whereas interfaces
// annotated with @ThriftService are clients (sinks): see
// https://github.com/facebook/swift/blob/master/swift-service/README.md#clients-and-servers
@Retention(RetentionPolicy.CLASS) @Retention(RetentionPolicy.CLASS)
@interface ThriftService { @interface ThriftService {
} }
@ThriftService @ThriftService
class Service1 { interface GeneratedServiceInterface {
public void serviceMethodBad(String s) throws IOException;
public void paramToSql1Bad(String s) throws SQLException;
public void paramToSql2Bad(String s) throws SQLException;
public void paramToSql3Bad(String s) throws SQLException;
public void paramToSql4Bad(String s) throws SQLException;
public void paramToSql5Bad(String s) throws SQLException;
void packageProtectedServiceMethodBad(String s) throws IOException;
}
class Service1 implements GeneratedServiceInterface {
@Override
public void serviceMethodBad(String s) throws IOException { public void serviceMethodBad(String s) throws IOException {
Runtime.getRuntime().exec(s); // RCE if s is tainted, we should warn Runtime.getRuntime().exec(s); // RCE if s is tainted, we should warn
} }
Statement mStatement; Statement mStatement;
@Override
public void paramToSql1Bad(String s) throws SQLException { public void paramToSql1Bad(String s) throws SQLException {
mStatement.execute(s); mStatement.execute(s);
} }
@Override
public void paramToSql2Bad(String s) throws SQLException { public void paramToSql2Bad(String s) throws SQLException {
mStatement.executeLargeUpdate(s); mStatement.executeLargeUpdate(s);
} }
@Override
public void paramToSql3Bad(String s) throws SQLException { public void paramToSql3Bad(String s) throws SQLException {
mStatement.executeQuery(s); mStatement.executeQuery(s);
} }
@Override
public void paramToSql4Bad(String s) throws SQLException { public void paramToSql4Bad(String s) throws SQLException {
mStatement.executeUpdate(s); mStatement.executeUpdate(s);
} }
@Override
public void paramToSql5Bad(String s) throws SQLException { public void paramToSql5Bad(String s) throws SQLException {
mStatement.addBatch(s); mStatement.addBatch(s);
mStatement.executeBatch(); mStatement.executeBatch();
} }
// assume protected methods aren't exported to Thrift @Override
protected void protectedServiceMethodOk(String s) throws IOException { public void packageProtectedServiceMethodBad(String s) throws IOException {
Runtime.getRuntime().exec(s); Runtime.getRuntime().exec(s);
} }
// assume package-protected methods aren't exported to Thrift // doesn't override a method from the service interface; not an endpoint
void packageProtectedServiceMethodOk(String s) throws IOException { public void publicMethodNotEndpointOk(String s) throws IOException {
Runtime.getRuntime().exec(s); Runtime.getRuntime().exec(s);
} }
// private methods can't be exported to thrift // same
private void privateMethodNotEndpointOk(String s) throws IOException { protected void protectedMethodNotEndpointOk(String s) throws IOException {
Runtime.getRuntime().exec(s); Runtime.getRuntime().exec(s);
} }
} void packageProtectedMethodNotEndpointOk(String s) throws IOException {
Runtime.getRuntime().exec(s);
@ThriftService }
interface ThriftInterface {
public void interfaceServiceMethodBad(String s) throws IOException;
}
// this is a service too
class Implementer implements ThriftInterface {
public void interfaceServiceMethodBad(String s) throws IOException { // same
Runtime.getRuntime().exec(s); // RCE if s is tainted, we should warn private void privateMethodNotEndpointOk(String s) throws IOException {
Runtime.getRuntime().exec(s);
} }
} }

@ -177,7 +177,7 @@ codetoanalyze/java/quandary/LoggingPrivateData.java, void LoggingPrivateData.log
codetoanalyze/java/quandary/Recursion.java, void Recursion.callSinkThenDivergeBad(), 1, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void Recursion.callSinkThenDiverge(Object) with tainted index 0,Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0] codetoanalyze/java/quandary/Recursion.java, void Recursion.callSinkThenDivergeBad(), 1, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void Recursion.callSinkThenDiverge(Object) with tainted index 0,Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]
codetoanalyze/java/quandary/Recursion.java, void Recursion.safeRecursionCallSinkBad(), 1, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void Recursion.safeRecursionCallSink(int,Object) with tainted index 0,Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0] codetoanalyze/java/quandary/Recursion.java, void Recursion.safeRecursionCallSinkBad(), 1, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void Recursion.safeRecursionCallSink(int,Object) with tainted index 0,Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]
codetoanalyze/java/quandary/Serialization.java, Object Serialization.taintedObjectInputStreamBad(), 2, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to ObjectInputStream.<init>(InputStream) with tainted index 1] codetoanalyze/java/quandary/Serialization.java, Object Serialization.taintedObjectInputStreamBad(), 2, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to ObjectInputStream.<init>(InputStream) with tainted index 1]
codetoanalyze/java/quandary/Services.java, void Implementer.interfaceServiceMethodBad(String), 1, SHELL_INJECTION_RISK, ERROR, [Return from void Implementer.interfaceServiceMethodBad(String),Call to Process Runtime.exec(String) with tainted index 1] codetoanalyze/java/quandary/Services.java, void Service1.packageProtectedServiceMethodBad(String), 1, SHELL_INJECTION_RISK, ERROR, [Return from void Service1.packageProtectedServiceMethodBad(String),Call to Process Runtime.exec(String) with tainted index 1]
codetoanalyze/java/quandary/Services.java, void Service1.paramToSql1Bad(String), 1, SQL_INJECTION_RISK, ERROR, [Return from void Service1.paramToSql1Bad(String),Call to boolean Statement.execute(String) with tainted index 1] codetoanalyze/java/quandary/Services.java, void Service1.paramToSql1Bad(String), 1, SQL_INJECTION_RISK, ERROR, [Return from void Service1.paramToSql1Bad(String),Call to boolean Statement.execute(String) with tainted index 1]
codetoanalyze/java/quandary/Services.java, void Service1.paramToSql2Bad(String), 1, USER_CONTROLLED_SQL_RISK, ERROR, [Return from void Service1.paramToSql2Bad(String),Call to long Statement.executeLargeUpdate(String) with tainted index 1] codetoanalyze/java/quandary/Services.java, void Service1.paramToSql2Bad(String), 1, USER_CONTROLLED_SQL_RISK, ERROR, [Return from void Service1.paramToSql2Bad(String),Call to long Statement.executeLargeUpdate(String) with tainted index 1]
codetoanalyze/java/quandary/Services.java, void Service1.paramToSql3Bad(String), 1, USER_CONTROLLED_SQL_RISK, ERROR, [Return from void Service1.paramToSql3Bad(String),Call to ResultSet Statement.executeQuery(String) with tainted index 1] codetoanalyze/java/quandary/Services.java, void Service1.paramToSql3Bad(String), 1, USER_CONTROLLED_SQL_RISK, ERROR, [Return from void Service1.paramToSql3Bad(String),Call to ResultSet Statement.executeQuery(String) with tainted index 1]

Loading…
Cancel
Save