Skip to content

Commit

Permalink
[taint] Support class name and procedure name regex matcher combination
Browse files Browse the repository at this point in the history
Summary: Support class name and procedure name regex matcher combination

Reviewed By: artempyanykh

Differential Revision:
D50171576

Privacy Context Container: L1208441

fbshipit-source-id: 7f6de8e4b994aa4c0d966d96e81b645c69905156
  • Loading branch information
geralt-encore authored and facebook-github-bot committed Oct 11, 2023
1 parent fb42a04 commit 7a81197
Show file tree
Hide file tree
Showing 12 changed files with 56 additions and 1 deletion.
3 changes: 3 additions & 0 deletions infer/man/man1/infer-analyze.txt
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,9 @@ PULSE CHECKER OPTIONS
match the OCaml regex
- "class_names" and "method_names":
match exact uses of methods of particular classes
- "class_names" and "procedure_regex":
match exact uses of methods of particular classes matching
specified OCaml regex
- "class_names" and "field_names":
match exact uses of fields of particular classes
- "class_names" and "method_return_type_names":
Expand Down
3 changes: 3 additions & 0 deletions infer/man/man1/infer-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,9 @@ OPTIONS
match the OCaml regex
- "class_names" and "method_names":
match exact uses of methods of particular classes
- "class_names" and "procedure_regex":
match exact uses of methods of particular classes matching
specified OCaml regex
- "class_names" and "field_names":
match exact uses of fields of particular classes
- "class_names" and "method_return_type_names":
Expand Down
3 changes: 3 additions & 0 deletions infer/man/man1/infer.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,9 @@ OPTIONS
match the OCaml regex
- "class_names" and "method_names":
match exact uses of methods of particular classes
- "class_names" and "procedure_regex":
match exact uses of methods of particular classes matching
specified OCaml regex
- "class_names" and "field_names":
match exact uses of fields of particular classes
- "class_names" and "method_return_type_names":
Expand Down
1 change: 1 addition & 0 deletions infer/src/atd/pulse_config.atd
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type matcher = {
(* exactly one of field_regex or procedure or procedure_regex or class_name_regex or allocation
or block_passed_to or block_passed_to_regex must be specified,
or else class_names and method_names must be specified,
or else class_names and procedure_regex must be specified
or else class_names and field_names must be specified,
or else class_names and method_return_type_names must be specified,
or else overrides_of_class_with_annotation/method_with_annotation *)
Expand Down
2 changes: 2 additions & 0 deletions infer/src/base/Config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2588,6 +2588,8 @@ and pulse_taint_sources =
- "class_name_regex": match all methods of classes whose names match the OCaml regex
- "class_names" and "method_names":
match exact uses of methods of particular classes
- "class_names" and "procedure_regex":
match exact uses of methods of particular classes matching specified OCaml regex
- "class_names" and "field_names":
match exact uses of fields of particular classes
- "class_names" and "method_return_type_names":
Expand Down
16 changes: 16 additions & 0 deletions infer/src/pulse/PulseTaintConfig.ml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ module Unit = struct
| ProcedureNameRegex of {name_regex: Str.regexp; exclude_in: string list option}
| ClassNameRegex of {name_regex: Str.regexp; exclude_in: string list option}
| ClassAndMethodNames of {class_names: string list; method_names: string list}
| ClassNameAndMethodRegex of {class_names: string list; method_name_regex: Str.regexp}
| ClassAndMethodReturnTypeNames of
{class_names: string list; method_return_type_names: string list}
| OverridesOfClassWithAnnotation of {annotation: string}
Expand All @@ -159,6 +160,8 @@ module Unit = struct
| ClassAndMethodNames {class_names; method_names} ->
F.fprintf f "class_names=%a, method_names=%a" (Pp.comma_seq String.pp) class_names
(Pp.comma_seq String.pp) method_names
| ClassNameAndMethodRegex {class_names} ->
F.fprintf f "class_names=%a and method name regex" (Pp.comma_seq String.pp) class_names
| ClassAndMethodReturnTypeNames {class_names; method_return_type_names} ->
F.fprintf f "class_names=%a, method_return_type_names=%a" (Pp.comma_seq String.pp)
class_names (Pp.comma_seq String.pp) method_return_type_names
Expand Down Expand Up @@ -266,6 +269,7 @@ module Unit = struct
\ \"allocation\" or \n\
\ \"overrides_of_class_with_annotation\" must be provided, \n\
or else \"class_names\" and \"method_names\" must be provided, \n\
or else \"class_names\" and \"procedure_regex\" must be provided, \n\
or else \"class_names\" and \"method_return_type_names\" must be provided, \n\
or else \"method_with_annotation\" and \"annotation_values\" must be provided, \n\
but got \n\
Expand Down Expand Up @@ -350,6 +354,18 @@ module Unit = struct
; block_passed_to= None
; allocation= None } ->
ClassAndMethodNames {class_names; method_names}
| { procedure= None
; procedure_regex= Some method_name_regex
; class_name_regex= None
; class_names= Some class_names
; method_names= None
; method_return_type_names= None
; overrides_of_class_with_annotation= None
; method_with_annotation= None
; annotation_values= None
; block_passed_to= None
; allocation= None } ->
ClassNameAndMethodRegex {class_names; method_name_regex= Str.regexp method_name_regex}
| { procedure= None
; procedure_regex= None
; class_name_regex= None
Expand Down
1 change: 1 addition & 0 deletions infer/src/pulse/PulseTaintConfig.mli
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module Unit : sig
| ProcedureNameRegex of {name_regex: Str.regexp; exclude_in: string list option}
| ClassNameRegex of {name_regex: Str.regexp; exclude_in: string list option}
| ClassAndMethodNames of {class_names: string list; method_names: string list}
| ClassNameAndMethodRegex of {class_names: string list; method_name_regex: Str.regexp}
| ClassAndMethodReturnTypeNames of
{class_names: string list; method_return_type_names: string list}
| OverridesOfClassWithAnnotation of {annotation: string}
Expand Down
4 changes: 4 additions & 0 deletions infer/src/pulse/PulseTaintItemMatcher.ml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ let procedure_matches tenv matchers ?block_passed_to ?proc_attributes proc_name
| ClassAndMethodNames {class_names; method_names} ->
class_names_match tenv class_names class_name
&& List.mem ~equal:String.equal method_names (Procname.get_method proc_name)
| ClassNameAndMethodRegex {class_names; method_name_regex} ->
let proc_name_s = get_proc_name_s proc_name in
class_names_match tenv class_names class_name
&& check_regex method_name_regex proc_name_s None
| ClassAndMethodReturnTypeNames {class_names; method_return_type_names} ->
let procedure_return_type_match method_return_type_names =
Option.exists proc_attributes ~f:(fun attrs ->
Expand Down
6 changes: 6 additions & 0 deletions infer/tests/codetoanalyze/java/.inferconfig
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@
"pulse-taint-sinks": [
{ "procedure": "inferSensitiveSink" },
{ "class_name_regex": "codetoanalyze.java.pulse.sinks.*"},
{
"class_names": [
"codetoanalyze.java.pulse.InferTaint"
],
"procedure_regex": "regex.*"
},
{ "class_names": ["android.app.Activity"],
"method_names": ["startActivityFromChild", "startActivityFromFragment"],
"kinds": ["StartComponent"],
Expand Down
1 change: 1 addition & 0 deletions infer/tests/codetoanalyze/java/pulse/issues.exp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ codetoanalyze/java/pulse/taint/TaintMatchers.java, codetoanalyze.java.pulse.Tain
codetoanalyze/java/pulse/taint/TaintMatchers.java, codetoanalyze.java.pulse.TaintMatchers.taintedBasedOnClassNameRegexBad():void, 3, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `Object InferTaint.inferSecretSource()` with kinds `Simple`,`UserControlledString`,value passed as argument `#0` to `void InferTaintSinks.sink2(Object)` with kind `Simple`], source: Object InferTaint.inferSecretSource(), sink: void InferTaintSinks.sink2(Object), tainted expression: src
codetoanalyze/java/pulse/taint/TaintMatchers.java, codetoanalyze.java.pulse.TaintMatchers.taintedFromInferBaseSourceBad():void, 3, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `String InferBaseSource.inferBaseSecretSource()` with kind `Simple`,value passed as argument `#0` to `void InferTaint.inferSensitiveSink(Object)` with kind `Simple`], source: String InferBaseSource.inferBaseSecretSource(), sink: void InferTaint.inferSensitiveSink(Object), tainted expression: source
codetoanalyze/java/pulse/taint/TaintMatchers.java, codetoanalyze.java.pulse.TaintMatchers.taintedFromInferChildSourceBad():void, 3, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `String InferChildSource.inferChildSecretSource()` with kind `Simple`,value passed as argument `#0` to `void InferTaint.inferSensitiveSink(Object)` with kind `Simple`], source: String InferChildSource.inferChildSecretSource(), sink: void InferTaint.inferSensitiveSink(Object), tainted expression: source
codetoanalyze/java/pulse/taint/TaintMatchers.java, codetoanalyze.java.pulse.TaintMatchers.taintedBasedOnClassNameAndMethodRegexBad():void, 2, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `Object InferTaint.inferSecretSource()` with kinds `Simple`,`UserControlledString`,value passed as argument `#0` to `void InferTaint.regexSink(Object)` with kind `Simple`], source: Object InferTaint.inferSecretSource(), sink: void InferTaint.regexSink(Object), tainted expression: src
codetoanalyze/java/pulse/taint/TaintedFormals.java, codetoanalyze.java.pulse.TaintedFormals.taintedContextBad(java.lang.String,android.content.Intent,java.lang.Integer):void, 2, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value passed as argument `#0` to `void TaintedFormals.taintedContextBad(String,Intent,Integer)` with kind `Simple`,value passed as argument `#0` to `void InferTaint.inferSensitiveSink(Object)` with kind `Simple`], source: void TaintedFormals.taintedContextBad(String,Intent,Integer), sink: void InferTaint.inferSensitiveSink(Object), tainted expression: taintedFormal1
codetoanalyze/java/pulse/taint/TaintedFormals.java, codetoanalyze.java.pulse.TaintedFormals.taintedContextBad(java.lang.String,android.content.Intent,java.lang.Integer):void, 3, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value passed as argument `#2` to `void TaintedFormals.taintedContextBad(String,Intent,Integer)` with kind `Simple`,value passed as argument `#0` to `void InferTaint.inferSensitiveSink(Object)` with kind `Simple`], source: void TaintedFormals.taintedContextBad(String,Intent,Integer), sink: void InferTaint.inferSensitiveSink(Object), tainted expression: taintedFormal2
codetoanalyze/java/pulse/taint/TaintedFormals.java, codetoanalyze.java.pulse.TaintedFormals.taintedContextBad(java.lang.String,android.content.Intent,java.lang.Integer):void, 4, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value passed as argument `#0` to `void TaintedFormals.taintedContextBad(String,Intent,Integer)` with kind `Simple`,when calling `void TaintedFormals.callSink(Object)` here,value passed as argument `#0` to `void InferTaint.inferSensitiveSink(Object)` with kind `Simple`], source: void TaintedFormals.taintedContextBad(String,Intent,Integer), sink: void InferTaint.inferSensitiveSink(Object), tainted expression: taintedFormal1
Expand Down
7 changes: 6 additions & 1 deletion infer/tests/codetoanalyze/java/pulse/taint/InferTaint.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,16 @@ public static Object inferUniversalSanitizer(Object iMightBeTainted) {

public static native void inferSensitiveSinkUndefined(Object iMightBeTainted);

// these are to tests that only calls of functions with the same names from InferTaintSinks are
// these are to test that only calls of functions with the same names from InferTaintSinks are
// recognized as sinks based on class_name_regex config
public static void sink1(Object iMightBeTainted) {}

public static void sink2(Object iMightBeTainted) {}

public static void addCallback(Callback callback) {}

// these are to test class name + method name regexes matcher combination
public static void regexSink(Object iMightBeTainted) {}

public static void notRegexSink(Object iMightBeTainted) {}
}
10 changes: 10 additions & 0 deletions infer/tests/codetoanalyze/java/pulse/taint/TaintMatchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,14 @@ void notTaintedFromInferChildNotSourceGood() {
Object notSource = ics.inferChildNotSource();
InferTaint.inferSensitiveSink(notSource);
}

void taintedBasedOnClassNameAndMethodRegexBad() {
Object src = InferTaint.inferSecretSource();
InferTaint.regexSink(src);
}

void notTaintedBasedOnClassNameAndMethodRegexBad() {
Object src = InferTaint.inferSecretSource();
InferTaint.notRegexSink(src);
}
}

0 comments on commit 7a81197

Please sign in to comment.