Skip to content

Data flow: since 2.27.0, ConfigSig::accessPathLimit() values above the language default have no effect #23041

Open

Description

@yuan2li

A configuration that raises accessPathLimit() above the language default (5) finds longer flows on CodeQL 2.26.2. It no longer does on 2.27.4, and the result is the same as with the default. Lower values still work.

CodeQL CLI release binaries 2.26.2 and 2.27.4 on macOS 26.6 (arm64), with the codeql/java-all and codeql/dataflow packs bundled with each.

Each program NestedN (N = 3 to 7) passes a parameter through N nested java.util.Lists and back into Runtime.exec. Nested6:

public class Nested6 {
  void handle(String input) throws java.io.IOException {
    java.util.List c0 = new java.util.ArrayList(); c0.add(input);
    java.util.List c1 = new java.util.ArrayList(); c1.add(c0);
    java.util.List c2 = new java.util.ArrayList(); c2.add(c1);
    java.util.List c3 = new java.util.ArrayList(); c3.add(c2);
    java.util.List c4 = new java.util.ArrayList(); c4.add(c3);
    java.util.List c5 = new java.util.ArrayList(); c5.add(c4);
    java.util.List cur = c5;
    cur = (java.util.List) cur.get(0);
    cur = (java.util.List) cur.get(0);
    cur = (java.util.List) cur.get(0);
    cur = (java.util.List) cur.get(0);
    cur = (java.util.List) cur.get(0);
    Runtime.getRuntime().exec((String) cur.get(0));
  }
}

The query only varies accessPathLimit:

import java
import semmle.code.java.dataflow.TaintTracking
module C implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node n) { n.asParameter().getName() = "input" }
  predicate isSink(DataFlow::Node n) {
    exists(MethodCall mc | mc.getMethod().hasName("exec") and n.asExpr() = mc.getArgument(0))
  }
  int accessPathLimit() { result = 8 }   // varied below
}
module F = TaintTracking::Global<C>;
from DataFlow::Node s, DataFlow::Node t where F::flow(s, t)
select t, s.getEnclosingCallable().getDeclaringType().getName()

Programs found (codeql database create --build-mode=none, then codeql query run):

accessPathLimit() 2.26.2 (java-all 9.2.2, dataflow 2.1.10) 2.27.4 (java-all 9.3.4, dataflow 2.1.17)
default (5) Nested3-5 Nested3-5
3 Nested3 Nested3
4 Nested3-4 Nested3-4
6 Nested3-6 Nested3-5
8 Nested3-7 Nested3-5
10, 20 Nested3-7 Nested3-5

I ran only 2.26.2 and 2.27.4. From the sources, the change below is not in 2.26.3 or 2.26.4, and it is in 2.27.0.

Where it seems to come from. #22392 ("Track access path lengths in stages 3 and 4") gave the cached access path fronts a length, in shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll:

TFrontHead(Content c, int length) { length in [1 .. accessPathLimit()] }
TApproxFrontHead(ContentApprox c, int length) { length in [1 .. accessPathLimit()] }

MakeImplCommon does private import Lang, so this accessPathLimit() is the language default, not the configuration's. DataFlowImpl.qll then uses Config::accessPathLimit(), for example len in [2 .. Config::accessPathLimit()]. A configured limit above the default cannot be represented by these fronts, so the longer paths are pruned.

As far as I can tell, the cap is a side effect rather than a decision. #22392 is about performance and does not mention the per-configuration
limit, and the fronts are cached per language, so they cannot see the configuration. Configurations in this repository only lower the limit (the
reason ConfigSig::accessPathLimit was added in #15867), so the existing tests would not notice the change.

Expected. As before 2.27.0, a configured accessPathLimit() is honoured in both directions. If capping it at the language default is intended, for example to keep the cached fronts small, the ConfigSig::accessPathLimit documentation should say so.

Activity

  1. sam-robson commented on Nov 6, 2026

    @sam-robson
    Contributor

    Thanks for the report @yuan2li . We'll look into this and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions