diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 2f18c89db9b..cbc5b853993 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -92,6 +92,7 @@ private module Frameworks { private import semmle.code.java.frameworks.JaxWS private import semmle.code.java.frameworks.JoddJson private import semmle.code.java.frameworks.JsonJava + private import semmle.code.java.frameworks.Logging private import semmle.code.java.frameworks.Objects private import semmle.code.java.frameworks.Optional private import semmle.code.java.frameworks.Stream diff --git a/java/ql/lib/semmle/code/java/frameworks/Logging.qll b/java/ql/lib/semmle/code/java/frameworks/Logging.qll new file mode 100644 index 00000000000..fe975c676a0 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/Logging.qll @@ -0,0 +1,237 @@ +/** Provides classes and predicates to reason about logging. */ + +import java +import semmle.code.java.dataflow.ExternalFlow + +private class LoggingSummaryModels extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.logging.log4j;Logger;true;entry;(Object[]);;Argument[0];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceEntry;(Message);;Argument[0];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Object[]);;Argument[0..1];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Supplier);;Argument[0..1];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceEntry;(Supplier);;Argument[0];ReturnValue;taint", + "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage,Object);;Argument[1];ReturnValue;value", + "org.apache.logging.log4j;Logger;true;traceExit;(Message,Object);;Argument[1];ReturnValue;value", + "org.apache.logging.log4j;Logger;true;traceExit;(Object);;Argument[0];ReturnValue;value", + "org.apache.logging.log4j;Logger;true;traceExit;(String,Object);;Argument[1];ReturnValue;value", + "org.slf4j.spi.LoggingEventBuilder;true;addArgument;;;Argument[1];Argument[-1];taint", + "org.slf4j.spi.LoggingEventBuilder;true;addArgument;;;Argument[-1];ReturnValue;value", + "org.slf4j.spi.LoggingEventBuilder;true;addKeyValue;;;Argument[1];Argument[-1];taint", + "org.slf4j.spi.LoggingEventBuilder;true;addKeyValue;;;Argument[-1];ReturnValue;value", + "org.slf4j.spi.LoggingEventBuilder;true;addMarker;;;Argument[-1];ReturnValue;value", + "org.slf4j.spi.LoggingEventBuilder;true;setCause;;;Argument[-1];ReturnValue;value", + "java.util.logging;LogRecord;false;LogRecord;;;Argument[1];Argument[-1];taint" + ] + } +} + +private string jBossLogger() { result = "org.jboss.logging;" + ["BasicLogger", "Logger"] } + +private class LoggingSinkModels extends SinkModelCsv { + override predicate row(string row) { + row = + [ + // org.apache.log4j.Category + "org.apache.log4j;Category;true;assertLog;;;Argument[1];logging", + "org.apache.log4j;Category;true;debug;;;Argument[0];logging", + "org.apache.log4j;Category;true;error;;;Argument[0];logging", + "org.apache.log4j;Category;true;fatal;;;Argument[0];logging", + "org.apache.log4j;Category;true;forcedLog;;;Argument[2];logging", + "org.apache.log4j;Category;true;info;;;Argument[0];logging", + "org.apache.log4j;Category;true;l7dlog;(Priority,String,Object[],Throwable);;Argument[2];logging", + "org.apache.log4j;Category;true;log;(Priority,Object);;Argument[1];logging", + "org.apache.log4j;Category;true;log;(String,Priority,Object,Throwable);;Argument[2];logging", + "org.apache.log4j;Category;true;warn;;;Argument[0];logging", + // org.apache.logging.log4j.Logger + "org.apache.logging.log4j;Logger;true;" + + [["debug", "error", "fatal", "info", "trace", "warn"] + ";(", "log;(Level,"] + + [ + "CharSequence);;Argument[0];logging", "CharSequence,Throwable);;Argument[0];logging", + "Marker,CharSequence);;Argument[1];logging", + "Marker,CharSequence,Throwable);;Argument[1];logging", + "Marker,Message);;Argument[1];logging", "Marker,MessageSupplier);;Argument[1];logging", + "Marker,MessageSupplier,Throwable);;Argument[1];logging", + "Marker,Object);;Argument[1];logging", "Marker,Object,Throwable);;Argument[1];logging", + "Marker,String);;Argument[1];logging", + "Marker,String,Object[]);;Argument[1..2];logging", + "Marker,String,Object);;Argument[1..2];logging", + "Marker,String,Object,Object);;Argument[1..3];logging", + "Marker,String,Object,Object,Object);;Argument[1..4];logging", + "Marker,String,Object,Object,Object,Object);;Argument[1..5];logging", + "Marker,String,Object,Object,Object,Object,Object);;Argument[1..6];logging", + "Marker,String,Object,Object,Object,Object,Object,Object);;Argument[1..7];logging", + "Marker,String,Object,Object,Object,Object,Object,Object,Object);;Argument[1..8];logging", + "Marker,String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..9];logging", + "Marker,String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..10];logging", + "Marker,String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[1..11];logging", + "Marker,String,Supplier);;Argument[1..2];logging", + "Marker,String,Throwable);;Argument[1];logging", + "Marker,Supplier);;Argument[1];logging", + "Marker,Supplier,Throwable);;Argument[1];logging", ";(Message);;Argument[0];logging", + "MessageSupplier);;Argument[0];logging", + "MessageSupplier,Throwable);;Argument[0];logging", + "Message,Throwable);;Argument[0];logging", ";(Object);;Argument[0];logging", + "Object,Throwable);;Argument[0];logging", ";(String);;Argument[0];logging", + "String,Object[]);;Argument[0..1];logging", "String,Object);;Argument[0..1];logging", + "String,Object,Object);;Argument[0..2];logging", + "String,Object,Object,Object);;Argument[0..3];logging", + "String,Object,Object,Object,Object);;Argument[0..4];logging", + "String,Object,Object,Object,Object,Object);;Argument[0..5];logging", + "String,Object,Object,Object,Object,Object,Object);;Argument[0..6];logging", + "String,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];logging", + "String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];logging", + "String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..10];logging", + "String,Supplier);;Argument[0..1];logging", "String,Throwable);;Argument[0];logging", + "Supplier);;Argument[0];logging", "Supplier,Throwable);;Argument[0];logging" + ], "org.apache.logging.log4j;Logger;true;entry;(Object[]);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;logMessage;(Level,Marker,String,StackTraceElement,Message,Throwable);;Argument[4];logging", + "org.apache.logging.log4j;Logger;true;printf;(Level,Marker,String,Object[]);;Argument[2..3];logging", + "org.apache.logging.log4j;Logger;true;printf;(Level,String,Object[]);;Argument[1..2];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(Message);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Object[]);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(String,Supplier);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceEntry;(Supplier);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(EntryMessage,Object);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(Message,Object);;Argument[0..1];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(Object);;Argument[0];logging", + "org.apache.logging.log4j;Logger;true;traceExit;(String,Object);;Argument[0..1];logging", + // org.apache.logging.log4j.LogBuilder + "org.apache.logging.log4j;LogBuilder;true;log;(CharSequence);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(Message);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(Object);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String);;Argument[0];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object[]);;Argument[0..1];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object);;Argument[0..1];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object);;Argument[0..2];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object);;Argument[0..3];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object);;Argument[0..4];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object);;Argument[0..5];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object);;Argument[0..6];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object);;Argument[0..7];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..8];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..9];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Object,Object,Object,Object,Object,Object,Object,Object,Object,Object);;Argument[0..10];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(String,Supplier);;Argument[0..1];logging", + "org.apache.logging.log4j;LogBuilder;true;log;(Supplier);;Argument[0];logging", + // org.apache.commons.logging.Log + "org.apache.commons.logging;Log;true;" + + ["debug", "error", "fatal", "info", "trace", "warn"] + ";;;Argument[0];logging", + // org.jboss.logging.BasicLogger and org.jboss.logging.Logger + // (org.jboss.logging.Logger does not implement BasicLogger in some implementations like JBoss Application Server 4.0.4) + jBossLogger() + ";true;" + + [["debug", "error", "fatal", "info", "trace", "warn"] + ";(", "log;(Level,"] + + [ + "Object);;Argument[0];logging", ";(Object,Object[]);;Argument[0..1];logging", + "Object,Object[],Throwable);;Argument[0..1];logging", + "Object,Throwable);;Argument[0];logging", + "String,Object,Object[],Throwable);;Argument[1..2];logging", + "String,Object,Throwable);;Argument[1];logging" + ], + jBossLogger() + ";true;log;(String,Level,Object,Object[],Throwable);;Argument[2..3];logging", + jBossLogger() + ";true;" + + [ + ["debug", "error", "fatal", "info", "trace", "warn"] + ["f", "v"] + ";(", + "log" + ["f", "v"] + ";(Level," + ] + + [ + "String,Object[]);;Argument[0..1];logging", "String,Object);;Argument[0..1];logging", + "String,Object,Object);;Argument[0..2];logging", + "String,Object,Object,Object);;Argument[0..3];logging", + "String,Object,Object,Object,Object);;Argument[0..4];logging", + "Throwable,String,Object);;Argument[1..2];logging", + "Throwable,String,Object,Object);;Argument[1..3];logging", + "Throwable,String,Object,Object,Object);;Argument[0..4];logging", + ], + jBossLogger() + ";true;log" + ["f", "v"] + + [ + ";(String,Level,Throwable,String,Object[]);;Argument[3..4];logging", + ";(String,Level,Throwable,String,Object);;Argument[3..4];logging", + ";(String,Level,Throwable,String,Object,Object);;Argument[3..5];logging", + ";(String,Level,Throwable,String,Object,Object,Object);;Argument[3..6];logging" + ], + // org.slf4j.spi.LoggingEventBuilder + "org.slf4j.spi;LoggingEventBuilder;true;log;;;Argument[0];logging", + "org.slf4j.spi;LoggingEventBuilder;true;log;(String,Object);;Argument[1];logging", + "org.slf4j.spi;LoggingEventBuilder;true;log;(String,Object[]);;Argument[1];logging", + "org.slf4j.spi;LoggingEventBuilder;true;log;(String,Object,Object);;Argument[1..2];logging", + "org.slf4j;Logger;true;" + ["debug", "error", "info", "trace", "warn"] + + [ + ";(String);;Argument[0];logging", ";(String,Object);;Argument[0..1];logging", + ";(String,Object[]);;Argument[0..1];logging", + ";(String,Object,Object);;Argument[0..2];logging", + ";(String,Throwable);;Argument[0];logging", ";(Marker,String);;Argument[1];logging", + ";(Marker,String,Object);;Argument[1..2];logging", + ";(Marker,String,Object[]);;Argument[1..2];logging", + ";(Marker,String,Object[],Object);;Argument[1..3];logging", + ";(Marker,String,Object[],Object,Object);;Argument[1..4];logging" + ], + // org.slf4j.Logger + "org.scijava.log;Logger;true;alwaysLog;(int,Object,Throwable);;Argument[1];logging", + "org.scijava.log;Logger;true;" + + [["debug", "error", "info", "trace", "warn"] + ";(", "log;(int,"] + + ["Object);;Argument[0];logging", "Object,Throwable);;Argument[0];logging"], + // com.google.common.flogger.LoggingApi + "com.google.common.flogger;LoggingApi;true;log;" + + [ + ";;;Argument[0];logging", "(String,Object);;Argument[1]", + "(String,Object,Object);;Argument[1..2]", + "(String,Object,Object,Object);;Argument[1..3]", "(String,Object,boolean);;Argument[1]", + "(String,Object,char);;Argument[1]", "(String,Object,byte);;Argument[1]", + "(String,Object,short);;Argument[1]", "(String,Object,int);;Argument[1]", + "(String,Object,long);;Argument[1]", "(String,Object,float);;Argument[1]", + "(String,Object,double);;Argument[1]", "(String,boolean,Object);;Argument[2]", + "(String,char,Object);;Argument[2]", "(String,byte,Object);;Argument[2]", + "(String,short,Object);;Argument[2]", "(String,int,Object);;Argument[2]", + "(String,long,Object);;Argument[2]", "(String,float,Object);;Argument[2]", + "(String,double,Object);;Argument[2]" + ] + ";logging", + // java.lang.System$Logger + "java.lang;System$Logger;true;log;" + + [ + "(Level,Object);;Argument[1]", "(Level,String);;Argument[1]", + "(Level,String,Object[]);;Argument[1..2]", "(Level,String,Throwable);;Argument[1]", + "(Level,String,Supplier);;Argument[1..2]", + "(Level,String,Supplier,Throwable);;Argument[1..2]", + "(Level,ResourceBundle,String,Object[]);;Argument[2..3]", + "(Level,ResourceBundle,String,Throwable);;Argument[2]" + ] + ";logging", + // java.util.logging.Logger + "java.util.logging;Logger;true;" + + ["config", "fine", "finer", "finest", "info", "severe", "warning"] + + ";;;Argument[0];logging", + "java.util.logging;Logger;true;entering;(String,String);;Argument[0..1];logging", + "java.util.logging;Logger;true;entering;(String,String,Object);;Argument[0..2];logging", + "java.util.logging;Logger;true;entering;(String,String,Object[]);;Argument[0..2];logging", + "java.util.logging;Logger;true;exiting;(String,String);;Argument[0..1];logging", + "java.util.logging;Logger;true;exiting;(String,String,Object);;Argument[0..2];logging", + "java.util.logging;Logger;true;log;(Level,String);;Argument[1];logging", + "java.util.logging;Logger;true;log;(Level,String,Object);;Argument[1..2];logging", + "java.util.logging;Logger;true;log;(Level,String,Object[]);;Argument[1..2];logging", + "java.util.logging;Logger;true;log;(Level,String,Throwable);;Argument[1];logging", + "java.util.logging;Logger;true;log;(Level,Supplier);;Argument[1];logging", + "java.util.logging;Logger;true;log;(Level,Throwable,Supplier);;Argument[2];logging", + "java.util.logging;Logger;true;log;(LogRecord);;Argument[1];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,String);;Argument[1..3];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,String,Object);;Argument[1..4];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,String,Object[]);;Argument[1..4];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,String,Object[]);;Argument[1..4];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,String,Throwable);;Argument[1..3];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,Supplier);;Argument[1..3];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,Throwable,Supplier);;Argument[1..2];logging", + "java.util.logging;Logger;true;logp;(Level,String,String,Throwable,Supplier);;Argument[4];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,ResourceBundle,String,Object[]);;Argument[1..2];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,ResourceBundle,String,Object[]);;Argument[4..5];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,ResourceBundle,String,Throwable);;Argument[1..2];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,ResourceBundle,String,Throwable);;Argument[3];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,String,String);;Argument[1..4];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,String,String,Object);;Argument[1..5];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,String,String,Object[]);;Argument[1..5];logging", + "java.util.logging;Logger;true;logrb;(Level,String,String,String,String,Throwable);;Argument[1..4];logging", + // android.util.Log + "android.util;Log;true;" + ["d", "v", "i", "w", "e", "wtf"] + ";;;Argument[1];logging" + ] + } +} diff --git a/java/ql/lib/semmle/code/java/security/LogInjection.qll b/java/ql/lib/semmle/code/java/security/LogInjection.qll new file mode 100644 index 00000000000..f446a7edee8 --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/LogInjection.qll @@ -0,0 +1,36 @@ +/** Provides classes and predicates related to Log Injection vulnerabilities. */ + +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.ExternalFlow + +/** A data flow sink for unvalidated user input that is used to log messages. */ +abstract class LogInjectionSink extends DataFlow::Node { } + +/** + * A node that sanitizes a message before logging to avoid log injection. + */ +abstract class LogInjectionSanitizer extends DataFlow::Node { } + +/** + * A unit class for adding additional taint steps. + * + * Extend this class to add additional taint steps that should apply to the `LogInjectionConfiguration`. + */ +class LogInjectionAdditionalTaintStep extends Unit { + /** + * Holds if the step from `node1` to `node2` should be considered a taint + * step for the `LogInjectionConfiguration` configuration. + */ + abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); +} + +private class DefaultLogInjectionSink extends LogInjectionSink { + DefaultLogInjectionSink() { sinkNode(this, "logging") } +} + +private class DefaultLogInjectionSanitizer extends LogInjectionSanitizer { + DefaultLogInjectionSanitizer() { + this.getType() instanceof BoxedType or this.getType() instanceof PrimitiveType + } +} diff --git a/java/ql/lib/semmle/code/java/security/LogInjectionQuery.qll b/java/ql/lib/semmle/code/java/security/LogInjectionQuery.qll new file mode 100644 index 00000000000..c50c09f04c4 --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/LogInjectionQuery.qll @@ -0,0 +1,22 @@ +/** Provides taint tracking configurations to be used in queries related to the Log Injection vulnerability. */ + +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.security.LogInjection + +/** + * A taint-tracking configuration for tracking untrusted user input used in log entries. + */ +class LogInjectionConfiguration extends TaintTracking::Configuration { + LogInjectionConfiguration() { this = "Log Injection" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof LogInjectionSink } + + override predicate isSanitizer(DataFlow::Node node) { node instanceof LogInjectionSanitizer } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + any(LogInjectionAdditionalTaintStep c).step(node1, node2) + } +} diff --git a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql index 7183c74b5bf..61e24f05c1c 100644 --- a/java/ql/src/Security/CWE/CWE-117/LogInjection.ql +++ b/java/ql/src/Security/CWE/CWE-117/LogInjection.ql @@ -11,28 +11,10 @@ */ import java +import semmle.code.java.security.LogInjectionQuery import DataFlow::PathGraph -import experimental.semmle.code.java.Logging -import semmle.code.java.dataflow.FlowSources - -/** - * A taint-tracking configuration for tracking untrusted user input used in log entries. - */ -private class LogInjectionConfiguration extends TaintTracking::Configuration { - LogInjectionConfiguration() { this = "Log Injection" } - - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } - - override predicate isSink(DataFlow::Node sink) { - sink.asExpr() = any(LoggingCall c).getALogArgument() - } - - override predicate isSanitizer(DataFlow::Node node) { - node.getType() instanceof BoxedType or node.getType() instanceof PrimitiveType - } -} from LogInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "$@ flows to log entry.", source.getNode(), - "User-provided value" +select sink.getNode(), source, sink, "This $@ flows to a log entry.", source.getNode(), + "user-provided value" diff --git a/java/ql/src/experimental/semmle/code/java/Logging.qll b/java/ql/src/experimental/semmle/code/java/Logging.qll deleted file mode 100644 index eea51d5b551..00000000000 --- a/java/ql/src/experimental/semmle/code/java/Logging.qll +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Provides classes and predicates for working with loggers. - */ - -import java - -/** Models a call to a logging method. */ -class LoggingCall extends MethodAccess { - LoggingCall() { - exists(RefType t, Method m | - t.hasQualifiedName("org.apache.log4j", "Category") or // Log4j 1 - t.hasQualifiedName("org.apache.logging.log4j", ["Logger", "LogBuilder"]) or // Log4j 2 - t.hasQualifiedName("org.apache.commons.logging", "Log") or - // JBoss Logging (`org.jboss.logging.Logger` in some implementations like JBoss Application Server 4.0.4 did not implement `BasicLogger`) - t.hasQualifiedName("org.jboss.logging", ["BasicLogger", "Logger"]) or - t.hasQualifiedName("org.slf4j.spi", "LoggingEventBuilder") or - t.hasQualifiedName("org.slf4j", "Logger") or - t.hasQualifiedName("org.scijava.log", "Logger") or - t.hasQualifiedName("com.google.common.flogger", "LoggingApi") or - t.hasQualifiedName("java.lang", "System$Logger") or - t.hasQualifiedName("java.util.logging", "Logger") - | - ( - m.getDeclaringType().getASourceSupertype*() = t or - m.getDeclaringType().extendsOrImplements*(t) - ) and - m.getReturnType() instanceof VoidType and - this = m.getAReference() - ) - or - exists(RefType t, Method m | t.hasQualifiedName("android.util", "Log") | - m.hasName(["d", "e", "i", "v", "w", "wtf"]) and - m.getDeclaringType() = t and - this = m.getAReference() - ) - } - - /** Returns an argument which would be logged by this call. */ - Argument getALogArgument() { result = this.getArgument(_) } -}