Files
codeql/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
Kaixuan Li c155394f25 the [] syntax directly
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
2026-03-19 14:36:28 +08:00

83 lines
2.9 KiB
Plaintext

/**
* @name Uncontrolled format string
* @description Using externally-controlled format strings in
* printf-style functions can lead to buffer overflows
* or data representation problems.
* @kind path-problem
* @problem.severity warning
* @security-severity 9.3
* @precision high
* @id cpp/tainted-format-string
* @tags reliability
* security
* external/cwe/cwe-134
*/
import cpp
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.FunctionWithWrappers
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.IR
import Flow::PathGraph
predicate isSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
/**
* Holds if `f` is a printf-like function or a (possibly nested) wrapper
* that forwards a format-string parameter to one.
*
* Functions that *implement* printf-like behavior (e.g. a custom
* `vsnprintf` variant) internally parse the caller-supplied format string
* and build small, bounded, local format strings such as `"%d"` or `"%ld"`
* for inner `sprintf` calls. Taint that reaches those inner calls via the
* parsed format specifier is not exploitable, so sinks inside such
* functions should be excluded.
*/
private predicate isPrintfImplementation(Function f) {
f instanceof PrintfLikeFunction
or
exists(PrintfLikeFunction printf | printf.wrapperFunction(f, _, _))
}
module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { isSource(node, _) }
predicate isSink(DataFlow::Node node) {
exists(PrintfLikeFunction printf |
printf.outermostWrapperFunctionCall([node.asExpr(), node.asIndirectExpr()], _)
) and
not isPrintfImplementation([node.asExpr(), node.asIndirectExpr()].getEnclosingFunction())
}
private predicate isArithmeticNonCharType(ArithmeticType type) {
not type instanceof CharType and
not type instanceof Char8Type and
not type instanceof Char16Type and
not type instanceof Char32Type
}
predicate isBarrier(DataFlow::Node node) {
isSink(node) and isArithmeticNonCharType(node.asExpr().getUnspecifiedType())
or
isArithmeticNonCharType(node.asCertainDefinition().getUnspecifiedType())
}
predicate observeDiffInformedIncrementalMode() { any() }
}
module Flow = TaintTracking::Global<Config>;
from
PrintfLikeFunction printf, string printfFunction, string sourceType, DataFlow::Node source,
DataFlow::Node sink, Flow::PathNode sourceNode, Flow::PathNode sinkNode
where
source = sourceNode.getNode() and
sink = sinkNode.getNode() and
isSource(source, sourceType) and
printf.outermostWrapperFunctionCall([sink.asExpr(), sink.asIndirectExpr()], printfFunction) and
Flow::flowPath(sourceNode, sinkNode)
select sink, sourceNode, sinkNode,
"The value of this argument may come from $@ and is being used as a formatting argument to " +
printfFunction + ".", source, sourceType