Merge pull request #5310 from joefarebrother/guava-io

Java: Add modelling for Guava IO utilities
This commit is contained in:
Joe Farebrother
2021-03-09 11:19:44 +00:00
committed by GitHub
41 changed files with 1927 additions and 106 deletions

View File

@@ -14,20 +14,20 @@ class TestCollect {
String x = taint();
ImmutableSet<String> xs = ImmutableSet.of(x, "y", "z");
sink(xs.asList());
sink(xs.asList()); // $numTaintFlow=1
ImmutableSet<String> ys = ImmutableSet.of("a", "b", "c");
sink(Sets.filter(Sets.union(xs, ys), y -> true));
sink(Sets.filter(Sets.union(xs, ys), y -> true)); // $numTaintFlow=1
sink(Sets.newHashSet("a", "b", "c", "d", x));
sink(Sets.newHashSet("a", "b", "c", "d", x)); // $numTaintFlow=1
}
void test2() {
sink(ImmutableList.of(taint(), taint(), taint(), taint())); // expect 4 alerts
sink(ImmutableMap.of(taint(), taint(), taint(), taint())); // expect 2 alerts
sink(ImmutableMultimap.of(taint(), taint(), taint(), taint())); // expect 2 alerts
sink(ImmutableTable.of(taint(),taint(), taint())); // expect 1 alert
sink(ImmutableList.of(taint(), taint(), taint(), taint())); // $numTaintFlow=4
sink(ImmutableMap.of(taint(), taint(), taint(), taint())); // $numTaintFlow=2
sink(ImmutableMultimap.of(taint(), taint(), taint(), taint())); // $numTaintFlow=2
sink(ImmutableTable.of(taint(),taint(), taint())); // $numTaintFlow=1
}
void test3() {
@@ -38,20 +38,20 @@ class TestCollect {
b.add("a");
sink(b);
b.add(x);
sink(b.build());
sink(b.build()); // $numTaintFlow=1
b = ImmutableList.builder();
b.add("a").add(x);
sink(b.build());
sink(b.build()); // $numTaintFlow=1
sink(ImmutableList.builder().add("a").add(x).build());
sink(ImmutableList.builder().add("a").add(x).build()); // $numTaintFlow=1
ImmutableMap.Builder<String, String> b2 = ImmutableMap.builder();
b2.put(x,"v");
sink(b2);
b2.put("k",x);
sink(b2.build());
sink(b2.build()); // $numTaintFlow=1
}
void test4(Table<String, String, String> t1, Table<String, String, String> t2, Table<String, String, String> t3) {
@@ -61,62 +61,62 @@ class TestCollect {
t1.put("r", x, "v");
sink(t1);
t1.put("r", "c", x);
sink(t1);
sink(t1.row("r"));
sink(t1); // $numTaintFlow=1
sink(t1.row("r")); // $numTaintFlow=1
t2.putAll(t1);
for (Table.Cell<String,String,String> c : t2.cellSet()) {
sink(c.getValue());
sink(c.getValue()); // $numTaintFlow=1
}
sink(t1.remove("r", "c"));
sink(t1.remove("r", "c")); // $numTaintFlow=1
t3.row("r").put("c", x);
sink(t3); // Not detected
sink(t3); // $ MISSING:numTaintFlow=1
}
void test4(Multimap<String, String> m1, Multimap<String, String> m2, Multimap<String, String> m3,
Multimap<String, String> m4, Multimap<String, String> m5){
String x = taint();
m1.put("k", x);
sink(m1);
sink(m1.get("k"));
sink(m1); // $numTaintFlow=1
sink(m1.get("k")); // $numTaintFlow=1
m2.putAll("k", ImmutableList.of("a", x, "b"));
sink(m2);
sink(m2); // $numTaintFlow=1
m3.putAll(m1);
sink(m3);
sink(m3); // $numTaintFlow=1
m4.replaceValues("k", m1.replaceValues("k", ImmutableList.of("a")));
for (Map.Entry<String, String> e : m4.entries()) {
sink(e.getValue());
sink(e.getValue()); // $numTaintFlow=1
}
m5.asMap().get("k").add(x);
sink(m5); // Not detected
sink(m5); // $ MISSING:numTaintFlow=1
}
void test5(Comparator<String> comp, SortedSet<String> sorS, SortedMap<String, String> sorM) {
ImmutableSortedSet<String> s = ImmutableSortedSet.of(taint());
sink(s);
sink(ImmutableSortedSet.copyOf(s));
sink(ImmutableSortedSet.copyOf(comp, s));
sink(s); // $numTaintFlow=1
sink(ImmutableSortedSet.copyOf(s)); // $numTaintFlow=1
sink(ImmutableSortedSet.copyOf(comp, s)); // $numTaintFlow=1
sorS.add(taint());
sink(ImmutableSortedSet.copyOfSorted(sorS));
sink(ImmutableSortedSet.copyOfSorted(sorS)); // $numTaintFlow=1
sink(ImmutableList.sortedCopyOf(s));
sink(ImmutableList.sortedCopyOf(comp, s));
sink(ImmutableList.sortedCopyOf(s)); // $numTaintFlow=1
sink(ImmutableList.sortedCopyOf(comp, s)); // $numTaintFlow=1
ImmutableSortedMap<String, String> m = ImmutableSortedMap.of("k", taint());
sink(m);
sink(ImmutableSortedMap.copyOf(m));
sink(ImmutableSortedMap.copyOf(m, comp));
sink(m); // $numTaintFlow=1
sink(ImmutableSortedMap.copyOf(m)); // $numTaintFlow=1
sink(ImmutableSortedMap.copyOf(m, comp)); // $numTaintFlow=1
sorM.put("k", taint());
sink(ImmutableSortedMap.copyOfSorted(sorM));
sink(ImmutableSortedMap.copyOfSorted(sorM)); // $numTaintFlow=1
}
}

View File

@@ -0,0 +1,126 @@
package com.google.common.io;
import com.google.common.collect.ImmutableList;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.StringBuffer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.Closeable;
import java.nio.file.Path;
import java.io.IOException;
class TestIO {
Object taint() { return null; }
String staint(){ return (String) taint(); }
byte[] btaint() { return (byte[]) taint(); }
InputStream itaint() { return (InputStream) taint(); }
Reader rtaint() { return new InputStreamReader(itaint()); }
Path ptaint() { return (Path) taint(); }
void sink(Object o) {}
void test1() {
BaseEncoding enc = BaseEncoding.base64();
sink(enc.decode(staint())); // $numTaintFlow=1
sink(enc.encode(btaint())); // $numTaintFlow=1
sink(enc.encode(btaint(), 0, 42)); // $numTaintFlow=1
sink(enc.decodingStream(rtaint())); // $numTaintFlow=1
sink(enc.decodingSource(CharSource.wrap(staint()))); // $numTaintFlow=1
sink(enc.withSeparator(staint(), 10).omitPadding().lowerCase().decode("abc")); // $numTaintFlow=1
}
void test2() throws IOException {
ByteSource b = ByteSource.wrap(btaint());
sink(b.openStream()); // $numTaintFlow=1
sink(b.openBufferedStream()); // $numTaintFlow=1
sink(b.asCharSource(null)); // $numTaintFlow=1
sink(b.slice(42,1337)); // $numTaintFlow=1
sink(b.read()); // $numTaintFlow=1
sink(ByteSource.concat(ByteSource.empty(), ByteSource.empty(), b)); // $numTaintFlow=1
sink(ByteSource.concat(ImmutableList.of(ByteSource.empty(), ByteSource.empty(), b))); // $numTaintFlow=1
sink(b.read(new MyByteProcessor())); // $ MISSING:numTaintFlow=1
ByteArrayOutputStream out = new ByteArrayOutputStream();
b.copyTo(out);
sink(out.toByteArray()); // $numTaintFlow=1
CharSource c = CharSource.wrap(staint());
sink(c.openStream()); // $numTaintFlow=1
sink(c.openBufferedStream()); // $numTaintFlow=1
sink(c.asByteSource(null)); // $numTaintFlow=1
sink(c.readFirstLine()); // $numTaintFlow=1
sink(c.readLines()); // $numTaintFlow=1
sink(c.read()); // $numTaintFlow=1
sink(c.lines()); // $numTaintFlow=1
sink(CharSource.concat(CharSource.empty(), CharSource.empty(), c)); // $numTaintFlow=1
sink(CharSource.concat(ImmutableList.of(CharSource.empty(), CharSource.empty(), c))); // $numTaintFlow=1
sink(c.readLines(new MyLineProcessor())); // $ MISSING:numTaintFlow=1
c.forEachLine(l -> sink(l)); // $ MISSING:numTaintFlow=1
StringBuffer buf = new StringBuffer();
c.copyTo(buf);
sink(buf); // $numTaintFlow=1
}
class MyByteProcessor implements ByteProcessor<Object> {
byte[] buf;
public Object getResult() { return buf; }
public boolean processBytes(byte[] b, int off, int len) { this.buf = b; return false; }
}
class MyLineProcessor implements LineProcessor<String> {
String s = "";
public String getResult() { return s; }
public boolean processLine(String l) { this.s += l; return true; }
}
void test3() throws IOException {
sink(ByteStreams.limit(itaint(), 1337)); // $numTaintFlow=1
sink(ByteStreams.newDataInput(btaint())); // $numTaintFlow=1
sink(ByteStreams.newDataInput(btaint(), 0)); // $numTaintFlow=1
sink(ByteStreams.newDataInput(btaint())); // $numTaintFlow=1
sink(ByteStreams.newDataInput(btaint()).readLine()); // $ MISSING:numTaintFlow=1
sink(ByteStreams.newDataInput(new ByteArrayInputStream(btaint()))); // $numTaintFlow=1
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(btaint());
sink(ByteStreams.newDataOutput(out)); // $numTaintFlow=1
byte[] b1 = null, b2 = null, b3 = null;
ByteStreams.read(itaint(), b1, 0, 42);
sink(b1); // $numTaintFlow=1
ByteStreams.readFully(itaint(), b2);
sink(b2); // $numTaintFlow=1
ByteStreams.readFully(itaint(), b3, 0, 42);
sink(b3); // $numTaintFlow=1
sink(ByteStreams.readBytes(itaint(), new MyByteProcessor())); // $ MISSING:numTaintFlow=1
sink(ByteStreams.toByteArray(itaint())); // $numTaintFlow=1
ByteArrayDataOutput out2 = ByteStreams.newDataOutput();
out2.writeUTF(staint());
sink(out2.toByteArray()); // $numTaintFlow=1
StringBuffer buf = new StringBuffer();
CharStreams.copy(rtaint(), buf);
sink(buf); // $numTaintFlow=1
sink(CharStreams.readLines(rtaint())); // $numTaintFlow=1
sink(CharStreams.readLines(rtaint(), new MyLineProcessor())); // $ MISSING:numTaintFlow=1
sink(CharStreams.toString(rtaint())); // $numTaintFlow=1
}
void test4() throws IOException {
sink(Closer.create().register((Closeable) taint())); // $numTaintFlow=1
sink(new LineReader(rtaint()).readLine()); // $numTaintFlow=1
sink(Files.simplifyPath(staint())); // $numTaintFlow=1
sink(Files.getFileExtension(staint())); // $numTaintFlow=1
sink(Files.getNameWithoutExtension(staint())); // $numTaintFlow=1
sink(MoreFiles.getFileExtension(ptaint())); // $numTaintFlow=1
sink(MoreFiles.getNameWithoutExtension(ptaint())); // $numTaintFlow=1
}
void test6() throws IOException {
sink(new CountingInputStream(itaint())); // $numTaintFlow=1
byte[] buf = null;
new CountingInputStream(itaint()).read(buf, 0, 42);
sink(buf); // $numTaintFlow=1
sink(new LittleEndianDataInputStream(itaint())); // $numTaintFlow=1
sink(new LittleEndianDataInputStream(itaint()).readUTF()); // $ MISSING:numTaintFlow=1
}
}

View File

@@ -14,14 +14,14 @@ class TestStrings {
void test1() {
String x = taint();
sink(Strings.padStart(x, 10, ' '));
sink(Strings.padEnd(x, 10, ' '));
sink(Strings.repeat(x, 3));
sink(Strings.emptyToNull(Strings.nullToEmpty(x)));
sink(Strings.lenientFormat(x, 3));
sink(Strings.commonPrefix(x, "abc"));
sink(Strings.commonSuffix(x, "cde"));
sink(Strings.lenientFormat("%s = %s", x, 3));
sink(Strings.padStart(x, 10, ' ')); // $numTaintFlow=1
sink(Strings.padEnd(x, 10, ' ')); // $numTaintFlow=1
sink(Strings.repeat(x, 3)); // $numTaintFlow=1
sink(Strings.emptyToNull(Strings.nullToEmpty(x))); // $numTaintFlow=1
sink(Strings.lenientFormat(x, 3)); // $numTaintFlow=1
sink(Strings.commonPrefix(x, "abc"));
sink(Strings.commonSuffix(x, "cde"));
sink(Strings.lenientFormat("%s = %s", x, 3)); // $numTaintFlow=1
}
void test2() {
@@ -29,10 +29,10 @@ class TestStrings {
Splitter s = Splitter.on(x).omitEmptyStrings();
sink(s.split("x y z"));
sink(s.split(x));
sink(s.splitToList(x));
sink(s.split(x)); // $numTaintFlow=1
sink(s.splitToList(x)); // $numTaintFlow=1
sink(s.withKeyValueSeparator("=").split("a=b"));
sink(s.withKeyValueSeparator("=").split(x));
sink(s.withKeyValueSeparator("=").split(x)); // $numTaintFlow=1
}
void test3() {
@@ -43,20 +43,20 @@ class TestStrings {
StringBuilder sb = new StringBuilder();
sink(safeJoiner.appendTo(sb, "a", "b", "c"));
sink(sb.toString());
sink(taintedJoiner.appendTo(sb, "a", "b", "c"));
sink(sb.toString());
sink(safeJoiner.appendTo(sb, "a", "b", "c"));
sink(sb.toString());
sink(taintedJoiner.appendTo(sb, "a", "b", "c")); // $numTaintFlow=1
sink(sb.toString()); // $numTaintFlow=1
sink(safeJoiner.appendTo(sb, "a", "b", "c")); // $numTaintFlow=1
sink(sb.toString()); // $numTaintFlow=1
sb = new StringBuilder();
sink(safeJoiner.appendTo(sb, x, x));
sink(safeJoiner.appendTo(sb, x, x)); // $numTaintFlow=1
Map<String, String> m = new HashMap<String, String>();
m.put("k", "v");
sink(safeJoiner.withKeyValueSeparator("=").join(m));
sink(safeJoiner.withKeyValueSeparator(x).join(m));
sink(taintedJoiner.useForNull("(null)").withKeyValueSeparator("=").join(m));
sink(safeJoiner.withKeyValueSeparator(x).join(m)); // $numTaintFlow=1
sink(taintedJoiner.useForNull("(null)").withKeyValueSeparator("=").join(m)); // $numTaintFlow=1
m.put("k2", x);
sink(safeJoiner.withKeyValueSeparator("=").join(m));
sink(safeJoiner.withKeyValueSeparator("=").join(m)); // $numTaintFlow=1
}
}

View File

@@ -1,52 +0,0 @@
| TestCollect.java:14:20:14:26 | taint(...) | TestCollect.java:17:14:17:24 | asList(...) |
| TestCollect.java:14:20:14:26 | taint(...) | TestCollect.java:21:14:21:55 | filter(...) |
| TestCollect.java:14:20:14:26 | taint(...) | TestCollect.java:23:14:23:51 | newHashSet(...) |
| TestCollect.java:27:31:27:37 | taint(...) | TestCollect.java:27:14:27:65 | of(...) |
| TestCollect.java:27:40:27:46 | taint(...) | TestCollect.java:27:14:27:65 | of(...) |
| TestCollect.java:27:49:27:55 | taint(...) | TestCollect.java:27:14:27:65 | of(...) |
| TestCollect.java:27:58:27:64 | taint(...) | TestCollect.java:27:14:27:65 | of(...) |
| TestCollect.java:28:39:28:45 | taint(...) | TestCollect.java:28:14:28:64 | of(...) |
| TestCollect.java:28:57:28:63 | taint(...) | TestCollect.java:28:14:28:64 | of(...) |
| TestCollect.java:29:44:29:50 | taint(...) | TestCollect.java:29:14:29:69 | of(...) |
| TestCollect.java:29:62:29:68 | taint(...) | TestCollect.java:29:14:29:69 | of(...) |
| TestCollect.java:30:49:30:55 | taint(...) | TestCollect.java:30:14:30:56 | of(...) |
| TestCollect.java:34:20:34:26 | taint(...) | TestCollect.java:41:14:41:22 | build(...) |
| TestCollect.java:34:20:34:26 | taint(...) | TestCollect.java:46:14:46:22 | build(...) |
| TestCollect.java:34:20:34:26 | taint(...) | TestCollect.java:48:14:48:60 | build(...) |
| TestCollect.java:34:20:34:26 | taint(...) | TestCollect.java:54:14:54:23 | build(...) |
| TestCollect.java:58:20:58:26 | taint(...) | TestCollect.java:64:14:64:15 | t1 |
| TestCollect.java:58:20:58:26 | taint(...) | TestCollect.java:65:14:65:24 | row(...) |
| TestCollect.java:58:20:58:26 | taint(...) | TestCollect.java:69:18:69:29 | getValue(...) |
| TestCollect.java:58:20:58:26 | taint(...) | TestCollect.java:72:14:72:32 | remove(...) |
| TestCollect.java:80:20:80:26 | taint(...) | TestCollect.java:82:14:82:15 | m1 |
| TestCollect.java:80:20:80:26 | taint(...) | TestCollect.java:83:14:83:24 | get(...) |
| TestCollect.java:80:20:80:26 | taint(...) | TestCollect.java:86:14:86:15 | m2 |
| TestCollect.java:80:20:80:26 | taint(...) | TestCollect.java:89:14:89:15 | m3 |
| TestCollect.java:80:20:80:26 | taint(...) | TestCollect.java:93:18:93:29 | getValue(...) |
| TestCollect.java:101:62:101:68 | taint(...) | TestCollect.java:103:14:103:14 | s |
| TestCollect.java:101:62:101:68 | taint(...) | TestCollect.java:104:14:104:41 | copyOf(...) |
| TestCollect.java:101:62:101:68 | taint(...) | TestCollect.java:105:14:105:47 | copyOf(...) |
| TestCollect.java:101:62:101:68 | taint(...) | TestCollect.java:110:14:110:42 | sortedCopyOf(...) |
| TestCollect.java:101:62:101:68 | taint(...) | TestCollect.java:111:14:111:48 | sortedCopyOf(...) |
| TestCollect.java:107:18:107:24 | taint(...) | TestCollect.java:108:14:108:50 | copyOfSorted(...) |
| TestCollect.java:113:75:113:81 | taint(...) | TestCollect.java:115:14:115:14 | m |
| TestCollect.java:113:75:113:81 | taint(...) | TestCollect.java:116:14:116:41 | copyOf(...) |
| TestCollect.java:113:75:113:81 | taint(...) | TestCollect.java:117:14:117:47 | copyOf(...) |
| TestCollect.java:119:23:119:29 | taint(...) | TestCollect.java:120:14:120:50 | copyOfSorted(...) |
| TestStrings.java:15:20:15:26 | taint(...) | TestStrings.java:17:14:17:41 | padStart(...) |
| TestStrings.java:15:20:15:26 | taint(...) | TestStrings.java:18:14:18:39 | padEnd(...) |
| TestStrings.java:15:20:15:26 | taint(...) | TestStrings.java:19:14:19:33 | repeat(...) |
| TestStrings.java:15:20:15:26 | taint(...) | TestStrings.java:20:14:20:56 | emptyToNull(...) |
| TestStrings.java:15:20:15:26 | taint(...) | TestStrings.java:21:14:21:40 | lenientFormat(...) |
| TestStrings.java:15:20:15:26 | taint(...) | TestStrings.java:24:14:24:51 | lenientFormat(...) |
| TestStrings.java:28:20:28:26 | taint(...) | TestStrings.java:32:14:32:23 | split(...) |
| TestStrings.java:28:20:28:26 | taint(...) | TestStrings.java:33:14:33:29 | splitToList(...) |
| TestStrings.java:28:20:28:26 | taint(...) | TestStrings.java:35:14:35:50 | split(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:46:14:46:54 | appendTo(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:47:14:47:26 | toString(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:48:14:48:51 | appendTo(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:49:14:49:26 | toString(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:52:14:52:42 | appendTo(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:57:14:57:56 | join(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:58:14:58:82 | join(...) |
| TestStrings.java:39:20:39:26 | taint(...) | TestStrings.java:60:14:60:58 | join(...) |

View File

@@ -1,5 +1,6 @@
import java
import semmle.code.java.dataflow.TaintTracking
import TestUtilities.InlineExpectationsTest
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:frameworks:guava" }
@@ -13,6 +14,18 @@ class Conf extends TaintTracking::Configuration {
}
}
from DataFlow::Node src, DataFlow::Node sink, Conf conf
where conf.hasFlow(src, sink)
select src, sink
class HasFlowTest extends InlineExpectationsTest {
HasFlowTest() { this = "HasFlowTest" }
override string getARelevantTag() { result = "numTaintFlow" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "numTaintFlow" and
exists(DataFlow::Node src, DataFlow::Node sink, Conf conf, int num | conf.hasFlow(src, sink) |
value = num.toString() and
sink.getLocation() = location and
element = sink.toString() and
num = strictcount(DataFlow::Node src2 | conf.hasFlow(src2, sink))
)
}
}