Skip to content

Commit 19305a2

Browse files
authored
Merge pull request github#5374 from joefarebrother/guava-base
Java: Model additional flow steps for the package `com.google.common.base` of the Guava framwork.
2 parents 501ba4b + 36cb207 commit 19305a2

File tree

12 files changed

+556
-20
lines changed

12 files changed

+556
-20
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Increased coverage of the Guava framework by modelling additional classes in the `com.google.common.base` package. This may result in more results for security queries on projects where the Guava framework is used.

java/ql/src/semmle/code/java/frameworks/guava/Base.qll

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@ private class GuavaBaseCsv extends SummaryModelCsv {
2222
"com.google.common.base;Joiner;false;withKeyValueSeparator;(String);;Argument[0];ReturnValue;taint",
2323
"com.google.common.base;Joiner;false;withKeyValueSeparator;(String);;Argument[-1];ReturnValue;taint",
2424
"com.google.common.base;Joiner;false;withKeyValueSeparator;(char);;Argument[-1];ReturnValue;taint",
25-
// Note: The signatures of some of the appendTo methods involve collection flow
26-
"com.google.common.base;Joiner;false;appendTo;;;Argument[-1..3];Argument[0];taint",
25+
"com.google.common.base;Joiner;false;appendTo;(Appendable,Object,Object,Object[]);;Argument[1..2];Argument[0];taint",
26+
"com.google.common.base;Joiner;false;appendTo;(Appendable,Object,Object,Object[]);;ArrayElement of Argument[3];Argument[0];taint",
27+
"com.google.common.base;Joiner;false;appendTo;(Appendable,Iterable);;Element of Argument[1];Argument[-1];taint",
28+
"com.google.common.base;Joiner;false;appendTo;(Appendable,Object[]);;ArrayElement of Argument[1];Argument[-1];taint",
29+
"com.google.common.base;Joiner;false;appendTo;(Appendable,Iterator);;Element of Argument[1];Argument[-1];taint",
30+
"com.google.common.base;Joiner;false;appendTo;(StringBuilder,Object,Object,Object[]);;Argument[1..2];Argument[0];taint",
31+
"com.google.common.base;Joiner;false;appendTo;(StringBuilder,Object,Object,Object[]);;ArrayElement of Argument[3];Argument[0];taint",
32+
"com.google.common.base;Joiner;false;appendTo;(StringBuilder,Iterable);;Element of Argument[1];Argument[-1];taint",
33+
"com.google.common.base;Joiner;false;appendTo;(StringBuilder,Object[]);;ArrayElement of Argument[1];Argument[-1];taint",
34+
"com.google.common.base;Joiner;false;appendTo;(StringBuilder,Iterator);;Element of Argument[1];Argument[-1];taint",
35+
"com.google.common.base;Joiner;false;appendTo;;;Argument[-1];Argument[0];taint",
2736
"com.google.common.base;Joiner;false;appendTo;;;Argument[0];ReturnValue;value",
2837
"com.google.common.base;Joiner;false;join;;;Argument[-1..2];ReturnValue;taint",
2938
"com.google.common.base;Joiner$MapJoiner;false;useForNull;(String);;Argument[0];ReturnValue;taint",
@@ -42,7 +51,48 @@ private class GuavaBaseCsv extends SummaryModelCsv {
4251
"com.google.common.base;Splitter;false;splitToStream;(CharSequence);;Argument[0];ReturnValue;taint",
4352
"com.google.common.base;Splitter$MapSplitter;false;split;(CharSequence);;Argument[0];ReturnValue;taint",
4453
"com.google.common.base;Preconditions;false;checkNotNull;;;Argument[0];ReturnValue;value",
45-
"com.google.common.base;MoreObjects;false;firstNonNull;;;Argument[0..1];ReturnValue;value"
54+
"com.google.common.base;Verify;false;verifyNotNull;;;Argument[0];ReturnValue;value",
55+
"com.google.common.base;Ascii;false;toLowerCase;(CharSequence);;Argument[0];ReturnValue;taint",
56+
"com.google.common.base;Ascii;false;toLowerCase;(String);;Argument[0];ReturnValue;taint",
57+
"com.google.common.base;Ascii;false;toUpperCase;(CharSequence);;Argument[0];ReturnValue;taint",
58+
"com.google.common.base;Ascii;false;toUpperCase;(String);;Argument[0];ReturnValue;taint",
59+
"com.google.common.base;Ascii;false;truncate;(CharSequence,int,String);;Argument[0];ReturnValue;taint",
60+
"com.google.common.base;Ascii;false;truncate;(CharSequence,int,String);;Argument[2];ReturnValue;taint",
61+
"com.google.common.base;CaseFormat;true;to;(CaseFormat,String);;Argument[1];ReturnValue;taint",
62+
"com.google.common.base;Converter;true;apply;(Object);;Argument[0];ReturnValue;taint",
63+
"com.google.common.base;Converter;true;convert;(Object);;Argument[0];ReturnValue;taint",
64+
"com.google.common.base;Converter;true;convertAll;(Iterable);;Element of Argument[0];Element of ReturnValue;taint",
65+
"com.google.common.base;Supplier;true;get;();;Argument[0];ReturnValue;taint",
66+
"com.google.common.base;Suppliers;false;ofInstance;(Object);;Argument[0];ReturnValue;taint",
67+
"com.google.common.base;Suppliers;false;memoize;(Supplier);;Argument[0];ReturnValue;taint",
68+
"com.google.common.base;Suppliers;false;memoizeWithExpiration;(Supplier,long,TimeUnit);;Argument[0];ReturnValue;taint",
69+
"com.google.common.base;Suppliers;false;synchronizedSupplier;(Supplier);;Argument[0];ReturnValue;taint",
70+
"com.google.common.base;Optional;true;fromJavaUtil;(Optional);;Element of Argument[0];Element of ReturnValue;value",
71+
"com.google.common.base;Optional;true;fromNullable;(Object);;Argument[0];Element of ReturnValue;value",
72+
"com.google.common.base;Optional;true;get;();;Element of Argument[-1];ReturnValue;value",
73+
"com.google.common.base;Optional;true;asSet;();;Element of Argument[-1];Element of ReturnValue;value",
74+
"com.google.common.base;Optional;true;of;(Object);;Argument[0];Element of ReturnValue;value",
75+
"com.google.common.base;Optional;true;or;(Optional);;Element of Argument[-1..0];Element of ReturnValue;value",
76+
"com.google.common.base;Optional;true;or;(Supplier);;Element of Argument[-1];ReturnValue;value",
77+
"com.google.common.base;Optional;true;or;(Supplier);;Argument[0];ReturnValue;taint",
78+
"com.google.common.base;Optional;true;or;(Object);;Element of Argument[-1];ReturnValue;value",
79+
"com.google.common.base;Optional;true;or;(Object);;Argument[0];ReturnValue;value",
80+
"com.google.common.base;Optional;true;orNull;();;Element of Argument[-1];ReturnValue;value",
81+
"com.google.common.base;Optional;true;presentInstances;(Iterable);;Element of Element of Argument[0];Element of ReturnValue;value",
82+
"com.google.common.base;Optional;true;toJavaUtil;();;Element of Argument[-1];Element of ReturnValue;value",
83+
"com.google.common.base;Optional;true;toJavaUtil;(Optional);;Element of Argument[0];Element of ReturnValue;value",
84+
"com.google.common.base;MoreObjects;false;firstNonNull;(Object,Object);;Argument[0..1];ReturnValue;value",
85+
"com.google.common.base;MoreObjects;false;toStringHelper;(String);;Argument[0];ReturnValue;taint",
86+
"com.google.common.base;MoreObjects$ToStringHelper;false;add;;;Argument[0];ReturnValue;taint",
87+
"com.google.common.base;MoreObjects$ToStringHelper;false;add;;;Argument[0];Argument[-1];taint",
88+
"com.google.common.base;MoreObjects$ToStringHelper;false;add;;;Argument[-1];ReturnValue;value",
89+
"com.google.common.base;MoreObjects$ToStringHelper;false;add;(String,Object);;Argument[1];ReturnValue;taint",
90+
"com.google.common.base;MoreObjects$ToStringHelper;false;add;(String,Object);;Argument[1];Argument[-1];taint",
91+
"com.google.common.base;MoreObjects$ToStringHelper;false;addValue;;;Argument[-1];ReturnValue;value",
92+
"com.google.common.base;MoreObjects$ToStringHelper;false;addValue;(Object);;Argument[0];ReturnValue;taint",
93+
"com.google.common.base;MoreObjects$ToStringHelper;false;addValue;(Object);;Argument[0];Argument[-1];taint",
94+
"com.google.common.base;MoreObjects$ToStringHelper;false;omitNullValues;();;Argument[-1];ReturnValue;value",
95+
"com.google.common.base;MoreObjects$ToStringHelper;false;toString;();;Argument[-1];ReturnValue;taint"
4696
]
4797
}
4898
}

java/ql/test/library-tests/frameworks/guava/TestBase.java

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.util.Map;
44
import java.util.HashMap;
5+
import java.util.concurrent.TimeUnit;
6+
import java.util.Set;
57

68
class TestBase {
79
String taint() { return "tainted"; }
@@ -14,7 +16,7 @@ void test1() {
1416
sink(Strings.padStart(x, 10, ' ')); // $numTaintFlow=1
1517
sink(Strings.padEnd(x, 10, ' ')); // $numTaintFlow=1
1618
sink(Strings.repeat(x, 3)); // $numTaintFlow=1
17-
sink(Strings.emptyToNull(Strings.nullToEmpty(x))); // $numTaintFlow=1
19+
sink(Strings.emptyToNull(Strings.nullToEmpty(x))); // $numValueFlow=1
1820
sink(Strings.lenientFormat(x, 3)); // $numTaintFlow=1
1921
sink(Strings.commonPrefix(x, "abc"));
2022
sink(Strings.commonSuffix(x, "cde"));
@@ -58,12 +60,50 @@ void test3() {
5860
}
5961

6062
void test4() {
61-
sink(Preconditions.checkNotNull(taint())); // $numTaintFlow=1
63+
sink(Preconditions.checkNotNull(taint())); // $numValueFlow=1
64+
sink(Verify.verifyNotNull(taint())); // $numValueFlow=1
6265
}
6366

6467
void test5() {
65-
sink(MoreObjects.firstNonNull(taint(), taint())); // $numTaintFlow=2
66-
sink(MoreObjects.firstNonNull(null, taint())); // $numTaintFlow=1
67-
sink(MoreObjects.firstNonNull(taint(), null)); // $numTaintFlow=1
68+
sink(Ascii.toLowerCase(taint())); // $numTaintFlow=1
69+
sink(Ascii.toUpperCase(taint())); // $numTaintFlow=1
70+
sink(Ascii.truncate(taint(), 3, "...")); // $numTaintFlow=1
71+
sink(Ascii.truncate("abcabcabc", 3, taint())); // $numTaintFlow=1
72+
sink(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, taint())); // $numTaintFlow=1
73+
sink(CaseFormat.LOWER_HYPHEN.converterTo(CaseFormat.UPPER_CAMEL).convert(taint())); // $numTaintFlow=1
74+
sink(CaseFormat.LOWER_UNDERSCORE.converterTo(CaseFormat.LOWER_HYPHEN).reverse().convert(taint())); // $numTaintFlow=1
75+
}
76+
77+
void test6() {
78+
sink(Suppliers.memoize(Suppliers.memoizeWithExpiration(Suppliers.synchronizedSupplier(Suppliers.ofInstance(taint())), 3, TimeUnit.HOURS))); // $numTaintFlow=1
79+
}
80+
81+
void test7() {
82+
sink(MoreObjects.firstNonNull(taint(), taint())); // $numValueFlow=2
83+
sink(MoreObjects.firstNonNull(null, taint())); // $numValueFlow=1
84+
sink(MoreObjects.firstNonNull(taint(), null)); // $numValueFlow=1
85+
sink(MoreObjects.toStringHelper(taint()).add("x", 3).omitNullValues().toString()); // $numTaintFlow=1
86+
sink(MoreObjects.toStringHelper((Object) taint()).toString());
87+
sink(MoreObjects.toStringHelper("a").add("x", 3).add(taint(), 4).toString()); // $numTaintFlow=1
88+
sink(MoreObjects.toStringHelper("a").add("x", taint()).toString()); // $numTaintFlow=1
89+
sink(MoreObjects.toStringHelper("a").addValue(taint()).toString()); // $numTaintFlow=1
90+
MoreObjects.ToStringHelper h = MoreObjects.toStringHelper("a");
91+
h.add("x", 3).add(taint(), 4);
92+
sink(h.add("z",5).toString()); // $numTaintFlow=1
93+
}
94+
95+
void test8() {
96+
Optional<String> x = Optional.of(taint());
97+
sink(x); // $numTaintFlow=1
98+
sink(x.get()); // $numValueFlow=1
99+
sink(x.or("hi")); // $numValueFlow=1
100+
sink(x.orNull()); // $numValueFlow=1
101+
sink(x.asSet().toArray()[0]); // $numValueFlow=1
102+
sink(Optional.fromJavaUtil(x.toJavaUtil()).get()); // $numValueFlow=1
103+
sink(Optional.fromJavaUtil(Optional.toJavaUtil(x)).get()); // $numValueFlow=1
104+
sink(Optional.fromNullable(taint()).get()); // $numValueFlow=1
105+
sink(Optional.absent().or(x).get()); // $numValueFlow=1
106+
sink(Optional.absent().or(taint())); // $numValueFlow=1
107+
sink(Optional.presentInstances(Set.of(x)).iterator().next()); // $numValueFlow=1
68108
}
69109
}

java/ql/test/library-tests/frameworks/guava/TestIO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ void test3() throws IOException {
106106
}
107107

108108
void test4() throws IOException {
109-
sink(Closer.create().register((Closeable) taint())); // $numTaintFlow=1
109+
sink(Closer.create().register((Closeable) taint())); // $numValueFlow=1
110110
sink(new LineReader(rtaint()).readLine()); // $numTaintFlow=1
111111
sink(Files.simplifyPath(staint())); // $numTaintFlow=1
112112
sink(Files.getFileExtension(staint())); // $numTaintFlow=1

java/ql/test/library-tests/frameworks/guava/flow.ql

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,20 @@ import java
22
import semmle.code.java.dataflow.TaintTracking
33
import TestUtilities.InlineExpectationsTest
44

5-
class Conf extends TaintTracking::Configuration {
6-
Conf() { this = "qltest:frameworks:guava" }
5+
class TaintFlowConf extends TaintTracking::Configuration {
6+
TaintFlowConf() { this = "qltest:frameworks:guava-taint" }
7+
8+
override predicate isSource(DataFlow::Node n) {
9+
n.asExpr().(MethodAccess).getMethod().hasName("taint")
10+
}
11+
12+
override predicate isSink(DataFlow::Node n) {
13+
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
14+
}
15+
}
16+
17+
class ValueFlowConf extends DataFlow::Configuration {
18+
ValueFlowConf() { this = "qltest:frameworks:guava-value" }
719

820
override predicate isSource(DataFlow::Node n) {
921
n.asExpr().(MethodAccess).getMethod().hasName("taint")
@@ -17,15 +29,28 @@ class Conf extends TaintTracking::Configuration {
1729
class HasFlowTest extends InlineExpectationsTest {
1830
HasFlowTest() { this = "HasFlowTest" }
1931

20-
override string getARelevantTag() { result = "numTaintFlow" }
32+
override string getARelevantTag() { result = ["numTaintFlow", "numValueFlow"] }
2133

2234
override predicate hasActualResult(Location location, string element, string tag, string value) {
2335
tag = "numTaintFlow" and
24-
exists(DataFlow::Node src, DataFlow::Node sink, Conf conf, int num | conf.hasFlow(src, sink) |
36+
exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf tconf, int num |
37+
tconf.hasFlow(src, sink)
38+
|
39+
not any(ValueFlowConf vconf).hasFlow(src, sink) and
40+
value = num.toString() and
41+
sink.getLocation() = location and
42+
element = sink.toString() and
43+
num = strictcount(DataFlow::Node src2 | tconf.hasFlow(src2, sink))
44+
)
45+
or
46+
tag = "numValueFlow" and
47+
exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf vconf, int num |
48+
vconf.hasFlow(src, sink)
49+
|
2550
value = num.toString() and
2651
sink.getLocation() = location and
2752
element = sink.toString() and
28-
num = strictcount(DataFlow::Node src2 | conf.hasFlow(src2, sink))
53+
num = strictcount(DataFlow::Node src2 | vconf.hasFlow(src2, sink))
2954
)
3055
}
3156
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (C) 2010 The Guava Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
15+
package com.google.common.base;
16+
17+
public final class Ascii {
18+
public static String toLowerCase(String string) {
19+
return null;
20+
}
21+
22+
public static String toLowerCase(CharSequence chars) {
23+
return null;
24+
}
25+
26+
public static char toLowerCase(char c) {
27+
return '0';
28+
}
29+
30+
public static String toUpperCase(String string) {
31+
return null;
32+
}
33+
34+
public static String toUpperCase(CharSequence chars) {
35+
return null;
36+
}
37+
38+
public static char toUpperCase(char c) {
39+
return '0';
40+
}
41+
42+
public static boolean isLowerCase(char c) {
43+
return false;
44+
}
45+
46+
public static boolean isUpperCase(char c) {
47+
return false;
48+
}
49+
50+
public static String truncate(CharSequence seq, int maxLength, String truncationIndicator) {
51+
return null;
52+
}
53+
54+
public static boolean equalsIgnoreCase(CharSequence s1, CharSequence s2) {
55+
return false;
56+
}
57+
58+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (C) 2006 The Guava Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
15+
package com.google.common.base;
16+
17+
public enum CaseFormat {
18+
LOWER_HYPHEN,
19+
LOWER_UNDERSCORE,
20+
LOWER_CAMEL,
21+
UPPER_CAMEL,
22+
UPPER_UNDERSCORE;
23+
24+
public final String to(CaseFormat format, String str) {
25+
return null;
26+
}
27+
28+
public Converter<String, String> converterTo(CaseFormat targetFormat) {
29+
return null;
30+
}
31+
32+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (C) 2008 The Guava Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
15+
package com.google.common.base;
16+
import org.checkerframework.checker.nullness.qual.Nullable;
17+
18+
public abstract class Converter<A, B> implements Function<A, B> {
19+
public final @Nullable B convert(@Nullable A a) {
20+
return null;
21+
}
22+
23+
public Iterable<B> convertAll(final Iterable<? extends A> fromIterable) {
24+
return null;
25+
}
26+
27+
public Converter<B, A> reverse() {
28+
return null;
29+
}
30+
31+
public final <C> Converter<A, C> andThen(Converter<B, C> secondConverter) {
32+
return null;
33+
}
34+
35+
@Override
36+
public final @Nullable B apply(@Nullable A a) {
37+
return null;
38+
}
39+
40+
@Override
41+
public boolean equals(@Nullable Object object) {
42+
return false;
43+
}
44+
45+
public static <A, B> Converter<A, B> from(
46+
Function<? super A, ? extends B> forwardFunction,
47+
Function<? super B, ? extends A> backwardFunction) {
48+
return null;
49+
}
50+
51+
public static <T> Converter<T, T> identity() {
52+
return null;
53+
}
54+
55+
}

0 commit comments

Comments
 (0)