Merge pull request #13788 from github/kaeluka/automodel-telemetry-testing

Java: Tests for Automodel Extraction Queries
This commit is contained in:
Stephan Brandauer
2023-08-01 15:30:26 +02:00
committed by GitHub
20 changed files with 146 additions and 3 deletions

View File

@@ -56,7 +56,7 @@ abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParameter {
Parameter param;
ExplicitParameterEndpoint() { this = TExplicitParameter(param) }
ExplicitParameterEndpoint() { this = TExplicitParameter(param) and param.fromSource() }
override int getIndex() { result = param.getPosition() }
@@ -70,7 +70,9 @@ class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParamete
class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
Callable callable;
QualifierEndpoint() { this = TQualifier(callable) }
QualifierEndpoint() {
this = TQualifier(callable) and not callable.isStatic() and callable.fromSource()
}
override int getIndex() { result = -1 }

View File

@@ -303,7 +303,7 @@ module SharedCharacteristics<CandidateSig Candidate> {
* analyzed.
*/
private class IsSanitizerCharacteristic extends NotASinkCharacteristic {
IsSanitizerCharacteristic() { this = "external" }
IsSanitizerCharacteristic() { this = "known sanitizer" }
override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSanitizer(e, _) }
}

View File

@@ -0,0 +1,2 @@
| Test.java:16:3:16:11 | reference | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:16:3:16:24 | set(...) | CallContext | file://java.util.concurrent.atomic:1:1:1:1 | java.util.concurrent.atomic | package | file://AtomicReference:1:1:1:1 | AtomicReference | type | file://false:1:1:1:1 | false | subtypes | file://set:1:1:1:1 | set | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input |
| Test.java:21:3:21:10 | supplier | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:21:3:21:16 | get(...) | CallContext | file://java.util.function:1:1:1:1 | java.util.function | package | file://Supplier:1:1:1:1 | Supplier | type | file://true:1:1:1:1 | true | subtypes | file://get:1:1:1:1 | get | name | file://():1:1:1:1 | () | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input |

View File

@@ -0,0 +1 @@
Telemetry/AutomodelApplicationModeExtractCandidates.ql

View File

@@ -0,0 +1,2 @@
| Test.java:40:14:40:21 | openPath | taint step\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:40:4:40:22 | get(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Paths:1:1:1:1 | Paths | type | file://false:1:1:1:1 | false | subtypes | file://get:1:1:1:1 | get | name | file://(String,String[]):1:1:1:1 | (String,String[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |
| Test.java:46:4:46:5 | f2 | known non-sink\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:45:10:47:3 | compareTo(...) | CallContext | file://java.io:1:1:1:1 | java.io | package | file://File:1:1:1:1 | File | type | file://true:1:1:1:1 | true | subtypes | file://compareTo:1:1:1:1 | compareTo | name | file://(File):1:1:1:1 | (File) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |

View File

@@ -0,0 +1 @@
Telemetry/AutomodelApplicationModeExtractNegativeExamples.ql

View File

@@ -0,0 +1,3 @@
| Test.java:26:4:26:9 | source | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:25:3:29:3 | copy(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,Path,CopyOption[]):1:1:1:1 | (Path,Path,CopyOption[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |
| Test.java:27:4:27:9 | target | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:25:3:29:3 | copy(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,Path,CopyOption[]):1:1:1:1 | (Path,Path,CopyOption[]) | signature | file://Argument[1]:1:1:1:1 | Argument[1] | input |
| Test.java:34:4:34:11 | openPath | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:33:10:35:3 | newInputStream(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://newInputStream:1:1:1:1 | newInputStream | name | file://(Path,OpenOption[]):1:1:1:1 | (Path,OpenOption[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |

View File

@@ -0,0 +1 @@
Telemetry/AutomodelApplicationModeExtractPositiveExamples.ql

View File

@@ -0,0 +1,50 @@
package com.github.codeql.test;
import java.io.InputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.io.File;
class Test {
public static void main(String[] args) throws Exception {
AtomicReference<String> reference = new AtomicReference<>(); // uninteresting (parameterless constructor)
reference.set(args[0]); // arg[0] is not a candidate (modeled as value flow step)
// ^^^^^^ Argument[this] is a candidate
}
public static void callSupplier(Supplier<String> supplier) {
supplier.get(); // Argument[this] is a candidate
}
public static void copyFiles(Path source, Path target, CopyOption option) throws Exception {
Files.copy(
source, // positive example (known sink)
target, // positive example (known sink)
option // no candidate (not modeled, but source and target are modeled)
);
}
public static InputStream getInputStream(Path openPath) throws Exception {
return Files.newInputStream(
openPath // positive example (known sink)
);
}
public static InputStream getInputStream(String openPath) throws Exception {
return Test.getInputStream(
Paths.get(openPath) // no candidate (argument to local call)
);
}
public static int compareFiles(File f1, File f2) {
return f1.compareTo(
f2 // negative example (modeled as not a sink)
);
}
}

View File

@@ -0,0 +1,7 @@
| com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | MethodDoc | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://this:1:1:1:1 | this | parameterName |
| com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName |
| com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName |
| com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | MethodDoc | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://this:1:1:1:1 | this | parameterName |
| com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName |
| com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName |
| java/nio/file/Files.java:10:9:10:24 | out | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:10:9:10:24 | out | MethodDoc | java/nio/file/Files.java:10:9:10:24 | out | ClassDoc | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,OutputStream):1:1:1:1 | (Path,OutputStream) | signature | file://Argument[1]:1:1:1:1 | Argument[1] | input | file://out:1:1:1:1 | out | parameterName |

View File

@@ -0,0 +1 @@
Telemetry/AutomodelFrameworkModeExtractCandidates.ql

View File

@@ -0,0 +1,2 @@
| java/io/File.java:4:9:4:17 | compareTo | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:4:9:4:17 | compareTo | MethodDoc | java/io/File.java:4:9:4:17 | compareTo | ClassDoc | file://java.io:1:1:1:1 | java.io | package | file://File:1:1:1:1 | File | type | file://true:1:1:1:1 | true | subtypes | file://compareTo:1:1:1:1 | compareTo | name | file://(File):1:1:1:1 | (File) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://this:1:1:1:1 | this | parameterName |
| java/io/File.java:5:9:5:21 | pathname | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:5:9:5:21 | pathname | MethodDoc | java/io/File.java:5:9:5:21 | pathname | ClassDoc | file://java.io:1:1:1:1 | java.io | package | file://File:1:1:1:1 | File | type | file://true:1:1:1:1 | true | subtypes | file://compareTo:1:1:1:1 | compareTo | name | file://(File):1:1:1:1 | (File) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://pathname:1:1:1:1 | pathname | parameterName |

View File

@@ -0,0 +1 @@
Telemetry/AutomodelFrameworkModeExtractNegativeExamples.ql

View File

@@ -0,0 +1 @@
| java/nio/file/Files.java:9:9:9:19 | source | path-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:9:9:9:19 | source | MethodDoc | java/nio/file/Files.java:9:9:9:19 | source | ClassDoc | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,OutputStream):1:1:1:1 | (Path,OutputStream) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://source:1:1:1:1 | source | parameterName |

View File

@@ -0,0 +1 @@
Telemetry/AutomodelFrameworkModeExtractPositiveExamples.ql

View File

@@ -0,0 +1,10 @@
package com.github.codeql.test;
/**
* No candidates in this class, as it's not public!
*/
class NonPublicClass {
public void noCandidates(String here) {
System.out.println(here);
}
}

View File

@@ -0,0 +1,21 @@
package com.github.codeql.test;
public class PublicClass {
public void stuff(String arg) { // `arg` is a candidate, `this` is a candidate
System.out.println(arg);
}
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method)
System.out.println(arg);
}
// `arg` and `this` are not a candidate because the method is not public:
protected void nonPublicStuff(String arg) {
System.out.println(arg);
}
// `arg` and `this are not candidates because the method is not public:
void packagePrivateStuff(String arg) {
System.out.println(arg);
}
}

View File

@@ -0,0 +1,9 @@
package com.github.codeql.test;
public interface PublicInterface {
public void stuff(String arg); // `arg` is a candidate, `this` is a candidate
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method)
System.out.println(arg);
}
}

View File

@@ -0,0 +1,9 @@
package java.io;
public class File {
int compareTo( // `this` is a negative example - this is modeled as a neutral model
File pathname // negative example - this is modeled as a neutral model
) {
return 0;
}
}

View File

@@ -0,0 +1,19 @@
package java.nio.file;
import java.nio.file.Path;
import java.io.IOException;
import java.io.OutputStream;
public class Files {
public static void copy(
Path source, // a positive example because a manual model exists
OutputStream out /* a candidate. NB: may be worthwhile to implement the
same behavior as in application mode where out would not be a
candidate because there already is a model for another parameter of
the same method and we assume that methods are always modeled
completely.
*/
) throws IOException {
// ...
}
}