mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Java: Add modelling for Guava Strings, Splitter, and Joiner
This commit is contained in:
@@ -79,6 +79,11 @@ Expr clearlyNotNullExpr(Expr reason) {
|
||||
)
|
||||
or
|
||||
exists(SsaVariable v | clearlyNotNull(v, reason) and result = v.getAUse())
|
||||
or
|
||||
exists(Method m | m = result.(MethodAccess).getMethod() and reason = result |
|
||||
m.getDeclaringType().hasQualifiedName("com.google.common.base", "Strings") and
|
||||
m.hasName("nullToEmpty")
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `v` is an SSA variable that is provably not `null`. */
|
||||
@@ -146,6 +151,11 @@ predicate nullCheckMethod(Method m, boolean branch, boolean isnull) {
|
||||
m.hasName("isNotEmpty") and
|
||||
branch = true and
|
||||
isnull = false
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("com.google.common.base", "Strings") and
|
||||
m.hasName("isNullOrEmpty") and
|
||||
branch = false and
|
||||
isnull = false
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,9 +7,14 @@ private import semmle.code.java.security.SecurityTests
|
||||
private import semmle.code.java.security.Validation
|
||||
private import semmle.code.java.Maps
|
||||
private import semmle.code.java.dataflow.internal.ContainerFlow
|
||||
<<<<<<< HEAD
|
||||
private import semmle.code.java.frameworks.spring.SpringController
|
||||
private import semmle.code.java.frameworks.spring.SpringHttp
|
||||
import semmle.code.java.dataflow.FlowSteps
|
||||
=======
|
||||
private import semmle.code.java.frameworks.jackson.JacksonSerializability
|
||||
private import semmle.code.java.frameworks.guava.Guava
|
||||
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `src` to `sink` in zero or more
|
||||
@@ -285,7 +290,11 @@ private predicate taintPreservingQualifierToArgument(Method m, int arg) {
|
||||
m.hasName("read") and
|
||||
arg = 0
|
||||
or
|
||||
<<<<<<< HEAD
|
||||
m.(TaintPreservingCallable).transfersTaint(-1, arg)
|
||||
=======
|
||||
m.(GuavaTaintPropagationMethod).propagatesTaint(-1, arg)
|
||||
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
|
||||
}
|
||||
|
||||
/** Access to a method that passes taint from the qualifier. */
|
||||
@@ -359,7 +368,11 @@ private predicate taintPreservingQualifierToMethod(Method m) {
|
||||
)
|
||||
)
|
||||
or
|
||||
<<<<<<< HEAD
|
||||
m.(TaintPreservingCallable).returnsTaintFrom(-1)
|
||||
=======
|
||||
m.(GuavaTaintPropagationMethod).propagatesTaint(-1, -2)
|
||||
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
|
||||
}
|
||||
|
||||
private class StringReplaceMethod extends TaintPreservingCallable {
|
||||
@@ -477,7 +490,26 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
|
||||
method.hasName("sourceToInputSource") and
|
||||
arg = 0
|
||||
or
|
||||
<<<<<<< HEAD
|
||||
method.(TaintPreservingCallable).returnsTaintFrom(arg)
|
||||
=======
|
||||
exists(ProtobufParser p | method = p.getAParseFromMethod()) and
|
||||
arg = 0
|
||||
or
|
||||
exists(ProtobufMessageLite m | method = m.getAParseFromMethod()) and
|
||||
arg = 0
|
||||
or
|
||||
// Jackson serialization methods that return the serialized data
|
||||
method instanceof JacksonWriteValueMethod and
|
||||
method.getNumberOfParameters() = 1 and
|
||||
arg = 0
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and
|
||||
method.hasName("append") and
|
||||
arg = 0
|
||||
or
|
||||
method.(GuavaTaintPropagationMethod).propagatesTaint(arg, -2)
|
||||
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,7 +557,17 @@ private predicate taintPreservingArgToArg(Method method, int input, int output)
|
||||
input = 0 and
|
||||
output = 2
|
||||
or
|
||||
<<<<<<< HEAD
|
||||
method.(TaintPreservingCallable).transfersTaint(input, output)
|
||||
=======
|
||||
// Jackson serialization methods that write data to the first argument
|
||||
method instanceof JacksonWriteValueMethod and
|
||||
method.getNumberOfParameters() > 1 and
|
||||
input = method.getNumberOfParameters() - 1 and
|
||||
output = 0
|
||||
or
|
||||
method.(GuavaTaintPropagationMethod).propagatesTaint(input, output)
|
||||
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -553,7 +595,18 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) {
|
||||
write.getDeclaringType().hasQualifiedName("java.io", "OutputStream")
|
||||
)
|
||||
or
|
||||
<<<<<<< HEAD
|
||||
method.(TaintPreservingCallable).transfersTaint(arg, -1)
|
||||
=======
|
||||
exists(Method append |
|
||||
method.overrides*(append) and
|
||||
append.hasName("append") and
|
||||
arg = 0 and
|
||||
append.getDeclaringType().hasQualifiedName("java.io", "StringWriter")
|
||||
)
|
||||
or
|
||||
method.(GuavaTaintPropagationMethod).propagatesTaint(arg, -1)
|
||||
>>>>>>> 61c00e344... Java: Add modelling for Guava `Strings`, `Splitter`, and `Joiner`
|
||||
}
|
||||
|
||||
/** A comparison or equality test with a constant. */
|
||||
|
||||
30
java/ql/src/semmle/code/java/frameworks/guava/Guava.qll
Normal file
30
java/ql/src/semmle/code/java/frameworks/guava/Guava.qll
Normal file
@@ -0,0 +1,30 @@
|
||||
import java
|
||||
import Strings
|
||||
import Splitter
|
||||
import Joiner
|
||||
|
||||
/**
|
||||
* A method in the guava framework that propegates taint.
|
||||
*/
|
||||
abstract class GuavaTaintPropagationMethod extends Method {
|
||||
/**
|
||||
* Holds if this method propagates taint between the given source and sink.
|
||||
* `src` and `sink` are indicies of arguments to this method, or -1 to represent the qualifier.
|
||||
* `sink` ca also be -2 to represent the return value.
|
||||
*/
|
||||
abstract predicate propagatesTaint(int src, int sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* A method in the guava framework that returns tainted data when a specific input
|
||||
* (either an argument or the qualifier) is tainted.
|
||||
*/
|
||||
abstract class GuavaTaintPropagationMethodToReturn extends GuavaTaintPropagationMethod {
|
||||
/**
|
||||
* Holds if this method returns tainted data when the given source is tainted.
|
||||
* `src` is an argument index, or -1 to indicate the qualifier.
|
||||
*/
|
||||
abstract predicate propagatesTaint(int src);
|
||||
|
||||
override predicate propagatesTaint(int src, int sink) { propagatesTaint(src) and sink = -2 }
|
||||
}
|
||||
93
java/ql/src/semmle/code/java/frameworks/guava/Joiner.qll
Normal file
93
java/ql/src/semmle/code/java/frameworks/guava/Joiner.qll
Normal file
@@ -0,0 +1,93 @@
|
||||
import java
|
||||
import Guava
|
||||
|
||||
/**
|
||||
* The class `com.google.common.base.Joiner`.
|
||||
*/
|
||||
class TypeGuavaJoiner extends Class {
|
||||
TypeGuavaJoiner() { this.hasQualifiedName("com.google.common.base", "Joiner") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The nested class `Joiner.MapJoiner`.
|
||||
*/
|
||||
class TypeGuavaMapJoiner extends NestedClass {
|
||||
TypeGuavaMapJoiner() {
|
||||
this.getEnclosingType() instanceof TypeGuavaJoiner and
|
||||
this.hasName("MapJoiner")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method of `Joiner` or `MapJoiner`.
|
||||
*/
|
||||
private class GuavaJoinerMethod extends Method {
|
||||
GuavaJoinerMethod() {
|
||||
this.getDeclaringType() instanceof TypeGuavaJoiner or
|
||||
this.getDeclaringType() instanceof TypeGuavaMapJoiner
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that builds a `Joiner` or `MapJoiner`.
|
||||
*/
|
||||
class GuavaJoinerBuilderMethod extends GuavaJoinerMethod, GuavaTaintPropagationMethodToReturn {
|
||||
GuavaJoinerBuilderMethod() {
|
||||
// static Joiner on(char separator)
|
||||
// static Joiner on(String separator)
|
||||
// Joiner skipNulls()
|
||||
// Joiner useForNull(String nullText)
|
||||
// Joiner.MapJoiner withKeyValueSeparator(String keyValueSeparator)
|
||||
// Joiner.MapJoiner useForNull(String nullText) [on MapJoiner]
|
||||
this.hasName(["on", "skipNulls", "useForNull", "withKeyValueSeparator"])
|
||||
}
|
||||
|
||||
override predicate propagatesTaint(int src) { src = [-1, 0] }
|
||||
}
|
||||
|
||||
/**
|
||||
* An `appendTo` method on `Joiner` or `MapJoiner`
|
||||
*/
|
||||
class GuavaJoinerAppendToMethod extends GuavaJoinerMethod, GuavaTaintPropagationMethod {
|
||||
GuavaJoinerAppendToMethod() {
|
||||
// <A extends Appendable> A appendTo(A appendable, Iterable<?> parts)
|
||||
// <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)
|
||||
// <A extends Appendable> A appendTo(A appendable, Object[] parts)
|
||||
// <A extends Appendable> A appendTo(A appendable, Object first, Object second, Object... rest)
|
||||
// StringBuilder appendTo(StringBuilder builder, Iterable<?> parts)
|
||||
// StringBuilder appendTo(StringBuilder builder, Iterator<?> parts)
|
||||
// StringBuilder appendTo(StringBuilder builder, Object[] parts)
|
||||
// StringBuilder appendTo(StringBuilder builder, Object first, Object second, Object... rest)
|
||||
// <A extends Appendable> A appendTo(A appendable, Iterable<? extends Map.Entry<?,?>> entries) [on MapJoiner]
|
||||
// <A extends Appendable> A appendTo(A appendable, Iterator<? extends Map.Entry<?,?>> parts)
|
||||
// <A extends Appendable> A appendTo(A appendable, Map<?,?> map)
|
||||
// StringBuilder appendTo(StringBuilder builder, Iterable<? extends Map.Entry<?,?>> entries)
|
||||
// StringBuilder appendTo(StringBuilder builder, Iterator<? extends Map.Entry<?,?>> entries)
|
||||
// StringBuilder appendTo(StringBuilder builder, Map<?,?> map)
|
||||
this.hasName("appendTo")
|
||||
}
|
||||
|
||||
override predicate propagatesTaint(int src, int sink) {
|
||||
src = [-1 .. getNumberOfParameters()] and
|
||||
src != sink and
|
||||
sink = [-2, 0]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `join` method on `Joiner` or `MapJoiner`
|
||||
*/
|
||||
class GuavaJoinMethod extends GuavaJoinerMethod, GuavaTaintPropagationMethodToReturn {
|
||||
GuavaJoinMethod() {
|
||||
// String join(Iterable<?> parts)
|
||||
// String join(Iterator<?> parts)
|
||||
// String join(Object[] parts)
|
||||
// String join(Object first, Object second, Object... rest)
|
||||
// String join(Iterable<? extends Map.Entry<?,?>> entries) [on MapJoiner]
|
||||
// String join(Iterator<? extends Map.Entry<?,?>> entries)
|
||||
// String join(Map<?,?> map)
|
||||
this.hasName("join")
|
||||
}
|
||||
|
||||
override predicate propagatesTaint(int src) { src = [-1 .. getNumberOfParameters()] }
|
||||
}
|
||||
39
java/ql/src/semmle/code/java/frameworks/guava/Splitter.qll
Normal file
39
java/ql/src/semmle/code/java/frameworks/guava/Splitter.qll
Normal file
@@ -0,0 +1,39 @@
|
||||
import java
|
||||
import Guava
|
||||
|
||||
/**
|
||||
* The class `com.google.common.base.Splitter`.
|
||||
*/
|
||||
class TypeGuavaSplitter extends Class {
|
||||
TypeGuavaSplitter() { this.hasQualifiedName("com.google.common.base", "Splitter") }
|
||||
}
|
||||
|
||||
/**
|
||||
* The nested class `Splitter.MapSplitter`.
|
||||
*/
|
||||
class TypeGuavaMapSplitter extends NestedClass {
|
||||
TypeGuavaMapSplitter() {
|
||||
this.getEnclosingType() instanceof TypeGuavaSplitter and
|
||||
this.hasName("MapSplitter")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method of `Splitter` or `MapSplitter` that splits its input string.
|
||||
*/
|
||||
class GuavaSplitMethod extends GuavaTaintPropagationMethodToReturn {
|
||||
GuavaSplitMethod() {
|
||||
(
|
||||
this.getDeclaringType() instanceof TypeGuavaSplitter
|
||||
or
|
||||
this.getDeclaringType() instanceof TypeGuavaMapSplitter
|
||||
) and
|
||||
// Iterable<String> split(CharSequence sequence)
|
||||
// List<String> splitToList(CharSequence sequence)
|
||||
// Stream<String> splitToStream(CharSequence sequence)
|
||||
// Map<String,String> split(CharSequence sequence) [on MapSplitter]
|
||||
this.hasName(["split", "splitToList", "splitToStream"])
|
||||
}
|
||||
|
||||
override predicate propagatesTaint(int src) { src = 0 }
|
||||
}
|
||||
39
java/ql/src/semmle/code/java/frameworks/guava/Strings.qll
Normal file
39
java/ql/src/semmle/code/java/frameworks/guava/Strings.qll
Normal file
@@ -0,0 +1,39 @@
|
||||
import java
|
||||
import Guava
|
||||
|
||||
/**
|
||||
* The class `com.google.common.base.Strings`.
|
||||
*/
|
||||
class TypeGuavaStrings extends Class {
|
||||
TypeGuavaStrings() { this.hasQualifiedName("com.google.common.base", "Strings") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Guava string utility method that preserves taint from its first argument.
|
||||
*/
|
||||
class GuavaStringsTaintPropagationMethod extends GuavaTaintPropagationMethodToReturn {
|
||||
GuavaStringsTaintPropagationMethod() {
|
||||
this.getDeclaringType() instanceof TypeGuavaStrings and
|
||||
// static String emptyToNull(String string)
|
||||
// static String emptyToNull(String string)
|
||||
// static String padEnd(String string, int minLength, char padChar)
|
||||
// static String padStart(String string, int minLength, char padChar)
|
||||
// static String repeat(String string, int count)
|
||||
this.hasName(["emptyToNull", "nullToEmpty", "padStart", "padEnd", "repeat"])
|
||||
}
|
||||
|
||||
override predicate propagatesTaint(int src) { src = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Strings.lenientFormat`.
|
||||
*/
|
||||
class GuavaStringsFormatMethod extends GuavaTaintPropagationMethodToReturn {
|
||||
GuavaStringsFormatMethod() {
|
||||
this.getDeclaringType() instanceof TypeGuavaStrings and
|
||||
// static String lenientFormat(String template, Object ... args)
|
||||
this.hasName("lenientFormat")
|
||||
}
|
||||
|
||||
override predicate propagatesTaint(int src) { src in [0 .. getNumberOfParameters()] }
|
||||
}
|
||||
Reference in New Issue
Block a user