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
codeql analyze multiple wrong paths in cpp project #8697
Comments
|
Hi @mrlzh, This is because CodeQL doesn't view the call to /**
* @name test
* @kind path-problem
* @problem.severity error
* @precision high
* @id cpp/test
* @tags security
* directory-traversal-vulnerability
*/
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import semmle.code.cpp.security.Security
import DataFlow::PathGraph
class DirectoryTraversalTaint extends TaintTracking::Configuration {
DirectoryTraversalTaint() { this = "DirectoryTraversalTaint" }
override predicate isSource(DataFlow::Node source) {
exists(FunctionCall func |
func.getTarget().getName() = "set_inarg" and
func.getArgument(0) = source.asExpr()
)
}
override predicate isSink(DataFlow::Node node) {
exists(FunctionCall func |
func.getTarget().getName() = "fopen" and
node.asExpr() = func.getArgument(0)
)
}
override predicate isSanitizer(DataFlow::Node node) {
exists(DataFlow::Node n |
// This is _almost_ the sanitizer you wrote originally. See its definition below
isDefinedByOperatorAssign(n) and
// And I added this.
dominates(n.asDefiningArgument(), node.asExpr())
)
}
}
predicate isDefinedByOperatorAssign(DataFlow::Node node) {
exists(FunctionCall fc |
fc.getTarget().getName() = "operator=" and // Note: This is `operator=` and not `operator+`.
fc.getQualifier() = node.asDefiningArgument()
)
}
from DataFlow::PathNode source, DataFlow::PathNode sink, DirectoryTraversalTaint config
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "DirectoryTraversal vulnerability"When I run this locally I get 0 results as expected. |
|
Thanks for @MathiasVP Path1 jumps from line 40 to line 44.I can not feel the existence of 'newline' and 'newline2'. Path result miss so many key PathNode. Is it possible to fix? We payed for codeql enterprise and used for discover vulnerabilities during CI. These problems lead to a large number of false positives which bring trouble to push vulnerability fixing. |
|
Hi @mrlzh, My solution worked in class DirectoryTraversalTaint extends TaintTracking::Configuration {
DirectoryTraversalTaint() { this = "DirectoryTraversalTaint" }
// ... as before
override predicate isSanitizer(DataFlow::Node node) {
exists(DataFlow::Node n |
isResultOfOperatorPlus(n) and
dominates(n.asExpr(), node.asExpr())
)
}
}
predicate isResultOfOperatorPlus(DataFlow::Node node) {
exists(FunctionCall fc |
fc.getTarget().hasName("operator+") and
node.asExpr() = fc
)
}That is, making any result of |
|
Hi @MathiasVP override predicate isSanitizer(DataFlow::Node node) {
exists(DataFlow::Node n |
isResultOfOperatorPlus(n) and
dominates(n.asExpr(), node.asExpr())
)
}My complete demo: #include <stdio.h>
#include <string>
class DemoReq{
public:
std::string value;
void set_inarg(const std::string& value){
this->value = value;
}
std::string& inarg(){
return this->value;
}
};
void dofileop_safe1(DemoReq& req)
{
std::string newline = req.inarg();
newline += ".jpg";
FILE *fp;
fp = fopen(newline.c_str(), "r");
fclose(fp);
}
void dofileop_safe2(DemoReq& req)
{
std::string newline = req.inarg();
newline = "/xxx/" + newline + ".jpg";
FILE *fp;
fp = fopen(newline.c_str(), "r");
fclose(fp);
}
void dofileop_safe3(DemoReq& req)
{
std::string newline = req.inarg();
std::string newline2 = "/xxx/" + newline + ".jpg";
FILE *fp;
fp = fopen(newline2.c_str(), "r");
fclose(fp);
}
void dofileop_unsafe(DemoReq& req)
{
std::string newline = req.inarg();
std::string newline2 = "/xxx/" + newline;
FILE *fp;
fp = fopen(newline2.c_str(), "r");
fclose(fp);
}
int main(){
DemoReq req;
req.set_inarg("hello");
dofileop_safe1(req);
dofileop_safe2(req);
dofileop_safe3(req);
dofileop_unsafe(req);
return 0;
}On why there are multiple paths and some path miss key PathNode. After delete class StdStringCStr from cpp/ql/lib/semmle/code/cpp/models/implementations/StdString.qll. |
Two things are worth pointing out. First: Why are there multiple paths?In this case, we're finding two paths because we're not realizing that the line: newline += ".jpg";will always unconditionally modify the value of This shouldn't be a problem for your analysis results, though. If we block flow using something like the Second: The missing
|
|
reply:Why are there multiple paths? reply:Second: The missing PathNodes reply: hasAppendedJpg demo //node is the first argument
// node + "xxx"
// ("xxx"+node) + "xxx"
// node + ("xxx"+"xxx")
exists(FunctionCall fc |
fc.getTarget().hasName("operator+") and
fc.getArgument(0)=node.asExpr()
)Your safe case:
node+"any_string"
node+any_function()
"any_string"+node+"any_string"
("any_string"+node)+"any_string"
("any_string"+node)+any_function()
node+("any_string"+"any_string")
unsafe case:
node+node
"any_string"+node
any_function()+node
("any_string"+"any_string")+nodeIt is not a good idea by using dominates. |



Here is a demo.
This demo analyzed three different paths.
Path1 and path3 lost their execution process about "assign to newline" and "operator+".
I add isSanitizer to block flow through code 'newline + ".jpg"'.
But it does not work.Only Path2 is blocked.
The text was updated successfully, but these errors were encountered: