Skip to content

Commit cb55b10

Browse files
authored
Merge pull request #13788 from github/kaeluka/automodel-telemetry-testing
Java: Tests for Automodel Extraction Queries
2 parents 15da4ee + 621c05d commit cb55b10

20 files changed

+146
-3
lines changed

java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
5656
class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParameter {
5757
Parameter param;
5858

59-
ExplicitParameterEndpoint() { this = TExplicitParameter(param) }
59+
ExplicitParameterEndpoint() { this = TExplicitParameter(param) and param.fromSource() }
6060

6161
override int getIndex() { result = param.getPosition() }
6262

@@ -70,7 +70,9 @@ class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParamete
7070
class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
7171
Callable callable;
7272

73-
QualifierEndpoint() { this = TQualifier(callable) }
73+
QualifierEndpoint() {
74+
this = TQualifier(callable) and not callable.isStatic() and callable.fromSource()
75+
}
7476

7577
override int getIndex() { result = -1 }
7678

java/ql/src/Telemetry/AutomodelSharedCharacteristics.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ module SharedCharacteristics<CandidateSig Candidate> {
303303
* analyzed.
304304
*/
305305
private class IsSanitizerCharacteristic extends NotASinkCharacteristic {
306-
IsSanitizerCharacteristic() { this = "external" }
306+
IsSanitizerCharacteristic() { this = "known sanitizer" }
307307

308308
override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSanitizer(e, _) }
309309
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| 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 |
2+
| 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 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Telemetry/AutomodelApplicationModeExtractCandidates.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| 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 |
2+
| 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 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Telemetry/AutomodelApplicationModeExtractNegativeExamples.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| 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 |
2+
| 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 |
3+
| 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 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Telemetry/AutomodelApplicationModeExtractPositiveExamples.ql
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.github.codeql.test;
2+
3+
import java.io.InputStream;
4+
import java.nio.file.CopyOption;
5+
import java.nio.file.Files;
6+
import java.nio.file.Path;
7+
import java.nio.file.Paths;
8+
import java.util.concurrent.atomic.AtomicReference;
9+
import java.util.function.Supplier;
10+
import java.io.File;
11+
12+
13+
class Test {
14+
public static void main(String[] args) throws Exception {
15+
AtomicReference<String> reference = new AtomicReference<>(); // uninteresting (parameterless constructor)
16+
reference.set(args[0]); // arg[0] is not a candidate (modeled as value flow step)
17+
// ^^^^^^ Argument[this] is a candidate
18+
}
19+
20+
public static void callSupplier(Supplier<String> supplier) {
21+
supplier.get(); // Argument[this] is a candidate
22+
}
23+
24+
public static void copyFiles(Path source, Path target, CopyOption option) throws Exception {
25+
Files.copy(
26+
source, // positive example (known sink)
27+
target, // positive example (known sink)
28+
option // no candidate (not modeled, but source and target are modeled)
29+
);
30+
}
31+
32+
public static InputStream getInputStream(Path openPath) throws Exception {
33+
return Files.newInputStream(
34+
openPath // positive example (known sink)
35+
);
36+
}
37+
38+
public static InputStream getInputStream(String openPath) throws Exception {
39+
return Test.getInputStream(
40+
Paths.get(openPath) // no candidate (argument to local call)
41+
);
42+
}
43+
44+
public static int compareFiles(File f1, File f2) {
45+
return f1.compareTo(
46+
f2 // negative example (modeled as not a sink)
47+
);
48+
}
49+
}
50+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| 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 |
2+
| 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 |
3+
| 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 |
4+
| 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 |
5+
| 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 |
6+
| 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 |
7+
| 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 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Telemetry/AutomodelFrameworkModeExtractCandidates.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| 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 |
2+
| 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 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Telemetry/AutomodelFrameworkModeExtractNegativeExamples.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Telemetry/AutomodelFrameworkModeExtractPositiveExamples.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.github.codeql.test;
2+
3+
/**
4+
* No candidates in this class, as it's not public!
5+
*/
6+
class NonPublicClass {
7+
public void noCandidates(String here) {
8+
System.out.println(here);
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.github.codeql.test;
2+
3+
public class PublicClass {
4+
public void stuff(String arg) { // `arg` is a candidate, `this` is a candidate
5+
System.out.println(arg);
6+
}
7+
8+
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method)
9+
System.out.println(arg);
10+
}
11+
12+
// `arg` and `this` are not a candidate because the method is not public:
13+
protected void nonPublicStuff(String arg) {
14+
System.out.println(arg);
15+
}
16+
17+
// `arg` and `this are not candidates because the method is not public:
18+
void packagePrivateStuff(String arg) {
19+
System.out.println(arg);
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.github.codeql.test;
2+
3+
public interface PublicInterface {
4+
public void stuff(String arg); // `arg` is a candidate, `this` is a candidate
5+
6+
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method)
7+
System.out.println(arg);
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package java.io;
2+
3+
public class File {
4+
int compareTo( // `this` is a negative example - this is modeled as a neutral model
5+
File pathname // negative example - this is modeled as a neutral model
6+
) {
7+
return 0;
8+
}
9+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package java.nio.file;
2+
3+
import java.nio.file.Path;
4+
import java.io.IOException;
5+
import java.io.OutputStream;
6+
7+
public class Files {
8+
public static void copy(
9+
Path source, // a positive example because a manual model exists
10+
OutputStream out /* a candidate. NB: may be worthwhile to implement the
11+
same behavior as in application mode where out would not be a
12+
candidate because there already is a model for another parameter of
13+
the same method and we assume that methods are always modeled
14+
completely.
15+
*/
16+
) throws IOException {
17+
// ...
18+
}
19+
}

0 commit comments

Comments
 (0)