Skip to content

Commit c3bc651

Browse files
authored
Merge pull request #19053 from owen-mc/go/fp/log-type
Go: Fix false positives when logging using `%T`
2 parents 6d61820 + f677ddd commit c3bc651

18 files changed

+317
-205
lines changed

go/ql/lib/semmle/go/Concepts.qll

+17
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,23 @@ module RegexpReplaceFunction {
357357
class LoggerCall extends DataFlow::Node instanceof LoggerCall::Range {
358358
/** Gets a node that is a part of the logged message. */
359359
DataFlow::Node getAMessageComponent() { result = super.getAMessageComponent() }
360+
361+
/**
362+
* Gets a node whose value is a part of the logged message.
363+
*
364+
* Components corresponding to the format specifier "%T" are excluded as
365+
* their type is logged rather than their value.
366+
*/
367+
DataFlow::Node getAValueFormattedMessageComponent() {
368+
result = this.getAMessageComponent() and
369+
not exists(string formatSpecifier |
370+
result = this.(StringOps::Formatting::StringFormatCall).getOperand(_, formatSpecifier) and
371+
// We already know that `formatSpecifier` starts with `%`, so we check
372+
// that it ends with `T` to confirm that it is `%T` or possibly some
373+
// variation on it.
374+
formatSpecifier.matches("%T")
375+
)
376+
}
360377
}
361378

362379
/** Provides a class for modeling new logging APIs. */

go/ql/lib/semmle/go/security/CleartextLoggingCustomizations.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ module CleartextLogging {
4040
* An argument to a logging mechanism.
4141
*/
4242
class LoggerSink extends Sink {
43-
LoggerSink() { this = any(LoggerCall log).getAMessageComponent() }
43+
LoggerSink() { this = any(LoggerCall log).getAValueFormattedMessageComponent() }
4444
}
4545

4646
/**

go/ql/lib/semmle/go/security/LogInjectionCustomizations.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ module LogInjection {
3535

3636
/** An argument to a logging mechanism. */
3737
class LoggerSink extends Sink {
38-
LoggerSink() { this = any(LoggerCall log).getAMessageComponent() }
38+
LoggerSink() { this = any(LoggerCall log).getAValueFormattedMessageComponent() }
3939
}
4040

4141
/**

go/ql/src/Security/CWE-352/ConstantOauth2State.ql

+3-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ predicate privateUrlFlowsToAuthCodeUrlCall(DataFlow::CallNode call) {
138138

139139
module FlowToPrintConfig implements DataFlow::ConfigSig {
140140
additional predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
141-
exists(LoggerCall logCall | call = logCall | sink = logCall.getAMessageComponent())
141+
exists(LoggerCall logCall | call = logCall |
142+
sink = logCall.getAValueFormattedMessageComponent()
143+
)
142144
}
143145

144146
predicate isSource(DataFlow::Node source) { source = any(AuthCodeUrl m).getACall().getResult() }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* False positives in "Log entries created from user input" (`go/log-injection`) and "Clear-text logging of sensitive information" (`go/clear-text-logging`) which involved the verb `%T` in a format specifier have been fixed. As a result, some users may also see more alerts from the "Use of constant `state` value in OAuth 2.0 URL" (`go/constant-oauth2-state`) query.

go/ql/test/library-tests/semmle/go/concepts/LoggerCall/LoggerCall.ql

+9-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@ import ModelValidation
44
import utils.test.InlineExpectationsTest
55

66
module LoggerTest implements TestSig {
7-
string getARelevantTag() { result = "logger" }
7+
string getARelevantTag() { result = ["type-logger", "logger"] }
88

99
predicate hasActualResult(Location location, string element, string tag, string value) {
1010
exists(LoggerCall log |
1111
log.getLocation() = location and
1212
element = log.toString() and
13-
value = log.getAMessageComponent().toString() and
14-
tag = "logger"
13+
(
14+
value = log.getAValueFormattedMessageComponent().toString() and
15+
tag = "logger"
16+
or
17+
value = log.getAMessageComponent().toString() and
18+
not value = log.getAValueFormattedMessageComponent().toString() and
19+
tag = "type-logger"
20+
)
1521
)
1622
}
1723
}

go/ql/test/library-tests/semmle/go/concepts/LoggerCall/glog.go

+14
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ func glogTest() {
3030
glog.Warningf(fmt, text) // $ logger=fmt logger=text
3131
glog.Warningln(text) // $ logger=text
3232

33+
// components corresponding to the format specifier "%T" are not considered vulnerable
34+
glog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
35+
glog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
36+
glog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
37+
glog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
38+
glog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
39+
3340
klog.Error(text) // $ logger=text
3441
klog.ErrorDepth(0, text) // $ logger=text
3542
klog.Errorf(fmt, text) // $ logger=fmt logger=text
@@ -50,4 +57,11 @@ func glogTest() {
5057
klog.WarningDepth(0, text) // $ logger=text
5158
klog.Warningf(fmt, text) // $ logger=fmt logger=text
5259
klog.Warningln(text) // $ logger=text
60+
61+
// components corresponding to the format specifier "%T" are not considered vulnerable
62+
klog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
63+
klog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
64+
klog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
65+
klog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
66+
klog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
5367
}

go/ql/test/library-tests/semmle/go/concepts/LoggerCall/logrus.go

+4
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,8 @@ func logrusCalls() {
3232
logrus.Panicln(text) // $ logger=text
3333
logrus.Infof(fmt, text) // $ logger=fmt logger=text
3434
logrus.FatalFn(fn) // $ logger=fn
35+
36+
// components corresponding to the format specifier "%T" are not considered vulnerable
37+
logrus.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
38+
logrus.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
3539
}

go/ql/test/library-tests/semmle/go/concepts/LoggerCall/main.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package main
33
const fmt = "formatted %s string"
44
const text = "test"
55

6-
func main() {
6+
var v []byte
77

8+
func main() {
9+
stdlib()
810
}

go/ql/test/library-tests/semmle/go/concepts/LoggerCall/stdlib.go

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ func stdlib() {
1717
logger.Printf(fmt, text) // $ logger=fmt logger=text
1818
logger.Println(text) // $ logger=text
1919

20+
// components corresponding to the format specifier "%T" are not considered vulnerable
21+
logger.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
22+
logger.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
23+
logger.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
24+
2025
log.SetPrefix("prefix: ")
2126
log.Fatal(text) // $ logger=text
2227
log.Fatalf(fmt, text) // $ logger=fmt logger=text
@@ -27,4 +32,9 @@ func stdlib() {
2732
log.Print(text) // $ logger=text
2833
log.Printf(fmt, text) // $ logger=fmt logger=text
2934
log.Println(text) // $ logger=text
35+
36+
// components corresponding to the format specifier "%T" are not considered vulnerable
37+
log.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
38+
log.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
39+
log.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
3040
}

0 commit comments

Comments
 (0)