Understanding C/C++ taint tracking in the presence of aliasing #9863
Unanswered
thinkmoore
asked this question in
Q&A
Replies: 1 comment 1 reply
-
Greetings! Thanks for getting in touch with this question. The query as you have written it certainly makes sense, and it's a pity that our taint tracking isn't smart enough to find all the vulnerable cases in your example. A few preliminary notes:
I've passed this on the the C analysis team who can hopefully give you some deeper answers here on why you are observing this and whether there is anything we could improve. Rewrite to use semmle.code.cpp.ir.dataflow.TaintTracking/**
* @name Uncontrolled data used in path expression
* @description Accessing paths influenced by users can allow an
* attacker to access unexpected resources.
* @kind path-problem
* @problem.severity warning
* @security-severity 7.5
* @precision medium
* @id cpp/path-injection
* @tags security
* external/cwe/cwe-022
* external/cwe/cwe-023
* external/cwe/cwe-036
* external/cwe/cwe-073
*/
import cpp
import DataFlow::PathGraph
import semmle.code.cpp.security.FunctionWithWrappers
import semmle.code.cpp.security.Security
import semmle.code.cpp.ir.dataflow.TaintTracking
/**
* A function for opening a file.
*/
class FileFunction extends FunctionWithWrappers {
FileFunction() {
exists(string nme | this.hasGlobalName(nme) |
nme =
[
"fopen", "_fopen", "_wfopen", "open", "_open", "_wopen", "opendir", "mkdir", "chdir",
"rename"
]
or
// create file function on windows
nme.matches("CreateFile%")
)
or
this.hasQualifiedName("std", "fopen")
or
// on any of the fstream classes, or filebuf
exists(string nme | this.getDeclaringType().hasQualifiedName("std", nme) |
nme = ["basic_fstream", "basic_ifstream", "basic_ofstream", "basic_filebuf"]
) and
// we look for either the open method or the constructor
(this.getName() = "open" or this instanceof Constructor)
}
// conveniently, all of these functions take the path as the first parameter!
override predicate interestingArg(int arg) { arg = 0 }
}
class TaintedPathConfiguration extends TaintTracking::Configuration {
TaintedPathConfiguration() { this = "TaintedPathConfiguration" }
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
override predicate isSink(DataFlow::Node tainted) {
exists(FileFunction fileFunction |
fileFunction.outermostWrapperFunctionCall(tainted.asExpr(), _)
)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, TaintedPathConfiguration config
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "User input used in file path." |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Hi, I'm trying to get a better understanding of how taint tracking in CodeQL handles aliasing. I adapted the following query and example from the CWE-022 query in the repository.
I expect this query to return four results, one for each sub-example in the file. However, only the final example involving
fileBuffer4
is found. That result is also confusing as it reports two paths: one with two nodesargv
andfileBuffer4
and one that additionally includes parameters and the return value ofgetinput
, which is not called in that part of the example.Does the query as I have written it make sense? Is this kind of pointer aliasing outside of what the taint tracking module is intended to reason about?
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions