Skip to content

Commit 7fb5bd0

Browse files
committed
Add tests for and slightly expand models of Commons Lang's ArrayUtils class
1 parent bc9682c commit 7fb5bd0

File tree

3 files changed

+1470
-4
lines changed

3 files changed

+1470
-4
lines changed

java/ql/src/semmle/code/java/frameworks/apache/Lang.qll

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,27 @@ private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingC
4949
src = [0 .. getNumberOfParameters() - 1]
5050
or
5151
this.hasName([
52-
"clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", "reverse",
53-
"shift", "shuffle", "subarray", "swap", "toArray", "toMap", "toObject", "toPrimitive",
54-
"toString", "toStringArray"
52+
"clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements",
53+
"subarray", "toArray", "toMap", "toObject", "removeAllOccurences", "removeAllOccurrences"
5554
]) and
5655
src = 0
5756
or
57+
this.hasName("toPrimitive") and
58+
src = [0, 1]
59+
or
5860
this.hasName("add") and
5961
this.getNumberOfParameters() = 2 and
6062
src = [0, 1]
6163
or
62-
this.hasName("add") and
64+
this.hasName(["add"]) and
6365
this.getNumberOfParameters() = 3 and
6466
src = [0, 2]
67+
or
68+
this.hasName("insert") and
69+
src = [1, 2]
70+
or
71+
this.hasName("get") and
72+
src = [0, 2]
6573
}
6674
}
6775

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import org.apache.commons.lang3.ArrayUtils;
2+
import java.io.StringReader;
3+
import java.nio.CharBuffer;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
import java.util.Locale;
7+
8+
class ArrayUtilsTest {
9+
String taint() { return "tainted"; }
10+
11+
private static class IntSource {
12+
static int taint() { return 0; }
13+
}
14+
15+
void sink(Object o) {}
16+
17+
void test() throws Exception {
18+
19+
// All methods of this class copy the input array, so the incoming array should not be assigned taint.
20+
String[] alreadyTainted = new String[] { taint() };
21+
String[] clean = new String[] { "Untainted" };
22+
23+
sink(ArrayUtils.add(clean, 0, taint())); // $hasTaintFlow
24+
sink(ArrayUtils.add(alreadyTainted, 0, "clean")); // $hasTaintFlow
25+
sink(ArrayUtils.add(clean, IntSource.taint(), "clean")); // Index argument does not contribute taint
26+
sink(ArrayUtils.add(clean, taint())); // $hasTaintFlow
27+
sink(ArrayUtils.add(alreadyTainted, "clean")); // $hasTaintFlow
28+
sink(ArrayUtils.addAll(clean, "clean", taint())); // $hasTaintFlow
29+
sink(ArrayUtils.addAll(clean, taint(), "clean")); // $hasTaintFlow
30+
sink(ArrayUtils.addAll(alreadyTainted, "clean", "also clean")); // $hasTaintFlow
31+
sink(ArrayUtils.addFirst(clean, taint())); // $hasTaintFlow
32+
sink(ArrayUtils.addFirst(alreadyTainted, "clean")); // $hasTaintFlow
33+
sink(ArrayUtils.clone(alreadyTainted)); // $hasTaintFlow
34+
sink(ArrayUtils.get(alreadyTainted, 0)); // $hasTaintFlow
35+
sink(ArrayUtils.get(clean, IntSource.taint())); // Index argument does not contribute taint
36+
sink(ArrayUtils.get(alreadyTainted, 0, "default value")); // $hasTaintFlow
37+
sink(ArrayUtils.get(clean, IntSource.taint(), "default value")); // Index argument does not contribute taint
38+
sink(ArrayUtils.get(clean, 0, taint())); // $hasTaintFlow
39+
sink(ArrayUtils.insert(IntSource.taint(), clean, "value1", "value2")); // Index argument does not contribute taint
40+
sink(ArrayUtils.insert(0, alreadyTainted, "value1", "value2")); // $hasTaintFlow
41+
sink(ArrayUtils.insert(0, clean, taint(), "value2")); // $hasTaintFlow
42+
sink(ArrayUtils.insert(0, clean, "value1", taint())); // $hasTaintFlow
43+
sink(ArrayUtils.nullToEmpty(alreadyTainted)); // $hasTaintFlow
44+
sink(ArrayUtils.nullToEmpty(alreadyTainted, String[].class)); // $hasTaintFlow
45+
sink(ArrayUtils.remove(alreadyTainted, 0)); // $hasTaintFlow
46+
sink(ArrayUtils.remove(clean, IntSource.taint())); // Index argument does not contribute taint
47+
sink(ArrayUtils.removeAll(alreadyTainted, 0, 1)); // $hasTaintFlow
48+
sink(ArrayUtils.removeAll(clean, IntSource.taint(), 1)); // Index argument does not contribute taint
49+
sink(ArrayUtils.removeAll(clean, 0, IntSource.taint())); // Index argument does not contribute taint
50+
sink(ArrayUtils.removeAllOccurences(clean, taint())); // Removed argument does not contribute taint
51+
sink(ArrayUtils.removeAllOccurences(alreadyTainted, "value to remove")); // $hasTaintFlow
52+
sink(ArrayUtils.removeAllOccurrences(clean, taint())); // Removed argument does not contribute taint
53+
sink(ArrayUtils.removeAllOccurrences(alreadyTainted, "value to remove")); // $hasTaintFlow
54+
sink(ArrayUtils.removeElement(clean, taint())); // Removed argument does not contribute taint
55+
sink(ArrayUtils.removeElement(alreadyTainted, "value to remove")); // $hasTaintFlow
56+
sink(ArrayUtils.removeElements(alreadyTainted, 0, 1)); // $hasTaintFlow
57+
sink(ArrayUtils.removeElements(clean, IntSource.taint(), 1)); // Index argument does not contribute taint
58+
sink(ArrayUtils.removeElements(clean, 0, IntSource.taint())); // Index argument does not contribute taint
59+
sink(ArrayUtils.subarray(alreadyTainted, 0, 0)); // $hasTaintFlow
60+
sink(ArrayUtils.subarray(clean, IntSource.taint(), IntSource.taint())); // Index arguments do not contribute taint
61+
sink(ArrayUtils.toArray("clean", taint())); // $hasTaintFlow
62+
sink(ArrayUtils.toArray(taint(), "clean")); // $hasTaintFlow
63+
sink(ArrayUtils.toMap(alreadyTainted).get("key")); // $hasTaintFlow
64+
65+
// Check that none of the above had an effect on `clean`:
66+
sink(clean);
67+
68+
int[] taintedInts = new int[] { IntSource.taint() };
69+
Integer[] taintedBoxedInts = ArrayUtils.toObject(taintedInts);
70+
sink(taintedBoxedInts); // $hasTaintFlow
71+
sink(ArrayUtils.toPrimitive(taintedBoxedInts)); // $hasTaintFlow
72+
sink(ArrayUtils.toPrimitive(new Integer[] {}, IntSource.taint())); // $hasTaintFlow
73+
74+
}
75+
}

0 commit comments

Comments
 (0)