Skip to content

Commit b542b08

Browse files
authored
Merge pull request #2726 from aschackmull/java/outputstream-write-taint
Java: Improve taint for OutputStream.write and InputStream.read.
2 parents 563be9f + 9bea581 commit b542b08

File tree

4 files changed

+59
-6
lines changed

4 files changed

+59
-6
lines changed

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,12 @@ private predicate taintPreservingQualifierToArgument(Method m, int arg) {
256256
m.hasName("writeTo") and
257257
arg = 0
258258
or
259-
m.getDeclaringType().hasQualifiedName("java.io", "InputStream") and
260-
m.hasName("read") and
261-
arg = 0
259+
exists(Method read |
260+
m.overrides*(read) and
261+
read.getDeclaringType().hasQualifiedName("java.io", "InputStream") and
262+
read.hasName("read") and
263+
arg = 0
264+
)
262265
or
263266
m.getDeclaringType().getASupertype*().hasQualifiedName("java.io", "Reader") and
264267
m.hasName("read") and
@@ -515,9 +518,12 @@ private predicate argToQualifierStep(Expr tracked, Expr sink) {
515518
* `arg` is the index of the argument.
516519
*/
517520
private predicate taintPreservingArgumentToQualifier(Method method, int arg) {
518-
method.getDeclaringType().hasQualifiedName("java.io", "ByteArrayOutputStream") and
519-
method.hasName("write") and
520-
arg = 0
521+
exists(Method write |
522+
method.overrides*(write) and
523+
write.getDeclaringType().hasQualifiedName("java.io", "OutputStream") and
524+
write.hasName("write") and
525+
arg = 0
526+
)
521527
}
522528

523529
/** A comparison or equality test with a constant. */
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import java.io.*;
2+
3+
public class A {
4+
byte[] taint() { return new byte[2]; }
5+
6+
void sink(Object o) { }
7+
8+
void test1() {
9+
ByteArrayOutputStream bOutput = new ByteArrayOutputStream();
10+
bOutput.write(taint(), 0, 1);
11+
byte[] b = bOutput.toByteArray();
12+
ByteArrayInputStream bInput = new ByteArrayInputStream(b);
13+
byte[] b2 = new byte[10];
14+
bInput.read(b2, 0, 1);
15+
sink(b2);
16+
}
17+
18+
void test2() {
19+
ByteArrayOutputStream bOutput = new ByteArrayOutputStream();
20+
bOutput.write(taint());
21+
byte[] b = bOutput.toByteArray();
22+
ByteArrayInputStream bInput = new ByteArrayInputStream(b);
23+
byte[] b2 = new byte[10];
24+
bInput.read(b2);
25+
sink(b2);
26+
}
27+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| A.java:10:19:10:25 | taint(...) | A.java:15:10:15:11 | b2 |
2+
| A.java:20:19:20:25 | taint(...) | A.java:25:10:25:11 | b2 |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import java
2+
import semmle.code.java.dataflow.TaintTracking
3+
4+
class Conf extends TaintTracking::Configuration {
5+
Conf() { this = "qqconf" }
6+
7+
override predicate isSource(DataFlow::Node n) {
8+
n.asExpr().(MethodAccess).getMethod().hasName("taint")
9+
}
10+
11+
override predicate isSink(DataFlow::Node n) {
12+
n.asExpr().(Argument).getCall().getCallee().hasName("sink")
13+
}
14+
}
15+
16+
from DataFlow::Node src, DataFlow::Node sink, Conf conf
17+
where conf.hasFlow(src, sink)
18+
select src, sink

0 commit comments

Comments
 (0)