[quandary] don't crash if JSON source/sink is invalid procedure name

Summary:
At the moment, Java and Clang sources/sinks live in the same inferconfig entry.
If we try to parse a Java procedure that happens to be an invalid Clang qualified name (e.g., `MyClass.<init>`),
parsing will crash.

As a temporary fix, throw an exception and catch it instead.
In the future, we can avoid this by requiring that JSON source/sink specifications to indicate the language.

Reviewed By: mbouaziz

Differential Revision: D7291880

fbshipit-source-id: f8f4502
master
Sam Blackshear 7 years ago committed by Facebook Github Bot
parent 1db6e0c2c6
commit b57aa90d7d

@ -8,8 +8,11 @@
*)
open! IStd
module F = Format
module L = Logging
exception ParseError of string
(* internally it uses reversed list to store qualified name, for example: ["get", "shared_ptr<int>", "std"]*)
type t = string list [@@deriving compare]
@ -27,13 +30,15 @@ let strip_template_args quals =
let append_template_args_to_last quals ~args =
match quals with
| [last; _] when String.contains last '<' ->
L.(die InternalError)
"expected qualified name without template args, but got %s, the last qualifier of %s" last
(String.concat ~sep:", " quals)
raise
(ParseError
(F.sprintf
"expected qualified name without template args, but got %s, the last qualifier of %s"
last (String.concat ~sep:", " quals)))
| last :: rest ->
(last ^ args) :: rest
| [] ->
L.(die InternalError) "expected non-empty qualified name"
raise (ParseError "expected non-empty qualified name")
let to_list = List.rev
@ -51,7 +56,7 @@ let from_field_qualified_name qual_name =
| _ :: rest ->
rest
| _ ->
L.(die InternalError) "expected non-empty qualified name"
raise (ParseError "expected non-empty qualified name")
(* define [cpp_separator_regex] here to compute it once *)
@ -93,7 +98,7 @@ module Match = struct
List.iter colon_splits ~f:(fun s ->
(* Filter out the '<' in operator< and operator<= *)
if not (String.is_prefix s ~prefix:"operator<") && String.contains s '<' then
L.(die InternalError) "Unexpected template in fuzzy qualified name %s." qual_name ) ;
raise (ParseError ("Unexpected template in fuzzy qualified name %s." ^ qual_name)) ) ;
of_qual_string qual_name

@ -9,6 +9,8 @@
open! IStd
exception ParseError of string
type t [@@deriving compare]
val empty : t

@ -11,6 +11,16 @@ open! IStd
module F = Format
module L = Logging
let parse_clang_procedure procedure kind index =
try Some (QualifiedCppName.Match.of_fuzzy_qual_names [procedure], kind, index)
with QualifiedCppName.ParseError _ ->
(* Java and Clang sources/sinks live in the same inferconfig entry. If we try to parse a Java
procedure that happens to be an invalid Clang qualified name (e.g., MyClass.<init>),
parsing will crash. In the future, we can avoid this by requiring JSON source/sink
specifications to indicate the language *)
None
module SourceKind = struct
type t =
| CommandLineFlag of (Var.t * Typ.desc) (** source that was read from a command line flag *)
@ -40,9 +50,9 @@ module SourceKind = struct
let external_sources =
List.map
List.filter_map
~f:(fun {QuandaryConfig.Source.procedure; kind; index} ->
(QualifiedCppName.Match.of_fuzzy_qual_names [procedure], kind, index) )
parse_clang_procedure procedure kind index )
(QuandaryConfig.Source.of_json Config.quandary_sources)
@ -215,9 +225,9 @@ module SinkKind = struct
let external_sinks =
List.map
List.filter_map
~f:(fun {QuandaryConfig.Sink.procedure; kind; index} ->
(QualifiedCppName.Match.of_fuzzy_qual_names [procedure], kind, index) )
parse_clang_procedure procedure kind index )
(QuandaryConfig.Sink.of_json Config.quandary_sinks)

@ -27,6 +27,11 @@
{
"procedure": "codetoanalyze.java.quandary.InterfaceSpec.sink",
"kind": "Logging"
},
{
"procedure": "codetoanalyze.java.quandary.ConstructorSink.<init>",
"kind": "Other",
"index": "0"
}
],
"quandary-sanitizers": [

@ -175,3 +175,15 @@ class InterfaceSpecImpl implements InterfaceSpec {
}
}
class ConstructorSink {
// specified as a source in .inferconfig
public ConstructorSink(Object o) {
}
public static ConstructorSink constructorSinkBad() {
Object source = InferTaint.inferSecretSource();
return new ConstructorSink(source);
}
}

@ -43,6 +43,7 @@ codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInCatchBad2(),
codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInFinallyBad1(), 5, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]
codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInFinallyBad2(), 6, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]
codetoanalyze/java/quandary/Exceptions.java, void Exceptions.sinkInFinallyBad3(), 7, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]
codetoanalyze/java/quandary/ExternalSpecs.java, ConstructorSink ConstructorSink.constructorSinkBad(), 2, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to ConstructorSink.<init>(Object) with tainted index 1]
codetoanalyze/java/quandary/ExternalSpecs.java, Object ExternalSpecs.missedSanitizerBad(), 3, QUANDARY_TAINT_ERROR, ERROR, [Return from Object InferTaint.inferSecretSource(),Call to void InferTaint.inferSensitiveSink(Object) with tainted index 0]
codetoanalyze/java/quandary/ExternalSpecs.java, void ExternalSpecs.callExternalSink2Bad1(), 1, LOGGING_PRIVATE_DATA, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink2(Object,Object) with tainted index 0]
codetoanalyze/java/quandary/ExternalSpecs.java, void ExternalSpecs.callExternalSink2Bad2(), 1, LOGGING_PRIVATE_DATA, ERROR, [Return from Object ExternalSpecs.privateDataSource(),Call to void ExternalSpecs.loggingSink2(Object,Object) with tainted index 1]

Loading…
Cancel
Save