mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
Add test cases for PolynomialRedos dataflow logic; make fixes
This commit is contained in:
@@ -37,7 +37,7 @@ abstract class RegexMatchMethodAccess extends MethodAccess {
|
||||
Method m;
|
||||
|
||||
RegexMatchMethodAccess() {
|
||||
this.getMethod().overrides*(m) and
|
||||
this.getMethod().getSourceDeclaration().overrides*(m) and
|
||||
m.hasQualifiedName(package, type, name) and
|
||||
regexArg in [-1 .. m.getNumberOfParameters() - 1] and
|
||||
stringArg in [-1 .. m.getNumberOfParameters() - 1]
|
||||
@@ -79,9 +79,9 @@ private class JdkRegexMatchMethodAccess extends RegexMatchMethodAccess {
|
||||
or
|
||||
name = "matches" and regexArg = 0 and stringArg = 1
|
||||
or
|
||||
name = "split" and regexArg = 0 and stringArg = 1
|
||||
name = "split" and regexArg = -1 and stringArg = 0
|
||||
or
|
||||
name = "splitAsStream" and regexArg = 0 and stringArg = 1
|
||||
name = "splitAsStream" and regexArg = -1 and stringArg = 0
|
||||
)
|
||||
or
|
||||
package = "java.lang" and
|
||||
@@ -90,7 +90,7 @@ private class JdkRegexMatchMethodAccess extends RegexMatchMethodAccess {
|
||||
regexArg = 0 and
|
||||
stringArg = -1
|
||||
or
|
||||
package = "java.util" and
|
||||
package = "java.util.function" and
|
||||
type = "Predicate" and
|
||||
name = "test" and
|
||||
regexArg = -1 and
|
||||
@@ -101,7 +101,7 @@ private class JdkRegexMatchMethodAccess extends RegexMatchMethodAccess {
|
||||
private class JdkRegexFlowStep extends RegexAdditionalFlowStep {
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma, Method m, string package, string type, string name, int arg |
|
||||
ma.getMethod().overrides*(m) and
|
||||
ma.getMethod().getSourceDeclaration().overrides*(m) and
|
||||
m.hasQualifiedName(package, type, name) and
|
||||
node1.asExpr() = argOf(ma, arg) and
|
||||
node2.asExpr() = ma
|
||||
@@ -116,7 +116,7 @@ private class JdkRegexFlowStep extends RegexAdditionalFlowStep {
|
||||
arg = 0
|
||||
)
|
||||
or
|
||||
package = "java.util" and
|
||||
package = "java.util.function" and
|
||||
type = "Predicate" and
|
||||
name = ["and", "or", "not", "negate"] and
|
||||
arg = [-1, 0]
|
||||
@@ -126,7 +126,7 @@ private class JdkRegexFlowStep extends RegexAdditionalFlowStep {
|
||||
|
||||
private class GuavaRegexMatchMethodAccess extends RegexMatchMethodAccess {
|
||||
GuavaRegexMatchMethodAccess() {
|
||||
package = "com.google.common.collect" and
|
||||
package = "com.google.common.base" and
|
||||
regexArg = -1 and
|
||||
stringArg = 0 and
|
||||
type = ["Splitter", "Splitter$MapSplitter"] and
|
||||
@@ -137,7 +137,7 @@ private class GuavaRegexMatchMethodAccess extends RegexMatchMethodAccess {
|
||||
private class GuavaRegexFlowStep extends RegexAdditionalFlowStep {
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma, Method m, string package, string type, string name, int arg |
|
||||
ma.getMethod().overrides*(m) and
|
||||
ma.getMethod().getSourceDeclaration().overrides*(m) and
|
||||
m.hasQualifiedName(package, type, name) and
|
||||
node1.asExpr() = argOf(ma, arg) and
|
||||
node2.asExpr() = ma
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
class Test {
|
||||
class ExpRedosTest {
|
||||
static String[] regs = {
|
||||
|
||||
// NOT GOOD; attack: "_" + "__".repeat(100)
|
||||
35
java/ql/test/query-tests/security/CWE-730/PolyRedosTest.java
Normal file
35
java/ql/test/query-tests/security/CWE-730/PolyRedosTest.java
Normal file
@@ -0,0 +1,35 @@
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.function.Predicate;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
class PolyRedosTest {
|
||||
void test(HttpServletRequest request) {
|
||||
String tainted = request.getParameter("inp");
|
||||
String reg = "a\\.\\d+E?\\d+b";
|
||||
Predicate<String> dummyPred = (s -> s.length() % 7 == 0);
|
||||
|
||||
tainted.matches(reg); // $ hasTaintFlow
|
||||
tainted.split(reg); // $ hasTaintFlow
|
||||
tainted.split(reg, 7); // $ hasTaintFlow
|
||||
Pattern.matches(reg, tainted); // $ hasTaintFlow
|
||||
Pattern.compile(reg).matcher(tainted).matches(); // $ hasTaintFlow
|
||||
Pattern.compile(reg).split(tainted); // $ hasTaintFlow
|
||||
Pattern.compile(reg, Pattern.DOTALL).split(tainted); // $ hasTaintFlow
|
||||
Pattern.compile(reg).split(tainted, 7); // $ hasTaintFlow
|
||||
Pattern.compile(reg).splitAsStream(tainted); // $ hasTaintFlow
|
||||
Pattern.compile(reg).asPredicate().test(tainted); // $ hasTaintFlow
|
||||
Pattern.compile(reg).asMatchPredicate().negate().and(dummyPred).or(dummyPred).test(tainted); // $ hasTaintFlow
|
||||
Predicate.not(dummyPred.and(dummyPred.or(Pattern.compile(reg).asPredicate()))).test(tainted); // $ hasTaintFlow
|
||||
|
||||
Splitter.on(Pattern.compile(reg)).split(tainted); // $ hasTaintFlow
|
||||
Splitter.on(reg).split(tainted);
|
||||
Splitter.onPattern(reg).split(tainted); // $ hasTaintFlow
|
||||
Splitter.onPattern(reg).splitToList(tainted); // $ hasTaintFlow
|
||||
Splitter.onPattern(reg).limit(7).omitEmptyStrings().trimResults().split(tainted); // $ hasTaintFlow
|
||||
Splitter.onPattern(reg).withKeyValueSeparator(" => ").split(tainted); // $ hasTaintFlow
|
||||
Splitter.on(";").withKeyValueSeparator(reg).split(tainted);
|
||||
Splitter.on(";").withKeyValueSeparator(Splitter.onPattern(reg)).split(tainted); // $ hasTaintFlow
|
||||
|
||||
}
|
||||
}
|
||||
1
java/ql/test/query-tests/security/CWE-730/options
Normal file
1
java/ql/test/query-tests/security/CWE-730/options
Normal file
@@ -0,0 +1 @@
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/guava-30.0
|
||||
53
java/ql/test/stubs/guava-30.0/com/google/common/base/CharMatcher.java
generated
Normal file
53
java/ql/test/stubs/guava-30.0/com/google/common/base/CharMatcher.java
generated
Normal file
@@ -0,0 +1,53 @@
|
||||
// Generated automatically from com.google.common.base.CharMatcher for testing purposes
|
||||
|
||||
package com.google.common.base;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
abstract public class CharMatcher implements Predicate<Character>
|
||||
{
|
||||
protected CharMatcher(){}
|
||||
public CharMatcher and(CharMatcher p0){ return null; }
|
||||
public CharMatcher negate(){ return null; }
|
||||
public CharMatcher or(CharMatcher p0){ return null; }
|
||||
public CharMatcher precomputed(){ return null; }
|
||||
public String collapseFrom(CharSequence p0, char p1){ return null; }
|
||||
public String removeFrom(CharSequence p0){ return null; }
|
||||
public String replaceFrom(CharSequence p0, CharSequence p1){ return null; }
|
||||
public String replaceFrom(CharSequence p0, char p1){ return null; }
|
||||
public String retainFrom(CharSequence p0){ return null; }
|
||||
public String toString(){ return null; }
|
||||
public String trimAndCollapseFrom(CharSequence p0, char p1){ return null; }
|
||||
public String trimFrom(CharSequence p0){ return null; }
|
||||
public String trimLeadingFrom(CharSequence p0){ return null; }
|
||||
public String trimTrailingFrom(CharSequence p0){ return null; }
|
||||
public abstract boolean matches(char p0);
|
||||
public boolean apply(Character p0){ return false; }
|
||||
public boolean matchesAllOf(CharSequence p0){ return false; }
|
||||
public boolean matchesAnyOf(CharSequence p0){ return false; }
|
||||
public boolean matchesNoneOf(CharSequence p0){ return false; }
|
||||
public int countIn(CharSequence p0){ return 0; }
|
||||
public int indexIn(CharSequence p0){ return 0; }
|
||||
public int indexIn(CharSequence p0, int p1){ return 0; }
|
||||
public int lastIndexIn(CharSequence p0){ return 0; }
|
||||
public static CharMatcher any(){ return null; }
|
||||
public static CharMatcher anyOf(CharSequence p0){ return null; }
|
||||
public static CharMatcher ascii(){ return null; }
|
||||
public static CharMatcher breakingWhitespace(){ return null; }
|
||||
public static CharMatcher digit(){ return null; }
|
||||
public static CharMatcher forPredicate(Predicate<? super Character> p0){ return null; }
|
||||
public static CharMatcher inRange(char p0, char p1){ return null; }
|
||||
public static CharMatcher invisible(){ return null; }
|
||||
public static CharMatcher is(char p0){ return null; }
|
||||
public static CharMatcher isNot(char p0){ return null; }
|
||||
public static CharMatcher javaDigit(){ return null; }
|
||||
public static CharMatcher javaIsoControl(){ return null; }
|
||||
public static CharMatcher javaLetter(){ return null; }
|
||||
public static CharMatcher javaLetterOrDigit(){ return null; }
|
||||
public static CharMatcher javaLowerCase(){ return null; }
|
||||
public static CharMatcher javaUpperCase(){ return null; }
|
||||
public static CharMatcher none(){ return null; }
|
||||
public static CharMatcher noneOf(CharSequence p0){ return null; }
|
||||
public static CharMatcher singleWidth(){ return null; }
|
||||
public static CharMatcher whitespace(){ return null; }
|
||||
}
|
||||
@@ -1,48 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
// Generated automatically from com.google.common.base.Splitter for testing purposes
|
||||
|
||||
package com.google.common.base;
|
||||
|
||||
import java.util.Iterator;
|
||||
import com.google.common.base.CharMatcher;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class Splitter {
|
||||
|
||||
public static Splitter on(final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Splitter omitEmptyStrings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Iterable<String> split(final CharSequence sequence) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> splitToList(CharSequence sequence) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public MapSplitter withKeyValueSeparator(String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final class MapSplitter {
|
||||
public Map<String, String> split(CharSequence sequence) {
|
||||
return null;
|
||||
public class Splitter
|
||||
{
|
||||
protected Splitter() {}
|
||||
public Iterable<String> split(CharSequence p0){ return null; }
|
||||
public List<String> splitToList(CharSequence p0){ return null; }
|
||||
public Splitter limit(int p0){ return null; }
|
||||
public Splitter omitEmptyStrings(){ return null; }
|
||||
public Splitter trimResults(){ return null; }
|
||||
public Splitter trimResults(CharMatcher p0){ return null; }
|
||||
public Splitter.MapSplitter withKeyValueSeparator(Splitter p0){ return null; }
|
||||
public Splitter.MapSplitter withKeyValueSeparator(String p0){ return null; }
|
||||
public Splitter.MapSplitter withKeyValueSeparator(char p0){ return null; }
|
||||
public Stream<String> splitToStream(CharSequence p0){ return null; }
|
||||
public static Splitter fixedLength(int p0){ return null; }
|
||||
public static Splitter on(CharMatcher p0){ return null; }
|
||||
public static Splitter on(Pattern p0){ return null; }
|
||||
public static Splitter on(String p0){ return null; }
|
||||
public static Splitter on(char p0){ return null; }
|
||||
public static Splitter onPattern(String p0){ return null; }
|
||||
static public class MapSplitter
|
||||
{
|
||||
protected MapSplitter() {}
|
||||
public Map<String, String> split(CharSequence p0){ return null; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user