Skip to content

Commit

Permalink
[taint] Add class annotation based taint matcher
Browse files Browse the repository at this point in the history
Summary: Add class annotation based taint matcher

Reviewed By: dulmarod

Differential Revision:
D50269417

Privacy Context Container: L1122176

fbshipit-source-id: bb3431cb45e15333d585e20e4daf5bbf0eb2e95a
  • Loading branch information
geralt-encore authored and facebook-github-bot committed Oct 16, 2023
1 parent 95ef448 commit 95db034
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 2 deletions.
1 change: 1 addition & 0 deletions infer/src/atd/pulse_config.atd
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type matcher = {
?procedure_regex: string option;
?class_name_regex: string option;
?class_names: string list option;
?class_with_annotation: string option;
?field_names: string list option;
?method_names: string list option;
?method_return_type_names: string list option;
Expand Down
31 changes: 30 additions & 1 deletion infer/src/pulse/PulseTaintConfig.ml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ module Unit = struct
| ClassNameAndMethodRegex of {class_names: string list; method_name_regex: Str.regexp}
| ClassAndMethodReturnTypeNames of
{class_names: string list; method_return_type_names: string list}
| ClassWithAnnotation of {annotation: string; annotation_values: string list option}
| OverridesOfClassWithAnnotation of {annotation: string}
| MethodWithAnnotation of {annotation: string; annotation_values: string list option}
| Block of {name: string}
Expand All @@ -165,6 +166,10 @@ module Unit = struct
| 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
| ClassWithAnnotation {annotation; annotation_values: string list option} ->
F.fprintf f "class with annotation=%s and annotation_values=%a" annotation
(Pp.option (Pp.comma_seq String.pp))
annotation_values
| OverridesOfClassWithAnnotation {annotation} ->
F.fprintf f "overrides of class with annotation=%s" annotation
| MethodWithAnnotation {annotation; annotation_values: string list option} ->
Expand Down Expand Up @@ -235,6 +240,7 @@ module Unit = struct
\ \"procedure_regex\": %a, \n\
\ \"class_name_regex\": %a, \n\
\ \"class_names\": %a, \n\
\ \"class_with_annotation\": %a, \n\
\ \"method_names\": %a, \n\
\ \"method_return_type_names\": %a, \n\
\ \"overrides_of_class_with_annotation\": %a,\n\
Expand All @@ -246,7 +252,7 @@ module Unit = struct
(Pp.option F.pp_print_string) matcher.procedure_regex (Pp.option F.pp_print_string)
matcher.class_name_regex
(Pp.option (Pp.seq ~sep:"," F.pp_print_string))
matcher.class_names
matcher.class_names (Pp.option F.pp_print_string) matcher.class_with_annotation
(Pp.option (Pp.seq ~sep:"," F.pp_print_string))
matcher.method_names
(Pp.option (Pp.seq ~sep:"," F.pp_print_string))
Expand All @@ -263,6 +269,7 @@ module Unit = struct
\ \"procedure\", \n\
\ \"procedure_regex\", \n\
\ \"class_name_regex\", \n\
\ \"class_with_annotation\", \n\
\ \"block_passed_to\", \n\
\ \"block_passed_to_regex\", \n\
\ \"method_with_annotation\", \n\
Expand Down Expand Up @@ -309,6 +316,7 @@ module Unit = struct
; procedure_regex= None
; class_name_regex= None
; class_names= None
; class_with_annotation= None
; method_names= None
; method_return_type_names= None
; overrides_of_class_with_annotation= None
Expand All @@ -321,6 +329,7 @@ module Unit = struct
; procedure_regex= Some name_regex
; class_name_regex= None
; class_names= None
; class_with_annotation= None
; method_names= None
; method_return_type_names= None
; annotation_values= None
Expand All @@ -334,6 +343,7 @@ module Unit = struct
; procedure_regex= None
; class_name_regex= Some name_regex
; class_names= None
; class_with_annotation= None
; method_names= None
; overrides_of_class_with_annotation= None
; method_with_annotation= None
Expand All @@ -358,6 +368,7 @@ module Unit = struct
; procedure_regex= Some method_name_regex
; class_name_regex= None
; class_names= Some class_names
; class_with_annotation= None
; method_names= None
; method_return_type_names= None
; overrides_of_class_with_annotation= None
Expand All @@ -370,13 +381,27 @@ module Unit = struct
; procedure_regex= None
; class_name_regex= None
; class_names= Some class_names
; class_with_annotation= None
; method_names= None
; method_return_type_names= Some method_return_type_names
; overrides_of_class_with_annotation= None
; method_with_annotation= None
; annotation_values= None
; allocation= None } ->
ClassAndMethodReturnTypeNames {class_names; method_return_type_names}
| { procedure= None
; procedure_regex= None
; class_name_regex= None
; class_names= None
; class_with_annotation= Some annotation
; method_names= None
; method_return_type_names= None
; overrides_of_class_with_annotation= None
; method_with_annotation= None
; annotation_values
; block_passed_to= None
; allocation= None } ->
ClassWithAnnotation {annotation; annotation_values}
| { procedure= None
; procedure_regex= None
; class_names= None
Expand All @@ -390,6 +415,7 @@ module Unit = struct
; procedure_regex= None
; class_name_regex= None
; class_names= None
; class_with_annotation= None
; method_names= None
; method_return_type_names= None
; overrides_of_class_with_annotation= None
Expand All @@ -402,6 +428,7 @@ module Unit = struct
; procedure_regex= None
; class_name_regex= None
; class_names= None
; class_with_annotation= None
; method_names= None
; method_return_type_names= None
; overrides_of_class_with_annotation= None
Expand All @@ -414,6 +441,7 @@ module Unit = struct
; procedure_regex= None
; class_name_regex= None
; class_names= None
; class_with_annotation= None
; method_names= None
; overrides_of_class_with_annotation= None
; method_with_annotation= None
Expand All @@ -425,6 +453,7 @@ module Unit = struct
; procedure_regex= None
; class_name_regex= None
; class_names= None
; class_with_annotation= None
; method_names= None
; overrides_of_class_with_annotation= None
; method_with_annotation= 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 @@ -44,6 +44,7 @@ module Unit : sig
| ClassNameAndMethodRegex of {class_names: string list; method_name_regex: Str.regexp}
| ClassAndMethodReturnTypeNames of
{class_names: string list; method_return_type_names: string list}
| ClassWithAnnotation of {annotation: string; annotation_values: string list option}
| OverridesOfClassWithAnnotation of {annotation: string}
| MethodWithAnnotation of {annotation: string; annotation_values: string list option}
| Block of {name: string}
Expand Down
10 changes: 10 additions & 0 deletions infer/src/pulse/PulseTaintItemMatcher.ml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,16 @@ let procedure_matches tenv matchers ?block_passed_to ?proc_attributes proc_name
in
class_names_match tenv class_names class_name
&& procedure_return_type_match method_return_type_names
| ClassWithAnnotation {annotation; annotation_values} ->
let res =
let open IOption.Let_syntax in
let* name = class_name in
let* struct_typ = Tenv.lookup tenv name in
Annotations.struct_typ_has_annot struct_typ (fun annot_item ->
match_annotation_with_values annot_item annotation annotation_values )
|> Option.some
in
Option.value res ~default:false
| OverridesOfClassWithAnnotation {annotation} ->
Option.exists (Procname.get_class_type_name proc_name) ~f:(fun procedure_class_name ->
let method_name = Procname.get_method proc_name in
Expand Down
3 changes: 2 additions & 1 deletion infer/tests/codetoanalyze/java/.inferconfig
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@
{ "class_names": ["codetoanalyze.java.pulse.Fields"],
"field_names": ["sourceField"],
"taint_target": "GetField"
}
},
{ "class_with_annotation": "codetoanalyze.java.pulse.SensitiveSourceMarker" }
],
"pulse-taint-sinks": [
{ "procedure": "inferSensitiveSink" },
Expand Down
2 changes: 2 additions & 0 deletions infer/tests/codetoanalyze/java/pulse/issues.exp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,8 @@ codetoanalyze/java/pulse/taint/TaintMatchers.java, codetoanalyze.java.pulse.Tain
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/TaintMatchers.java, codetoanalyze.java.pulse.TaintMatchers.taintedBasedOnClassAnnotationBad1():void, 2, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `Object InferTaintSources$Sources.source1()` with kind `Simple`,value passed as argument `#0` to `void InferTaint.inferSensitiveSink(Object)` with kind `Simple`], source: Object InferTaintSources$Sources.source1(), sink: void InferTaint.inferSensitiveSink(Object), tainted expression: src
codetoanalyze/java/pulse/taint/TaintMatchers.java, codetoanalyze.java.pulse.TaintMatchers.taintedBasedOnClassAnnotationBad2():void, 2, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `Object InferTaintSources$Sources.source2()` with kind `Simple`,value passed as argument `#0` to `void InferTaint.inferSensitiveSink(Object)` with kind `Simple`], source: Object InferTaintSources$Sources.source2(), sink: void InferTaint.inferSensitiveSink(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
34 changes: 34 additions & 0 deletions infer/tests/codetoanalyze/java/pulse/taint/InferTaintSources.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package codetoanalyze.java.pulse;

/**
* WARNING! These methods are for testing the taint analysis only! Don't use them in models or in
* real code.
*/
public class InferTaintSources {

@SensitiveSourceMarker
static class Sources {

static Object source1() {
return new Object();
}

static Object source2() {
return new Object();
}
}

static class NotSources {

static Object notSource() {
return new Object();
}
}
}
15 changes: 15 additions & 0 deletions infer/tests/codetoanalyze/java/pulse/taint/TaintMatchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,19 @@ void notTaintedBasedOnClassNameAndMethodRegexBad() {
Object src = InferTaint.inferSecretSource();
InferTaint.notRegexSink(src);
}

void taintedBasedOnClassAnnotationBad1() {
Object src = InferTaintSources.Sources.source1();
InferTaint.inferSensitiveSink(src);
}

void taintedBasedOnClassAnnotationBad2() {
Object src = InferTaintSources.Sources.source2();
InferTaint.inferSensitiveSink(src);
}

void notTaintedBasedOnClassAnnotationGood() {
Object src = InferTaintSources.NotSources.notSource();
InferTaint.inferSensitiveSink(src);
}
}

0 comments on commit 95db034

Please sign in to comment.