From ff48ac5434e334cb724295e626d4c998c4043fc1 Mon Sep 17 00:00:00 2001 From: MarkLee131 Date: Tue, 17 Mar 2026 22:45:38 +0800 Subject: [PATCH 1/4] C++: exclude printf implementation internals from format string sinks --- .../CWE/CWE-134/UncontrolledFormatString.ql | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql index 37e3fa0c49f8..4c0271ef96e7 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql @@ -23,13 +23,32 @@ 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 behaviour (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().getEnclosingFunction()) and + not isPrintfImplementation(node.asIndirectExpr().getEnclosingFunction()) } private predicate isArithmeticNonCharType(ArithmeticType type) { From 2c76e6e63740dd4cd1307141819fb25efd8c31c9 Mon Sep 17 00:00:00 2001 From: Kaixuan Li Date: Thu, 19 Mar 2026 14:35:45 +0800 Subject: [PATCH 2/4] use American spellings in documentation Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql index 4c0271ef96e7..c3e94c989bd4 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql @@ -27,7 +27,7 @@ predicate isSource(FlowSource source, string sourceType) { sourceType = source.g * 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 behaviour (e.g. a custom + * 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 From c155394f25b11de265224cbc462cbf518739c383 Mon Sep 17 00:00:00 2001 From: Kaixuan Li Date: Thu, 19 Mar 2026 14:36:28 +0800 Subject: [PATCH 3/4] the [] syntax directly Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com> --- cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql index c3e94c989bd4..bf6f014672fb 100644 --- a/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql +++ b/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql @@ -47,8 +47,7 @@ module Config implements DataFlow::ConfigSig { exists(PrintfLikeFunction printf | printf.outermostWrapperFunctionCall([node.asExpr(), node.asIndirectExpr()], _) ) and - not isPrintfImplementation(node.asExpr().getEnclosingFunction()) and - not isPrintfImplementation(node.asIndirectExpr().getEnclosingFunction()) + not isPrintfImplementation([node.asExpr(), node.asIndirectExpr()].getEnclosingFunction()) } private predicate isArithmeticNonCharType(ArithmeticType type) { From 9c6276ef48ecef9d01fcc6b9038e5c3330ec0a7f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:17:04 +0000 Subject: [PATCH 4/4] C++: Change note. --- cpp/ql/src/change-notes/2026-03-19-tainted-format-string.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cpp/ql/src/change-notes/2026-03-19-tainted-format-string.md diff --git a/cpp/ql/src/change-notes/2026-03-19-tainted-format-string.md b/cpp/ql/src/change-notes/2026-03-19-tainted-format-string.md new file mode 100644 index 000000000000..6a1133917bf7 --- /dev/null +++ b/cpp/ql/src/change-notes/2026-03-19-tainted-format-string.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed an issue with the "Uncontrolled format string" (`cpp/tainted-format-string`) query involving certain kinds of formatting function implementations.