-
Hello, I have several question regarding local data flow and global data flow. Q1. Is there any differences between local data flow and global data flow except the scope of computation? If yes, what is it? Q2. I tried to detect use-after-free of This is the example of C++ code struct MyStruct {
char* content;
};
void free_ptr(char * ptr) {
free(ptr);
}
void test_free_in_other_func() {
int ct_size = 200;
MyStruct * s = (MyStruct*) malloc(sizeof(MyStruct));
s->content = (char*) malloc(sizeof(char)*ct_size);
sprintf(s->content, "test_free_in_other_func");
printf("%s\n", s->content);
free_ptr(s->content);
char * s_ptr = s->content;
printf("%s\n", s_ptr);
}
int main() {
int ct_size = 200;
MyStruct * s = (MyStruct*) malloc(sizeof(MyStruct));
s->content = (char*) malloc(sizeof(char)*ct_size);
sprintf(s->content, "test_free_in_other_func");
printf("%s\n", s->content);
free(s->content);
char * s_ptr = s->content;
printf("%s\n", s_ptr);
return 0;
} and this is the use-after-free query that uses local data flow: import cpp
import semmle.code.cpp.dataflow.DataFlow
predicate nodeSource(Expr src) {
exists( FunctionCall call|
call.getArgument(0) = src and
call.getTarget().hasGlobalOrStdName("free")
)
}
predicate nodeSink(Expr sink) {
dereferenced(sink)
}
from DataFlow::Node source, DataFlow::Node sink
where
nodeSource(source.asDefiningArgument()) and
nodeSink(sink.asExpr()) and
DataFlow::localFlow(source , sink)
select sink, "Potential use after free: occur in ", sink, " from ", source Thank you. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Hi @irfanariq,
Your query looks correct. The reason you're not finding the result in Now, why we're not detecting the flow in You can find your results by using global flow like this, though: import cpp
import semmle.code.cpp.dataflow.DataFlow
predicate nodeSource(Expr src) {
exists(FunctionCall call |
call.getArgument(0) = src and
call.getTarget().hasGlobalOrStdName("free")
)
}
predicate nodeSink(Expr sink) { dereferenced(sink) }
class Config extends DataFlow::Configuration {
Config() { this = "Config" }
override predicate isSource(DataFlow::Node src) { nodeSource(src.asDefiningArgument()) }
override predicate isSink(DataFlow::Node sink) { nodeSink(sink.asExpr()) }
}
from Config config, DataFlow::Node source, DataFlow::Node sink
where config.hasFlow(source, sink)
select sink, "Potential use after free: occur in ", sink, " from ", source This should give you both of the results. I hope this helps! |
Beta Was this translation helpful? Give feedback.
Hi @irfanariq,
There's a difference between the precision of the analysis. For instance, global dataflow has to deal with complicated issues like matching up function call entry and return points. This has both a precision and a performance impact.
You can read more about the difference between local and global dataflow here: https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-cpp/#analyzing-data-flow-in-c-and-c.
As it happens, we previously had a workshop on creating just this kind of query :) You can watch it here:
https://www.youtube.com/watch?v=eAjecQrfv3o.
Your query looks correct. The reason you're not finding the result in
test_free_in_other_func
is b…