Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: control-flow paths #17457

Open
KylerKatz opened this issue Sep 13, 2024 · 2 comments
Open

Java: control-flow paths #17457

KylerKatz opened this issue Sep 13, 2024 · 2 comments
Assignees
Labels
Java question Further information is requested

Comments

@KylerKatz
Copy link

Hello,

I am trying to use CodeQL to get the control flow of a program. More specifically I want to get the control flow into methods that I have marked as sensitive in a classes named SensitiveMethodCall. The goal is to parse the results to get the path. However, right now I am not generating a path. It is hard to tell if a path isn't being generated because of the query itself (I am used to using dataflow, so this is new to me) or if it has to do with this error

Error was: Expected result pattern(s) are not present for path-problem query: Expected at least two result patterns. These should include at least an 'edges' result set (see https://codeql.github.com/docs/writing-codeql-queries/creating-path-queries/). [INVALID_RESULT_PATTERNS]

All of the examples I see on this link have to deal with dataflow and not control flow, so I am having trouble figuring out what I am doing wrong to get the correct output. Here is my query.

import java
import semmle.code.java.ControlFlowGraph
import SensitiveInfo.SensitiveInfo

/**
 * @name Control flow path from normal method call to sensitive method call
 * @description This query identifies the full control flow path from a normal method call to a sensitive method call.
 *              It traces every control flow node between the normal and sensitive calls.
 * @kind path-problem
 * @id java/custom/control-flow-path
 * @problem.severity warning
 * @tags control-flow, data-flow, security, sensitive-data
 * @precision medium
 * @security-severity 5.0
 * @cwe CWE-200, CWE-201, CWE-209
 * @sub-severity high
 * 
 * Get the control flow path from a normal method call to a sensitive method call.
 * Returns the full sequence of control flow nodes.
 */
predicate controlFlowPath(MethodCall start, MethodCall end, ControlFlowNode node) {
  exists(ControlFlowNode startNode, ControlFlowNode endNode |
    startNode = start.getControlFlowNode() and
    endNode = end.getControlFlowNode() and
    startNode.getANormalSuccessor*() = node and
    node.getANormalSuccessor*() = endNode
  )
}

/**
 * Get the full control flow path between normal and sensitive method calls.
 */
from MethodCall normalCall, SensitiveMethodCall sensitiveCall, ControlFlowNode node
where controlFlowPath(normalCall, sensitiveCall, node)
select normalCall.getControlFlowNode(), normalCall, sensitiveCall, "Full control flow path from normal method call to sensitive method call."

Any help would be greatly appreciated. Thank you.

@KylerKatz KylerKatz added the question Further information is requested label Sep 13, 2024
@mbg
Copy link
Member

mbg commented Sep 13, 2024

Hi again @KylerKatz 👋🏻

Queries of type path-problem are intended to capture the path that data takes through a program in a data flow query. I do not believe that you can write control flow queries of type path-problem. So you should use a different query type here.

To then understand where your query goes wrong, the first step would be to identify where the problem is by starting with the smallest components involved and then working your way up. For example, if you query all instances of SensitiveMethodCall, do you get the results you would expect? Similarly, if you use the quick evaluation feature to evaluate all possible results for controlFlowPath, do you get the results you expect?

Also, query metadata should normally be at the very top of the file, above the import statements.

@mbg mbg self-assigned this Sep 13, 2024
@mbg mbg added the Java label Sep 13, 2024
@KylerKatz
Copy link
Author

Hello @mbg,

Thank you for all your help.

I have broken the problem down and done some quick evaluations. Using this example,

public class BAD_APIEndpointDebugging {
    private static final boolean API_DEBUG = Boolean.parseBoolean(System.getenv("API_DEBUG"));

    public static void main(String[] args) {
        String apiEndpoint = "https://api.example.com/data";
        String apiKey = "api_key_123456789"; 

        if (API_DEBUG) {
            testAPI(apiEndpoint, apiKey);
        }
    }

    private static void testAPI(String url, String key) {
        System.out.println("DEBUG: Testing API endpoint: " + url + " with API Key: " + key);
        // Assume some testing logic here
    }
}

SensitiveMethodCall

I get these results

image

Which lines up with the data that I have in my YML file

extensions:
  - addsTo:
      pack: custom-codeql-queries
      extensible: sinks
    data:
    - ["fileName", "sinkName", "type"]
    - ["BAD_APIEndpointDebugging.java", "println", "Log Sink"]
    - ["BAD_APIEndpointDebugging.java", "parseBoolean", "Log Sink"]
    - ["BAD_APIEndpointDebugging.java", "testAPI", "Log Sink"]
    - ["BAD_APIEndpointDebugging.java", "getenv", "Log Sink"]

So SensitiveMethodCall seems to be returning the desired results

ControlFlowPath

I did the same for this
image

Looking at this, it seems to almost be alright
Results 1 - 3 correspond to this line

private static final boolean API_DEBUG = Boolean.parseBoolean(System.getenv("API_DEBUG"));

4 & 5 correspond to their own self use, however, there should be one starting at testAPI and ending at println I am not sure why this control flow is being missed?

Also, I am still looking for a way to get the actual path. Something like this.
image

Is this possible for control flow?

Also, here is my updated query for reference

/**
 * @name Control flow path from normal method call to sensitive method call
 * @description This query identifies the control flow path from a normal method call to a sensitive method call.
 *              It traces every control flow node between the normal and sensitive calls.
 * @kind problem
 * @id java/custom/control-flow-path
 * @problem.severity warning
 * @tags control-flow, security, sensitive-data
 * @precision medium
 * @security-severity 5.0
 * @cwe CWE-200, CWE-201, CWE-209
 * @sub-severity high
 */

 import java
 import semmle.code.java.ControlFlowGraph
 import SensitiveInfo.SensitiveInfo
 
 /**
  * Predicate to define a control flow path between a start method call and an end method call.
  */
 predicate controlFlowPath(MethodCall start, MethodCall end) {
   exists(ControlFlowNode startNode, ControlFlowNode endNode |
     startNode = start.getControlFlowNode() and
     endNode = end.getControlFlowNode() and
     startNode.getANormalSuccessor*() = endNode // Track the normal successors between start and end
   )
 }
 
 from MethodCall normalCall, SensitiveMethodCall sensitiveCall
 where controlFlowPath(normalCall, sensitiveCall)
 select normalCall, sensitiveCall.getControlFlowNode().toString(), sensitiveCall.getMethod().getReturnType(),
   "Control flow path from normal method call to sensitive method call."

Thank you once again for your help.

@smowton smowton changed the title General issue Java: control-flow paths Sep 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Java question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants