Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package issues;

import base.RuleSample;
import base.RuleSet;

/**
* Repro: taint is lost when an element of a tainted array is itself an array
* that is later indexed (array-of-arrays / Object[] holding a String[]).
*
* The source marks the returned {@code Object[]} with element-level taint
* ({@code args[*]}). Reading a scalar element ({@code args[0]}) keeps the taint
* (see {@link PositiveScalarElementControl}), but reading an element that is
* itself an array and then indexing that inner array
* ({@code ((String[]) args[1])[0]}) drops it: the engine transfers the source's
* element path to a reference fact on the destination ({@code types.$}) instead
* of a nested element fact ({@code types[*]}), so the inner element read is not
* considered tainted.
*
* This is the shape of Apache Dubbo's GenericFilter provider path:
* String[] parameterTypes = (String[]) invocation.getArguments()[1];
* ... ReflectUtils.name2class(parameterTypes[i]) ...
*/
@RuleSet("issues/issue98.yaml")
public abstract class issue98 implements RuleSample {

Object[] src() {
return new Object[] {"", new String[] {""}};
}

void sink(String data) {}

/**
* Control: scalar element of a tainted array reaches the sink. This already
* works today and anchors that the source/sink/element-read all function;
* the only difference from the failing case is that the element here is a
* scalar, not a nested array.
*/
static class PositiveScalarElementControl extends issue98 {
@Override
public void entrypoint() {
Object[] args = src();
String name = (String) args[0];
sink(name);
}
}

/**
* False negative: the element {@code args[1]} is itself a {@code String[]};
* indexing it ({@code types[0]}) loses the taint. Expected: a finding at the
* {@code sink(types[0])} call. Observed: none.
*/
static class PositiveNestedArrayElement extends issue98 {
@Override
public void entrypoint() {
Object[] args = src();
String[] types = (String[]) args[1];
sink(types[0]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
rules:
- id: i98
languages:
- java
severity: ERROR
message: tainted array element reaches sink
mode: taint
pattern-sources:
- patterns:
- focus-metavariable: $X
- pattern: $X = src();
pattern-sinks:
- patterns:
- pattern: sink($Y);
- focus-metavariable: $Y
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import issues.issue94
import issues.issue95
import issues.issue96
import issues.issue97
import issues.issue98
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.TestInstance
Expand Down Expand Up @@ -105,6 +106,9 @@ class IssuesTest : SampleBasedTest() {
@Test
fun `issue 97`() = runTest<issue97>()

@Test // todo: nested array element taint — element of a tainted array that is itself an array loses taint when indexed
fun `issue 98`() = runTest<issue98>()

@AfterAll
fun close() {
closeRunner()
Expand Down
Loading