Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e196c75

Browse files
Java: Add modelling for Guava Strings, Splitter, and Joiner
1 parent a92a701 commit e196c75

6 files changed

Lines changed: 264 additions & 0 deletions

File tree

java/ql/src/semmle/code/java/dataflow/NullGuards.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ Expr clearlyNotNullExpr(Expr reason) {
7979
)
8080
or
8181
exists(SsaVariable v | clearlyNotNull(v, reason) and result = v.getAUse())
82+
or
83+
exists(Method m | m = result.(MethodAccess).getMethod() and reason = result |
84+
m.getDeclaringType().hasQualifiedName("com.google.common.base", "Strings") and
85+
m.hasName("nullToEmpty")
86+
)
8287
}
8388

8489
/** Holds if `v` is an SSA variable that is provably not `null`. */
@@ -146,6 +151,11 @@ predicate nullCheckMethod(Method m, boolean branch, boolean isnull) {
146151
m.hasName("isNotEmpty") and
147152
branch = true and
148153
isnull = false
154+
or
155+
m.getDeclaringType().hasQualifiedName("com.google.common.base", "Strings") and
156+
m.hasName("isNullOrEmpty") and
157+
branch = false and
158+
isnull = false
149159
}
150160

151161
/**

java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ private import semmle.code.java.security.SecurityTests
77
private import semmle.code.java.security.Validation
88
private import semmle.code.java.Maps
99
private import semmle.code.java.dataflow.internal.ContainerFlow
10+
<<<<<<< HEAD
1011
private import semmle.code.java.frameworks.spring.SpringController
1112
private import semmle.code.java.frameworks.spring.SpringHttp
1213
import semmle.code.java.dataflow.FlowSteps
14+
=======
15+
private import semmle.code.java.frameworks.jackson.JacksonSerializability
16+
private import semmle.code.java.frameworks.guava.Guava
17+
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
1318

1419
/**
1520
* Holds if taint can flow from `src` to `sink` in zero or more
@@ -285,7 +290,11 @@ private predicate taintPreservingQualifierToArgument(Method m, int arg) {
285290
m.hasName("read") and
286291
arg = 0
287292
or
293+
<<<<<<< HEAD
288294
m.(TaintPreservingCallable).transfersTaint(-1, arg)
295+
=======
296+
m.(GuavaTaintPropagationMethod).propagatesTaint(-1, arg)
297+
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
289298
}
290299

291300
/** Access to a method that passes taint from the qualifier. */
@@ -359,7 +368,11 @@ private predicate taintPreservingQualifierToMethod(Method m) {
359368
)
360369
)
361370
or
371+
<<<<<<< HEAD
362372
m.(TaintPreservingCallable).returnsTaintFrom(-1)
373+
=======
374+
m.(GuavaTaintPropagationMethod).propagatesTaint(-1, -2)
375+
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
363376
}
364377

365378
private class StringReplaceMethod extends TaintPreservingCallable {
@@ -477,7 +490,26 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
477490
method.hasName("sourceToInputSource") and
478491
arg = 0
479492
or
493+
<<<<<<< HEAD
480494
method.(TaintPreservingCallable).returnsTaintFrom(arg)
495+
=======
496+
exists(ProtobufParser p | method = p.getAParseFromMethod()) and
497+
arg = 0
498+
or
499+
exists(ProtobufMessageLite m | method = m.getAParseFromMethod()) and
500+
arg = 0
501+
or
502+
// Jackson serialization methods that return the serialized data
503+
method instanceof JacksonWriteValueMethod and
504+
method.getNumberOfParameters() = 1 and
505+
arg = 0
506+
or
507+
method.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and
508+
method.hasName("append") and
509+
arg = 0
510+
or
511+
method.(GuavaTaintPropagationMethod).propagatesTaint(arg, -2)
512+
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
481513
}
482514

483515
/**
@@ -525,7 +557,17 @@ private predicate taintPreservingArgToArg(Method method, int input, int output)
525557
input = 0 and
526558
output = 2
527559
or
560+
<<<<<<< HEAD
528561
method.(TaintPreservingCallable).transfersTaint(input, output)
562+
=======
563+
// Jackson serialization methods that write data to the first argument
564+
method instanceof JacksonWriteValueMethod and
565+
method.getNumberOfParameters() > 1 and
566+
input = method.getNumberOfParameters() - 1 and
567+
output = 0
568+
or
569+
method.(GuavaTaintPropagationMethod).propagatesTaint(input, output)
570+
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
529571
}
530572

531573
/**
@@ -553,7 +595,18 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) {
553595
write.getDeclaringType().hasQualifiedName("java.io", "OutputStream")
554596
)
555597
or
598+
<<<<<<< HEAD
556599
method.(TaintPreservingCallable).transfersTaint(arg, -1)
600+
=======
601+
exists(Method append |
602+
method.overrides*(append) and
603+
append.hasName("append") and
604+
arg = 0 and
605+
append.getDeclaringType().hasQualifiedName("java.io", "StringWriter")
606+
)
607+
or
608+
method.(GuavaTaintPropagationMethod).propagatesTaint(arg, -1)
609+
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
557610
}
558611

559612
/** A comparison or equality test with a constant. */
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import java
2+
import Strings
3+
import Splitter
4+
import Joiner
5+
6+
/**
7+
* A method in the guava framework that propegates taint.
8+
*/
9+
abstract class GuavaTaintPropagationMethod extends Method {
10+
/**
11+
* Holds if this method propagates taint between the given source and sink.
12+
* `src` and `sink` are indicies of arguments to this method, or -1 to represent the qualifier.
13+
* `sink` ca also be -2 to represent the return value.
14+
*/
15+
abstract predicate propagatesTaint(int src, int sink);
16+
}
17+
18+
/**
19+
* A method in the guava framework that returns tainted data when a specific input
20+
* (either an argument or the qualifier) is tainted.
21+
*/
22+
abstract class GuavaTaintPropagationMethodToReturn extends GuavaTaintPropagationMethod {
23+
/**
24+
* Holds if this method returns tainted data when the given source is tainted.
25+
* `src` is an argument index, or -1 to indicate the qualifier.
26+
*/
27+
abstract predicate propagatesTaint(int src);
28+
29+
override predicate propagatesTaint(int src, int sink) { propagatesTaint(src) and sink = -2 }
30+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import java
2+
import Guava
3+
4+
/**
5+
* The class `com.google.common.base.Joiner`.
6+
*/
7+
class TypeGuavaJoiner extends Class {
8+
TypeGuavaJoiner() { this.hasQualifiedName("com.google.common.base", "Joiner") }
9+
}
10+
11+
/**
12+
* The nested class `Joiner.MapJoiner`.
13+
*/
14+
class TypeGuavaMapJoiner extends NestedClass {
15+
TypeGuavaMapJoiner() {
16+
this.getEnclosingType() instanceof TypeGuavaJoiner and
17+
this.hasName("MapJoiner")
18+
}
19+
}
20+
21+
/**
22+
* A method of `Joiner` or `MapJoiner`.
23+
*/
24+
private class GuavaJoinerMethod extends Method {
25+
GuavaJoinerMethod() {
26+
this.getDeclaringType() instanceof TypeGuavaJoiner or
27+
this.getDeclaringType() instanceof TypeGuavaMapJoiner
28+
}
29+
}
30+
31+
/**
32+
* A method that builds a `Joiner` or `MapJoiner`.
33+
*/
34+
class GuavaJoinerBuilderMethod extends GuavaJoinerMethod, GuavaTaintPropagationMethodToReturn {
35+
GuavaJoinerBuilderMethod() {
36+
// static Joiner on(char separator)
37+
// static Joiner on(String separator)
38+
// Joiner skipNulls()
39+
// Joiner useForNull(String nullText)
40+
// Joiner.MapJoiner withKeyValueSeparator(String keyValueSeparator)
41+
// Joiner.MapJoiner useForNull(String nullText) [on MapJoiner]
42+
this.hasName(["on", "skipNulls", "useForNull", "withKeyValueSeparator"])
43+
}
44+
45+
override predicate propagatesTaint(int src) { src = [-1, 0] }
46+
}
47+
48+
/**
49+
* An `appendTo` method on `Joiner` or `MapJoiner`
50+
*/
51+
class GuavaJoinerAppendToMethod extends GuavaJoinerMethod, GuavaTaintPropagationMethod {
52+
GuavaJoinerAppendToMethod() {
53+
// <A extends Appendable> A appendTo(A appendable, Iterable<?> parts)
54+
// <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)
55+
// <A extends Appendable> A appendTo(A appendable, Object[] parts)
56+
// <A extends Appendable> A appendTo(A appendable, Object first, Object second, Object... rest)
57+
// StringBuilder appendTo(StringBuilder builder, Iterable<?> parts)
58+
// StringBuilder appendTo(StringBuilder builder, Iterator<?> parts)
59+
// StringBuilder appendTo(StringBuilder builder, Object[] parts)
60+
// StringBuilder appendTo(StringBuilder builder, Object first, Object second, Object... rest)
61+
// <A extends Appendable> A appendTo(A appendable, Iterable<? extends Map.Entry<?,?>> entries) [on MapJoiner]
62+
// <A extends Appendable> A appendTo(A appendable, Iterator<? extends Map.Entry<?,?>> parts)
63+
// <A extends Appendable> A appendTo(A appendable, Map<?,?> map)
64+
// StringBuilder appendTo(StringBuilder builder, Iterable<? extends Map.Entry<?,?>> entries)
65+
// StringBuilder appendTo(StringBuilder builder, Iterator<? extends Map.Entry<?,?>> entries)
66+
// StringBuilder appendTo(StringBuilder builder, Map<?,?> map)
67+
this.hasName("appendTo")
68+
}
69+
70+
override predicate propagatesTaint(int src, int sink) {
71+
src = [-1 .. getNumberOfParameters()] and
72+
src != sink and
73+
sink = [-2, 0]
74+
}
75+
}
76+
77+
/**
78+
* A `join` method on `Joiner` or `MapJoiner`
79+
*/
80+
class GuavaJoinMethod extends GuavaJoinerMethod, GuavaTaintPropagationMethodToReturn {
81+
GuavaJoinMethod() {
82+
// String join(Iterable<?> parts)
83+
// String join(Iterator<?> parts)
84+
// String join(Object[] parts)
85+
// String join(Object first, Object second, Object... rest)
86+
// String join(Iterable<? extends Map.Entry<?,?>> entries) [on MapJoiner]
87+
// String join(Iterator<? extends Map.Entry<?,?>> entries)
88+
// String join(Map<?,?> map)
89+
this.hasName("join")
90+
}
91+
92+
override predicate propagatesTaint(int src) { src = [-1 .. getNumberOfParameters()] }
93+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import java
2+
import Guava
3+
4+
/**
5+
* The class `com.google.common.base.Splitter`.
6+
*/
7+
class TypeGuavaSplitter extends Class {
8+
TypeGuavaSplitter() { this.hasQualifiedName("com.google.common.base", "Splitter") }
9+
}
10+
11+
/**
12+
* The nested class `Splitter.MapSplitter`.
13+
*/
14+
class TypeGuavaMapSplitter extends NestedClass {
15+
TypeGuavaMapSplitter() {
16+
this.getEnclosingType() instanceof TypeGuavaSplitter and
17+
this.hasName("MapSplitter")
18+
}
19+
}
20+
21+
/**
22+
* A method of `Splitter` or `MapSplitter` that splits its input string.
23+
*/
24+
class GuavaSplitMethod extends GuavaTaintPropagationMethodToReturn {
25+
GuavaSplitMethod() {
26+
(
27+
this.getDeclaringType() instanceof TypeGuavaSplitter
28+
or
29+
this.getDeclaringType() instanceof TypeGuavaMapSplitter
30+
) and
31+
// Iterable<String> split(CharSequence sequence)
32+
// List<String> splitToList(CharSequence sequence)
33+
// Stream<String> splitToStream(CharSequence sequence)
34+
// Map<String,String> split(CharSequence sequence) [on MapSplitter]
35+
this.hasName(["split", "splitToList", "splitToStream"])
36+
}
37+
38+
override predicate propagatesTaint(int src) { src = 0 }
39+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import java
2+
import Guava
3+
4+
/**
5+
* The class `com.google.common.base.Strings`.
6+
*/
7+
class TypeGuavaStrings extends Class {
8+
TypeGuavaStrings() { this.hasQualifiedName("com.google.common.base", "Strings") }
9+
}
10+
11+
/**
12+
* A Guava string utility method that preserves taint from its first argument.
13+
*/
14+
class GuavaStringsTaintPropagationMethod extends GuavaTaintPropagationMethodToReturn {
15+
GuavaStringsTaintPropagationMethod() {
16+
this.getDeclaringType() instanceof TypeGuavaStrings and
17+
// static String emptyToNull(String string)
18+
// static String emptyToNull(String string)
19+
// static String padEnd(String string, int minLength, char padChar)
20+
// static String padStart(String string, int minLength, char padChar)
21+
// static String repeat(String string, int count)
22+
this.hasName(["emptyToNull", "nullToEmpty", "padStart", "padEnd", "repeat"])
23+
}
24+
25+
override predicate propagatesTaint(int src) { src = 0 }
26+
}
27+
28+
/**
29+
* The method `Strings.lenientFormat`.
30+
*/
31+
class GuavaStringsFormatMethod extends GuavaTaintPropagationMethodToReturn {
32+
GuavaStringsFormatMethod() {
33+
this.getDeclaringType() instanceof TypeGuavaStrings and
34+
// static String lenientFormat(String template, Object ... args)
35+
this.hasName("lenientFormat")
36+
}
37+
38+
override predicate propagatesTaint(int src) { src in [0 .. getNumberOfParameters()] }
39+
}

0 commit comments

Comments
 (0)