Skip to content

Taint propagation problem in AnonymousClass #17473

@rccccat

Description

@rccccat

Hi guys, I'm using CodeQL for some research. But I've encountered some strange problems regarding Taint Tracking in anonymous classes.

  1. We have an abstract class as follows:
public abstract class UploadTemplate<E,T> {
    protected UploadTemplate() {
    }

    protected abstract E filterStrategy();

    protected abstract T process(E builder);

    public T execute() {
        return process(filterStrategy());
    }
}

2、And we have a function:

public class UploadTemplateImpl {
    public static String paramPropagate(String[] args) { // <- source here
        return new UploadTemplate<Integer, String>() {
            private final String field = args[0];

            @Override
            protected Integer filterStrategy() {
                String input = args[0];
                boolean result = input.chars().allMatch(Character::isDigit);

                int obj1 = 0;
                if (result) {
                    obj1 = Integer.parseInt(input);
                }

                return obj1;
            }

            @Override
            protected String process(Integer obj1) {
                return obj1 + this.field;  // <- sink here, simpified
            }
        }.execute();
    }
}
  1. My CodeQL snippet:
/**
 * @name name
 * @description desc
 * @kind path-problem
 * @problem.severity error
 * @security-severity 9.1
 * @precision high
 * @id id
 */

import java
import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.SSA

class CustomSource extends Parameter {
  CustomSource() {
    exists(Method m | m.hasQualifiedName("com.example", "UploadTemplateImpl", "paramPropagate") |
      this = m.getAParameter()
    )
  }
}

class CustomSink extends Expr {
  CustomSink() { exists(BinaryExpr be | be.getLeftOperand() = this or be.getRightOperand() = this) }
}

module MyCustomConfig implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) { source.asParameter() instanceof CustomSource }

  predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof CustomSink }
}

module MyCustomFlow = TaintTracking::Global<MyCustomConfig>;

import MyCustomFlow::PathGraph

from MyCustomFlow::PathNode source, MyCustomFlow::PathNode sink
where MyCustomFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "entry depends on a $@.", source.getNode(),
  "user-provided value"

After running the query, we only get one alert:
image
I only obtain a flow starting from args[0] to the return value of filterStrategy, and then to the parameter of process.
We are supposed to have a flow from args[0] to the field declaration in the anonymous class, and then to process, right?
Please correct me if i'm wrong 🙏

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