Skip to content

Missing C/C++ DataFlow/TaintTracking edges for fields accessed through pointers #19405

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

Closed
MyEyes opened this issue Apr 28, 2025 · 2 comments
Closed
Labels
question Further information is requested

Comments

@MyEyes
Copy link

MyEyes commented Apr 28, 2025

Description of the issue
CodeQL seems to not handle data flow and taint tracking through fields of structs the way I expected when accessed through a pointer.
It's possible that I am misusing the library, but I would have expected the two cases below to behave basically identically under dataflow or taint tracking.

Mini reproducer

#include <stdlib.h>

struct A { int dummy; };

struct B { struct A *ptr; };

int main(int argc, char** argv)
{
    struct B b = {0};
    struct B* b_ptr = &b;
    struct A *a_ptr = NULL;

    //Flow from malloc into if stmt not identified by query below
    b_ptr->ptr = malloc(sizeof(*b_ptr->ptr));
    if(!b_ptr->ptr)
        return -1;

    //Flow from malloc into if stmt correctly identified by query below
    a_ptr = malloc(sizeof(*a_ptr));
    if(!a_ptr)
        return -1;
    return 0;
}

I am trying to query missing null checks after an allocation.
The query below only finds the second call to malloc and the corresponding if statement.

import cpp
import semmle.code.cpp.dataflow.new.DataFlow

predicate flowsIntoIfStmt(FunctionCall fc, IfStmt if_stmt)
{
    exists(DataFlow::Node src, DataFlow::Node dst |
        src.asExpr() = fc
        and if_stmt.getControllingExpr().getAChild*() = dst.asExpr()
        and DataFlow::localFlow(src, dst))
}

from FunctionCall fc, IfStmt if_stmt
where flowsIntoIfStmt(fc, if_stmt)
select fc, if_stmt

I have observed the same behaviour using TaintTracking instead of DataFlow.

@MyEyes MyEyes added the question Further information is requested label Apr 28, 2025
@hvitved
Copy link
Contributor

hvitved commented Apr 29, 2025

I would expect flow through pointers to only work for global dataflow and not for local data flow that you use above. While global data flow is normally allowed to track flow into/out of function calls, you can limit it to sources and sinks in the same function by implementing the getAFeature predicate like here.

@MyEyes
Copy link
Author

MyEyes commented Apr 29, 2025

Thank you for the response and clarification.

I was under the mistaken impression that the only difference between local and global dataflow was that it wouldn't traverse inter-procedural edges.

@MyEyes MyEyes closed this as completed Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants