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

Issue with new Dataflow module #14740

Closed
tardigrade-9 opened this issue Nov 10, 2023 · 3 comments
Closed

Issue with new Dataflow module #14740

tardigrade-9 opened this issue Nov 10, 2023 · 3 comments
Labels
C++ DataFlow Library question Further information is requested

Comments

@tardigrade-9
Copy link

tardigrade-9 commented Nov 10, 2023

Unable to find UAF

import cpp

 import semmle.code.cpp.dataflow.DataFlow
  
 class Config extends DataFlow::Configuration {
   Config() { this = "Use after free config (doesn't matter)"}
 
   override predicate isSource(DataFlow::Node arg) {
     exists(FunctionCall call |
       call.getArgument(0) = arg.asDefiningArgument() and
       call.getTarget().hasGlobalOrStdName("free")
     )
   }
 
   override predicate isSink(DataFlow::Node sink) {
     dereferenced(sink.asExpr()) // depends on DataFlow1
   }
 
 }
 
 from DataFlow::Node source, DataFlow::Node sink, Config config
 where config.hasFlow(source, sink)
 select sink, source, sink,
   "Potential use-after-free vulnerability: memory is $@ and $@.",
   source, "freed here", sink, "used here"

The above query is able to find the UAF. I refered this from githubuniversal workshop. Since this DataFlow module is deprecated, I used new::DataFlow to rewrite the same query, but I don't see any results.


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

class UAFConfig extends DataFlow::Configuration{
    
    UAFConfig(){this = "UAF configration"}
   override  predicate isSource(DataFlow::Node arg) {
         exists(FunctionCall fc | 
             fc.getArgument(0) = arg.asDefiningArgument() and
             fc.getTarget().hasGlobalOrStdName("free"))
    }

    override predicate isSink(DataFlow::Node sink) {
        dereferenced(sink.asExpr())
    }

}


from DataFlow::Node source , DataFlow::Node sink, UAFConfig uafconfig
where uafconfig.hasFlow(source, sink)
select sink, source, sink, "Potential use-after-free vulnerability: memory is $@ and $@.",
source, "freed here", sink, "used here"

Additionally, I also tried module approach as mentioned in docs, no luck there too.

Can someone please point what I am missing, thanks.

@tardigrade-9 tardigrade-9 added the question Further information is requested label Nov 10, 2023
@aeisenberg
Copy link
Contributor

Thanks for your question. I've asked our C++ analysis engineers to take a look.

@MathiasVP
Copy link
Contributor

Hi @tardigrade-9,

Yes, unfortunately it has not been possible for us to do a one-to-one porting of the old, and now deprecated dataflow library. This is because the old dataflow library often was too imprecise in its distinction between a pointer and what it pointed to.

The problem is that the isSource predicate specifies that we're tracking the data as it's coming coming out of the free function (i.e., the data pointed to by free after leaving the function).

So the isSink also needs to specify that we're interested in the data that is pointed to by the expression that is being dereferenced.

The new library has a predicate another predicate called asIndirectExpr (in addition to the asExpr predicate) that can be used to select exactly such a dataflow node.

Here's an updated query that should find the right use-after-free vulnerabilities. The only difference should be the use of asIndirectExpr instead of asExpr:

/**
 * @kind path-problem
 */

import cpp
import semmle.code.cpp.dataflow.new.DataFlow
import Flow::PathGraph

module UAFConfig implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node arg) {
    exists(FunctionCall fc |
      fc.getArgument(0) = arg.asDefiningArgument() and
      fc.getTarget().hasGlobalOrStdName("free")
    )
  }

  predicate isSink(DataFlow::Node sink) { dereferenced(sink.asIndirectExpr()) }
}

module Flow = DataFlow::Global<UAFConfig>;

from Flow::PathNode source, Flow::PathNode sink
where Flow::flowPath(source, sink)
select sink, source, sink, "Potential use-after-free vulnerability: memory is $@ and $@.", source,
  "freed here", sink, "used here"

I've also updated it to use the module-based API. I will ask around to see how we can update the QL code in the workshop repository.

@tardigrade-9
Copy link
Author

Thanks @MathiasVP , the query is working.. Appreciate the quick response...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C++ DataFlow Library question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants