There are many different serialization frameworks. This query currently
-supports Kryo, XmlDecoder, XStream, SnakeYaml, and Java IO serialization through
-ObjectInputStream/ObjectOutputStream.
+supports Kryo, XmlDecoder, XStream, SnakeYaml, Hessian, JsonIO, YAMLBeans, Castor, Burlap,
+and Java IO serialization through ObjectInputStream/ObjectOutputStream.
@@ -75,6 +75,22 @@ Alvaro Muñoz & Christian Schneider, RSAConference 2016:
SnakeYaml documentation on deserialization:
SnakeYaml deserialization.
+
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
index bb4df03cd4f..3a77af853cf 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
@@ -21,6 +21,39 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node prod, DataFlow::Node succ) {
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof JsonReader and
+ cie.getArgument(0) = prod.asExpr() and
+ cie = succ.asExpr() and
+ not exists(SafeJsonIo sji | sji.hasFlowToExpr(cie.getArgument(1)))
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof YamlReader and
+ cie.getArgument(0) = prod.asExpr() and
+ cie = succ.asExpr()
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof UnSafeHessianInput and
+ cie.getArgument(0) = prod.asExpr() and
+ cie = succ.asExpr()
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof BurlapInput and
+ cie.getArgument(0) = prod.asExpr() and
+ cie = succ.asExpr()
+ )
+ or
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof BurlapInputInitMethod and
+ ma.getArgument(0) = prod.asExpr() and
+ ma.getQualifier() = succ.asExpr()
+ )
+ }
}
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeDeserializationConfig conf
diff --git a/java/ql/src/semmle/code/java/frameworks/Castor.qll b/java/ql/src/semmle/code/java/frameworks/Castor.qll
new file mode 100644
index 00000000000..76abef7b5fe
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/Castor.qll
@@ -0,0 +1,20 @@
+/**
+ * Provides classes and predicates for working with the Castor framework.
+ */
+
+import java
+
+/**
+ * The class `org.exolab.castor.xml.Unmarshaller`.
+ */
+class Unmarshaller extends RefType {
+ Unmarshaller() { this.hasQualifiedName("org.exolab.castor.xml", "Unmarshaller") }
+}
+
+/** A method with the name `unmarshal` declared in `org.exolab.castor.xml.Unmarshaller`. */
+class UnmarshalMethod extends Method {
+ UnmarshalMethod() {
+ this.getDeclaringType() instanceof Unmarshaller and
+ this.getName() = "unmarshal"
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/Hessian.qll b/java/ql/src/semmle/code/java/frameworks/Hessian.qll
new file mode 100644
index 00000000000..78798d2b2fb
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/Hessian.qll
@@ -0,0 +1,47 @@
+/**
+ * Provides classes and predicates for working with the Hession framework.
+ */
+
+import java
+
+/**
+ * The class `com.caucho.hessian.io.HessianInput` or `com.caucho.hessian.io.Hessian2Input`.
+ */
+class UnSafeHessianInput extends RefType {
+ UnSafeHessianInput() {
+ this.hasQualifiedName("com.caucho.hessian.io", ["HessianInput", "Hessian2Input"])
+ }
+}
+
+/**
+ * A HessianInput readObject method. This is either `HessianInput.readObject` or `Hessian2Input.readObject`.
+ */
+class UnSafeHessianInputReadObjectMethod extends Method {
+ UnSafeHessianInputReadObjectMethod() {
+ this.getDeclaringType() instanceof UnSafeHessianInput and
+ this.getName() = "readObject"
+ }
+}
+
+/**
+ * The class `com.caucho.burlap.io.BurlapInput`.
+ */
+class BurlapInput extends RefType {
+ BurlapInput() { this.hasQualifiedName("com.caucho.burlap.io", "BurlapInput") }
+}
+
+/** A method with the name `readObject` declared in `com.caucho.burlap.io.BurlapInput`. */
+class BurlapInputReadObjectMethod extends Method {
+ BurlapInputReadObjectMethod() {
+ this.getDeclaringType() instanceof BurlapInput and
+ this.getName() = "readObject"
+ }
+}
+
+/** A method with the name `init` declared in `com.caucho.burlap.io.BurlapInput`. */
+class BurlapInputInitMethod extends Method {
+ BurlapInputInitMethod() {
+ this.getDeclaringType() instanceof BurlapInput and
+ this.getName() = "init"
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/JYaml.qll b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
new file mode 100644
index 00000000000..bf523bec202
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
@@ -0,0 +1,41 @@
+/**
+ * Provides classes and predicates for working with the JYaml framework.
+ */
+
+import java
+
+/**
+ * The class `org.ho.yaml.Yaml`.
+ */
+class JYaml extends RefType {
+ JYaml() { this.hasQualifiedName("org.ho.yaml", "Yaml") }
+}
+
+/**
+ * A JYaml unsafe load method. This is either `YAML.load` or
+ * `YAML.loadType` or `YAML.loadStream` or `YAML.loadStreamOfType`.
+ */
+class JYamlUnSafeLoadMethod extends Method {
+ JYamlUnSafeLoadMethod() {
+ this.getDeclaringType() instanceof JYaml and
+ this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
+ }
+}
+
+/**
+ * The class `org.ho.yaml.YamlConfig`.
+ */
+class JYamlConfig extends RefType {
+ JYamlConfig() { this.hasQualifiedName("org.ho.yaml", "YamlConfig") }
+}
+
+/**
+ * A JYamlConfig unsafe load method. This is either `YamlConfig.load` or
+ * `YAML.loadType` or `YamlConfig.loadStream` or `YamlConfig.loadStreamOfType`.
+ */
+class JYamlConfigUnSafeLoadMethod extends Method {
+ JYamlConfigUnSafeLoadMethod() {
+ this.getDeclaringType() instanceof JYamlConfig and
+ this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/JsonIo.qll b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
new file mode 100644
index 00000000000..4170488f78d
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
@@ -0,0 +1,41 @@
+/**
+ * Provides classes and predicates for working with the Json-io framework.
+ */
+
+import java
+import semmle.code.java.Maps
+
+/**
+ * The class `com.cedarsoftware.util.io.JsonReader`.
+ */
+class JsonReader extends RefType {
+ JsonReader() { this.hasQualifiedName("com.cedarsoftware.util.io", "JsonReader") }
+}
+
+/** A method with the name `jsonToJava` declared in `com.cedarsoftware.util.io.JsonReader`. */
+class JsonIoJsonToJavaMethod extends Method {
+ JsonIoJsonToJavaMethod() {
+ this.getDeclaringType() instanceof JsonReader and
+ this.getName() = "jsonToJava"
+ }
+}
+
+/** A method with the name `readObject` declared in `com.cedarsoftware.util.io.JsonReader`. */
+class JsonIoReadObjectMethod extends Method {
+ JsonIoReadObjectMethod() {
+ this.getDeclaringType() instanceof JsonReader and
+ this.getName() = "readObject"
+ }
+}
+
+/**
+ * A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`.
+ */
+class JsonIoSafeOptionalArgs extends MethodAccess {
+ JsonIoSafeOptionalArgs() {
+ this.getMethod().getDeclaringType().getASourceSupertype*() instanceof MapType and
+ this.getMethod().hasName("put") and
+ this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "USE_MAPS" and
+ this.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll b/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
new file mode 100644
index 00000000000..63c282a80ec
--- /dev/null
+++ b/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
@@ -0,0 +1,20 @@
+/**
+ * Provides classes and predicates for working with the YamlBeans framework.
+ */
+
+import java
+
+/**
+ * The class `com.esotericsoftware.yamlbeans.YamlReader`.
+ */
+class YamlReader extends RefType {
+ YamlReader() { this.hasQualifiedName("com.esotericsoftware.yamlbeans", "YamlReader") }
+}
+
+/** A method with the name `read` declared in `com.esotericsoftware.yamlbeans.YamlReader`. */
+class YamlReaderReadMethod extends Method {
+ YamlReaderReadMethod() {
+ this.getDeclaringType() instanceof YamlReader and
+ this.getName() = "read"
+ }
+}
diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
index ab809f07d6d..377303601d4 100644
--- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
+++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
@@ -2,6 +2,11 @@ import semmle.code.java.frameworks.Kryo
import semmle.code.java.frameworks.XStream
import semmle.code.java.frameworks.SnakeYaml
import semmle.code.java.frameworks.FastJson
+import semmle.code.java.frameworks.JYaml
+import semmle.code.java.frameworks.JsonIo
+import semmle.code.java.frameworks.YamlBeans
+import semmle.code.java.frameworks.Hessian
+import semmle.code.java.frameworks.Castor
import semmle.code.java.frameworks.apache.Lang
class ObjectInputStreamReadObjectMethod extends Method {
@@ -50,6 +55,29 @@ class SafeKryo extends DataFlow2::Configuration {
}
}
+class SafeJsonIo extends DataFlow2::Configuration {
+ SafeJsonIo() { this = "UnsafeDeserialization::SafeJsonIo" }
+
+ override predicate isSource(DataFlow::Node src) {
+ exists(MethodAccess ma |
+ ma instanceof JsonIoSafeOptionalArgs and
+ src.asExpr() = ma.getQualifier()
+ )
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof JsonIoJsonToJavaMethod and
+ sink.asExpr() = ma.getArgument(1)
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof JsonReader and
+ sink.asExpr() = cie.getArgument(1)
+ )
+ }
+}
+
predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
exists(Method m | m = ma.getMethod() |
m instanceof ObjectInputStreamReadObjectMethod and
@@ -81,6 +109,27 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
ma.getMethod() instanceof FastJsonParseMethod and
not fastJsonLooksSafe() and
sink = ma.getArgument(0)
+ or
+ ma.getMethod() instanceof JYamlUnSafeLoadMethod and
+ sink = ma.getArgument(0)
+ or
+ ma.getMethod() instanceof JYamlConfigUnSafeLoadMethod and
+ sink = ma.getArgument(0)
+ or
+ ma.getMethod() instanceof JsonIoJsonToJavaMethod and
+ sink = ma.getArgument(0) and
+ not exists(SafeJsonIo sji | sji.hasFlowToExpr(ma.getArgument(1)))
+ or
+ ma.getMethod() instanceof JsonIoReadObjectMethod and
+ sink = ma.getQualifier()
+ or
+ ma.getMethod() instanceof YamlReaderReadMethod and sink = ma.getQualifier()
+ or
+ ma.getMethod() instanceof UnSafeHessianInputReadObjectMethod and sink = ma.getQualifier()
+ or
+ ma.getMethod() instanceof UnmarshalMethod and sink = ma.getAnArgument()
+ or
+ ma.getMethod() instanceof BurlapInputReadObjectMethod and sink = ma.getQualifier()
)
}
diff --git a/java/ql/test/query-tests/security/CWE-502/C.java b/java/ql/test/query-tests/security/CWE-502/C.java
new file mode 100644
index 00000000000..ede36d8410b
--- /dev/null
+++ b/java/ql/test/query-tests/security/CWE-502/C.java
@@ -0,0 +1,98 @@
+import java.util.HashMap;
+import java.io.StringReader;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import com.cedarsoftware.util.io.JsonReader;
+import com.esotericsoftware.yamlbeans.YamlReader;
+import org.ho.yaml.Yaml;
+import org.ho.yaml.YamlConfig;
+import org.exolab.castor.xml.Unmarshaller;
+import com.caucho.hessian.io.Hessian2Input;
+import com.caucho.hessian.io.HessianInput;
+import com.caucho.burlap.io.BurlapInput;
+import com.caucho.hessian.io.Hessian2Input;
+import com.caucho.hessian.io.HessianInput;
+import java.io.ByteArrayInputStream;
+
+@Controller
+public class C {
+
+ @GetMapping(value = "jyaml")
+ public void bad1(HttpServletRequest request) throws Exception {
+ String data = request.getParameter("data");
+ Yaml.load(data); //bad
+ Yaml.loadStream(data); //bad
+ Yaml.loadStreamOfType(data, Object.class); //bad
+ Yaml.loadType(data, Object.class); //bad
+
+ org.ho.yaml.YamlConfig yamlConfig = new YamlConfig();
+ yamlConfig.load(data); //bad
+ yamlConfig.loadStream(data); //bad
+ yamlConfig.loadStreamOfType(data, Object.class); //bad
+ yamlConfig.loadType(data, Object.class); //bad
+ }
+
+ @GetMapping(value = "jsonio")
+ public void bad2(HttpServletRequest request) {
+ String data = request.getParameter("data");
+
+ HashMap hashMap = new HashMap();
+ hashMap.put("USE_MAPS", true);
+
+ JsonReader.jsonToJava(data); //bad
+
+ JsonReader.jsonToJava(data, hashMap); //good
+
+ JsonReader jr = new JsonReader(data, null); //bad
+ jr.readObject();
+
+ JsonReader jr1 = new JsonReader(data, hashMap); //good
+ jr1.readObject();
+ }
+
+ @GetMapping(value = "yamlbeans")
+ public void bad3(HttpServletRequest request) throws Exception {
+ String data = request.getParameter("data");
+ YamlReader r = new YamlReader(data);
+ r.read(); //bad
+ r.read(Object.class); //bad
+ r.read(Object.class, Object.class); //bad
+ }
+
+ @GetMapping(value = "hessian")
+ public void bad4(HttpServletRequest request) throws Exception {
+ byte[] bytes = request.getParameter("data").getBytes();
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ HessianInput hessianInput = new HessianInput(bis);
+ hessianInput.readObject(); //bad
+ hessianInput.readObject(Object.class); //bad
+ }
+
+ @GetMapping(value = "hessian2")
+ public void bad5(HttpServletRequest request) throws Exception {
+ byte[] bytes = request.getParameter("data").getBytes();
+ ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+ Hessian2Input hessianInput = new Hessian2Input(bis);
+ hessianInput.readObject(); //bad
+ hessianInput.readObject(Object.class); //bad
+ }
+
+ @GetMapping(value = "castor")
+ public void bad6(HttpServletRequest request) throws Exception {
+ Unmarshaller unmarshaller = new Unmarshaller();
+ unmarshaller.unmarshal(new StringReader(request.getParameter("data"))); //bad
+ }
+
+ @GetMapping(value = "burlap")
+ public void bad7(HttpServletRequest request) throws Exception {
+ byte[] serializedData = request.getParameter("data").getBytes();
+ ByteArrayInputStream is = new ByteArrayInputStream(serializedData);
+ BurlapInput burlapInput = new BurlapInput(is);
+ burlapInput.readObject(); //bad
+
+ BurlapInput burlapInput1 = new BurlapInput();
+ burlapInput1.init(is);
+ burlapInput1.readObject(); //bad
+ }
+}
diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
index f575a093d6e..d583caafc9b 100644
--- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
+++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
@@ -25,6 +25,26 @@ edges
| B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes |
| B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s |
| B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:31:23:31:23 | s |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data |
+| C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data |
+| C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data |
+| C.java:38:17:38:44 | getParameter(...) : String | C.java:48:3:48:4 | jr |
+| C.java:56:17:56:44 | getParameter(...) : String | C.java:58:3:58:3 | r |
+| C.java:56:17:56:44 | getParameter(...) : String | C.java:59:3:59:3 | r |
+| C.java:56:17:56:44 | getParameter(...) : String | C.java:60:3:60:3 | r |
+| C.java:65:18:65:45 | getParameter(...) : String | C.java:68:3:68:14 | hessianInput |
+| C.java:65:18:65:45 | getParameter(...) : String | C.java:69:3:69:14 | hessianInput |
+| C.java:74:18:74:45 | getParameter(...) : String | C.java:77:3:77:14 | hessianInput |
+| C.java:74:18:74:45 | getParameter(...) : String | C.java:78:3:78:14 | hessianInput |
+| C.java:84:43:84:70 | getParameter(...) : String | C.java:84:26:84:71 | new StringReader(...) |
+| C.java:89:27:89:54 | getParameter(...) : String | C.java:92:3:92:13 | burlapInput |
+| C.java:89:27:89:54 | getParameter(...) : String | C.java:96:3:96:14 | burlapInput1 |
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) |
nodes
| A.java:13:31:13:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
@@ -65,6 +85,33 @@ nodes
| B.java:23:29:23:29 | s | semmle.label | s |
| B.java:27:31:27:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
| B.java:31:23:31:23 | s | semmle.label | s |
+| C.java:23:17:23:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:24:13:24:16 | data | semmle.label | data |
+| C.java:25:19:25:22 | data | semmle.label | data |
+| C.java:26:25:26:28 | data | semmle.label | data |
+| C.java:27:17:27:20 | data | semmle.label | data |
+| C.java:30:19:30:22 | data | semmle.label | data |
+| C.java:31:25:31:28 | data | semmle.label | data |
+| C.java:32:31:32:34 | data | semmle.label | data |
+| C.java:33:23:33:26 | data | semmle.label | data |
+| C.java:38:17:38:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:43:25:43:28 | data | semmle.label | data |
+| C.java:48:3:48:4 | jr | semmle.label | jr |
+| C.java:56:17:56:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:58:3:58:3 | r | semmle.label | r |
+| C.java:59:3:59:3 | r | semmle.label | r |
+| C.java:60:3:60:3 | r | semmle.label | r |
+| C.java:65:18:65:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:68:3:68:14 | hessianInput | semmle.label | hessianInput |
+| C.java:69:3:69:14 | hessianInput | semmle.label | hessianInput |
+| C.java:74:18:74:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:77:3:77:14 | hessianInput | semmle.label | hessianInput |
+| C.java:78:3:78:14 | hessianInput | semmle.label | hessianInput |
+| C.java:84:26:84:71 | new StringReader(...) | semmle.label | new StringReader(...) |
+| C.java:84:43:84:70 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:89:27:89:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:92:3:92:13 | burlapInput | semmle.label | burlapInput |
+| C.java:96:3:96:14 | burlapInput1 | semmle.label | burlapInput1 |
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | semmle.label | entityStream : InputStream |
| TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | semmle.label | new ObjectInputStream(...) |
#select
@@ -94,4 +141,24 @@ nodes
| B.java:15:12:15:28 | parse(...) | B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes | Unsafe deserialization of $@. | B.java:12:31:12:51 | getInputStream(...) | user input |
| B.java:23:12:23:30 | parseObject(...) | B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s | Unsafe deserialization of $@. | B.java:19:31:19:51 | getInputStream(...) | user input |
| B.java:31:12:31:24 | parse(...) | B.java:27:31:27:51 | getInputStream(...) : InputStream | B.java:31:23:31:23 | s | Unsafe deserialization of $@. | B.java:27:31:27:51 | getInputStream(...) | user input |
+| C.java:24:3:24:17 | load(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:24:13:24:16 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:25:3:25:23 | loadStream(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:25:19:25:22 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:26:3:26:43 | loadStreamOfType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:26:25:26:28 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:27:3:27:35 | loadType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:27:17:27:20 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:30:3:30:23 | load(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:30:19:30:22 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:31:3:31:29 | loadStream(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:31:25:31:28 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:32:3:32:49 | loadStreamOfType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:33:3:33:41 | loadType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
+| C.java:43:3:43:29 | jsonToJava(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
+| C.java:48:3:48:17 | readObject(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:48:3:48:4 | jr | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
+| C.java:58:3:58:10 | read(...) | C.java:56:17:56:44 | getParameter(...) : String | C.java:58:3:58:3 | r | Unsafe deserialization of $@. | C.java:56:17:56:44 | getParameter(...) | user input |
+| C.java:59:3:59:22 | read(...) | C.java:56:17:56:44 | getParameter(...) : String | C.java:59:3:59:3 | r | Unsafe deserialization of $@. | C.java:56:17:56:44 | getParameter(...) | user input |
+| C.java:60:3:60:36 | read(...) | C.java:56:17:56:44 | getParameter(...) : String | C.java:60:3:60:3 | r | Unsafe deserialization of $@. | C.java:56:17:56:44 | getParameter(...) | user input |
+| C.java:68:3:68:27 | readObject(...) | C.java:65:18:65:45 | getParameter(...) : String | C.java:68:3:68:14 | hessianInput | Unsafe deserialization of $@. | C.java:65:18:65:45 | getParameter(...) | user input |
+| C.java:69:3:69:39 | readObject(...) | C.java:65:18:65:45 | getParameter(...) : String | C.java:69:3:69:14 | hessianInput | Unsafe deserialization of $@. | C.java:65:18:65:45 | getParameter(...) | user input |
+| C.java:77:3:77:27 | readObject(...) | C.java:74:18:74:45 | getParameter(...) : String | C.java:77:3:77:14 | hessianInput | Unsafe deserialization of $@. | C.java:74:18:74:45 | getParameter(...) | user input |
+| C.java:78:3:78:39 | readObject(...) | C.java:74:18:74:45 | getParameter(...) : String | C.java:78:3:78:14 | hessianInput | Unsafe deserialization of $@. | C.java:74:18:74:45 | getParameter(...) | user input |
+| C.java:84:3:84:72 | unmarshal(...) | C.java:84:43:84:70 | getParameter(...) : String | C.java:84:26:84:71 | new StringReader(...) | Unsafe deserialization of $@. | C.java:84:43:84:70 | getParameter(...) | user input |
+| C.java:92:3:92:26 | readObject(...) | C.java:89:27:89:54 | getParameter(...) : String | C.java:92:3:92:13 | burlapInput | Unsafe deserialization of $@. | C.java:89:27:89:54 | getParameter(...) | user input |
+| C.java:96:3:96:27 | readObject(...) | C.java:89:27:89:54 | getParameter(...) : String | C.java:96:3:96:14 | burlapInput1 | Unsafe deserialization of $@. | C.java:89:27:89:54 | getParameter(...) | user input |
| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input |
diff --git a/java/ql/test/query-tests/security/CWE-502/options b/java/ql/test/query-tests/security/CWE-502/options
index 6df0c9374c2..ebf1581cc8a 100644
--- a/java/ql/test/query-tests/security/CWE-502/options
+++ b/java/ql/test/query-tests/security/CWE-502/options
@@ -1 +1 @@
-//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/snakeyaml-1.21:${testdir}/../../../stubs/xstream-1.4.10:${testdir}/../../../stubs/kryo-4.0.2:${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/fastjson-1.2.74:${testdir}/../../../stubs/springframework-5.2.3:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/jyaml-1.3:${testdir}/../../../stubs/json-io-4.10.0:${testdir}/../../../stubs/yamlbeans-1.09:${testdir}/../../../stubs/hessian-4.0.38:${testdir}/../../../stubs/castor-1.4.1
diff --git a/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/types/AnyNode.java b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/types/AnyNode.java
new file mode 100644
index 00000000000..f29270d2521
--- /dev/null
+++ b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/types/AnyNode.java
@@ -0,0 +1,11 @@
+package org.exolab.castor.types;
+
+import java.io.Serializable;
+
+public final class AnyNode implements Serializable {
+
+ private static final long serialVersionUID = -4104117996051705975L;
+
+ public AnyNode() { }
+}
+
diff --git a/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/EventProducer.java b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/EventProducer.java
new file mode 100644
index 00000000000..08893c95a48
--- /dev/null
+++ b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/EventProducer.java
@@ -0,0 +1,12 @@
+package org.exolab.castor.xml;
+
+import org.xml.sax.DocumentHandler;
+import org.xml.sax.SAXException;
+
+/** @deprecated */
+public interface EventProducer {
+ void setDocumentHandler(DocumentHandler var1);
+
+ void start() throws SAXException;
+}
+
diff --git a/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/SAX2EventAndErrorProducer.java b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/SAX2EventAndErrorProducer.java
new file mode 100644
index 00000000000..77978b53f01
--- /dev/null
+++ b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/SAX2EventAndErrorProducer.java
@@ -0,0 +1,8 @@
+package org.exolab.castor.xml;
+
+import org.xml.sax.ErrorHandler;
+
+public interface SAX2EventAndErrorProducer extends SAX2EventProducer {
+ void setErrorHandler(ErrorHandler var1);
+}
+
diff --git a/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/SAX2EventProducer.java b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/SAX2EventProducer.java
new file mode 100644
index 00000000000..66b2cf8259f
--- /dev/null
+++ b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/SAX2EventProducer.java
@@ -0,0 +1,11 @@
+package org.exolab.castor.xml;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+public interface SAX2EventProducer {
+ void setContentHandler(ContentHandler var1);
+
+ void start() throws SAXException;
+}
+
diff --git a/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/Unmarshaller.java b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/Unmarshaller.java
new file mode 100644
index 00000000000..cc76c2c5e6a
--- /dev/null
+++ b/java/ql/test/stubs/castor-1.4.1/org/exolab/castor/xml/Unmarshaller.java
@@ -0,0 +1,74 @@
+package org.exolab.castor.xml;
+
+import java.io.Reader;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.Source;
+import org.exolab.castor.types.AnyNode;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+public class Unmarshaller {
+
+ public Unmarshaller() { }
+
+ public Object unmarshal(Reader reader) {
+ return null;
+ }
+
+ public Object unmarshal(EventProducer eventProducer) {
+ return null;
+ }
+
+ public Object unmarshal(SAX2EventProducer eventProducer) {
+ return null;
+ }
+
+ public Object unmarshal(AnyNode anyNode) {
+ return null;
+ }
+
+ public Object unmarshal(InputSource source) {
+ return null;
+ }
+
+ public Object unmarshal(Node node) {
+ return null;
+ }
+
+ public Object unmarshal(XMLEventReader eventReader) {
+ return null;
+ }
+
+ public Object unmarshal(XMLStreamReader streamReader) {
+ return null;
+ }
+
+ public Object unmarshal(SAX2EventAndErrorProducer eventProducer) {
+ return null;
+ }
+
+ public Object unmarshal(Source source) {
+ return null;
+ }
+
+ public static Object unmarshal(Class c, Reader reader) {
+ return null;
+ }
+
+ private static Unmarshaller createUnmarshaller(Class clazz) {
+ return null;
+ }
+
+ public static Object unmarshal(Class c, InputSource source) {
+ return null;
+ }
+
+ public static Object unmarshal(Class c, Node node) {
+ return null;
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractBurlapInput.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractBurlapInput.java
new file mode 100644
index 00000000000..9bf1892ea5b
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractBurlapInput.java
@@ -0,0 +1,9 @@
+package com.caucho.burlap.io;
+
+import com.caucho.hessian.io.AbstractHessianInput;
+
+public abstract class AbstractBurlapInput extends AbstractHessianInput {
+ public AbstractBurlapInput() {
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractHessianInput.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractHessianInput.java
new file mode 100644
index 00000000000..aff9f533850
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractHessianInput.java
@@ -0,0 +1,110 @@
+package com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import org.w3c.dom.Node;
+
+public abstract class AbstractHessianInput {
+
+ public AbstractHessianInput() {
+ }
+
+ public void init(InputStream is) {
+ }
+
+ public abstract String getMethod();
+
+ public void setSerializerFactory(SerializerFactory ser) {
+ }
+
+ public abstract int readCall() throws IOException;
+
+ public void skipOptionalCall() throws IOException {
+ }
+
+ public abstract String readHeader() throws IOException;
+
+ public abstract String readMethod() throws IOException;
+
+ public int readMethodArgLength() throws IOException {
+ return -1;
+ }
+
+ public abstract void startCall() throws IOException;
+
+ public abstract void completeCall() throws IOException;
+
+ public abstract Object readReply(Class var1) throws Throwable;
+
+ public abstract void startReply() throws Throwable;
+
+ public void startReplyBody() throws Throwable {
+ }
+
+ public abstract void completeReply() throws IOException;
+
+ public abstract boolean readBoolean() throws IOException;
+
+ public abstract void readNull() throws IOException;
+
+ public abstract int readInt() throws IOException;
+
+ public abstract long readLong() throws IOException;
+
+ public abstract double readDouble() throws IOException;
+
+ public abstract long readUTCDate() throws IOException;
+
+ public abstract String readString() throws IOException;
+
+ public Node readNode() throws IOException {
+ return null;
+ }
+
+ public abstract Reader getReader() throws IOException;
+
+ public abstract InputStream readInputStream() throws IOException;
+
+ public boolean readToOutputStream(OutputStream os) throws IOException {
+ return true;
+ }
+
+ public abstract byte[] readBytes() throws IOException;
+
+ public abstract Object readObject(Class var1) throws IOException;
+
+ public abstract Object readObject() throws IOException;
+
+ public abstract Object readRemote() throws IOException;
+
+ public abstract Object readRef() throws IOException;
+
+ public abstract int addRef(Object var1) throws IOException;
+
+ public abstract void setRef(int var1, Object var2) throws IOException;
+
+ public void resetReferences() {
+ }
+
+ public abstract int readListStart() throws IOException;
+
+ public abstract int readLength() throws IOException;
+
+ public abstract int readMapStart() throws IOException;
+
+ public abstract String readType() throws IOException;
+
+ public abstract boolean isEnd() throws IOException;
+
+ public abstract void readEnd() throws IOException;
+
+ public abstract void readMapEnd() throws IOException;
+
+ public abstract void readListEnd() throws IOException;
+
+ public void close() throws IOException {
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractSerializerFactory.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractSerializerFactory.java
new file mode 100644
index 00000000000..d4bc523ec87
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/AbstractSerializerFactory.java
@@ -0,0 +1,11 @@
+package com.caucho.hessian.io;
+
+public abstract class AbstractSerializerFactory {
+ public AbstractSerializerFactory() {
+ }
+
+ public abstract Serializer getSerializer(Class var1) throws HessianProtocolException;
+
+ public abstract Deserializer getDeserializer(Class var1) throws HessianProtocolException;
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/BurlapInput.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/BurlapInput.java
new file mode 100644
index 00000000000..ec02d2f302b
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/BurlapInput.java
@@ -0,0 +1,274 @@
+package com.caucho.burlap.io;
+
+import com.caucho.hessian.io.SerializerFactory;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.TimeZone;
+import org.w3c.dom.Node;
+
+public class BurlapInput extends AbstractBurlapInput {
+
+ public BurlapInput() { }
+
+ public BurlapInput(InputStream is) { }
+
+ public void setSerializerFactory(SerializerFactory factory) { }
+
+ public SerializerFactory getSerializerFactory() {
+ return null;
+ }
+
+ public void init(InputStream is) { }
+
+ public String getMethod() {
+ return null;
+ }
+
+ public Throwable getReplyFault() {
+ return null;
+ }
+
+ public void startCall() throws IOException { }
+
+ public int readCall() throws IOException {
+ return 1;
+ }
+
+ public String readMethod() throws IOException {
+ return null;
+ }
+
+ public void completeCall() throws IOException { }
+
+ public Object readReply(Class expectedClass) throws Throwable {
+ return null;
+ }
+
+ public void startReply() throws Throwable { }
+
+ private Throwable prepareFault() throws IOException {
+ return null;
+ }
+
+ public void completeReply() throws IOException { }
+
+ public String readHeader() throws IOException {
+ return null;
+ }
+
+ public void readNull() throws IOException { }
+
+ public boolean readBoolean() throws IOException {
+ return true;
+ }
+
+ public byte readByte() throws IOException {
+ return 1;
+ }
+
+ public short readShort() throws IOException {
+ return 1;
+ }
+
+ public int readInt() throws IOException {
+ return 1;
+ }
+
+ public long readLong() throws IOException {
+ return 1L;
+ }
+
+ public float readFloat() throws IOException {
+ return 1.1F;
+ }
+
+ public double readDouble() throws IOException {
+ return 1.1;
+ }
+
+ public long readUTCDate() throws IOException {
+ return 1L;
+ }
+
+ public long readLocalDate() throws IOException {
+ return 1L;
+ }
+
+ public String readString() throws IOException {
+ return null;
+ }
+
+ public Node readNode() throws IOException {
+ return null;
+ }
+
+ public byte[] readBytes() throws IOException {
+ return null;
+ }
+
+ public int readLength() throws IOException {
+ return 1;
+ }
+
+ private HashMap readFault() throws IOException {
+ return null;
+ }
+
+ public Object readObject(Class cl) throws IOException {
+ return null;
+ }
+
+ public Object readObject() throws IOException {
+ return null;
+ }
+
+ public Object readRemote() throws IOException {
+ return null;
+ }
+
+ public Object readRef() throws IOException {
+ return null;
+ }
+
+ public int readListStart() throws IOException {
+ return 1;
+ }
+
+ public int readMapStart() throws IOException {
+ return 1;
+ }
+
+ public boolean isEnd() throws IOException {
+ return true;
+ }
+
+ public void readEnd() throws IOException { }
+
+ public void readMapEnd() throws IOException { }
+
+ public void readListEnd() throws IOException { }
+
+ public int addRef(Object ref) {
+ return 1;
+ }
+
+ public void setRef(int i, Object ref) { }
+
+ public Object resolveRemote(String type, String url) throws IOException {
+ return null;
+ }
+
+ public String readType() throws IOException {
+ return null;
+ }
+
+ private int parseInt() throws IOException {
+ return 1;
+ }
+
+ private long parseLong() throws IOException {
+ return 1L;
+ }
+
+ private double parseDouble() throws IOException {
+ return 1.1;
+ }
+
+ protected long parseDate() throws IOException {
+ return 1L;
+ }
+
+ protected long parseDate(Calendar calendar) throws IOException {
+ return 1L;
+ }
+
+ protected String parseString() throws IOException {
+ return null;
+ }
+
+ protected StringBuffer parseString(StringBuffer sbuf) throws IOException {
+ return null;
+ }
+
+ Node parseXML() throws IOException {
+ return null;
+ }
+
+ int readChar() throws IOException {
+ return 1;
+ }
+
+ protected byte[] parseBytes() throws IOException {
+ return null;
+ }
+
+ protected ByteArrayOutputStream parseBytes(ByteArrayOutputStream bos) throws IOException {
+ return null;
+ }
+
+ public void expectTag(int expectTag) throws IOException { }
+
+ protected int parseTag() throws IOException {
+ return 1;
+ }
+
+ private boolean isTagChar(int ch) {
+ return true;
+ }
+
+ protected int skipWhitespace() throws IOException {
+ return 1;
+ }
+
+ protected boolean isWhitespace(int ch) throws IOException {
+ return true;
+ }
+
+ int read(byte[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ int read() throws IOException {
+ return 1;
+ }
+
+ public Reader getReader() {
+ return null;
+ }
+
+ public InputStream readInputStream() {
+ return null;
+ }
+
+ public InputStream getInputStream() {
+ return null;
+ }
+
+ protected IOException expectBeginTag(String expect, String tag) {
+ return null;
+ }
+
+ protected IOException expectedChar(String expect, int ch) {
+ return null;
+ }
+
+ protected IOException expectedTag(String expect, int tag) {
+ return null;
+ }
+
+ protected IOException error(String message) {
+ return null;
+ }
+
+ protected static String tagName(int tag) {
+ return null;
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/Deserializer.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/Deserializer.java
new file mode 100644
index 00000000000..2a96e53c397
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/Deserializer.java
@@ -0,0 +1,26 @@
+package com.caucho.hessian.io;
+
+import java.io.IOException;
+
+public interface Deserializer {
+ Class> getType();
+
+ boolean isReadResolve();
+
+ Object readObject(AbstractHessianInput var1) throws IOException;
+
+ Object readList(AbstractHessianInput var1, int var2) throws IOException;
+
+ Object readLengthList(AbstractHessianInput var1, int var2) throws IOException;
+
+ Object readMap(AbstractHessianInput var1) throws IOException;
+
+ Object[] createFields(int var1);
+
+ Object createField(String var1);
+
+ Object readObject(AbstractHessianInput var1, Object[] var2) throws IOException;
+
+ Object readObject(AbstractHessianInput var1, String[] var2) throws IOException;
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/HessianProtocolException.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/HessianProtocolException.java
new file mode 100644
index 00000000000..173d5876c03
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/HessianProtocolException.java
@@ -0,0 +1,24 @@
+package com.caucho.hessian.io;
+
+import java.io.IOException;
+
+public class HessianProtocolException extends IOException {
+
+ public HessianProtocolException() {
+ }
+
+ public HessianProtocolException(String message) { }
+
+ public HessianProtocolException(String message, Throwable rootCause) { }
+
+ public HessianProtocolException(Throwable rootCause) { }
+
+ public Throwable getRootCause() {
+ return null;
+ }
+
+ public Throwable getCause() {
+ return null;
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/Serializer.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/Serializer.java
new file mode 100644
index 00000000000..fbd3f5bc9c8
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/Serializer.java
@@ -0,0 +1,8 @@
+package com.caucho.hessian.io;
+
+import java.io.IOException;
+
+public interface Serializer {
+
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/SerializerFactory.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/SerializerFactory.java
new file mode 100644
index 00000000000..96716eca3ae
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/burlap/io/SerializerFactory.java
@@ -0,0 +1,12 @@
+package com.caucho.hessian.io;
+
+public class SerializerFactory extends AbstractSerializerFactory {
+
+ public Serializer getSerializer(Class cl) throws HessianProtocolException {
+ return null;
+ }
+
+ public Deserializer getDeserializer(Class cl) throws HessianProtocolException {
+ return null;
+ }
+}
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/AbstractHessianInput.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/AbstractHessianInput.java
new file mode 100644
index 00000000000..4b9d3b7ad44
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/AbstractHessianInput.java
@@ -0,0 +1,111 @@
+package com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+
+public abstract class AbstractHessianInput {
+
+ public AbstractHessianInput() {
+ }
+
+ public void init(InputStream is) {
+ }
+
+ public abstract String getMethod();
+
+ public void setRemoteResolver(HessianRemoteResolver resolver) { }
+
+ public HessianRemoteResolver getRemoteResolver() {
+ return null;
+ }
+
+ public void setSerializerFactory(SerializerFactory ser) {
+ }
+
+ public abstract int readCall() throws IOException;
+
+ public void skipOptionalCall() throws IOException {
+ }
+
+ public abstract String readHeader() throws IOException;
+
+ public abstract String readMethod() throws IOException;
+
+ public int readMethodArgLength() throws IOException {
+ return -1;
+ }
+
+ public abstract void startCall() throws IOException;
+
+ public abstract void completeCall() throws IOException;
+
+ public abstract Object readReply(Class var1) throws Throwable;
+
+ public abstract void startReply() throws Throwable;
+
+ public void startReplyBody() throws Throwable {
+ }
+
+ public abstract void completeReply() throws IOException;
+
+ public abstract boolean readBoolean() throws IOException;
+
+ public abstract void readNull() throws IOException;
+
+ public abstract int readInt() throws IOException;
+
+ public abstract long readLong() throws IOException;
+
+ public abstract double readDouble() throws IOException;
+
+ public abstract long readUTCDate() throws IOException;
+
+ public abstract String readString() throws IOException;
+
+ public abstract Reader getReader() throws IOException;
+
+ public abstract InputStream readInputStream() throws IOException;
+
+ public boolean readToOutputStream(OutputStream os) throws IOException {
+ return true;
+ }
+
+ public abstract byte[] readBytes() throws IOException;
+
+ public abstract Object readObject(Class var1) throws IOException;
+
+ public abstract Object readObject() throws IOException;
+
+ public abstract Object readRemote() throws IOException;
+
+ public abstract Object readRef() throws IOException;
+
+ public abstract int addRef(Object var1) throws IOException;
+
+ public abstract void setRef(int var1, Object var2) throws IOException;
+
+ public void resetReferences() {
+ }
+
+ public abstract int readListStart() throws IOException;
+
+ public abstract int readLength() throws IOException;
+
+ public abstract int readMapStart() throws IOException;
+
+ public abstract String readType() throws IOException;
+
+ public abstract boolean isEnd() throws IOException;
+
+ public abstract void readEnd() throws IOException;
+
+ public abstract void readMapEnd() throws IOException;
+
+ public abstract void readListEnd() throws IOException;
+
+ public void close() throws IOException {
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/Hessian2Input.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/Hessian2Input.java
new file mode 100644
index 00000000000..1ed011945e1
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/Hessian2Input.java
@@ -0,0 +1,297 @@
+package com.caucho.hessian.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class Hessian2Input extends AbstractHessianInput {
+
+ public Hessian2Input() { }
+
+ public Hessian2Input(InputStream is) { }
+
+ public String getMethod() {
+ return null;
+ }
+
+ public Throwable getReplyFault() {
+ return null;
+ }
+
+ public int readCall() throws IOException {
+ return 1;
+ }
+
+ public int readEnvelope() throws IOException {
+ return 1;
+ }
+
+ public void completeEnvelope() throws IOException { }
+
+ public String readMethod() throws IOException {
+ return null;
+ }
+
+ public int readMethodArgLength() throws IOException {
+ return 1;
+ }
+
+ public void startCall() throws IOException { }
+
+ public Object[] readArguments() throws IOException {
+ return null;
+ }
+
+ public void completeCall() throws IOException { }
+
+ public Object readReply(Class expectedClass) throws Throwable {
+ return null;
+ }
+
+ public void startReply() throws Throwable { }
+
+ private Throwable prepareFault(HashMap fault) throws IOException {
+ return null;
+ }
+
+ public void completeReply() throws IOException { }
+
+ public void completeValueReply() throws IOException { }
+
+ public String readHeader() throws IOException {
+ return null;
+ }
+
+ public int startMessage() throws IOException {
+ return 1;
+ }
+
+ public void completeMessage() throws IOException { }
+
+ public void readNull() throws IOException { }
+
+ public boolean readBoolean() throws IOException {
+ return true;
+ }
+
+ public short readShort() throws IOException {
+ return 11111;
+ }
+
+ public final int readInt() throws IOException {
+ return 1;
+ }
+
+ public long readLong() throws IOException {
+ return 1L;
+ }
+
+ public float readFloat() throws IOException {
+ return 1.1F;
+ }
+
+ public double readDouble() throws IOException {
+ return 1.1;
+ }
+
+ public long readUTCDate() throws IOException {
+ return 1L;
+ }
+
+ public int readChar() throws IOException {
+ return 1;
+ }
+
+ public int readString(char[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ public String readString() throws IOException {
+ return null;
+ }
+
+ public byte[] readBytes() throws IOException {
+ return null;
+ }
+
+ public int readByte() throws IOException {
+ return 1;
+ }
+
+ public int readBytes(byte[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ private HashMap readFault() throws IOException {
+ return null;
+ }
+
+ public Object readObject(Class cl) throws IOException {
+ return null;
+ }
+
+ public Object readObject() throws IOException {
+ return null;
+ }
+
+ private void readObjectDefinition(Class> cl) throws IOException { }
+
+ private Object readObjectInstance(Class> cl, Hessian2Input.ObjectDefinition def) throws IOException {
+ return null;
+ }
+
+ public Object readRemote() throws IOException {
+ return null;
+ }
+
+ public Object readRef() throws IOException {
+ return null;
+ }
+
+ public int readListStart() throws IOException {
+ return 1;
+ }
+
+ public int readMapStart() throws IOException {
+ return 1;
+ }
+
+ public boolean isEnd() throws IOException {
+ return true;
+ }
+
+ public void readEnd() throws IOException { }
+
+ public void readMapEnd() throws IOException { }
+
+ public void readListEnd() throws IOException { }
+
+ public int addRef(Object ref) {
+ return 1;
+ }
+
+ public void setRef(int i, Object ref) { }
+
+ public void resetReferences() { }
+
+ public void reset() { }
+
+ public void resetBuffer() { }
+
+ public Object readStreamingObject() throws IOException {
+ return null;
+ }
+
+ public Object resolveRemote(String type, String url) throws IOException {
+ return null;
+ }
+
+ public String readType() throws IOException {
+ return null;
+ }
+
+ public int readLength() throws IOException {
+ return 1;
+ }
+
+ private int parseInt() throws IOException {
+ return 1;
+ }
+
+ private long parseLong() throws IOException {
+ return 1L;
+ }
+
+ private double parseDouble() throws IOException {
+ return 1.1;
+ }
+
+ private void parseString(StringBuilder sbuf) throws IOException { }
+
+ private int parseChar() throws IOException {
+ return 1;
+ }
+
+ private boolean parseChunkLength() throws IOException {
+ return true;
+ }
+
+ private int parseUTF8Char() throws IOException {
+ return 1;
+ }
+
+ private int parseByte() throws IOException {
+ return 1;
+ }
+
+ public InputStream readInputStream() throws IOException {
+ return null;
+ }
+
+ int read(byte[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ public final int read() throws IOException {
+ return 1;
+ }
+
+ protected void unread() { }
+
+ private final boolean readBuffer() throws IOException {
+ return true;
+ }
+
+ public Reader getReader() {
+ return null;
+ }
+
+ protected IOException expect(String expect, int ch) throws IOException {
+ return null;
+ }
+
+ private String buildDebugContext(byte[] buffer, int offset, int length, int errorOffset) {
+ return null;
+ }
+
+ private void addDebugChar(StringBuilder sb, int ch) { }
+
+ protected String codeName(int ch) {
+ return null;
+ }
+
+ protected IOException error(String message) {
+ return null;
+ }
+
+ public void free() { }
+
+ public void close() throws IOException { }
+
+ static final class ObjectDefinition {
+ }
+
+ class ReadInputStream extends InputStream {
+
+ ReadInputStream() { }
+
+ public int read() throws IOException {
+ return 1;
+ }
+
+ public int read(byte[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ public void close() throws IOException { }
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/HessianInput.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/HessianInput.java
new file mode 100644
index 00000000000..e10a11ad706
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/HessianInput.java
@@ -0,0 +1,229 @@
+package com.caucho.hessian.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+public class HessianInput extends AbstractHessianInput {
+
+ public HessianInput() {
+ }
+
+ public HessianInput(InputStream is) { }
+
+ public void init(InputStream is) { }
+
+ public String getMethod() {
+ return null;
+ }
+
+ public Throwable getReplyFault() {
+ return null;
+ }
+
+ public int readCall() throws IOException {
+ return 0;
+ }
+
+ public void skipOptionalCall() throws IOException { }
+
+ public String readMethod() throws IOException {
+ return null;
+ }
+
+ public void startCall() throws IOException { }
+
+ public void completeCall() throws IOException { }
+
+ public Object readReply(Class expectedClass) throws Throwable {
+ return null;
+ }
+
+ public void startReply() throws Throwable { }
+
+ public void startReplyBody() throws Throwable { }
+
+ private Throwable prepareFault() throws IOException {
+ return null;
+ }
+
+ public void completeReply() throws IOException { }
+
+ public void completeValueReply() throws IOException { }
+
+ public String readHeader() throws IOException {
+ return null;
+ }
+
+ public void readNull() throws IOException { }
+
+ public boolean readBoolean() throws IOException {
+ return true;
+ }
+
+ public short readShort() throws IOException {
+ return 11111;
+ }
+
+ public int readInt() throws IOException {
+ return 1;
+ }
+
+ public long readLong() throws IOException {
+ return 1L;
+ }
+
+ public float readFloat() throws IOException {
+ return 1.1F;
+ }
+
+ public double readDouble() throws IOException {
+ return 1.1;
+ }
+
+ public long readUTCDate() throws IOException {
+ return 1L;
+ }
+
+ public int readChar() throws IOException {
+ return 1;
+ }
+
+ public int readString(char[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ public String readString() throws IOException {
+ return null;
+ }
+
+ public byte[] readBytes() throws IOException {
+ return null;
+ }
+
+ public int readByte() throws IOException {
+ return 1;
+ }
+
+ public int readBytes(byte[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ private HashMap readFault() throws IOException {
+ return null;
+ }
+
+ public Object readObject(Class cl) throws IOException {
+ return null;
+ }
+
+ public Object readObject() throws IOException {
+ return null;
+ }
+
+ public Object readRemote() throws IOException {
+ return null;
+ }
+
+ public Object readRef() throws IOException {
+ return null;
+ }
+
+ public int readListStart() throws IOException {
+ return 1;
+ }
+
+ public int readMapStart() throws IOException {
+ return 1;
+ }
+
+ public boolean isEnd() throws IOException {
+ return true;
+ }
+
+ public void readEnd() throws IOException { }
+
+ public void readMapEnd() throws IOException { }
+
+ public void readListEnd() throws IOException { }
+
+ public int addRef(Object ref) {
+ return 1;
+ }
+
+ public void setRef(int i, Object ref) { }
+
+ public void resetReferences() { }
+
+ public Object resolveRemote(String type, String url) throws IOException {
+ return null;
+ }
+
+ public String readType() throws IOException {
+ return null;
+ }
+
+ public int readLength() throws IOException {
+ return 1;
+ }
+
+ private int parseInt() throws IOException {
+ return 1;
+ }
+
+ private long parseLong() throws IOException {
+ return 1L;
+ }
+
+ private double parseDouble() throws IOException {
+ return 1.1;
+ }
+
+ private int parseChar() throws IOException {
+ return 1;
+ }
+
+ private int parseUTF8Char() throws IOException {
+ return 1;
+ }
+
+ private int parseByte() throws IOException {
+ return 1;
+ }
+
+ public InputStream readInputStream() throws IOException {
+ return null;
+ }
+
+ int read(byte[] buffer, int offset, int length) throws IOException {
+ return 1;
+ }
+
+ final int read() throws IOException {
+ return 1;
+ }
+
+ public void close() { }
+
+ public Reader getReader() {
+ return null;
+ }
+
+ protected IOException expect(String expect, int ch) {
+ return null;
+ }
+
+ protected String codeName(int ch) {
+ return null;
+ }
+
+ protected IOException error(String message) {
+ return null;
+ }
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/HessianRemoteResolver.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/HessianRemoteResolver.java
new file mode 100644
index 00000000000..3a6b7f86604
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/HessianRemoteResolver.java
@@ -0,0 +1,8 @@
+package com.caucho.hessian.io;
+
+import java.io.IOException;
+
+public interface HessianRemoteResolver {
+ Object lookup(String var1, String var2) throws IOException;
+}
+
diff --git a/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/SerializerFactory.java b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/SerializerFactory.java
new file mode 100644
index 00000000000..2e87899e6dd
--- /dev/null
+++ b/java/ql/test/stubs/hessian-4.0.38/com/caucho/hessian/io/SerializerFactory.java
@@ -0,0 +1,5 @@
+package com.caucho.hessian.io;
+
+public class SerializerFactory {
+
+}
diff --git a/java/ql/test/stubs/json-io-4.10.0/com/cedarsoftware/util/io/JsonReader.java b/java/ql/test/stubs/json-io-4.10.0/com/cedarsoftware/util/io/JsonReader.java
new file mode 100644
index 00000000000..75bfce50eeb
--- /dev/null
+++ b/java/ql/test/stubs/json-io-4.10.0/com/cedarsoftware/util/io/JsonReader.java
@@ -0,0 +1,41 @@
+package com.cedarsoftware.util.io;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.util.Map;
+
+public class JsonReader implements Closeable {
+
+ public static Object jsonToJava(String json) {
+ return null;
+ }
+
+ public static Object jsonToJava(String json, Map optionalArgs) {
+ return null;
+ }
+
+ public static Object jsonToJava(InputStream inputStream, Map optionalArgs) {
+ return null;
+ }
+
+ public JsonReader() { }
+
+ public JsonReader(InputStream inp) { }
+
+ public JsonReader(Map optionalArgs) { }
+
+ public JsonReader(InputStream inp, boolean useMaps) { }
+
+ public JsonReader(InputStream inp, Map optionalArgs) { }
+
+ public JsonReader(String inp, Map optionalArgs) { }
+
+ public JsonReader(byte[] inp, Map optionalArgs) { }
+
+ public Object readObject() {
+ return null;
+ }
+
+ public void close() { }
+}
+
diff --git a/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/Yaml.java b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/Yaml.java
new file mode 100644
index 00000000000..43c10a12142
--- /dev/null
+++ b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/Yaml.java
@@ -0,0 +1,77 @@
+package org.ho.yaml;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.Reader;
+
+public class Yaml {
+
+ public Yaml() {
+ }
+
+ public static Object load(Reader var0) {
+ return null;
+ }
+
+ public static Object load(InputStream var0) {
+ return null;
+ }
+
+ public static Object load(File var0) throws FileNotFoundException {
+ return null;
+ }
+
+ public static Object load(String var0) {
+ return null;
+ }
+
+ public static T loadType(Reader var0, Class var1) {
+ return null;
+ }
+
+ public static T loadType(InputStream var0, Class var1) throws FileNotFoundException {
+ return null;
+ }
+
+ public static T loadType(File var0, Class var1) throws FileNotFoundException {
+ return null;
+ }
+
+ public static T loadType(String var0, Class var1) {
+ return null;
+ }
+
+ public static YamlStream loadStream(Reader var0) {
+ return null;
+ }
+
+ public static YamlStream loadStream(InputStream var0) {
+ return null;
+ }
+
+ public static YamlStream loadStream(File var0) throws FileNotFoundException {
+ return null;
+ }
+
+ public static YamlStream loadStream(String var0) {
+ return null;
+ }
+
+ public static YamlStream loadStreamOfType(Reader var0, Class var1) {
+ return null;
+ }
+
+ public static YamlStream loadStreamOfType(InputStream var0, Class var1) {
+ return null;
+ }
+
+ public static YamlStream loadStreamOfType(File var0, Class var1) throws FileNotFoundException {
+ return null;
+ }
+
+ public static YamlStream loadStreamOfType(String var0, Class var1) throws FileNotFoundException {
+ return null;
+ }
+}
+
diff --git a/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlConfig.java b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlConfig.java
new file mode 100644
index 00000000000..bdf3059eec7
--- /dev/null
+++ b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlConfig.java
@@ -0,0 +1,122 @@
+package org.ho.yaml;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.Iterator;
+
+public class YamlConfig implements YamlOperations, Cloneable {
+
+ public YamlConfig() { }
+
+ public Object load(YamlDecoder var1) {
+ return null;
+ }
+
+ public Object load(InputStream var1) {
+ return null;
+ }
+
+ public Object load(Reader var1) {
+ return null;
+ }
+
+ public Object load(File var1) throws FileNotFoundException {
+ return null;
+ }
+
+ public Object load(String var1) {
+ return null;
+ }
+
+ public T loadType(YamlDecoder var1, Class var2) {
+ return null;
+ }
+
+ public T loadType(InputStream var1, Class var2) {
+ return null;
+ }
+
+ public T loadType(Reader var1, Class var2) {
+ return null;
+ }
+
+ public T loadType(File var1, Class var2) throws FileNotFoundException {
+ return null;
+ }
+
+ public T loadType(String var1, Class var2) {
+ return null;
+ }
+
+ public YamlStream loadStream(YamlDecoder var1) {
+ return null;
+ }
+
+ public YamlStream loadStream(Reader var1) {
+ return null;
+ }
+
+ public YamlStream loadStream(InputStream var1) {
+ return null;
+ }
+
+ public YamlStream loadStream(File var1) throws FileNotFoundException {
+ return null;
+ }
+
+ public YamlStream loadStream(String var1) {
+ return null;
+ }
+
+ public YamlStream loadStreamOfType(YamlDecoder var1, Class var2) {
+ return null;
+ }
+
+ public YamlStream loadStreamOfType(Reader var1, Class var2) {
+ return null;
+ }
+
+ public YamlStream loadStreamOfType(InputStream var1, Class var2) {
+ return null;
+ }
+
+ public YamlStream loadStreamOfType(File var1, Class var2) throws FileNotFoundException {
+ return null;
+ }
+
+ public YamlStream loadStreamOfType(String var1, Class var2) {
+ return null;
+ }
+
+ public void dump(Object var1, File var2) throws FileNotFoundException { }
+
+ public void dump(Object var1, File var2, boolean var3) throws FileNotFoundException { }
+
+ public String dump(Object var1) {
+ return null;
+ }
+
+ public String dump(Object var1, boolean var2) {
+ return null;
+ }
+
+ public void dump(Object var1, OutputStream var2, boolean var3) { }
+
+ public void dump(Object var1, OutputStream var2) { }
+
+ public void dumpStream(Iterator var1, File var2, boolean var3) throws FileNotFoundException { }
+
+ public void dumpStream(Iterator var1, File var2) throws FileNotFoundException { }
+
+ public String dumpStream(Iterator var1) {
+ return null;
+ }
+
+ public String dumpStream(Iterator var1, boolean var2) {
+ return null;
+ }
+}
+
diff --git a/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlDecoder.java b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlDecoder.java
new file mode 100644
index 00000000000..b3bd4982a77
--- /dev/null
+++ b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlDecoder.java
@@ -0,0 +1,16 @@
+package org.ho.yaml;
+
+import java.io.InputStream;
+import java.io.Reader;
+
+public class YamlDecoder {
+
+ YamlDecoder(InputStream var1, YamlConfig var2) { }
+
+ public YamlDecoder(InputStream var1) { }
+
+ public YamlDecoder(Reader var1) { }
+
+ public YamlDecoder(Reader var1, YamlConfig var2) { }
+}
+
diff --git a/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlOperations.java b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlOperations.java
new file mode 100644
index 00000000000..b4af6ee7125
--- /dev/null
+++ b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlOperations.java
@@ -0,0 +1,63 @@
+package org.ho.yaml;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.Iterator;
+
+public interface YamlOperations {
+ Object load(InputStream var1);
+
+ Object load(Reader var1);
+
+ Object load(File var1) throws FileNotFoundException;
+
+ Object load(String var1);
+
+ T loadType(InputStream var1, Class var2);
+
+ T loadType(Reader var1, Class var2);
+
+ T loadType(File var1, Class var2) throws FileNotFoundException;
+
+ T loadType(String var1, Class var2);
+
+ YamlStream loadStream(InputStream var1);
+
+ YamlStream loadStream(Reader var1);
+
+ YamlStream loadStream(File var1) throws FileNotFoundException;
+
+ YamlStream loadStream(String var1);
+
+ YamlStream loadStreamOfType(InputStream var1, Class var2);
+
+ YamlStream loadStreamOfType(Reader var1, Class var2);
+
+ YamlStream loadStreamOfType(File var1, Class var2) throws FileNotFoundException;
+
+ YamlStream loadStreamOfType(String var1, Class var2);
+
+ void dump(Object var1, File var2) throws FileNotFoundException;
+
+ void dump(Object var1, File var2, boolean var3) throws FileNotFoundException;
+
+ String dump(Object var1);
+
+ String dump(Object var1, boolean var2);
+
+ void dumpStream(Iterator var1, File var2) throws FileNotFoundException;
+
+ void dumpStream(Iterator var1, File var2, boolean var3) throws FileNotFoundException;
+
+ String dumpStream(Iterator var1);
+
+ String dumpStream(Iterator var1, boolean var2);
+
+ void dump(Object var1, OutputStream var2);
+
+ void dump(Object var1, OutputStream var2, boolean var3);
+}
+
diff --git a/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlStream.java b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlStream.java
new file mode 100644
index 00000000000..53f0ddf144e
--- /dev/null
+++ b/java/ql/test/stubs/jyaml-1.3/org/ho/yaml/YamlStream.java
@@ -0,0 +1,7 @@
+package org.ho.yaml;
+
+import java.util.Iterator;
+
+public interface YamlStream extends Iterable, Iterator {
+}
+
diff --git a/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlConfig.java b/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlConfig.java
new file mode 100644
index 00000000000..3488ef83dab
--- /dev/null
+++ b/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlConfig.java
@@ -0,0 +1,7 @@
+package com.esotericsoftware.yamlbeans;
+
+public class YamlConfig {
+
+ public YamlConfig() { }
+}
+
diff --git a/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlException.java b/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlException.java
new file mode 100644
index 00000000000..cb2e54f97e0
--- /dev/null
+++ b/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlException.java
@@ -0,0 +1,18 @@
+package com.esotericsoftware.yamlbeans;
+
+import java.io.IOException;
+
+public class YamlException extends IOException {
+ public YamlException() {
+ }
+
+ public YamlException(String message, Throwable cause) {
+ }
+
+ public YamlException(String message) {
+ }
+
+ public YamlException(Throwable cause) {
+ }
+}
+
diff --git a/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlReader.java b/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlReader.java
new file mode 100644
index 00000000000..edaeeb911e0
--- /dev/null
+++ b/java/ql/test/stubs/yamlbeans-1.09/com/esotericsoftware/yamlbeans/YamlReader.java
@@ -0,0 +1,28 @@
+package com.esotericsoftware.yamlbeans;
+
+
+import java.io.Reader;
+
+public class YamlReader {
+
+ public YamlReader(Reader reader) { }
+
+ public YamlReader(Reader reader, YamlConfig config) { }
+
+ public YamlReader(String yaml) { }
+
+ public YamlReader(String yaml, YamlConfig config) { }
+
+ public Object read() throws YamlException {
+ return null;
+ }
+
+ public T read(Class type) throws YamlException {
+ return null;
+ }
+
+ public T read(Class type, Class elementType) throws YamlException {
+ return null;
+ }
+}
+
From 60fc607449b58f73e119cbffea699a303c0f10e0 Mon Sep 17 00:00:00 2001
From: haby0
Date: Fri, 14 May 2021 18:17:05 +0800
Subject: [PATCH 002/153] Modify ql
---
.../CWE/CWE-502/UnsafeDeserialization.ql | 40 +++++-----
.../semmle/code/java/frameworks/Castor.qll | 6 +-
.../{Hessian.qll => HessianBurlap.qll} | 20 ++---
.../src/semmle/code/java/frameworks/JYaml.qll | 8 +-
.../semmle/code/java/frameworks/JsonIo.qll | 36 +++++++--
.../semmle/code/java/frameworks/YamlBeans.qll | 10 +--
.../java/security/UnsafeDeserialization.qll | 36 ++-------
.../test/query-tests/security/CWE-502/C.java | 26 +++++--
.../CWE-502/UnsafeDeserialization.expected | 76 +++++++++----------
9 files changed, 139 insertions(+), 119 deletions(-)
rename java/ql/src/semmle/code/java/frameworks/{Hessian.qll => HessianBurlap.qll} (50%)
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
index 3a77af853cf..fe990179de4 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
@@ -24,28 +24,14 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
override predicate isAdditionalTaintStep(DataFlow::Node prod, DataFlow::Node succ) {
exists(ClassInstanceExpr cie |
- cie.getConstructor().getDeclaringType() instanceof JsonReader and
cie.getArgument(0) = prod.asExpr() and
cie = succ.asExpr() and
- not exists(SafeJsonIo sji | sji.hasFlowToExpr(cie.getArgument(1)))
- )
- or
- exists(ClassInstanceExpr cie |
- cie.getConstructor().getDeclaringType() instanceof YamlReader and
- cie.getArgument(0) = prod.asExpr() and
- cie = succ.asExpr()
- )
- or
- exists(ClassInstanceExpr cie |
- cie.getConstructor().getDeclaringType() instanceof UnSafeHessianInput and
- cie.getArgument(0) = prod.asExpr() and
- cie = succ.asExpr()
- )
- or
- exists(ClassInstanceExpr cie |
- cie.getConstructor().getDeclaringType() instanceof BurlapInput and
- cie.getArgument(0) = prod.asExpr() and
- cie = succ.asExpr()
+ (
+ cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
+ cie.getConstructor().getDeclaringType() instanceof YamlBeansReader or
+ cie.getConstructor().getDeclaringType().getASupertype*() instanceof UnsafeHessianInput or
+ cie.getConstructor().getDeclaringType() instanceof BurlapInput
+ )
)
or
exists(MethodAccess ma |
@@ -54,6 +40,20 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
ma.getQualifier() = succ.asExpr()
)
}
+
+ override predicate isSanitizer(DataFlow::Node node) {
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
+ cie = node.asExpr() and
+ exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(cie.getArgument(1)))
+ )
+ or
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof JsonIoJsonToJavaMethod and
+ ma.getArgument(0) = node.asExpr() and
+ exists(SafeJsonIoConfig sji | sji.hasFlowToExpr(ma.getArgument(1)))
+ )
+ }
}
from DataFlow::PathNode source, DataFlow::PathNode sink, UnsafeDeserializationConfig conf
diff --git a/java/ql/src/semmle/code/java/frameworks/Castor.qll b/java/ql/src/semmle/code/java/frameworks/Castor.qll
index 76abef7b5fe..16884849d51 100644
--- a/java/ql/src/semmle/code/java/frameworks/Castor.qll
+++ b/java/ql/src/semmle/code/java/frameworks/Castor.qll
@@ -7,14 +7,14 @@ import java
/**
* The class `org.exolab.castor.xml.Unmarshaller`.
*/
-class Unmarshaller extends RefType {
- Unmarshaller() { this.hasQualifiedName("org.exolab.castor.xml", "Unmarshaller") }
+class CastorUnmarshaller extends RefType {
+ CastorUnmarshaller() { this.hasQualifiedName("org.exolab.castor.xml", "Unmarshaller") }
}
/** A method with the name `unmarshal` declared in `org.exolab.castor.xml.Unmarshaller`. */
class UnmarshalMethod extends Method {
UnmarshalMethod() {
- this.getDeclaringType() instanceof Unmarshaller and
+ this.getDeclaringType() instanceof CastorUnmarshaller and
this.getName() = "unmarshal"
}
}
diff --git a/java/ql/src/semmle/code/java/frameworks/Hessian.qll b/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
similarity index 50%
rename from java/ql/src/semmle/code/java/frameworks/Hessian.qll
rename to java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
index 78798d2b2fb..ce53e8261c1 100644
--- a/java/ql/src/semmle/code/java/frameworks/Hessian.qll
+++ b/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
@@ -1,24 +1,26 @@
/**
- * Provides classes and predicates for working with the Hession framework.
+ * Provides classes and predicates for working with the HessianBurlap framework.
*/
import java
/**
- * The class `com.caucho.hessian.io.HessianInput` or `com.caucho.hessian.io.Hessian2Input`.
+ * The class `com.caucho.hessian.io.AbstractHessianInput` or `com.alibaba.com.caucho.hessian.io.Hessian2StreamingInput`.
*/
-class UnSafeHessianInput extends RefType {
- UnSafeHessianInput() {
- this.hasQualifiedName("com.caucho.hessian.io", ["HessianInput", "Hessian2Input"])
+class UnsafeHessianInput extends RefType {
+ UnsafeHessianInput() {
+ this.hasQualifiedName(["com.caucho.hessian.io", "com.alibaba.com.caucho.hessian.io"],
+ ["AbstractHessianInput", "Hessian2StreamingInput"])
}
}
/**
- * A HessianInput readObject method. This is either `HessianInput.readObject` or `Hessian2Input.readObject`.
+ * A AbstractHessianInput or Hessian2StreamingInput subclass readObject method.
+ * This is either `AbstractHessianInput.readObject` or `Hessian2StreamingInput.readObject`.
*/
-class UnSafeHessianInputReadObjectMethod extends Method {
- UnSafeHessianInputReadObjectMethod() {
- this.getDeclaringType() instanceof UnSafeHessianInput and
+class UnsafeHessianInputReadObjectMethod extends Method {
+ UnsafeHessianInputReadObjectMethod() {
+ this.getDeclaringType().getASupertype*() instanceof UnsafeHessianInput and
this.getName() = "readObject"
}
}
diff --git a/java/ql/src/semmle/code/java/frameworks/JYaml.qll b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
index bf523bec202..1e0f3180607 100644
--- a/java/ql/src/semmle/code/java/frameworks/JYaml.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
@@ -15,8 +15,8 @@ class JYaml extends RefType {
* A JYaml unsafe load method. This is either `YAML.load` or
* `YAML.loadType` or `YAML.loadStream` or `YAML.loadStreamOfType`.
*/
-class JYamlUnSafeLoadMethod extends Method {
- JYamlUnSafeLoadMethod() {
+class JYamlUnsafeLoadMethod extends Method {
+ JYamlUnsafeLoadMethod() {
this.getDeclaringType() instanceof JYaml and
this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
}
@@ -33,8 +33,8 @@ class JYamlConfig extends RefType {
* A JYamlConfig unsafe load method. This is either `YamlConfig.load` or
* `YAML.loadType` or `YamlConfig.loadStream` or `YamlConfig.loadStreamOfType`.
*/
-class JYamlConfigUnSafeLoadMethod extends Method {
- JYamlConfigUnSafeLoadMethod() {
+class JYamlConfigUnsafeLoadMethod extends Method {
+ JYamlConfigUnsafeLoadMethod() {
this.getDeclaringType() instanceof JYamlConfig and
this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
}
diff --git a/java/ql/src/semmle/code/java/frameworks/JsonIo.qll b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
index 4170488f78d..1a2acf754ad 100644
--- a/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
@@ -4,18 +4,20 @@
import java
import semmle.code.java.Maps
+import semmle.code.java.dataflow.DataFlow
+import semmle.code.java.dataflow.DataFlow2
/**
* The class `com.cedarsoftware.util.io.JsonReader`.
*/
-class JsonReader extends RefType {
- JsonReader() { this.hasQualifiedName("com.cedarsoftware.util.io", "JsonReader") }
+class JsonIoJsonReader extends RefType {
+ JsonIoJsonReader() { this.hasQualifiedName("com.cedarsoftware.util.io", "JsonReader") }
}
/** A method with the name `jsonToJava` declared in `com.cedarsoftware.util.io.JsonReader`. */
class JsonIoJsonToJavaMethod extends Method {
JsonIoJsonToJavaMethod() {
- this.getDeclaringType() instanceof JsonReader and
+ this.getDeclaringType() instanceof JsonIoJsonReader and
this.getName() = "jsonToJava"
}
}
@@ -23,13 +25,13 @@ class JsonIoJsonToJavaMethod extends Method {
/** A method with the name `readObject` declared in `com.cedarsoftware.util.io.JsonReader`. */
class JsonIoReadObjectMethod extends Method {
JsonIoReadObjectMethod() {
- this.getDeclaringType() instanceof JsonReader and
+ this.getDeclaringType() instanceof JsonIoJsonReader and
this.getName() = "readObject"
}
}
/**
- * A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`.
+ * A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`.
*/
class JsonIoSafeOptionalArgs extends MethodAccess {
JsonIoSafeOptionalArgs() {
@@ -39,3 +41,27 @@ class JsonIoSafeOptionalArgs extends MethodAccess {
this.getArgument(1).(CompileTimeConstantExpr).getBooleanValue() = true
}
}
+
+/** A data flow configuration tracing flow from JsonIo safe settings. */
+class SafeJsonIoConfig extends DataFlow2::Configuration {
+ SafeJsonIoConfig() { this = "UnsafeDeserialization::SafeJsonIoConfig" }
+
+ override predicate isSource(DataFlow::Node src) {
+ exists(MethodAccess ma |
+ ma instanceof JsonIoSafeOptionalArgs and
+ src.asExpr() = ma.getQualifier()
+ )
+ }
+
+ override predicate isSink(DataFlow::Node sink) {
+ exists(MethodAccess ma |
+ ma.getMethod() instanceof JsonIoJsonToJavaMethod and
+ sink.asExpr() = ma.getArgument(1)
+ )
+ or
+ exists(ClassInstanceExpr cie |
+ cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
+ sink.asExpr() = cie.getArgument(1)
+ )
+ }
+}
diff --git a/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll b/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
index 63c282a80ec..b5db59926be 100644
--- a/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
+++ b/java/ql/src/semmle/code/java/frameworks/YamlBeans.qll
@@ -7,14 +7,14 @@ import java
/**
* The class `com.esotericsoftware.yamlbeans.YamlReader`.
*/
-class YamlReader extends RefType {
- YamlReader() { this.hasQualifiedName("com.esotericsoftware.yamlbeans", "YamlReader") }
+class YamlBeansReader extends RefType {
+ YamlBeansReader() { this.hasQualifiedName("com.esotericsoftware.yamlbeans", "YamlReader") }
}
/** A method with the name `read` declared in `com.esotericsoftware.yamlbeans.YamlReader`. */
-class YamlReaderReadMethod extends Method {
- YamlReaderReadMethod() {
- this.getDeclaringType() instanceof YamlReader and
+class YamlBeansReaderReadMethod extends Method {
+ YamlBeansReaderReadMethod() {
+ this.getDeclaringType() instanceof YamlBeansReader and
this.getName() = "read"
}
}
diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
index 377303601d4..4f5070edb2a 100644
--- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
+++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
@@ -5,7 +5,7 @@ import semmle.code.java.frameworks.FastJson
import semmle.code.java.frameworks.JYaml
import semmle.code.java.frameworks.JsonIo
import semmle.code.java.frameworks.YamlBeans
-import semmle.code.java.frameworks.Hessian
+import semmle.code.java.frameworks.HessianBurlap
import semmle.code.java.frameworks.Castor
import semmle.code.java.frameworks.apache.Lang
@@ -55,29 +55,6 @@ class SafeKryo extends DataFlow2::Configuration {
}
}
-class SafeJsonIo extends DataFlow2::Configuration {
- SafeJsonIo() { this = "UnsafeDeserialization::SafeJsonIo" }
-
- override predicate isSource(DataFlow::Node src) {
- exists(MethodAccess ma |
- ma instanceof JsonIoSafeOptionalArgs and
- src.asExpr() = ma.getQualifier()
- )
- }
-
- override predicate isSink(DataFlow::Node sink) {
- exists(MethodAccess ma |
- ma.getMethod() instanceof JsonIoJsonToJavaMethod and
- sink.asExpr() = ma.getArgument(1)
- )
- or
- exists(ClassInstanceExpr cie |
- cie.getConstructor().getDeclaringType() instanceof JsonReader and
- sink.asExpr() = cie.getArgument(1)
- )
- }
-}
-
predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
exists(Method m | m = ma.getMethod() |
m instanceof ObjectInputStreamReadObjectMethod and
@@ -110,22 +87,21 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
not fastJsonLooksSafe() and
sink = ma.getArgument(0)
or
- ma.getMethod() instanceof JYamlUnSafeLoadMethod and
+ ma.getMethod() instanceof JYamlUnsafeLoadMethod and
sink = ma.getArgument(0)
or
- ma.getMethod() instanceof JYamlConfigUnSafeLoadMethod and
+ ma.getMethod() instanceof JYamlConfigUnsafeLoadMethod and
sink = ma.getArgument(0)
or
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
- sink = ma.getArgument(0) and
- not exists(SafeJsonIo sji | sji.hasFlowToExpr(ma.getArgument(1)))
+ sink = ma.getArgument(0)
or
ma.getMethod() instanceof JsonIoReadObjectMethod and
sink = ma.getQualifier()
or
- ma.getMethod() instanceof YamlReaderReadMethod and sink = ma.getQualifier()
+ ma.getMethod() instanceof YamlBeansReaderReadMethod and sink = ma.getQualifier()
or
- ma.getMethod() instanceof UnSafeHessianInputReadObjectMethod and sink = ma.getQualifier()
+ ma.getMethod() instanceof UnsafeHessianInputReadObjectMethod and sink = ma.getQualifier()
or
ma.getMethod() instanceof UnmarshalMethod and sink = ma.getAnArgument()
or
diff --git a/java/ql/test/query-tests/security/CWE-502/C.java b/java/ql/test/query-tests/security/CWE-502/C.java
index ede36d8410b..bae0ca8ceae 100644
--- a/java/ql/test/query-tests/security/CWE-502/C.java
+++ b/java/ql/test/query-tests/security/CWE-502/C.java
@@ -42,13 +42,8 @@ public class C {
JsonReader.jsonToJava(data); //bad
- JsonReader.jsonToJava(data, hashMap); //good
-
JsonReader jr = new JsonReader(data, null); //bad
jr.readObject();
-
- JsonReader jr1 = new JsonReader(data, hashMap); //good
- jr1.readObject();
}
@GetMapping(value = "yamlbeans")
@@ -95,4 +90,25 @@ public class C {
burlapInput1.init(is);
burlapInput1.readObject(); //bad
}
+
+ @GetMapping(value = "jsonio1")
+ public void good1(HttpServletRequest request) {
+ String data = request.getParameter("data");
+
+ HashMap hashMap = new HashMap();
+ hashMap.put("USE_MAPS", true);
+
+ JsonReader.jsonToJava(data, hashMap); //good
+ }
+
+ @GetMapping(value = "jsonio2")
+ public void good2(HttpServletRequest request) {
+ String data = request.getParameter("data");
+
+ HashMap hashMap = new HashMap();
+ hashMap.put("USE_MAPS", true);
+
+ JsonReader jr1 = new JsonReader(data, hashMap); //good
+ jr1.readObject();
+ }
}
diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
index d583caafc9b..6f25b28bda5 100644
--- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
+++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected
@@ -34,17 +34,17 @@ edges
| C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data |
| C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data |
| C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data |
-| C.java:38:17:38:44 | getParameter(...) : String | C.java:48:3:48:4 | jr |
-| C.java:56:17:56:44 | getParameter(...) : String | C.java:58:3:58:3 | r |
-| C.java:56:17:56:44 | getParameter(...) : String | C.java:59:3:59:3 | r |
-| C.java:56:17:56:44 | getParameter(...) : String | C.java:60:3:60:3 | r |
-| C.java:65:18:65:45 | getParameter(...) : String | C.java:68:3:68:14 | hessianInput |
-| C.java:65:18:65:45 | getParameter(...) : String | C.java:69:3:69:14 | hessianInput |
-| C.java:74:18:74:45 | getParameter(...) : String | C.java:77:3:77:14 | hessianInput |
-| C.java:74:18:74:45 | getParameter(...) : String | C.java:78:3:78:14 | hessianInput |
-| C.java:84:43:84:70 | getParameter(...) : String | C.java:84:26:84:71 | new StringReader(...) |
-| C.java:89:27:89:54 | getParameter(...) : String | C.java:92:3:92:13 | burlapInput |
-| C.java:89:27:89:54 | getParameter(...) : String | C.java:96:3:96:14 | burlapInput1 |
+| C.java:38:17:38:44 | getParameter(...) : String | C.java:46:3:46:4 | jr |
+| C.java:51:17:51:44 | getParameter(...) : String | C.java:53:3:53:3 | r |
+| C.java:51:17:51:44 | getParameter(...) : String | C.java:54:3:54:3 | r |
+| C.java:51:17:51:44 | getParameter(...) : String | C.java:55:3:55:3 | r |
+| C.java:60:18:60:45 | getParameter(...) : String | C.java:63:3:63:14 | hessianInput |
+| C.java:60:18:60:45 | getParameter(...) : String | C.java:64:3:64:14 | hessianInput |
+| C.java:69:18:69:45 | getParameter(...) : String | C.java:72:3:72:14 | hessianInput |
+| C.java:69:18:69:45 | getParameter(...) : String | C.java:73:3:73:14 | hessianInput |
+| C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) |
+| C.java:84:27:84:54 | getParameter(...) : String | C.java:87:3:87:13 | burlapInput |
+| C.java:84:27:84:54 | getParameter(...) : String | C.java:91:3:91:14 | burlapInput1 |
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) |
nodes
| A.java:13:31:13:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
@@ -96,22 +96,22 @@ nodes
| C.java:33:23:33:26 | data | semmle.label | data |
| C.java:38:17:38:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| C.java:43:25:43:28 | data | semmle.label | data |
-| C.java:48:3:48:4 | jr | semmle.label | jr |
-| C.java:56:17:56:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| C.java:58:3:58:3 | r | semmle.label | r |
-| C.java:59:3:59:3 | r | semmle.label | r |
-| C.java:60:3:60:3 | r | semmle.label | r |
-| C.java:65:18:65:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| C.java:68:3:68:14 | hessianInput | semmle.label | hessianInput |
-| C.java:69:3:69:14 | hessianInput | semmle.label | hessianInput |
-| C.java:74:18:74:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| C.java:77:3:77:14 | hessianInput | semmle.label | hessianInput |
-| C.java:78:3:78:14 | hessianInput | semmle.label | hessianInput |
-| C.java:84:26:84:71 | new StringReader(...) | semmle.label | new StringReader(...) |
-| C.java:84:43:84:70 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| C.java:89:27:89:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| C.java:92:3:92:13 | burlapInput | semmle.label | burlapInput |
-| C.java:96:3:96:14 | burlapInput1 | semmle.label | burlapInput1 |
+| C.java:46:3:46:4 | jr | semmle.label | jr |
+| C.java:51:17:51:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:53:3:53:3 | r | semmle.label | r |
+| C.java:54:3:54:3 | r | semmle.label | r |
+| C.java:55:3:55:3 | r | semmle.label | r |
+| C.java:60:18:60:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:63:3:63:14 | hessianInput | semmle.label | hessianInput |
+| C.java:64:3:64:14 | hessianInput | semmle.label | hessianInput |
+| C.java:69:18:69:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:72:3:72:14 | hessianInput | semmle.label | hessianInput |
+| C.java:73:3:73:14 | hessianInput | semmle.label | hessianInput |
+| C.java:79:26:79:71 | new StringReader(...) | semmle.label | new StringReader(...) |
+| C.java:79:43:79:70 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:84:27:84:54 | getParameter(...) : String | semmle.label | getParameter(...) : String |
+| C.java:87:3:87:13 | burlapInput | semmle.label | burlapInput |
+| C.java:91:3:91:14 | burlapInput1 | semmle.label | burlapInput1 |
| TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | semmle.label | entityStream : InputStream |
| TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | semmle.label | new ObjectInputStream(...) |
#select
@@ -150,15 +150,15 @@ nodes
| C.java:32:3:32:49 | loadStreamOfType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:32:31:32:34 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
| C.java:33:3:33:41 | loadType(...) | C.java:23:17:23:44 | getParameter(...) : String | C.java:33:23:33:26 | data | Unsafe deserialization of $@. | C.java:23:17:23:44 | getParameter(...) | user input |
| C.java:43:3:43:29 | jsonToJava(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:43:25:43:28 | data | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
-| C.java:48:3:48:17 | readObject(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:48:3:48:4 | jr | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
-| C.java:58:3:58:10 | read(...) | C.java:56:17:56:44 | getParameter(...) : String | C.java:58:3:58:3 | r | Unsafe deserialization of $@. | C.java:56:17:56:44 | getParameter(...) | user input |
-| C.java:59:3:59:22 | read(...) | C.java:56:17:56:44 | getParameter(...) : String | C.java:59:3:59:3 | r | Unsafe deserialization of $@. | C.java:56:17:56:44 | getParameter(...) | user input |
-| C.java:60:3:60:36 | read(...) | C.java:56:17:56:44 | getParameter(...) : String | C.java:60:3:60:3 | r | Unsafe deserialization of $@. | C.java:56:17:56:44 | getParameter(...) | user input |
-| C.java:68:3:68:27 | readObject(...) | C.java:65:18:65:45 | getParameter(...) : String | C.java:68:3:68:14 | hessianInput | Unsafe deserialization of $@. | C.java:65:18:65:45 | getParameter(...) | user input |
-| C.java:69:3:69:39 | readObject(...) | C.java:65:18:65:45 | getParameter(...) : String | C.java:69:3:69:14 | hessianInput | Unsafe deserialization of $@. | C.java:65:18:65:45 | getParameter(...) | user input |
-| C.java:77:3:77:27 | readObject(...) | C.java:74:18:74:45 | getParameter(...) : String | C.java:77:3:77:14 | hessianInput | Unsafe deserialization of $@. | C.java:74:18:74:45 | getParameter(...) | user input |
-| C.java:78:3:78:39 | readObject(...) | C.java:74:18:74:45 | getParameter(...) : String | C.java:78:3:78:14 | hessianInput | Unsafe deserialization of $@. | C.java:74:18:74:45 | getParameter(...) | user input |
-| C.java:84:3:84:72 | unmarshal(...) | C.java:84:43:84:70 | getParameter(...) : String | C.java:84:26:84:71 | new StringReader(...) | Unsafe deserialization of $@. | C.java:84:43:84:70 | getParameter(...) | user input |
-| C.java:92:3:92:26 | readObject(...) | C.java:89:27:89:54 | getParameter(...) : String | C.java:92:3:92:13 | burlapInput | Unsafe deserialization of $@. | C.java:89:27:89:54 | getParameter(...) | user input |
-| C.java:96:3:96:27 | readObject(...) | C.java:89:27:89:54 | getParameter(...) : String | C.java:96:3:96:14 | burlapInput1 | Unsafe deserialization of $@. | C.java:89:27:89:54 | getParameter(...) | user input |
+| C.java:46:3:46:17 | readObject(...) | C.java:38:17:38:44 | getParameter(...) : String | C.java:46:3:46:4 | jr | Unsafe deserialization of $@. | C.java:38:17:38:44 | getParameter(...) | user input |
+| C.java:53:3:53:10 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:53:3:53:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
+| C.java:54:3:54:22 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:54:3:54:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
+| C.java:55:3:55:36 | read(...) | C.java:51:17:51:44 | getParameter(...) : String | C.java:55:3:55:3 | r | Unsafe deserialization of $@. | C.java:51:17:51:44 | getParameter(...) | user input |
+| C.java:63:3:63:27 | readObject(...) | C.java:60:18:60:45 | getParameter(...) : String | C.java:63:3:63:14 | hessianInput | Unsafe deserialization of $@. | C.java:60:18:60:45 | getParameter(...) | user input |
+| C.java:64:3:64:39 | readObject(...) | C.java:60:18:60:45 | getParameter(...) : String | C.java:64:3:64:14 | hessianInput | Unsafe deserialization of $@. | C.java:60:18:60:45 | getParameter(...) | user input |
+| C.java:72:3:72:27 | readObject(...) | C.java:69:18:69:45 | getParameter(...) : String | C.java:72:3:72:14 | hessianInput | Unsafe deserialization of $@. | C.java:69:18:69:45 | getParameter(...) | user input |
+| C.java:73:3:73:39 | readObject(...) | C.java:69:18:69:45 | getParameter(...) : String | C.java:73:3:73:14 | hessianInput | Unsafe deserialization of $@. | C.java:69:18:69:45 | getParameter(...) | user input |
+| C.java:79:3:79:72 | unmarshal(...) | C.java:79:43:79:70 | getParameter(...) : String | C.java:79:26:79:71 | new StringReader(...) | Unsafe deserialization of $@. | C.java:79:43:79:70 | getParameter(...) | user input |
+| C.java:87:3:87:26 | readObject(...) | C.java:84:27:84:54 | getParameter(...) : String | C.java:87:3:87:13 | burlapInput | Unsafe deserialization of $@. | C.java:84:27:84:54 | getParameter(...) | user input |
+| C.java:91:3:91:27 | readObject(...) | C.java:84:27:84:54 | getParameter(...) : String | C.java:91:3:91:14 | burlapInput1 | Unsafe deserialization of $@. | C.java:84:27:84:54 | getParameter(...) | user input |
| TestMessageBodyReader.java:22:18:22:65 | readObject(...) | TestMessageBodyReader.java:20:55:20:78 | entityStream : InputStream | TestMessageBodyReader.java:22:18:22:52 | new ObjectInputStream(...) | Unsafe deserialization of $@. | TestMessageBodyReader.java:20:55:20:78 | entityStream | user input |
From 58d774ae85b7af152b28fce465c315c0a0bed5e4 Mon Sep 17 00:00:00 2001
From: haby0
Date: Mon, 17 May 2021 14:52:05 +0800
Subject: [PATCH 003/153] add change notes
---
...-05-17-add-unsafe-deserialization-sinks.md | 3 ++
.../CWE/CWE-502/UnsafeDeserialization.qhelp | 2 +-
.../code/java/frameworks/HessianBurlap.qll | 2 +-
.../src/semmle/code/java/frameworks/JYaml.qll | 33 ++++---------------
.../java/security/UnsafeDeserialization.qll | 5 +--
5 files changed, 13 insertions(+), 32 deletions(-)
create mode 100644 java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
diff --git a/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md b/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
new file mode 100644
index 00000000000..2304cecbf49
--- /dev/null
+++ b/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
@@ -0,0 +1,3 @@
+lgtm,codescanning
+* The "Deserialization of user-controlled data" (`java/unsafe-deserialization`) query
+ now recognizes `JYaml`, `JsonIO`, `YAMLBeans`, `HessianBurlap`, `Castor`, `Burlap` deserialization.
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
index ce7f4751800..f1831ac5c21 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
@@ -14,7 +14,7 @@ may have unforeseen effects, such as the execution of arbitrary code.
There are many different serialization frameworks. This query currently
-supports Kryo, XmlDecoder, XStream, SnakeYaml, Hessian, JsonIO, YAMLBeans, Castor, Burlap,
+supports Kryo, XmlDecoder, XStream, SnakeYaml, JYaml, JsonIO, YAMLBeans, HessianBurlap, Castor, Burlap
and Java IO serialization through ObjectInputStream/ObjectOutputStream.
diff --git a/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll b/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
index ce53e8261c1..95803d192a7 100644
--- a/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
+++ b/java/ql/src/semmle/code/java/frameworks/HessianBurlap.qll
@@ -5,7 +5,7 @@
import java
/**
- * The class `com.caucho.hessian.io.AbstractHessianInput` or `com.alibaba.com.caucho.hessian.io.Hessian2StreamingInput`.
+ * The classes `[com.alibaba.]com.caucho.hessian.io.AbstractHessianInput` or `[com.alibaba.]com.caucho.hessian.io.Hessian2StreamingInput`.
*/
class UnsafeHessianInput extends RefType {
UnsafeHessianInput() {
diff --git a/java/ql/src/semmle/code/java/frameworks/JYaml.qll b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
index 1e0f3180607..9d77b86f6c1 100644
--- a/java/ql/src/semmle/code/java/frameworks/JYaml.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JYaml.qll
@@ -5,37 +5,18 @@
import java
/**
- * The class `org.ho.yaml.Yaml`.
+ * The class `org.ho.yaml.Yaml` or `org.ho.yaml.YamlConfig`.
*/
-class JYaml extends RefType {
- JYaml() { this.hasQualifiedName("org.ho.yaml", "Yaml") }
+class JYamlLoader extends RefType {
+ JYamlLoader() { this.hasQualifiedName("org.ho.yaml", ["Yaml", "YamlConfig"]) }
}
/**
- * A JYaml unsafe load method. This is either `YAML.load` or
- * `YAML.loadType` or `YAML.loadStream` or `YAML.loadStreamOfType`.
+ * A JYaml unsafe load method, declared on either `Yaml` or `YamlConfig`.
*/
-class JYamlUnsafeLoadMethod extends Method {
- JYamlUnsafeLoadMethod() {
- this.getDeclaringType() instanceof JYaml and
- this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
- }
-}
-
-/**
- * The class `org.ho.yaml.YamlConfig`.
- */
-class JYamlConfig extends RefType {
- JYamlConfig() { this.hasQualifiedName("org.ho.yaml", "YamlConfig") }
-}
-
-/**
- * A JYamlConfig unsafe load method. This is either `YamlConfig.load` or
- * `YAML.loadType` or `YamlConfig.loadStream` or `YamlConfig.loadStreamOfType`.
- */
-class JYamlConfigUnsafeLoadMethod extends Method {
- JYamlConfigUnsafeLoadMethod() {
- this.getDeclaringType() instanceof JYamlConfig and
+class JYamlLoaderUnsafeLoadMethod extends Method {
+ JYamlLoaderUnsafeLoadMethod() {
+ this.getDeclaringType() instanceof JYamlLoader and
this.getName() in ["load", "loadType", "loadStream", "loadStreamOfType"]
}
}
diff --git a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
index 4f5070edb2a..41840e4c1f7 100644
--- a/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
+++ b/java/ql/src/semmle/code/java/security/UnsafeDeserialization.qll
@@ -87,10 +87,7 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
not fastJsonLooksSafe() and
sink = ma.getArgument(0)
or
- ma.getMethod() instanceof JYamlUnsafeLoadMethod and
- sink = ma.getArgument(0)
- or
- ma.getMethod() instanceof JYamlConfigUnsafeLoadMethod and
+ ma.getMethod() instanceof JYamlLoaderUnsafeLoadMethod and
sink = ma.getArgument(0)
or
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
From 95c33a240fe962487a1597cd9d307a925e591790 Mon Sep 17 00:00:00 2001
From: haby0
Date: Mon, 17 May 2021 18:49:16 +0800
Subject: [PATCH 004/153] Update
java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
Co-authored-by: Chris Smowton
---
.../change-notes/2021-05-17-add-unsafe-deserialization-sinks.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md b/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
index 2304cecbf49..f294b223d01 100644
--- a/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
+++ b/java/change-notes/2021-05-17-add-unsafe-deserialization-sinks.md
@@ -1,3 +1,3 @@
lgtm,codescanning
* The "Deserialization of user-controlled data" (`java/unsafe-deserialization`) query
- now recognizes `JYaml`, `JsonIO`, `YAMLBeans`, `HessianBurlap`, `Castor`, `Burlap` deserialization.
+ now recognizes `JYaml`, `JsonIO`, `YAMLBeans`, `Castor`, `Hessian` and `Burlap` deserialization.
From 689c28a1780eb1aa83fb6ea0ccc5c71d642cf2f4 Mon Sep 17 00:00:00 2001
From: haby0
Date: Mon, 17 May 2021 19:00:59 +0800
Subject: [PATCH 005/153] modified JsonIoSafeOptionalArgs
---
java/ql/src/semmle/code/java/frameworks/JsonIo.qll | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/java/ql/src/semmle/code/java/frameworks/JsonIo.qll b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
index 1a2acf754ad..ab4c1b115d9 100644
--- a/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JsonIo.qll
@@ -33,8 +33,8 @@ class JsonIoReadObjectMethod extends Method {
/**
* A call to `Map.put` method, set the value of the `USE_MAPS` key to `true`.
*/
-class JsonIoSafeOptionalArgs extends MethodAccess {
- JsonIoSafeOptionalArgs() {
+class JsonIoUseMapsSetter extends MethodAccess {
+ JsonIoUseMapsSetter() {
this.getMethod().getDeclaringType().getASourceSupertype*() instanceof MapType and
this.getMethod().hasName("put") and
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "USE_MAPS" and
@@ -48,7 +48,7 @@ class SafeJsonIoConfig extends DataFlow2::Configuration {
override predicate isSource(DataFlow::Node src) {
exists(MethodAccess ma |
- ma instanceof JsonIoSafeOptionalArgs and
+ ma instanceof JsonIoUseMapsSetter and
src.asExpr() = ma.getQualifier()
)
}
From 9a4709c13477b83fbaa2dc401687e4845396663e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 21 May 2021 15:57:10 +0200
Subject: [PATCH 006/153] Python: API graph tests: Disallow results outside
project
Running the tests locally would result in thousands of results before
this :scream:
---
python/ql/test/experimental/dataflow/ApiGraphs/use.ql | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/use.ql b/python/ql/test/experimental/dataflow/ApiGraphs/use.ql
index 2bcc05d443b..4e56fc3ff44 100644
--- a/python/ql/test/experimental/dataflow/ApiGraphs/use.ql
+++ b/python/ql/test/experimental/dataflow/ApiGraphs/use.ql
@@ -13,7 +13,8 @@ class ApiUseTest extends InlineExpectationsTest {
l = n.getLocation() and
// Module variable nodes have no suitable location, so it's best to simply exclude them entirely
// from the inline tests.
- not n instanceof DataFlow::ModuleVariableNode
+ not n instanceof DataFlow::ModuleVariableNode and
+ exists(l.getFile().getRelativePath())
}
override predicate hasActualResult(Location location, string element, string tag, string value) {
From 7a5fd02442a08c1cb70a4b5f8ff87285b7ca759e Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 21 May 2021 15:58:15 +0200
Subject: [PATCH 007/153] Python: API graph tests: add --max-import-depth=1
Before this, I ended up extracting 454 modules locally :scream:
---
python/ql/test/experimental/dataflow/ApiGraphs/options | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/options b/python/ql/test/experimental/dataflow/ApiGraphs/options
index 1099600818b..89369a90996 100644
--- a/python/ql/test/experimental/dataflow/ApiGraphs/options
+++ b/python/ql/test/experimental/dataflow/ApiGraphs/options
@@ -1 +1 @@
-semmle-extractor-options: --lang=3
\ No newline at end of file
+semmle-extractor-options: --lang=3 --max-import-depth=1
From 2408573a0a41197e93a790d42d3914b8500bcb99 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 21 May 2021 16:07:14 +0200
Subject: [PATCH 008/153] Python: Add API graph test for calling coroutines
---
.../dataflow/ApiGraphs/async_test.py | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/async_test.py b/python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
new file mode 100644
index 00000000000..71f9e93ccdd
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
@@ -0,0 +1,17 @@
+import pkg # $ use=moduleImport("pkg")
+
+async def foo():
+ coro = pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn()
+ coro # $ use=moduleImport("pkg").getMember("async_func").getReturn()
+ result = await coro # $ use=moduleImport("pkg").getMember("async_func").getReturn()
+ result # $ MISSING: use=...
+ return result # $ MISSING: use=...
+
+async def bar():
+ result = await pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn()
+ return result # $ MISSING: use=...
+
+def check_annotations():
+ # Just to make sure how annotations should look like :)
+ result = pkg.sync_func() # $ use=moduleImport("pkg").getMember("sync_func").getReturn()
+ return result # $ use=moduleImport("pkg").getMember("sync_func").getReturn()
From e29b7568bf20f2a4702b0f378f57c6f0f1ec9830 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 21 May 2021 16:17:17 +0200
Subject: [PATCH 009/153] Python: Add missing QLDoc for subclass label
---
python/ql/src/semmle/python/ApiGraphs.qll | 1 +
1 file changed, 1 insertion(+)
diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll
index 61c9f4c1c7f..d7a39338c1f 100644
--- a/python/ql/src/semmle/python/ApiGraphs.qll
+++ b/python/ql/src/semmle/python/ApiGraphs.qll
@@ -585,5 +585,6 @@ private module Label {
/** Gets the `return` edge label. */
string return() { result = "getReturn()" }
+ /** Gets the `subclass` edge label. */
string subclass() { result = "getASubclass()" }
}
From c4e244eb80204cd511152274404ce859f6eb69ca Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Fri, 21 May 2021 17:09:15 +0200
Subject: [PATCH 010/153] Python: Add `getAwaited` to API::Node
I _really_ wanted to call this `.await()`, but that did not fit in with
the convention, or the corresponding `getPromised` in JS.
https://github.com/github/codeql/blob/54f191cfe37e136bcc7189b2fb01f44dbb01758b/javascript/ql/src/semmle/javascript/ApiGraphs.qll#L184
---
.../change-notes/2021-05-21-api-graph-await.md | 2 ++
python/ql/src/semmle/python/ApiGraphs.qll | 16 ++++++++++++++++
.../dataflow/ApiGraphs/async_test.py | 10 +++++-----
3 files changed, 23 insertions(+), 5 deletions(-)
create mode 100644 python/change-notes/2021-05-21-api-graph-await.md
diff --git a/python/change-notes/2021-05-21-api-graph-await.md b/python/change-notes/2021-05-21-api-graph-await.md
new file mode 100644
index 00000000000..81463fb7517
--- /dev/null
+++ b/python/change-notes/2021-05-21-api-graph-await.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* API graph nodes now contain a `getAwaited()` member predicate, for getting the result of awaiting an item, such as `await foo`.
diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll
index d7a39338c1f..2969d317576 100644
--- a/python/ql/src/semmle/python/ApiGraphs.qll
+++ b/python/ql/src/semmle/python/ApiGraphs.qll
@@ -97,6 +97,11 @@ module API {
*/
Node getASubclass() { result = getASuccessor(Label::subclass()) }
+ /**
+ * Gets a node representing the result from awaiting this node.
+ */
+ Node getAwaited() { result = getASuccessor(Label::await()) }
+
/**
* Gets a string representation of the lexicographically least among all shortest access paths
* from the root to this node.
@@ -469,6 +474,14 @@ module API {
exists(DataFlow::Node superclass | pred.flowsTo(superclass) |
ref.asExpr().(ClassExpr).getABase() = superclass.asExpr()
)
+ or
+ // awaiting
+ exists(Await await, DataFlow::Node awaitedValue |
+ lbl = Label::await() and
+ ref.asExpr() = await and
+ await.getValue() = awaitedValue.asExpr() and
+ pred.flowsTo(awaitedValue)
+ )
)
or
// Built-ins, treated as members of the module `builtins`
@@ -587,4 +600,7 @@ private module Label {
/** Gets the `subclass` edge label. */
string subclass() { result = "getASubclass()" }
+
+ /** Gets the `await` edge label. */
+ string await() { result = "getAwaited()" }
}
diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/async_test.py b/python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
index 71f9e93ccdd..85b14c86644 100644
--- a/python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
+++ b/python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
@@ -3,13 +3,13 @@ import pkg # $ use=moduleImport("pkg")
async def foo():
coro = pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn()
coro # $ use=moduleImport("pkg").getMember("async_func").getReturn()
- result = await coro # $ use=moduleImport("pkg").getMember("async_func").getReturn()
- result # $ MISSING: use=...
- return result # $ MISSING: use=...
+ result = await coro # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
+ result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
+ return result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
async def bar():
- result = await pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn()
- return result # $ MISSING: use=...
+ result = await pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
+ return result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
def check_annotations():
# Just to make sure how annotations should look like :)
From ee3477c20a41f64c89b3eed6c75f0be9f014818f Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 25 May 2021 14:27:29 +0200
Subject: [PATCH 011/153] Python: Remove dummy clickhouse SQL injection query
---
.../CWE-089/ClickHouseSQLInjection.py | 28 ---------
.../CWE-089/ClickHouseSQLInjection.qhelp | 59 -------------------
.../CWE-089/ClickHouseSQLInjection.ql | 22 -------
3 files changed, 109 deletions(-)
delete mode 100644 python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.py
delete mode 100644 python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.qhelp
delete mode 100644 python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.ql
diff --git a/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.py b/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.py
deleted file mode 100644
index 6668d8eb15f..00000000000
--- a/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from django.conf.urls import url
-from clickhouse_driver import Client
-from clickhouse_driver import connect
-from aioch import Client as aiochClient
-
-class MyClient(Client):
- def dummy(self):
- return None
-
-def show_user(request, username):
-
- # BAD -- Untrusted user input is directly injected into the sql query using async library 'aioch'
- aclient = aiochClient("localhost")
- progress = await aclient.execute_with_progress("SELECT * FROM users WHERE username = '%s'" % username)
-
- # BAD -- Untrusted user input is directly injected into the sql query using native client of library 'clickhouse_driver'
- Client('localhost').execute("SELECT * FROM users WHERE username = '%s'" % username)
-
- # GOOD -- query uses prepared statements
- query = "SELECT * FROM users WHERE username = %(username)s"
- Client('localhost').execute(query, {"username": username})
-
- # BAD -- PEP249 interface
- conn = connect('clickhouse://localhost')
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE username = '%s'" % username)
-
-urlpatterns = [url(r'^users/(?P[^/]+)$', show_user)]
diff --git a/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.qhelp b/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.qhelp
deleted file mode 100644
index be007545632..00000000000
--- a/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.qhelp
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-If a database query (such as a SQL or NoSQL query) is built from
-user-provided data without sufficient sanitization, a user
-may be able to run malicious database queries.
-
-
-
-
-
-Most database connector libraries offer a way of safely
-embedding untrusted data into a query by means of query parameters
-or prepared statements.
-
-
-
-
-
-In the following snippet, a user is fetched from a ClickHouse database
-using five different queries. In the "BAD" cases the query is built directly from user-controlled data.
-In the "GOOD" case the user-controlled data is safely embedded into the query by using query parameters.
-
-
-
-In the first case, the query executed via aioch Client. aioch - is a module
-for asynchronous queries to database.
-
-
-
-In the second and third cases, the connection is established via `Client` class.
-This class implement different method to execute a query.
-
-
-
-In the forth case, good pattern is presented. Query parameters are send through
-second dict-like argument.
-
-
-
-In the fifth case, there is example of PEP249 interface usage.
-
-
-
-In the sixth case, there is custom Class usge which is a subclass of default Client.
-
-
-
diff --git a/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.ql b/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.ql
deleted file mode 100644
index f0efb523756..00000000000
--- a/python/ql/src/experimental/Security/CWE-089/ClickHouseSQLInjection.ql
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * @id py/yandex/clickhouse-sql-injection
- * @name Clickhouse SQL query built from user-controlled sources
- * @description Building a SQL query from user-controlled sources is vulnerable to insertion of
- * malicious SQL code by the user.
- * @kind path-problem
- * @problem.severity error
- * @precision high
- * @tags security
- * external/cwe/cwe-089
- * external/owasp/owasp-a1
- */
-
-import python
-import experimental.semmle.python.frameworks.ClickHouseDriver
-import semmle.python.security.dataflow.SqlInjection
-import DataFlow::PathGraph
-
-from SQLInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
-where config.hasFlowPath(source, sink)
-select sink.getNode(), source, sink, "This SQL query depends on $@.", source.getNode(),
- "a user-provided value"
From c9a9535dbcc6b3565032cadb97ead4b883756f36 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 25 May 2021 14:53:09 +0200
Subject: [PATCH 012/153] Python: Use ConceptsTests for ClickHouse SQL libs
This did reveal a few places where we do not detect the incoming SQL
---
.../frameworks/aioch/ConceptsTest.expected | 0
.../ConceptsTest.ql} | 5 +--
.../semmle/python/frameworks/aioch/options | 1 +
.../python/frameworks/aioch/sql_test.py | 30 +++++++++++++
.../ClickHouseDriver.expected | 5 ---
.../clickhouse-driver/ClickHouseDriver.py | 32 --------------
.../clickhouse_driver/ConceptsTest.expected | 0
.../clickhouse_driver/ConceptsTest.ql | 3 ++
.../frameworks/clickhouse_driver/sql_test.py | 42 +++++++++++++++++++
.../semmle/python/frameworks/options | 1 +
10 files changed, 78 insertions(+), 41 deletions(-)
create mode 100644 python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.expected
rename python/ql/test/experimental/semmle/python/frameworks/{clickhouse-driver/ClickHouseDriver.ql => aioch/ConceptsTest.ql} (51%)
create mode 100644 python/ql/test/experimental/semmle/python/frameworks/aioch/options
create mode 100644 python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py
delete mode 100644 python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.expected
delete mode 100644 python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.py
create mode 100644 python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.expected
create mode 100644 python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
create mode 100644 python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py
create mode 100644 python/ql/test/experimental/semmle/python/frameworks/options
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.expected b/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.ql b/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
similarity index 51%
rename from python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.ql
rename to python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
index bedd47c0af6..65b2c78c74a 100644
--- a/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.ql
+++ b/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
@@ -1,6 +1,3 @@
import python
+import experimental.meta.ConceptsTest
import experimental.semmle.python.frameworks.ClickHouseDriver
-import semmle.python.Concepts
-
-from SqlExecution s
-select s, s.getSql()
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/options b/python/ql/test/experimental/semmle/python/frameworks/aioch/options
new file mode 100644
index 00000000000..cfef58cf2b2
--- /dev/null
+++ b/python/ql/test/experimental/semmle/python/frameworks/aioch/options
@@ -0,0 +1 @@
+semmle-extractor-options: --max-import-depth=1 --lang=3
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py b/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py
new file mode 100644
index 00000000000..468791aa3dc
--- /dev/null
+++ b/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py
@@ -0,0 +1,30 @@
+import aioch
+
+
+SQL = "SOME SQL"
+
+
+async def aioch_test():
+ client = aioch.Client("localhost")
+
+ await client.execute(SQL) # $ getSql=SQL
+ await client.execute(query=SQL) # $ MISSING: getSql=SQL
+
+ await client.execute_with_progress(SQL) # $ getSql=SQL
+ await client.execute_with_progress(query=SQL) # $ MISSING: getSql=SQL
+
+ await client.execute_iter(SQL) # $ getSql=SQL
+ await client.execute_iter(query=SQL) # $ MISSING: getSql=SQL
+
+
+# Using custom client (this has been seen done for the blocking version in
+# `clickhouse_driver` PyPI package)
+
+
+class MyClient(aioch.Client):
+ pass
+
+
+async def test_custom_client():
+ client = MyClient("localhost")
+ await client.execute(SQL) # $ getSql=SQL
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.expected b/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.expected
deleted file mode 100644
index 52aa30cb8c1..00000000000
--- a/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.expected
+++ /dev/null
@@ -1,5 +0,0 @@
-| ClickHouseDriver.py:15:22:15:106 | ControlFlowNode for Attribute() | ClickHouseDriver.py:15:52:15:105 | ControlFlowNode for BinaryExpr |
-| ClickHouseDriver.py:18:5:18:87 | ControlFlowNode for Attribute() | ClickHouseDriver.py:18:33:18:86 | ControlFlowNode for BinaryExpr |
-| ClickHouseDriver.py:22:5:22:62 | ControlFlowNode for Attribute() | ClickHouseDriver.py:22:33:22:37 | ControlFlowNode for query |
-| ClickHouseDriver.py:27:5:27:74 | ControlFlowNode for Attribute() | ClickHouseDriver.py:27:20:27:73 | ControlFlowNode for BinaryExpr |
-| ClickHouseDriver.py:30:5:30:89 | ControlFlowNode for Attribute() | ClickHouseDriver.py:30:35:30:88 | ControlFlowNode for BinaryExpr |
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.py b/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.py
deleted file mode 100644
index 7684f3df795..00000000000
--- a/python/ql/test/experimental/semmle/python/frameworks/clickhouse-driver/ClickHouseDriver.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from django.conf.urls import url
-from clickhouse_driver import Client
-from clickhouse_driver import connect
-from aioch import Client as aiochClient
-
-# Dummy Client subclass
-class MyClient(Client):
- def dummy(self):
- return None
-
-def show_user(request, username):
-
- # BAD -- Untrusted user input is directly injected into the sql query using async library 'aioch'
- aclient = aiochClient("localhost")
- progress = await aclient.execute_with_progress("SELECT * FROM users WHERE username = '%s'" % username)
-
- # BAD -- Untrusted user input is directly injected into the sql query using native client of library 'clickhouse_driver'
- Client('localhost').execute("SELECT * FROM users WHERE username = '%s'" % username)
-
- # GOOD -- query uses prepared statements
- query = "SELECT * FROM users WHERE username = %(username)s"
- Client('localhost').execute(query, {"username": username})
-
- # BAD -- Untrusted user input is directly injected into the sql query using PEP249 interface
- conn = connect('clickhouse://localhost')
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM users WHERE username = '%s'" % username)
-
- # BAD -- Untrusted user input is directly injected into the sql query using MyClient, which is a subclass of Client
- MyClient('localhost').execute("SELECT * FROM users WHERE username = '%s'" % username)
-
-urlpatterns = [url(r'^users/(?P[^/]+)$', show_user)]
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.expected b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
new file mode 100644
index 00000000000..65b2c78c74a
--- /dev/null
+++ b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
@@ -0,0 +1,3 @@
+import python
+import experimental.meta.ConceptsTest
+import experimental.semmle.python.frameworks.ClickHouseDriver
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py
new file mode 100644
index 00000000000..d1e2491e86e
--- /dev/null
+++ b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py
@@ -0,0 +1,42 @@
+import clickhouse_driver
+
+
+SQL = "SOME SQL"
+
+
+# Normal operation
+client = clickhouse_driver.client.Client("localhost")
+
+client.execute(SQL) # $ MISSING: getSql=SQL
+client.execute(query=SQL) # $ MISSING: getSql=SQL
+
+client.execute_with_progress(SQL) # $ MISSING: getSql=SQL
+client.execute_with_progress(query=SQL) # $ MISSING: getSql=SQL
+
+client.execute_iter(SQL) # $ MISSING: getSql=SQL
+client.execute_iter(query=SQL) # $ MISSING: getSql=SQL
+
+
+# commonly used alias
+client = clickhouse_driver.Client("localhost")
+client.execute(SQL) # $ getSql=SQL
+
+
+# Using PEP249 interface
+conn = clickhouse_driver.connect('clickhouse://localhost')
+cursor = conn.cursor()
+cursor.execute(SQL) # $ getSql=SQL
+
+
+# Using custom client
+#
+# examples from real world code
+# https://github.com/Altinity/clickhouse-mysql-data-reader/blob/3b1b7088751b05e5bbf45890c5949b58208c2343/clickhouse_mysql/dbclient/chclient.py#L10
+# https://github.com/Felixoid/clickhouse-plantuml/blob/d8b2ba7d164a836770ec21f5e4035dfb04c41d9c/clickhouse_plantuml/client.py#L9
+
+
+class MyClient(clickhouse_driver.Client):
+ pass
+
+
+MyClient("localhost").execute(SQL) # $ getSql=SQL
diff --git a/python/ql/test/experimental/semmle/python/frameworks/options b/python/ql/test/experimental/semmle/python/frameworks/options
new file mode 100644
index 00000000000..eb214fc2931
--- /dev/null
+++ b/python/ql/test/experimental/semmle/python/frameworks/options
@@ -0,0 +1 @@
+semmle-extractor-options: --max-import-depth=1
From eb1da152a0d54bff63094056f12ba92a309a9a91 Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 25 May 2021 16:13:31 +0200
Subject: [PATCH 013/153] Python: Rewrite ClickHouse SQL lib modeling
This did turn into a few changes, that maybe could have been split into
separate PRs :shrug:
* Rename `ClickHouseDriver` => `ClickhouseDriver`, to better follow
import name in `.qll` name
* Rewrote modeling to use API graphs
* Split modeling of `aioch` into separate `.qll` file, which does re-use
the `getExecuteMethodName` predicate. I feel that sharing code between
the modeling like this was the best approach, and stuck the
`INTERNAL: Do not use.` labels on both modules.
* I also added handling of keyword arguments (see change in .py files)
---
.../semmle/python/frameworks/Aioch.qll | 52 ++++++++++++
.../python/frameworks/ClickHouseDriver.qll | 85 -------------------
.../python/frameworks/ClickhouseDriver.qll | 65 ++++++++++++++
.../python/frameworks/aioch/ConceptsTest.ql | 2 +-
.../python/frameworks/aioch/sql_test.py | 6 +-
.../clickhouse_driver/ConceptsTest.ql | 2 +-
.../frameworks/clickhouse_driver/sql_test.py | 12 +--
7 files changed, 128 insertions(+), 96 deletions(-)
create mode 100644 python/ql/src/experimental/semmle/python/frameworks/Aioch.qll
delete mode 100644 python/ql/src/experimental/semmle/python/frameworks/ClickHouseDriver.qll
create mode 100644 python/ql/src/experimental/semmle/python/frameworks/ClickhouseDriver.qll
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Aioch.qll b/python/ql/src/experimental/semmle/python/frameworks/Aioch.qll
new file mode 100644
index 00000000000..dde97047046
--- /dev/null
+++ b/python/ql/src/experimental/semmle/python/frameworks/Aioch.qll
@@ -0,0 +1,52 @@
+/**
+ * Provides classes modeling security-relevant aspects of the `aioch` PyPI package (an
+ * async-io version of the `clickhouse-driver` PyPI package).
+ *
+ * See https://pypi.org/project/aioch/
+ */
+
+private import python
+private import semmle.python.Concepts
+private import semmle.python.ApiGraphs
+private import semmle.python.frameworks.PEP249
+private import experimental.semmle.python.frameworks.ClickhouseDriver
+
+/**
+ * INTERNAL: Do not use.
+ *
+ * Provides models for `aioch` PyPI package (an async-io version of the
+ * `clickhouse-driver` PyPI package).
+ *
+ * See https://pypi.org/project/aioch/
+ */
+module Aioch {
+ /** Provides models for `aioch.Client` class and subclasses. */
+ module Client {
+ /** Gets a reference to the `aioch.Client` class or any subclass. */
+ API::Node subclassRef() {
+ result = API::moduleImport("aioch").getMember("Client").getASubclass*()
+ }
+
+ /** Gets a reference to an instance of `clickhouse_driver.Client` or any subclass. */
+ API::Node instance() { result = subclassRef().getReturn() }
+ }
+
+ /**
+ * A call to any of the the execute methods on a `aioch.Client`, which are just async
+ * versions of the methods in the `clickhouse-driver` PyPI package.
+ *
+ * See
+ * - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute
+ * - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_iter
+ * - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_with_progress
+ */
+ class ClientExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
+ ClientExecuteCall() {
+ exists(string methodName | methodName = ClickhouseDriver::getExecuteMethodName() |
+ this = Client::instance().getMember(methodName).getACall()
+ )
+ }
+
+ override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("query")] }
+ }
+}
diff --git a/python/ql/src/experimental/semmle/python/frameworks/ClickHouseDriver.qll b/python/ql/src/experimental/semmle/python/frameworks/ClickHouseDriver.qll
deleted file mode 100644
index c456b6bdb89..00000000000
--- a/python/ql/src/experimental/semmle/python/frameworks/ClickHouseDriver.qll
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Provides classes modeling security-relevant aspects of `clickhouse-driver` and `aioch` PyPI packages.
- * See
- * - https://pypi.org/project/clickhouse-driver/
- * - https://pypi.org/project/aioch/
- * - https://clickhouse-driver.readthedocs.io/en/latest/
- */
-
-private import python
-private import semmle.python.Concepts
-private import semmle.python.ApiGraphs
-private import semmle.python.frameworks.PEP249
-
-/**
- * Provides models for `clickhouse-driver` and `aioch` PyPI packages.
- * See
- * - https://pypi.org/project/clickhouse-driver/
- * - https://pypi.org/project/aioch/
- * - https://clickhouse-driver.readthedocs.io/en/latest/
- */
-module ClickHouseDriver {
- /** Gets a reference to the `clickhouse_driver` module. */
- API::Node clickhouse_driver() { result = API::moduleImport("clickhouse_driver") }
-
- /** Gets a reference to the `aioch` module. This module allows to make async db queries. */
- API::Node aioch() { result = API::moduleImport("aioch") }
-
- /**
- * `clickhouse_driver` implements PEP249,
- * providing ways to execute SQL statements against a database.
- */
- class ClickHouseDriverPEP249 extends PEP249ModuleApiNode {
- ClickHouseDriverPEP249() { this = clickhouse_driver() }
- }
-
- module Client {
- /** Gets a reference to a Client call. */
- private DataFlow::Node client_ref() {
- result = clickhouse_driver().getMember("Client").getASubclass*().getAUse()
- or
- result = aioch().getMember("Client").getASubclass*().getAUse()
- }
-
- /** A direct instantiation of `clickhouse_driver.Client`. */
- private class ClientInstantiation extends DataFlow::CallCfgNode {
- ClientInstantiation() { this.getFunction() = client_ref() }
- }
-
- /** Gets a reference to an instance of `clickhouse_driver.Client`. */
- private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
- t.start() and
- result instanceof ClientInstantiation
- or
- exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
- }
-
- /** Gets a reference to an instance of `clickhouse_driver.Client`. */
- DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
- }
-
- /** clickhouse_driver.Client execute methods */
- private string execute_function() {
- result in ["execute_with_progress", "execute", "execute_iter"]
- }
-
- /** Gets a reference to the `clickhouse_driver.Client.execute` method */
- private DataFlow::LocalSourceNode clickhouse_execute(DataFlow::TypeTracker t) {
- t.startInAttr(execute_function()) and
- result = Client::instance()
- or
- exists(DataFlow::TypeTracker t2 | result = clickhouse_execute(t2).track(t2, t))
- }
-
- /** Gets a reference to the `clickhouse_driver.Client.execute` method */
- DataFlow::Node clickhouse_execute() {
- clickhouse_execute(DataFlow::TypeTracker::end()).flowsTo(result)
- }
-
- /** A call to the `clickhouse_driver.Client.execute` method */
- private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
- ExecuteCall() { this.getFunction() = clickhouse_execute() }
-
- override DataFlow::Node getSql() { result.asCfgNode() = node.getArg(0) }
- }
-}
diff --git a/python/ql/src/experimental/semmle/python/frameworks/ClickhouseDriver.qll b/python/ql/src/experimental/semmle/python/frameworks/ClickhouseDriver.qll
new file mode 100644
index 00000000000..8863b1dbe66
--- /dev/null
+++ b/python/ql/src/experimental/semmle/python/frameworks/ClickhouseDriver.qll
@@ -0,0 +1,65 @@
+/**
+ * Provides classes modeling security-relevant aspects of the `clickhouse-driver` PyPI package.
+ * See
+ * - https://pypi.org/project/clickhouse-driver/
+ * - https://clickhouse-driver.readthedocs.io/en/latest/
+ */
+
+private import python
+private import semmle.python.Concepts
+private import semmle.python.ApiGraphs
+private import semmle.python.frameworks.PEP249
+
+/**
+ * INTERNAL: Do not use.
+ *
+ * Provides models for `clickhouse-driver` PyPI package (imported as `clickhouse_driver`).
+ * See
+ * - https://pypi.org/project/clickhouse-driver/
+ * - https://clickhouse-driver.readthedocs.io/en/latest/
+ */
+module ClickhouseDriver {
+ /**
+ * `clickhouse_driver` implements PEP249,
+ * providing ways to execute SQL statements against a database.
+ */
+ class ClickHouseDriverPEP249 extends PEP249ModuleApiNode {
+ ClickHouseDriverPEP249() { this = API::moduleImport("clickhouse_driver") }
+ }
+
+ /** Provides models for `clickhouse_driver.Client` class and subclasses. */
+ module Client {
+ /** Gets a reference to the `clickhouse_driver.Client` class or any subclass. */
+ API::Node subclassRef() {
+ exists(API::Node classRef |
+ // canonical definition
+ classRef = API::moduleImport("clickhouse_driver").getMember("client").getMember("Client")
+ or
+ // commonly used alias
+ classRef = API::moduleImport("clickhouse_driver").getMember("Client")
+ |
+ result = classRef.getASubclass*()
+ )
+ }
+
+ /** Gets a reference to an instance of `clickhouse_driver.Client` or any subclass. */
+ API::Node instance() { result = subclassRef().getReturn() }
+ }
+
+ /** `clickhouse_driver.Client` execute method names */
+ string getExecuteMethodName() { result in ["execute_with_progress", "execute", "execute_iter"] }
+
+ /**
+ * A call to any of the the execute methods on a `clickhouse_driver.Client` method
+ *
+ * See
+ * - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute
+ * - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_iter
+ * - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_with_progress
+ */
+ class ClientExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
+ ClientExecuteCall() { this = Client::instance().getMember(getExecuteMethodName()).getACall() }
+
+ override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("query")] }
+ }
+}
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql b/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
index 65b2c78c74a..c0c26131055 100644
--- a/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
+++ b/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
@@ -1,3 +1,3 @@
import python
import experimental.meta.ConceptsTest
-import experimental.semmle.python.frameworks.ClickHouseDriver
+import experimental.semmle.python.frameworks.Aioch
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py b/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py
index 468791aa3dc..de6b018b0d4 100644
--- a/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py
+++ b/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py
@@ -8,13 +8,13 @@ async def aioch_test():
client = aioch.Client("localhost")
await client.execute(SQL) # $ getSql=SQL
- await client.execute(query=SQL) # $ MISSING: getSql=SQL
+ await client.execute(query=SQL) # $ getSql=SQL
await client.execute_with_progress(SQL) # $ getSql=SQL
- await client.execute_with_progress(query=SQL) # $ MISSING: getSql=SQL
+ await client.execute_with_progress(query=SQL) # $ getSql=SQL
await client.execute_iter(SQL) # $ getSql=SQL
- await client.execute_iter(query=SQL) # $ MISSING: getSql=SQL
+ await client.execute_iter(query=SQL) # $ getSql=SQL
# Using custom client (this has been seen done for the blocking version in
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
index 65b2c78c74a..86e878cf8c7 100644
--- a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
+++ b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
@@ -1,3 +1,3 @@
import python
import experimental.meta.ConceptsTest
-import experimental.semmle.python.frameworks.ClickHouseDriver
+import experimental.semmle.python.frameworks.ClickhouseDriver
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py
index d1e2491e86e..36d4966c186 100644
--- a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py
+++ b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py
@@ -7,14 +7,14 @@ SQL = "SOME SQL"
# Normal operation
client = clickhouse_driver.client.Client("localhost")
-client.execute(SQL) # $ MISSING: getSql=SQL
-client.execute(query=SQL) # $ MISSING: getSql=SQL
+client.execute(SQL) # $ getSql=SQL
+client.execute(query=SQL) # $ getSql=SQL
-client.execute_with_progress(SQL) # $ MISSING: getSql=SQL
-client.execute_with_progress(query=SQL) # $ MISSING: getSql=SQL
+client.execute_with_progress(SQL) # $ getSql=SQL
+client.execute_with_progress(query=SQL) # $ getSql=SQL
-client.execute_iter(SQL) # $ MISSING: getSql=SQL
-client.execute_iter(query=SQL) # $ MISSING: getSql=SQL
+client.execute_iter(SQL) # $ getSql=SQL
+client.execute_iter(query=SQL) # $ getSql=SQL
# commonly used alias
From 1b3f857a2fdeb03e38fe0964c68d984fc23c5feb Mon Sep 17 00:00:00 2001
From: Rasmus Wriedt Larsen
Date: Tue, 25 May 2021 16:27:23 +0200
Subject: [PATCH 014/153] Python: Promote ClickHouse SQL models
---
docs/codeql/support/reusables/frameworks.rst | 2 ++
python/change-notes/2021-05-25-add-ClickHouse-sql-libs.md | 2 ++
python/ql/src/semmle/python/Frameworks.qll | 2 ++
.../src/{experimental => }/semmle/python/frameworks/Aioch.qll | 2 +-
.../semmle/python/frameworks/ClickhouseDriver.qll | 0
.../semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql | 3 ---
python/ql/test/experimental/semmle/python/frameworks/options | 1 -
.../frameworks/aioch/ConceptsTest.expected | 0
.../python => library-tests}/frameworks/aioch/ConceptsTest.ql | 1 -
.../semmle/python => library-tests}/frameworks/aioch/options | 0
.../python => library-tests}/frameworks/aioch/sql_test.py | 0
.../frameworks/clickhouse_driver/ConceptsTest.expected | 0
.../library-tests/frameworks/clickhouse_driver/ConceptsTest.ql | 2 ++
.../frameworks/clickhouse_driver/sql_test.py | 0
14 files changed, 9 insertions(+), 6 deletions(-)
create mode 100644 python/change-notes/2021-05-25-add-ClickHouse-sql-libs.md
rename python/ql/src/{experimental => }/semmle/python/frameworks/Aioch.qll (96%)
rename python/ql/src/{experimental => }/semmle/python/frameworks/ClickhouseDriver.qll (100%)
delete mode 100644 python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
delete mode 100644 python/ql/test/experimental/semmle/python/frameworks/options
rename python/ql/test/{experimental/semmle/python => library-tests}/frameworks/aioch/ConceptsTest.expected (100%)
rename python/ql/test/{experimental/semmle/python => library-tests}/frameworks/aioch/ConceptsTest.ql (50%)
rename python/ql/test/{experimental/semmle/python => library-tests}/frameworks/aioch/options (100%)
rename python/ql/test/{experimental/semmle/python => library-tests}/frameworks/aioch/sql_test.py (100%)
rename python/ql/test/{experimental/semmle/python => library-tests}/frameworks/clickhouse_driver/ConceptsTest.expected (100%)
create mode 100644 python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.ql
rename python/ql/test/{experimental/semmle/python => library-tests}/frameworks/clickhouse_driver/sql_test.py (100%)
diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst
index be9949aad77..532456d76b4 100644
--- a/docs/codeql/support/reusables/frameworks.rst
+++ b/docs/codeql/support/reusables/frameworks.rst
@@ -162,6 +162,8 @@ Python built-in support
fabric, Utility library
invoke, Utility library
idna, Utility library
+ aioch, Database
+ clickhouse-driver, Database
mysql-connector-python, Database
MySQLdb, Database
psycopg2, Database
diff --git a/python/change-notes/2021-05-25-add-ClickHouse-sql-libs.md b/python/change-notes/2021-05-25-add-ClickHouse-sql-libs.md
new file mode 100644
index 00000000000..4638180f8c5
--- /dev/null
+++ b/python/change-notes/2021-05-25-add-ClickHouse-sql-libs.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* Added model of SQL execution in `clickhouse-driver` and `aioch` PyPI packages, resulting in additional sinks for the SQL Injection query (`py/sql-injection`). This modeling was originally [submitted as a contribution by @japroc](https://github.com/github/codeql/pull/5889).
diff --git a/python/ql/src/semmle/python/Frameworks.qll b/python/ql/src/semmle/python/Frameworks.qll
index 3115c3ffac6..96ae176465e 100644
--- a/python/ql/src/semmle/python/Frameworks.qll
+++ b/python/ql/src/semmle/python/Frameworks.qll
@@ -4,6 +4,8 @@
// If you add modeling of a new framework/library, remember to add it it to the docs in
// `docs/codeql/support/reusables/frameworks.rst`
+private import semmle.python.frameworks.Aioch
+private import semmle.python.frameworks.ClickhouseDriver
private import semmle.python.frameworks.Cryptodome
private import semmle.python.frameworks.Cryptography
private import semmle.python.frameworks.Dill
diff --git a/python/ql/src/experimental/semmle/python/frameworks/Aioch.qll b/python/ql/src/semmle/python/frameworks/Aioch.qll
similarity index 96%
rename from python/ql/src/experimental/semmle/python/frameworks/Aioch.qll
rename to python/ql/src/semmle/python/frameworks/Aioch.qll
index dde97047046..ede732e35dc 100644
--- a/python/ql/src/experimental/semmle/python/frameworks/Aioch.qll
+++ b/python/ql/src/semmle/python/frameworks/Aioch.qll
@@ -9,7 +9,7 @@ private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.PEP249
-private import experimental.semmle.python.frameworks.ClickhouseDriver
+private import semmle.python.frameworks.ClickhouseDriver
/**
* INTERNAL: Do not use.
diff --git a/python/ql/src/experimental/semmle/python/frameworks/ClickhouseDriver.qll b/python/ql/src/semmle/python/frameworks/ClickhouseDriver.qll
similarity index 100%
rename from python/ql/src/experimental/semmle/python/frameworks/ClickhouseDriver.qll
rename to python/ql/src/semmle/python/frameworks/ClickhouseDriver.qll
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql b/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
deleted file mode 100644
index 86e878cf8c7..00000000000
--- a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.ql
+++ /dev/null
@@ -1,3 +0,0 @@
-import python
-import experimental.meta.ConceptsTest
-import experimental.semmle.python.frameworks.ClickhouseDriver
diff --git a/python/ql/test/experimental/semmle/python/frameworks/options b/python/ql/test/experimental/semmle/python/frameworks/options
deleted file mode 100644
index eb214fc2931..00000000000
--- a/python/ql/test/experimental/semmle/python/frameworks/options
+++ /dev/null
@@ -1 +0,0 @@
-semmle-extractor-options: --max-import-depth=1
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/aioch/ConceptsTest.expected
similarity index 100%
rename from python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.expected
rename to python/ql/test/library-tests/frameworks/aioch/ConceptsTest.expected
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/aioch/ConceptsTest.ql
similarity index 50%
rename from python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
rename to python/ql/test/library-tests/frameworks/aioch/ConceptsTest.ql
index c0c26131055..b557a0bccb6 100644
--- a/python/ql/test/experimental/semmle/python/frameworks/aioch/ConceptsTest.ql
+++ b/python/ql/test/library-tests/frameworks/aioch/ConceptsTest.ql
@@ -1,3 +1,2 @@
import python
import experimental.meta.ConceptsTest
-import experimental.semmle.python.frameworks.Aioch
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/options b/python/ql/test/library-tests/frameworks/aioch/options
similarity index 100%
rename from python/ql/test/experimental/semmle/python/frameworks/aioch/options
rename to python/ql/test/library-tests/frameworks/aioch/options
diff --git a/python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py b/python/ql/test/library-tests/frameworks/aioch/sql_test.py
similarity index 100%
rename from python/ql/test/experimental/semmle/python/frameworks/aioch/sql_test.py
rename to python/ql/test/library-tests/frameworks/aioch/sql_test.py
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.expected
similarity index 100%
rename from python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/ConceptsTest.expected
rename to python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.expected
diff --git a/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.ql
new file mode 100644
index 00000000000..b557a0bccb6
--- /dev/null
+++ b/python/ql/test/library-tests/frameworks/clickhouse_driver/ConceptsTest.ql
@@ -0,0 +1,2 @@
+import python
+import experimental.meta.ConceptsTest
diff --git a/python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py b/python/ql/test/library-tests/frameworks/clickhouse_driver/sql_test.py
similarity index 100%
rename from python/ql/test/experimental/semmle/python/frameworks/clickhouse_driver/sql_test.py
rename to python/ql/test/library-tests/frameworks/clickhouse_driver/sql_test.py
From d6782767b7c289a68baaaf037245047a4ba9d844 Mon Sep 17 00:00:00 2001
From: haby0
Date: Mon, 31 May 2021 11:12:22 +0800
Subject: [PATCH 015/153] Fix typos
---
java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
index fe990179de4..27ababae1d4 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql
@@ -22,9 +22,9 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeDeserializationSink }
- override predicate isAdditionalTaintStep(DataFlow::Node prod, DataFlow::Node succ) {
+ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(ClassInstanceExpr cie |
- cie.getArgument(0) = prod.asExpr() and
+ cie.getArgument(0) = pred.asExpr() and
cie = succ.asExpr() and
(
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader or
@@ -36,7 +36,7 @@ class UnsafeDeserializationConfig extends TaintTracking::Configuration {
or
exists(MethodAccess ma |
ma.getMethod() instanceof BurlapInputInitMethod and
- ma.getArgument(0) = prod.asExpr() and
+ ma.getArgument(0) = pred.asExpr() and
ma.getQualifier() = succ.asExpr()
)
}
From cc497bf213f290280bb7118bd12e158714a084ed Mon Sep 17 00:00:00 2001
From: "lcartey@github.com"
Date: Tue, 16 Jun 2020 11:27:47 +0100
Subject: [PATCH 016/153] Java: Improve JaxRS modelling
- Handle inherited annotations
- Fix `ResponseBuilder` charpred.
- Model `@Produces` annotations.
---
.../src/semmle/code/java/frameworks/JaxWS.qll | 64 ++++++++++++++++++-
1 file changed, 62 insertions(+), 2 deletions(-)
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index 50471d68fbf..5e4999bcd31 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -50,6 +50,27 @@ class JaxRsResourceMethod extends Method {
a.hasName("OPTIONS") or
a.hasName("HEAD")
)
+ or
+ // A JaxRS resource method can also inherit these annotations from a supertype, but only if
+ // there are no JaxRS annotations on the method itself
+ getAnOverride() instanceof JaxRsResourceMethod and
+ not exists(getAnAnnotation().(JaxRSAnnotation))
+ }
+
+ /** Gets an `@Produces` annotation that applies to this method */
+ JaxRSProducesAnnotation getProducesAnnotation() {
+ result = getAnAnnotation()
+ or
+ // No direct annotations
+ not exists(getAnAnnotation().(JaxRSProducesAnnotation)) and
+ (
+ // Annotations on a method we've overridden
+ result = getAnOverride().getAnAnnotation()
+ or
+ // No annotations on this method, or a method we've overridden, so look to the class
+ not exists(getAnOverride().getAnAnnotation().(JaxRSProducesAnnotation)) and
+ result = getDeclaringType().getAnAnnotation()
+ )
}
}
@@ -139,11 +160,21 @@ class JaxRsResourceClass extends Class {
}
}
+/** An annotation from the `javax.ws.rs` package hierarchy. */
+class JaxRSAnnotation extends Annotation {
+ JaxRSAnnotation() {
+ exists(AnnotationType a |
+ a = getType() and
+ a.getPackage().getName().regexpMatch("javax\\.ws\\.rs(\\..*)?")
+ )
+ }
+}
+
/**
* An annotation that is used by JaxRS containers to determine a value to inject into the annotated
* element.
*/
-class JaxRsInjectionAnnotation extends Annotation {
+class JaxRsInjectionAnnotation extends JaxRSAnnotation {
JaxRsInjectionAnnotation() {
exists(AnnotationType a |
a = getType() and
@@ -167,7 +198,7 @@ class JaxRsResponse extends Class {
}
class JaxRsResponseBuilder extends Class {
- JaxRsResponseBuilder() { this.hasQualifiedName("javax.ws.rs.core", "ResponseBuilder") }
+ JaxRsResponseBuilder() { this.hasQualifiedName("javax.ws.rs.core", "Response$ResponseBuilder") }
}
/**
@@ -223,3 +254,32 @@ class MessageBodyReaderRead extends Method {
)
}
}
+
+/** An `@Produces` annotation that describes which MIME types can be produced by this resource. */
+class JaxRSProducesAnnotation extends JaxRSAnnotation {
+ JaxRSProducesAnnotation() {
+ getType().hasQualifiedName("javax.ws.rs", "Produces")
+ }
+
+ /**
+ * Gets a declared MIME type that can be produced by this resource.
+ */
+ string getADeclaredMimeType() {
+ result = getAValue().(CompileTimeConstantExpr).getStringValue() or
+ exists(Field jaxMediaType |
+ // Accesses to static fields on `MediaType` class do not have constant strings in the database
+ // so convert the field name to a mime type string
+ jaxMediaType.getDeclaringType().hasQualifiedName("javax.ws.rs.core", "MediaType") and
+ jaxMediaType.getAnAccess() = getAValue() and
+ // e.g. MediaType.TEXT_PLAIN => text/plain
+ result = jaxMediaType.getName().toLowerCase().replaceAll("_", "/")
+ )
+ }
+}
+
+/** An `@Consumes` annotation that describes MIME types can be consumed by this resource. */
+class JaxRSConsumesAnnotation extends JaxRSAnnotation {
+ JaxRSConsumesAnnotation() {
+ getType().hasQualifiedName("javax.ws.rs", "Consumes")
+ }
+}
From 5f7165efbbf1108820487197d275eb5baad6afec Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Fri, 19 Mar 2021 17:43:11 +0000
Subject: [PATCH 017/153] Add JaxWS XSS sink
Based on https://github.com/lcartey/codeql/commit/d44e4d0e63af44f2683f7175d3114226d7316aa6 by @lcartey
---
java/ql/src/semmle/code/java/frameworks/JaxWS.qll | 11 ++++-------
java/ql/src/semmle/code/java/security/XSS.qll | 11 +++++++++++
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index 5e4999bcd31..a8c1478ed84 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -257,15 +257,14 @@ class MessageBodyReaderRead extends Method {
/** An `@Produces` annotation that describes which MIME types can be produced by this resource. */
class JaxRSProducesAnnotation extends JaxRSAnnotation {
- JaxRSProducesAnnotation() {
- getType().hasQualifiedName("javax.ws.rs", "Produces")
- }
+ JaxRSProducesAnnotation() { getType().hasQualifiedName("javax.ws.rs", "Produces") }
/**
* Gets a declared MIME type that can be produced by this resource.
*/
string getADeclaredMimeType() {
- result = getAValue().(CompileTimeConstantExpr).getStringValue() or
+ result = getAValue().(CompileTimeConstantExpr).getStringValue()
+ or
exists(Field jaxMediaType |
// Accesses to static fields on `MediaType` class do not have constant strings in the database
// so convert the field name to a mime type string
@@ -279,7 +278,5 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
/** An `@Consumes` annotation that describes MIME types can be consumed by this resource. */
class JaxRSConsumesAnnotation extends JaxRSAnnotation {
- JaxRSConsumesAnnotation() {
- getType().hasQualifiedName("javax.ws.rs", "Consumes")
- }
+ JaxRSConsumesAnnotation() { getType().hasQualifiedName("javax.ws.rs", "Consumes") }
}
diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll
index 14f10cad9c8..e0a15753334 100644
--- a/java/ql/src/semmle/code/java/security/XSS.qll
+++ b/java/ql/src/semmle/code/java/security/XSS.qll
@@ -1,6 +1,7 @@
/** Provides classes to reason about Cross-site scripting (XSS) vulnerabilities. */
import java
+import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.Servlets
import semmle.code.java.frameworks.android.WebView
import semmle.code.java.frameworks.spring.SpringController
@@ -93,6 +94,16 @@ private class DefaultXssSink extends XssSink {
returnType instanceof RawClass
)
)
+ or
+ exists(JaxRsResourceMethod resourceMethod, ReturnStmt rs |
+ resourceMethod = any(JaxRsResourceClass resourceClass).getAResourceMethod() and
+ rs.getEnclosingCallable() = resourceMethod and
+ this.asExpr() = rs.getResult()
+ |
+ not exists(resourceMethod.getProducesAnnotation())
+ or
+ resourceMethod.getProducesAnnotation().getADeclaredMimeType() = "text/plain"
+ )
}
}
From 9335e095a92bf3ef83ec094dc884ec8fcea0aac6 Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Fri, 19 Mar 2021 17:44:45 +0000
Subject: [PATCH 018/153] MIME type -> content type
This matches the terminology used elsewhere
---
java/ql/src/semmle/code/java/frameworks/JaxWS.qll | 10 +++++-----
java/ql/src/semmle/code/java/security/XSS.qll | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index a8c1478ed84..330124004c5 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -255,19 +255,19 @@ class MessageBodyReaderRead extends Method {
}
}
-/** An `@Produces` annotation that describes which MIME types can be produced by this resource. */
+/** An `@Produces` annotation that describes which content types can be produced by this resource. */
class JaxRSProducesAnnotation extends JaxRSAnnotation {
JaxRSProducesAnnotation() { getType().hasQualifiedName("javax.ws.rs", "Produces") }
/**
- * Gets a declared MIME type that can be produced by this resource.
+ * Gets a declared content type that can be produced by this resource.
*/
- string getADeclaredMimeType() {
+ string getADeclaredContentType() {
result = getAValue().(CompileTimeConstantExpr).getStringValue()
or
exists(Field jaxMediaType |
// Accesses to static fields on `MediaType` class do not have constant strings in the database
- // so convert the field name to a mime type string
+ // so convert the field name to a content type string
jaxMediaType.getDeclaringType().hasQualifiedName("javax.ws.rs.core", "MediaType") and
jaxMediaType.getAnAccess() = getAValue() and
// e.g. MediaType.TEXT_PLAIN => text/plain
@@ -276,7 +276,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
}
}
-/** An `@Consumes` annotation that describes MIME types can be consumed by this resource. */
+/** An `@Consumes` annotation that describes content types can be consumed by this resource. */
class JaxRSConsumesAnnotation extends JaxRSAnnotation {
JaxRSConsumesAnnotation() { getType().hasQualifiedName("javax.ws.rs", "Consumes") }
}
diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll
index e0a15753334..471dd8a9124 100644
--- a/java/ql/src/semmle/code/java/security/XSS.qll
+++ b/java/ql/src/semmle/code/java/security/XSS.qll
@@ -102,7 +102,7 @@ private class DefaultXssSink extends XssSink {
|
not exists(resourceMethod.getProducesAnnotation())
or
- resourceMethod.getProducesAnnotation().getADeclaredMimeType() = "text/plain"
+ resourceMethod.getProducesAnnotation().getADeclaredContentType() = "text/plain"
)
}
}
From 314980c64cb225c4ae2dc14f39db08a1116ae0c7 Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Mon, 22 Mar 2021 16:46:58 +0000
Subject: [PATCH 019/153] Model taint-propagating methods in the core JAX-WS
library.
---
.../code/java/dataflow/ExternalFlow.qll | 1 +
.../src/semmle/code/java/frameworks/JaxWS.qll | 248 ++++++++++++++++++
2 files changed, 249 insertions(+)
diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
index 8080bd28ab6..71b11b0900b 100644
--- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
+++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
@@ -81,6 +81,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.frameworks.guava.Guava
private import semmle.code.java.frameworks.jackson.JacksonSerializability
+ private import semmle.code.java.frameworks.JaxWS
private import semmle.code.java.security.ResponseSplitting
private import semmle.code.java.security.InformationLeak
private import semmle.code.java.security.XSS
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index 330124004c5..e62bd1ebd48 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -1,4 +1,5 @@
import java
+private import semmle.code.java.dataflow.ExternalFlow
/**
* A JAX WS endpoint is constructed by the container, and its methods
@@ -280,3 +281,250 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
class JaxRSConsumesAnnotation extends JaxRSAnnotation {
JaxRSConsumesAnnotation() { getType().hasQualifiedName("javax.ws.rs", "Consumes") }
}
+
+/**
+ * Model Response:
+ *
+ * - the returned ResponseBuilder gains taint from a tainted entity or existing Response
+ */
+private class ResponseModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Response;false;accepted;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;Response;false;fromResponse;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;Response;false;ok;;;Argument[0];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model ResponseBuilder:
+ *
+ * - becomes tainted by a tainted entity, but not by metadata, headers etc
+ * - build() method returns taint
+ * - almost all methods are fluent, and so preserve value
+ */
+private class ResponseBuilderModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Response$ResponseBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[0];Argument[-1];taint",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;allow;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;cacheControl;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;contentLocation;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;cookie;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;encoding;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;expires;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;header;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;language;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;lastModified;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;link;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;links;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;location;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;replaceAll;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;status;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;tag;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;type;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;variant;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;Response$ResponseBuilder;true;variants;;;Argument[-1];ReturnValue;value"
+ ]
+ }
+}
+
+/**
+ * Model HttpHeaders: methods that Date have to be syntax-checked, but those returning MediaType
+ * or Locale are assumed potentially dangerous, as these types do not generally check that the
+ * input data is recognised, only that it conforms to the expected syntax.
+ */
+private class HttpHeadersModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;HttpHeaders;true;getAcceptableLanguages;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getAcceptableMediaTypes;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getCookies;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getHeaderString;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getLanguage;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getMediaType;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getRequestHeader;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;HttpHeaders;true;getRequestHeaders;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model MultivaluedMap, which extends Map, V> and provides a few extra helper methods.
+ */
+private class MultivaluedMapModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;MultivaluedMap;true;add;;;Argument;Argument[-1];taint",
+ "javax.ws.rs.core;MultivaluedMap;true;addAll;;;Argument;Argument[-1];taint",
+ "javax.ws.rs.core;MultivaluedMap;true;addFirst;;;Argument;Argument[-1];taint",
+ "javax.ws.rs.core;MultivaluedMap;true;getFirst;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument;Argument[-1];taint"
+ ]
+ }
+}
+
+/**
+ * Model PathSegment, which wraps a path and its associated matrix parameters.
+ */
+private class PathSegmentModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;PathSegment;true;getMatrixParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;PathSegment;true;getPath;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model UriInfo, which provides URI element accessors.
+ */
+private class UriInfoModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;UriInfo;true;getPathParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getRequestUri;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriInfo;true;getRequestUriBuilder;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model Cookie, a simple tuple type.
+ */
+private class CookieModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Cookie;true;getDomain;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getName;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getPath;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getValue;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;getVersion;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;true;toString;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Cookie;false;Cookie;;;Argument;Argument[-1];taint",
+ "javax.ws.rs.core;Cookie;false;valueOf;;;Argument;ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model Form, a simple container type.
+ */
+private class FormModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;Form;true;asMap;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;Form;true;param;;;Argument;Argument[-1];taint",
+ "javax.ws.rs.core;Form;true;param;;;Argument[-1];ReturnValue;value"
+ ]
+ }
+}
+
+/**
+ * Model GenericEntity, a wrapper for HTTP entities (e.g., documents).
+ */
+private class GenericEntityModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;GenericEntity;false;GenericEntity;;;Argument[0];Argument[-1];taint",
+ "javax.ws.rs.core;GenericEntity;true;getEntity;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model MediaType, which provides accessors for elements of Content-Type and similar
+ * media type specifications.
+ */
+private class MediaTypeModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;MediaType;false;MediaType;;;Argument;Argument[-1];taint",
+ "javax.ws.rs.core;MediaType;true;getParameters;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;true;getSubtype;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;true;getType;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;false;valueOf;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;MediaType;true;withCharset;;;Argument[-1];ReturnValue;taint"
+ ]
+ }
+}
+
+/**
+ * Model UriBuilder, which provides a fluent interface to build a URI from components.
+ */
+private class UriBuilderModel extends SummaryModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ "javax.ws.rs.core;UriBuilder;true;build;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncoded;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncoded;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromMap;;;Argument[0];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;buildFromMap;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;fragment;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;fragment;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;false;fromLink;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;false;fromPath;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;false;fromUri;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;host;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;host;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;matrixParam;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;matrixParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;path;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;path;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;queryParam;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;queryParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replacePath;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replacePath;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplates;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplates;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;scheme;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;scheme;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;segment;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;segment;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;toTemplate;;;Argument[-1];ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;uri;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;uri;;;Argument[-1];ReturnValue;value",
+ "javax.ws.rs.core;UriBuilder;true;userInfo;;;Argument;ReturnValue;taint",
+ "javax.ws.rs.core;UriBuilder;true;userInfo;;;Argument[-1];ReturnValue;value"
+ ]
+ }
+}
From 260a2283673dcada2fe89650b4801c1c3f66019f Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Mon, 22 Mar 2021 16:53:31 +0000
Subject: [PATCH 020/153] Add change note
---
java/change-notes/2021-03-22-jax-ws-improvements.md | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 java/change-notes/2021-03-22-jax-ws-improvements.md
diff --git a/java/change-notes/2021-03-22-jax-ws-improvements.md b/java/change-notes/2021-03-22-jax-ws-improvements.md
new file mode 100644
index 00000000000..2fbd33fa109
--- /dev/null
+++ b/java/change-notes/2021-03-22-jax-ws-improvements.md
@@ -0,0 +1,2 @@
+lgtm,codescanning
+* Added support for detecting XSS via JAX-WS sinks, and propagating tainted data via various container types (e.g. Form, Cookie, MultivaluedMap).
From adb5764aacd999f7743bdb48239500c0662bca27 Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Tue, 23 Mar 2021 11:25:32 +0000
Subject: [PATCH 021/153] Add URL redirect sinks relating to JAX-WS
---
.../src/semmle/code/java/security/UrlRedirect.qll | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
index d2be51d2fae..e42738c4efc 100644
--- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll
+++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
@@ -35,3 +35,17 @@ private class ApacheUrlRedirectSink extends UrlRedirectSink {
)
}
}
+
+/** A URL redirection sink from JAX-WS */
+private class JaxWsUrlRedirectSink extends UrlRedirectSink {
+ JaxWsUrlRedirectSink() {
+ exists(MethodAccess ma |
+ ma.getMethod()
+ .getDeclaringType()
+ .getAnAncestor()
+ .hasQualifiedName("javax.ws.rs.core", "Response") and
+ ma.getMethod().getName() in ["seeOther", "temporaryRedirect"] and
+ this.asExpr() = ma.getArgument(0)
+ )
+ }
+}
From ca684bea0ea4d1f6ccf98e26ebc8ecb5ac08509f Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Tue, 23 Mar 2021 11:49:29 +0000
Subject: [PATCH 022/153] Jax-WS: support jakarta.ws.rs package everywhere
Releases since Java EE 9 use this.
---
.../src/semmle/code/java/frameworks/JaxWS.qll | 170 +++++++++++++++---
.../semmle/code/java/security/UrlRedirect.qll | 3 +-
2 files changed, 149 insertions(+), 24 deletions(-)
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index e62bd1ebd48..a131cdc41bc 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -1,6 +1,11 @@
import java
private import semmle.code.java.dataflow.ExternalFlow
+string getAJaxWsPackage() { result in ["javax.ws.rs", "jakarta.ws.rs"] }
+
+bindingset[subpackage]
+string getAJaxWsPackage(string subpackage) { result = getAJaxWsPackage() + "." + subpackage }
+
/**
* A JAX WS endpoint is constructed by the container, and its methods
* are -- where annotated -- called remotely.
@@ -29,7 +34,7 @@ class JaxWsEndpoint extends Class {
private predicate hasPathAnnotation(Annotatable annotatable) {
exists(AnnotationType a |
a = annotatable.getAnAnnotation().getType() and
- a.getPackage().getName() = "javax.ws.rs"
+ a.getPackage().getName() = getAJaxWsPackage()
|
a.hasName("Path")
)
@@ -42,7 +47,7 @@ class JaxRsResourceMethod extends Method {
JaxRsResourceMethod() {
exists(AnnotationType a |
a = this.getAnAnnotation().getType() and
- a.getPackage().getName() = "javax.ws.rs"
+ a.getPackage().getName() = getAJaxWsPackage()
|
a.hasName("GET") or
a.hasName("POST") or
@@ -179,7 +184,7 @@ class JaxRsInjectionAnnotation extends JaxRSAnnotation {
JaxRsInjectionAnnotation() {
exists(AnnotationType a |
a = getType() and
- a.getPackage().getName() = "javax.ws.rs"
+ a.getPackage().getName() = getAJaxWsPackage()
|
a.hasName("BeanParam") or
a.hasName("CookieParam") or
@@ -190,23 +195,25 @@ class JaxRsInjectionAnnotation extends JaxRSAnnotation {
a.hasName("QueryParam")
)
or
- getType().hasQualifiedName("javax.ws.rs.core", "Context")
+ getType().hasQualifiedName(getAJaxWsPackage("core"), "Context")
}
}
class JaxRsResponse extends Class {
- JaxRsResponse() { this.hasQualifiedName("javax.ws.rs.core", "Response") }
+ JaxRsResponse() { this.hasQualifiedName(getAJaxWsPackage("core"), "Response") }
}
class JaxRsResponseBuilder extends Class {
- JaxRsResponseBuilder() { this.hasQualifiedName("javax.ws.rs.core", "Response$ResponseBuilder") }
+ JaxRsResponseBuilder() {
+ this.hasQualifiedName(getAJaxWsPackage("core"), "Response$ResponseBuilder")
+ }
}
/**
* The class `javax.ws.rs.client.Client`.
*/
class JaxRsClient extends RefType {
- JaxRsClient() { this.hasQualifiedName("javax.ws.rs.client", "Client") }
+ JaxRsClient() { this.hasQualifiedName(getAJaxWsPackage("client"), "Client") }
}
/**
@@ -219,7 +226,7 @@ class JaxRsBeanParamConstructor extends Constructor {
c = resourceClass.getAnInjectableCallable()
|
p = c.getAParameter() and
- p.getAnAnnotation().getType().hasQualifiedName("javax.ws.rs", "BeanParam") and
+ p.getAnAnnotation().getType().hasQualifiedName(getAJaxWsPackage(), "BeanParam") and
this.getDeclaringType().getSourceDeclaration() = p.getType().(RefType).getSourceDeclaration()
) and
forall(Parameter p | p = getAParameter() |
@@ -232,7 +239,7 @@ class JaxRsBeanParamConstructor extends Constructor {
* The class `javax.ws.rs.ext.MessageBodyReader`.
*/
class MessageBodyReader extends GenericInterface {
- MessageBodyReader() { this.hasQualifiedName("javax.ws.rs.ext", "MessageBodyReader") }
+ MessageBodyReader() { this.hasQualifiedName(getAJaxWsPackage("ext"), "MessageBodyReader") }
}
/**
@@ -258,7 +265,7 @@ class MessageBodyReaderRead extends Method {
/** An `@Produces` annotation that describes which content types can be produced by this resource. */
class JaxRSProducesAnnotation extends JaxRSAnnotation {
- JaxRSProducesAnnotation() { getType().hasQualifiedName("javax.ws.rs", "Produces") }
+ JaxRSProducesAnnotation() { getType().hasQualifiedName(getAJaxWsPackage(), "Produces") }
/**
* Gets a declared content type that can be produced by this resource.
@@ -269,7 +276,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
exists(Field jaxMediaType |
// Accesses to static fields on `MediaType` class do not have constant strings in the database
// so convert the field name to a content type string
- jaxMediaType.getDeclaringType().hasQualifiedName("javax.ws.rs.core", "MediaType") and
+ jaxMediaType.getDeclaringType().hasQualifiedName(getAJaxWsPackage("core"), "MediaType") and
jaxMediaType.getAnAccess() = getAValue() and
// e.g. MediaType.TEXT_PLAIN => text/plain
result = jaxMediaType.getName().toLowerCase().replaceAll("_", "/")
@@ -279,7 +286,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
/** An `@Consumes` annotation that describes content types can be consumed by this resource. */
class JaxRSConsumesAnnotation extends JaxRSAnnotation {
- JaxRSConsumesAnnotation() { getType().hasQualifiedName("javax.ws.rs", "Consumes") }
+ JaxRSConsumesAnnotation() { getType().hasQualifiedName(getAJaxWsPackage(), "Consumes") }
}
/**
@@ -293,7 +300,10 @@ private class ResponseModel extends SummaryModelCsv {
[
"javax.ws.rs.core;Response;false;accepted;;;Argument[0];ReturnValue;taint",
"javax.ws.rs.core;Response;false;fromResponse;;;Argument[0];ReturnValue;taint",
- "javax.ws.rs.core;Response;false;ok;;;Argument[0];ReturnValue;taint"
+ "javax.ws.rs.core;Response;false;ok;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response;false;accepted;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response;false;fromResponse;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response;false;ok;;;Argument[0];ReturnValue;taint"
]
}
}
@@ -330,7 +340,29 @@ private class ResponseBuilderModel extends SummaryModelCsv {
"javax.ws.rs.core;Response$ResponseBuilder;true;tag;;;Argument[-1];ReturnValue;value",
"javax.ws.rs.core;Response$ResponseBuilder;true;type;;;Argument[-1];ReturnValue;value",
"javax.ws.rs.core;Response$ResponseBuilder;true;variant;;;Argument[-1];ReturnValue;value",
- "javax.ws.rs.core;Response$ResponseBuilder;true;variants;;;Argument[-1];ReturnValue;value"
+ "javax.ws.rs.core;Response$ResponseBuilder;true;variants;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[0];Argument[-1];taint",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;allow;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;cacheControl;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;contentLocation;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;cookie;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;encoding;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;entity;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;expires;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;header;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;language;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;lastModified;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;link;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;links;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;location;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;replaceAll;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;status;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;tag;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;type;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;variant;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Response$ResponseBuilder;true;variants;;;Argument[-1];ReturnValue;value"
]
}
}
@@ -351,7 +383,15 @@ private class HttpHeadersModel extends SummaryModelCsv {
"javax.ws.rs.core;HttpHeaders;true;getLanguage;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;HttpHeaders;true;getMediaType;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;HttpHeaders;true;getRequestHeader;;;Argument[-1];ReturnValue;taint",
- "javax.ws.rs.core;HttpHeaders;true;getRequestHeaders;;;Argument[-1];ReturnValue;taint"
+ "javax.ws.rs.core;HttpHeaders;true;getRequestHeaders;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getAcceptableLanguages;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getAcceptableMediaTypes;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getCookies;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getHeaderString;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getLanguage;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getMediaType;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getRequestHeader;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;HttpHeaders;true;getRequestHeaders;;;Argument[-1];ReturnValue;taint"
]
}
}
@@ -367,7 +407,12 @@ private class MultivaluedMapModel extends SummaryModelCsv {
"javax.ws.rs.core;MultivaluedMap;true;addAll;;;Argument;Argument[-1];taint",
"javax.ws.rs.core;MultivaluedMap;true;addFirst;;;Argument;Argument[-1];taint",
"javax.ws.rs.core;MultivaluedMap;true;getFirst;;;Argument[-1];ReturnValue;taint",
- "javax.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument;Argument[-1];taint"
+ "javax.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument;Argument[-1];taint",
+ "jakarta.ws.rs.core;MultivaluedMap;true;add;;;Argument;Argument[-1];taint",
+ "jakarta.ws.rs.core;MultivaluedMap;true;addAll;;;Argument;Argument[-1];taint",
+ "jakarta.ws.rs.core;MultivaluedMap;true;addFirst;;;Argument;Argument[-1];taint",
+ "jakarta.ws.rs.core;MultivaluedMap;true;getFirst;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MultivaluedMap;true;putSingle;;;Argument;Argument[-1];taint"
]
}
}
@@ -380,7 +425,9 @@ private class PathSegmentModel extends SummaryModelCsv {
row =
[
"javax.ws.rs.core;PathSegment;true;getMatrixParameters;;;Argument[-1];ReturnValue;taint",
- "javax.ws.rs.core;PathSegment;true;getPath;;;Argument[-1];ReturnValue;taint"
+ "javax.ws.rs.core;PathSegment;true;getPath;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;PathSegment;true;getMatrixParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;PathSegment;true;getPath;;;Argument[-1];ReturnValue;taint"
]
}
}
@@ -396,7 +443,12 @@ private class UriInfoModel extends SummaryModelCsv {
"javax.ws.rs.core;UriInfo;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getRequestUri;;;Argument[-1];ReturnValue;taint",
- "javax.ws.rs.core;UriInfo;true;getRequestUriBuilder;;;Argument[-1];ReturnValue;taint"
+ "javax.ws.rs.core;UriInfo;true;getRequestUriBuilder;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getPathParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getRequestUri;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriInfo;true;getRequestUriBuilder;;;Argument[-1];ReturnValue;taint"
]
}
}
@@ -415,7 +467,15 @@ private class CookieModel extends SummaryModelCsv {
"javax.ws.rs.core;Cookie;true;getVersion;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;Cookie;true;toString;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;Cookie;false;Cookie;;;Argument;Argument[-1];taint",
- "javax.ws.rs.core;Cookie;false;valueOf;;;Argument;ReturnValue;taint"
+ "javax.ws.rs.core;Cookie;false;valueOf;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getDomain;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getName;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getPath;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getValue;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;getVersion;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;true;toString;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Cookie;false;Cookie;;;Argument;Argument[-1];taint",
+ "jakarta.ws.rs.core;Cookie;false;valueOf;;;Argument;ReturnValue;taint"
]
}
}
@@ -429,7 +489,10 @@ private class FormModel extends SummaryModelCsv {
[
"javax.ws.rs.core;Form;true;asMap;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;Form;true;param;;;Argument;Argument[-1];taint",
- "javax.ws.rs.core;Form;true;param;;;Argument[-1];ReturnValue;value"
+ "javax.ws.rs.core;Form;true;param;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;Form;true;asMap;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;Form;true;param;;;Argument;Argument[-1];taint",
+ "jakarta.ws.rs.core;Form;true;param;;;Argument[-1];ReturnValue;value"
]
}
}
@@ -442,7 +505,9 @@ private class GenericEntityModel extends SummaryModelCsv {
row =
[
"javax.ws.rs.core;GenericEntity;false;GenericEntity;;;Argument[0];Argument[-1];taint",
- "javax.ws.rs.core;GenericEntity;true;getEntity;;;Argument[-1];ReturnValue;taint"
+ "javax.ws.rs.core;GenericEntity;true;getEntity;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;GenericEntity;false;GenericEntity;;;Argument[0];Argument[-1];taint",
+ "jakarta.ws.rs.core;GenericEntity;true;getEntity;;;Argument[-1];ReturnValue;taint"
]
}
}
@@ -460,7 +525,13 @@ private class MediaTypeModel extends SummaryModelCsv {
"javax.ws.rs.core;MediaType;true;getSubtype;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;MediaType;true;getType;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;MediaType;false;valueOf;;;Argument;ReturnValue;taint",
- "javax.ws.rs.core;MediaType;true;withCharset;;;Argument[-1];ReturnValue;taint"
+ "javax.ws.rs.core;MediaType;true;withCharset;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;false;MediaType;;;Argument;Argument[-1];taint",
+ "jakarta.ws.rs.core;MediaType;true;getParameters;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;true;getSubtype;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;true;getType;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;false;valueOf;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;MediaType;true;withCharset;;;Argument[-1];ReturnValue;taint"
]
}
}
@@ -524,7 +595,60 @@ private class UriBuilderModel extends SummaryModelCsv {
"javax.ws.rs.core;UriBuilder;true;uri;;;Argument;ReturnValue;taint",
"javax.ws.rs.core;UriBuilder;true;uri;;;Argument[-1];ReturnValue;value",
"javax.ws.rs.core;UriBuilder;true;userInfo;;;Argument;ReturnValue;taint",
- "javax.ws.rs.core;UriBuilder;true;userInfo;;;Argument[-1];ReturnValue;value"
+ "javax.ws.rs.core;UriBuilder;true;userInfo;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;build;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;build;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncoded;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncoded;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromEncodedMap;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromMap;;;Argument[0];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;buildFromMap;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;clone;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;fragment;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;fragment;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;false;fromLink;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;false;fromPath;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;false;fromUri;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;host;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;host;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;matrixParam;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;matrixParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;path;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;path;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;queryParam;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;queryParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrix;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceMatrixParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replacePath;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replacePath;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQuery;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;replaceQueryParam;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplate;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplateFromEncoded;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplates;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplates;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;resolveTemplatesFromEncoded;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;scheme;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;scheme;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;segment;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;segment;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;schemeSpecificPart;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;toTemplate;;;Argument[-1];ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;uri;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;uri;;;Argument[-1];ReturnValue;value",
+ "jakarta.ws.rs.core;UriBuilder;true;userInfo;;;Argument;ReturnValue;taint",
+ "jakarta.ws.rs.core;UriBuilder;true;userInfo;;;Argument[-1];ReturnValue;value"
]
}
}
diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
index e42738c4efc..8c7ce5112c7 100644
--- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll
+++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
@@ -4,6 +4,7 @@ import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.frameworks.Servlets
import semmle.code.java.frameworks.ApacheHttp
+private import semmle.code.java.frameworks.JaxWS
/** A URL redirection sink */
abstract class UrlRedirectSink extends DataFlow::Node { }
@@ -43,7 +44,7 @@ private class JaxWsUrlRedirectSink extends UrlRedirectSink {
ma.getMethod()
.getDeclaringType()
.getAnAncestor()
- .hasQualifiedName("javax.ws.rs.core", "Response") and
+ .hasQualifiedName(getAJaxWsPackage("core"), "Response") and
ma.getMethod().getName() in ["seeOther", "temporaryRedirect"] and
this.asExpr() = ma.getArgument(0)
)
From f71897d1667ac29fc42bce308ac656d928dc9b42 Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Tue, 6 Apr 2021 11:19:55 +0100
Subject: [PATCH 023/153] Rename JAX-WS -> JAX-RS where necessary. Improve
change note and fix missing QLDoc.
---
...s.md => 2021-03-22-jax-rs-improvements.md} | 2 +-
.../src/semmle/code/java/frameworks/JaxWS.qll | 34 +++++++++++--------
.../semmle/code/java/security/UrlRedirect.qll | 8 ++---
3 files changed, 25 insertions(+), 19 deletions(-)
rename java/change-notes/{2021-03-22-jax-ws-improvements.md => 2021-03-22-jax-rs-improvements.md} (60%)
diff --git a/java/change-notes/2021-03-22-jax-ws-improvements.md b/java/change-notes/2021-03-22-jax-rs-improvements.md
similarity index 60%
rename from java/change-notes/2021-03-22-jax-ws-improvements.md
rename to java/change-notes/2021-03-22-jax-rs-improvements.md
index 2fbd33fa109..0fe567fab89 100644
--- a/java/change-notes/2021-03-22-jax-ws-improvements.md
+++ b/java/change-notes/2021-03-22-jax-rs-improvements.md
@@ -1,2 +1,2 @@
lgtm,codescanning
-* Added support for detecting XSS via JAX-WS sinks, and propagating tainted data via various container types (e.g. Form, Cookie, MultivaluedMap).
+* Added support for detecting XSS via JAX-RS sinks, and propagating tainted data via various container types (e.g. Form, Cookie, MultivaluedMap).
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index a131cdc41bc..b45ad93e59f 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -1,10 +1,16 @@
import java
private import semmle.code.java.dataflow.ExternalFlow
-string getAJaxWsPackage() { result in ["javax.ws.rs", "jakarta.ws.rs"] }
+/**
+ * Gets a name for the root package of JAX-RS.
+ */
+string getAJaxRsPackage() { result in ["javax.ws.rs", "jakarta.ws.rs"] }
+/**
+ * Gets a name for package `subpackage` within the JAX-RS hierarchy.
+ */
bindingset[subpackage]
-string getAJaxWsPackage(string subpackage) { result = getAJaxWsPackage() + "." + subpackage }
+string getAJaxRsPackage(string subpackage) { result = getAJaxRsPackage() + "." + subpackage }
/**
* A JAX WS endpoint is constructed by the container, and its methods
@@ -34,7 +40,7 @@ class JaxWsEndpoint extends Class {
private predicate hasPathAnnotation(Annotatable annotatable) {
exists(AnnotationType a |
a = annotatable.getAnAnnotation().getType() and
- a.getPackage().getName() = getAJaxWsPackage()
+ a.getPackage().getName() = getAJaxRsPackage()
|
a.hasName("Path")
)
@@ -47,7 +53,7 @@ class JaxRsResourceMethod extends Method {
JaxRsResourceMethod() {
exists(AnnotationType a |
a = this.getAnAnnotation().getType() and
- a.getPackage().getName() = getAJaxWsPackage()
+ a.getPackage().getName() = getAJaxRsPackage()
|
a.hasName("GET") or
a.hasName("POST") or
@@ -184,7 +190,7 @@ class JaxRsInjectionAnnotation extends JaxRSAnnotation {
JaxRsInjectionAnnotation() {
exists(AnnotationType a |
a = getType() and
- a.getPackage().getName() = getAJaxWsPackage()
+ a.getPackage().getName() = getAJaxRsPackage()
|
a.hasName("BeanParam") or
a.hasName("CookieParam") or
@@ -195,17 +201,17 @@ class JaxRsInjectionAnnotation extends JaxRSAnnotation {
a.hasName("QueryParam")
)
or
- getType().hasQualifiedName(getAJaxWsPackage("core"), "Context")
+ getType().hasQualifiedName(getAJaxRsPackage("core"), "Context")
}
}
class JaxRsResponse extends Class {
- JaxRsResponse() { this.hasQualifiedName(getAJaxWsPackage("core"), "Response") }
+ JaxRsResponse() { this.hasQualifiedName(getAJaxRsPackage("core"), "Response") }
}
class JaxRsResponseBuilder extends Class {
JaxRsResponseBuilder() {
- this.hasQualifiedName(getAJaxWsPackage("core"), "Response$ResponseBuilder")
+ this.hasQualifiedName(getAJaxRsPackage("core"), "Response$ResponseBuilder")
}
}
@@ -213,7 +219,7 @@ class JaxRsResponseBuilder extends Class {
* The class `javax.ws.rs.client.Client`.
*/
class JaxRsClient extends RefType {
- JaxRsClient() { this.hasQualifiedName(getAJaxWsPackage("client"), "Client") }
+ JaxRsClient() { this.hasQualifiedName(getAJaxRsPackage("client"), "Client") }
}
/**
@@ -226,7 +232,7 @@ class JaxRsBeanParamConstructor extends Constructor {
c = resourceClass.getAnInjectableCallable()
|
p = c.getAParameter() and
- p.getAnAnnotation().getType().hasQualifiedName(getAJaxWsPackage(), "BeanParam") and
+ p.getAnAnnotation().getType().hasQualifiedName(getAJaxRsPackage(), "BeanParam") and
this.getDeclaringType().getSourceDeclaration() = p.getType().(RefType).getSourceDeclaration()
) and
forall(Parameter p | p = getAParameter() |
@@ -239,7 +245,7 @@ class JaxRsBeanParamConstructor extends Constructor {
* The class `javax.ws.rs.ext.MessageBodyReader`.
*/
class MessageBodyReader extends GenericInterface {
- MessageBodyReader() { this.hasQualifiedName(getAJaxWsPackage("ext"), "MessageBodyReader") }
+ MessageBodyReader() { this.hasQualifiedName(getAJaxRsPackage("ext"), "MessageBodyReader") }
}
/**
@@ -265,7 +271,7 @@ class MessageBodyReaderRead extends Method {
/** An `@Produces` annotation that describes which content types can be produced by this resource. */
class JaxRSProducesAnnotation extends JaxRSAnnotation {
- JaxRSProducesAnnotation() { getType().hasQualifiedName(getAJaxWsPackage(), "Produces") }
+ JaxRSProducesAnnotation() { getType().hasQualifiedName(getAJaxRsPackage(), "Produces") }
/**
* Gets a declared content type that can be produced by this resource.
@@ -276,7 +282,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
exists(Field jaxMediaType |
// Accesses to static fields on `MediaType` class do not have constant strings in the database
// so convert the field name to a content type string
- jaxMediaType.getDeclaringType().hasQualifiedName(getAJaxWsPackage("core"), "MediaType") and
+ jaxMediaType.getDeclaringType().hasQualifiedName(getAJaxRsPackage("core"), "MediaType") and
jaxMediaType.getAnAccess() = getAValue() and
// e.g. MediaType.TEXT_PLAIN => text/plain
result = jaxMediaType.getName().toLowerCase().replaceAll("_", "/")
@@ -286,7 +292,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
/** An `@Consumes` annotation that describes content types can be consumed by this resource. */
class JaxRSConsumesAnnotation extends JaxRSAnnotation {
- JaxRSConsumesAnnotation() { getType().hasQualifiedName(getAJaxWsPackage(), "Consumes") }
+ JaxRSConsumesAnnotation() { getType().hasQualifiedName(getAJaxRsPackage(), "Consumes") }
}
/**
diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
index 8c7ce5112c7..ee3e9cb9b1c 100644
--- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll
+++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll
@@ -37,14 +37,14 @@ private class ApacheUrlRedirectSink extends UrlRedirectSink {
}
}
-/** A URL redirection sink from JAX-WS */
-private class JaxWsUrlRedirectSink extends UrlRedirectSink {
- JaxWsUrlRedirectSink() {
+/** A URL redirection sink from JAX-RS */
+private class JaxRsUrlRedirectSink extends UrlRedirectSink {
+ JaxRsUrlRedirectSink() {
exists(MethodAccess ma |
ma.getMethod()
.getDeclaringType()
.getAnAncestor()
- .hasQualifiedName(getAJaxWsPackage("core"), "Response") and
+ .hasQualifiedName(getAJaxRsPackage("core"), "Response") and
ma.getMethod().getName() in ["seeOther", "temporaryRedirect"] and
this.asExpr() = ma.getArgument(0)
)
From 55d584b0445f04bf6510fa1d79d83d6b9d562e0b Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Wed, 7 Apr 2021 10:55:46 +0100
Subject: [PATCH 024/153] Add doc comment for JaxWS file
---
java/ql/src/semmle/code/java/frameworks/JaxWS.qll | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index b45ad93e59f..4c2627f85f8 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -1,3 +1,8 @@
+/**
+ * Definitions relating to JAX-WS (Java/Jakarta API for XML Web Services) and JAX-RS
+ * (Java/Jakarta API for RESTful Web Services).
+ */
+
import java
private import semmle.code.java.dataflow.ExternalFlow
From d9cf1aaf391a9ce48e175c7aa2e95534071cb79f Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Thu, 18 Mar 2021 11:18:52 +0000
Subject: [PATCH 025/153] Add stubs for JAX-WS
---
.../code/java/frameworks/JavaxAnnotations.qll | 7 +
java/ql/test/stubs/jaxws-api-2.0/LICENSE.md | 761 ++++++++++++++++++
.../javax/xml/ws/WebEndpoint.java | 73 ++
.../javax/xml/ws/WebServiceClient.java | 84 ++
.../javax/xml/ws/WebServiceProvider.java | 85 ++
java/ql/test/stubs/jsr181-api/LICENSE | 759 +++++++++++++++++
.../stubs/jsr181-api/javax/jws/WebMethod.java | 48 ++
.../jsr181-api/javax/jws/WebService.java | 97 +++
8 files changed, 1914 insertions(+)
create mode 100644 java/ql/test/stubs/jaxws-api-2.0/LICENSE.md
create mode 100644 java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebEndpoint.java
create mode 100644 java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceClient.java
create mode 100644 java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceProvider.java
create mode 100644 java/ql/test/stubs/jsr181-api/LICENSE
create mode 100644 java/ql/test/stubs/jsr181-api/javax/jws/WebMethod.java
create mode 100644 java/ql/test/stubs/jsr181-api/javax/jws/WebService.java
diff --git a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll
index 833db9a9e44..0f5da6c39ea 100644
--- a/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JavaxAnnotations.qll
@@ -137,6 +137,13 @@ class InterceptorsAnnotation extends Annotation {
* Annotations in the package `javax.jws`.
*/
+/**
+ * A `@javax.jws.WebMethod` annotation.
+ */
+class WebMethodAnnotation extends Annotation {
+ WebMethodAnnotation() { this.getType().hasQualifiedName("javax.jws", "WebMethod") }
+}
+
/**
* A `@javax.jws.WebService` annotation.
*/
diff --git a/java/ql/test/stubs/jaxws-api-2.0/LICENSE.md b/java/ql/test/stubs/jaxws-api-2.0/LICENSE.md
new file mode 100644
index 00000000000..1c4d55ea74f
--- /dev/null
+++ b/java/ql/test/stubs/jaxws-api-2.0/LICENSE.md
@@ -0,0 +1,761 @@
+---
+---
+
+## COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
+
+ 1. Definitions.
+
+ 1.1. "Contributor" means each individual or entity that creates or
+ contributes to the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Software, prior Modifications used by a Contributor (if any), and
+ the Modifications made by that particular Contributor.
+
+ 1.3. "Covered Software" means (a) the Original Software, or (b)
+ Modifications, or (c) the combination of files containing Original
+ Software with files containing Modifications, in each case including
+ portions thereof.
+
+ 1.4. "Executable" means the Covered Software in any form other than
+ Source Code.
+
+ 1.5. "Initial Developer" means the individual or entity that first
+ makes Original Software available under this License.
+
+ 1.6. "Larger Work" means a work which combines Covered Software or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.7. "License" means this document.
+
+ 1.8. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means the Source Code and Executable form of
+ any of the following:
+
+ A. Any file that results from an addition to, deletion from or
+ modification of the contents of a file containing Original Software
+ or previous Modifications;
+
+ B. Any new file that contains any part of the Original Software or
+ previous Modification; or
+
+ C. Any new file that is contributed or otherwise made available
+ under the terms of this License.
+
+ 1.10. "Original Software" means the Source Code and Executable form
+ of computer software code that is originally released under this
+ License.
+
+ 1.11. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.12. "Source Code" means (a) the common form of computer software
+ code in which modifications are made and (b) associated
+ documentation included in or with such code.
+
+ 1.13. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of,
+ this License. For legal entities, "You" includes any entity which
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+ 2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and subject
+ to third party intellectual property claims, the Initial Developer
+ hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer, to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Software (or portions thereof), with or without Modifications,
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using or selling of
+ Original Software, to make, have made, use, practice, sell, and
+ offer for sale, and/or otherwise dispose of the Original Software
+ (or portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b) are effective on
+ the date Initial Developer first distributes or otherwise makes the
+ Original Software available to a third party under the terms of this
+ License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: (1) for code that You delete from the Original Software, or
+ (2) for infringements caused by: (i) the modification of the
+ Original Software, or (ii) the combination of the Original Software
+ with other software or devices.
+
+ 2.2. Contributor Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and subject
+ to third party intellectual property claims, each Contributor hereby
+ grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof), either on an
+ unmodified basis, with other Modifications, as Covered Software
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or selling
+ of Modifications made by that Contributor either alone and/or in
+ combination with its Contributor Version (or portions of such
+ combination), to make, use, sell, offer for sale, have made, and/or
+ otherwise dispose of: (1) Modifications made by that Contributor (or
+ portions thereof); and (2) the combination of Modifications made by
+ that Contributor with its Contributor Version (or portions of such
+ combination).
+
+ (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective
+ on the date Contributor first distributes or otherwise makes the
+ Modifications available to a third party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: (1) for any code that Contributor has deleted from the
+ Contributor Version; (2) for infringements caused by: (i) third
+ party modifications of Contributor Version, or (ii) the combination
+ of Modifications made by that Contributor with other software
+ (except as part of the Contributor Version) or other devices; or (3)
+ under Patent Claims infringed by Covered Software in the absence of
+ Modifications made by that Contributor.
+
+ 3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+
+ Any Covered Software that You distribute or otherwise make available
+ in Executable form must also be made available in Source Code form
+ and that Source Code form must be distributed only under the terms
+ of this License. You must include a copy of this License with every
+ copy of the Source Code form of the Covered Software You distribute
+ or otherwise make available. You must inform recipients of any such
+ Covered Software in Executable form as to how they can obtain such
+ Covered Software in Source Code form in a reasonable manner on or
+ through a medium customarily used for software exchange.
+
+ 3.2. Modifications.
+
+ The Modifications that You create or to which You contribute are
+ governed by the terms of this License. You represent that You
+ believe Your Modifications are Your original creation(s) and/or You
+ have sufficient rights to grant the rights conveyed by this License.
+
+ 3.3. Required Notices.
+
+ You must include a notice in each of Your Modifications that
+ identifies You as the Contributor of the Modification. You may not
+ remove or alter any copyright, patent or trademark notices contained
+ within the Covered Software, or any notices of licensing or any
+ descriptive text giving attribution to any Contributor or the
+ Initial Developer.
+
+ 3.4. Application of Additional Terms.
+
+ You may not offer or impose any terms on any Covered Software in
+ Source Code form that alters or restricts the applicable version of
+ this License or the recipients' rights hereunder. You may choose to
+ offer, and to charge a fee for, warranty, support, indemnity or
+ liability obligations to one or more recipients of Covered Software.
+ However, you may do so only on Your own behalf, and not on behalf of
+ the Initial Developer or any Contributor. You must make it
+ absolutely clear that any such warranty, support, indemnity or
+ liability obligation is offered by You alone, and You hereby agree
+ to indemnify the Initial Developer and every Contributor for any
+ liability incurred by the Initial Developer or such Contributor as a
+ result of warranty, support, indemnity or liability terms You offer.
+
+ 3.5. Distribution of Executable Versions.
+
+ You may distribute the Executable form of the Covered Software under
+ the terms of this License or under the terms of a license of Your
+ choice, which may contain terms different from this License,
+ provided that You are in compliance with the terms of this License
+ and that the license for the Executable form does not attempt to
+ limit or alter the recipient's rights in the Source Code form from
+ the rights set forth in this License. If You distribute the Covered
+ Software in Executable form under a different license, You must make
+ it absolutely clear that any terms which differ from this License
+ are offered by You alone, not by the Initial Developer or
+ Contributor. You hereby agree to indemnify the Initial Developer and
+ every Contributor for any liability incurred by the Initial
+ Developer or such Contributor as a result of any such terms You offer.
+
+ 3.6. Larger Works.
+
+ You may create a Larger Work by combining Covered Software with
+ other code not governed by the terms of this License and distribute
+ the Larger Work as a single product. In such a case, You must make
+ sure the requirements of this License are fulfilled for the Covered
+ Software.
+
+ 4. Versions of the License.
+
+ 4.1. New Versions.
+
+ Oracle is the initial license steward and may publish revised and/or
+ new versions of this License from time to time. Each version will be
+ given a distinguishing version number. Except as provided in Section
+ 4.3, no one other than the license steward has the right to modify
+ this License.
+
+ 4.2. Effect of New Versions.
+
+ You may always continue to use, distribute or otherwise make the
+ Covered Software available under the terms of the version of the
+ License under which You originally received the Covered Software. If
+ the Initial Developer includes a notice in the Original Software
+ prohibiting it from being distributed or otherwise made available
+ under any subsequent version of the License, You must distribute and
+ make the Covered Software available under the terms of the version
+ of the License under which You originally received the Covered
+ Software. Otherwise, You may also choose to use, distribute or
+ otherwise make the Covered Software available under the terms of any
+ subsequent version of the License published by the license steward.
+
+ 4.3. Modified Versions.
+
+ When You are an Initial Developer and You want to create a new
+ license for Your Original Software, You may create and use a
+ modified version of this License if You: (a) rename the license and
+ remove any references to the name of the license steward (except to
+ note that the license differs from this License); and (b) otherwise
+ make it clear that the license contains terms which differ from this
+ License.
+
+ 5. DISCLAIMER OF WARRANTY.
+
+ COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE
+ IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
+ NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF
+ THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE
+ DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY
+ OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING,
+ REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
+ ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS
+ AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+ 6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to
+ cure such breach within 30 days of becoming aware of the breach.
+ Provisions which, by their nature, must remain in effect beyond the
+ termination of this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding
+ declaratory judgment actions) against Initial Developer or a
+ Contributor (the Initial Developer or Contributor against whom You
+ assert such claim is referred to as "Participant") alleging that the
+ Participant Software (meaning the Contributor Version where the
+ Participant is a Contributor or the Original Software where the
+ Participant is the Initial Developer) directly or indirectly
+ infringes any patent, then any and all rights granted directly or
+ indirectly to You by such Participant, the Initial Developer (if the
+ Initial Developer is not the Participant) and all Contributors under
+ Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice
+ from Participant terminate prospectively and automatically at the
+ expiration of such 60 day notice period, unless if within such 60
+ day period You withdraw Your claim with respect to the Participant
+ Software against such Participant either unilaterally or pursuant to
+ a written agreement with Participant.
+
+ 6.3. If You assert a patent infringement claim against Participant
+ alleging that the Participant Software directly or indirectly
+ infringes any patent where such claim is resolved (such as by
+ license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 6.4. In the event of termination under Sections 6.1 or 6.2 above,
+ all end user licenses that have been validly granted by You or any
+ distributor hereunder prior to termination (excluding licenses
+ granted to You by any distributor) shall survive termination.
+
+ 7. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+ INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+ COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE
+ TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+ LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER
+ FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR
+ LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE
+ POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT
+ APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
+ PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
+ LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
+ LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION
+ AND LIMITATION MAY NOT APPLY TO YOU.
+
+ 8. U.S. GOVERNMENT END USERS.
+
+ The Covered Software is a "commercial item," as that term is defined
+ in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" (as that term is defined at 48 C.F.R. §
+ 252.227-7014(a)(1)) and "commercial computer software documentation"
+ as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent
+ with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4
+ (June 1995), all U.S. Government End Users acquire Covered Software
+ with only those rights set forth herein. This U.S. Government Rights
+ clause is in lieu of, and supersedes, any other FAR, DFAR, or other
+ clause or provision that addresses Government rights in computer
+ software under this License.
+
+ 9. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ the law of the jurisdiction specified in a notice contained within
+ the Original Software (except to the extent applicable law, if any,
+ provides otherwise), excluding such jurisdiction's conflict-of-law
+ provisions. Any litigation relating to this License shall be subject
+ to the jurisdiction of the courts located in the jurisdiction and
+ venue specified in a notice contained within the Original Software,
+ with the losing party responsible for costs, including, without
+ limitation, court costs and reasonable attorneys' fees and expenses.
+ The application of the United Nations Convention on Contracts for
+ the International Sale of Goods is expressly excluded. Any law or
+ regulation which provides that the language of a contract shall be
+ construed against the drafter shall not apply to this License. You
+ agree that You alone are responsible for compliance with the United
+ States export administration regulations (and the export control
+ laws and regulation of any other countries) when You use, distribute
+ or otherwise make available any Covered Software.
+
+ 10. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+---
+
+## NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)
+
+ The code released under the CDDL shall be governed by the laws of the
+ State of California (excluding conflict-of-law provisions). Any
+ litigation relating to this License shall be subject to the jurisdiction
+ of the Federal Courts of the Northern District of California and the
+ state courts of the State of California, with venue lying in Santa Clara
+ County, California.
+
+---
+
+## The GNU General Public License (GPL) Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor
+ Boston, MA 02110-1335
+ USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your freedom to
+ share and change it. By contrast, the GNU General Public License is
+ intended to guarantee your freedom to share and change free software--to
+ make sure the software is free for all its users. This General Public
+ License applies to most of the Free Software Foundation's software and
+ to any other program whose authors commit to using it. (Some other Free
+ Software Foundation software is covered by the GNU Library General
+ Public License instead.) You can apply it to your programs, too.
+
+ When we speak of free software, we are referring to freedom, not price.
+ Our General Public Licenses are designed to make sure that you have the
+ freedom to distribute copies of free software (and charge for this
+ service if you wish), that you receive source code or can get it if you
+ want it, that you can change the software or use pieces of it in new
+ free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid anyone
+ to deny you these rights or to ask you to surrender the rights. These
+ restrictions translate to certain responsibilities for you if you
+ distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether gratis
+ or for a fee, you must give the recipients all the rights that you have.
+ You must make sure that they, too, receive or can get the source code.
+ And you must show them these terms so they know their rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+ (2) offer you this license which gives you legal permission to copy,
+ distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+ that everyone understands that there is no warranty for this free
+ software. If the software is modified by someone else and passed on, we
+ want its recipients to know that what they have is not the original, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.
+
+ Finally, any free program is threatened constantly by software patents.
+ We wish to avoid the danger that redistributors of a free program will
+ individually obtain patent licenses, in effect making the program
+ proprietary. To prevent this, we have made it clear that any patent must
+ be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+ modification follow.
+
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains a
+ notice placed by the copyright holder saying it may be distributed under
+ the terms of this General Public License. The "Program", below, refers
+ to any such program or work, and a "work based on the Program" means
+ either the Program or any derivative work under copyright law: that is
+ to say, a work containing the Program or a portion of it, either
+ verbatim or with modifications and/or translated into another language.
+ (Hereinafter, translation is included without limitation in the term
+ "modification".) Each licensee is addressed as "you".
+
+ Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of running
+ the Program is not restricted, and the output from the Program is
+ covered only if its contents constitute a work based on the Program
+ (independent of having been made by running the Program). Whether that
+ is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's source
+ code as you receive it, in any medium, provided that you conspicuously
+ and appropriately publish on each copy an appropriate copyright notice
+ and disclaimer of warranty; keep intact all the notices that refer to
+ this License and to the absence of any warranty; and give any other
+ recipients of the Program a copy of this License along with the Program.
+
+ You may charge a fee for the physical act of transferring a copy, and
+ you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+ it, thus forming a work based on the Program, and copy and distribute
+ such modifications or work under the terms of Section 1 above, provided
+ that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any part
+ thereof, to be licensed as a whole at no charge to all third parties
+ under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a notice
+ that there is no warranty (or else, saying that you provide a
+ warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this License.
+ (Exception: if the Program itself is interactive but does not
+ normally print such an announcement, your work based on the Program
+ is not required to print an announcement.)
+
+ These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Program, and
+ can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based on
+ the Program, the distribution of the whole must be on the terms of this
+ License, whose permissions for other licensees extend to the entire
+ whole, and thus to each and every part regardless of who wrote it.
+
+ Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Program.
+
+ In addition, mere aggregation of another work not based on the Program
+ with the Program (or with a work based on the Program) on a volume of a
+ storage or distribution medium does not bring the other work under the
+ scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+ under Section 2) in object code or executable form under the terms of
+ Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your cost
+ of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to
+ distribute corresponding source code. (This alternative is allowed
+ only for noncommercial distribution and only if you received the
+ program in object code or executable form with such an offer, in
+ accord with Subsection b above.)
+
+ The source code for a work means the preferred form of the work for
+ making modifications to it. For an executable work, complete source code
+ means all the source code for all modules it contains, plus any
+ associated interface definition files, plus the scripts used to control
+ compilation and installation of the executable. However, as a special
+ exception, the source code distributed need not include anything that is
+ normally distributed (in either source or binary form) with the major
+ components (compiler, kernel, and so on) of the operating system on
+ which the executable runs, unless that component itself accompanies the
+ executable.
+
+ If distribution of executable or object code is made by offering access
+ to copy from a designated place, then offering equivalent access to copy
+ the source code from the same place counts as distribution of the source
+ code, even though third parties are not compelled to copy the source
+ along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+ except as expressly provided under this License. Any attempt otherwise
+ to copy, modify, sublicense or distribute the Program is void, and will
+ automatically terminate your rights under this License. However, parties
+ who have received copies, or rights, from you under this License will
+ not have their licenses terminated so long as such parties remain in
+ full compliance.
+
+ 5. You are not required to accept this License, since you have not
+ signed it. However, nothing else grants you permission to modify or
+ distribute the Program or its derivative works. These actions are
+ prohibited by law if you do not accept this License. Therefore, by
+ modifying or distributing the Program (or any work based on the
+ Program), you indicate your acceptance of this License to do so, and all
+ its terms and conditions for copying, distributing or modifying the
+ Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+ Program), the recipient automatically receives a license from the
+ original licensor to copy, distribute or modify the Program subject to
+ these terms and conditions. You may not impose any further restrictions
+ on the recipients' exercise of the rights granted herein. You are not
+ responsible for enforcing compliance by third parties to this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent issues),
+ conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot distribute
+ so as to satisfy simultaneously your obligations under this License and
+ any other pertinent obligations, then as a consequence you may not
+ distribute the Program at all. For example, if a patent license would
+ not permit royalty-free redistribution of the Program by all those who
+ receive copies directly or indirectly through you, then the only way you
+ could satisfy both it and this License would be to refrain entirely from
+ distribution of the Program.
+
+ If any portion of this section is held invalid or unenforceable under
+ any particular circumstance, the balance of the section is intended to
+ apply and the section as a whole is intended to apply in other
+ circumstances.
+
+ It is not the purpose of this section to induce you to infringe any
+ patents or other property right claims or to contest validity of any
+ such claims; this section has the sole purpose of protecting the
+ integrity of the free software distribution system, which is implemented
+ by public license practices. Many people have made generous
+ contributions to the wide range of software distributed through that
+ system in reliance on consistent application of that system; it is up to
+ the author/donor to decide if he or she is willing to distribute
+ software through any other system and a licensee cannot impose that choice.
+
+ This section is intended to make thoroughly clear what is believed to be
+ a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+ certain countries either by patents or by copyrighted interfaces, the
+ original copyright holder who places the Program under this License may
+ add an explicit geographical distribution limitation excluding those
+ countries, so that distribution is permitted only in or among countries
+ not thus excluded. In such case, this License incorporates the
+ limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new
+ versions of the General Public License from time to time. Such new
+ versions will be similar in spirit to the present version, but may
+ differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the Program
+ specifies a version number of this License which applies to it and "any
+ later version", you have the option of following the terms and
+ conditions either of that version or of any later version published by
+ the Free Software Foundation. If the Program does not specify a version
+ number of this License, you may choose any version ever published by the
+ Free Software Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+ programs whose distribution conditions are different, write to the
+ author to ask for permission. For software which is copyrighted by the
+ Free Software Foundation, write to the Free Software Foundation; we
+ sometimes make exceptions for this. Our decision will be guided by the
+ two goals of preserving the free status of all derivatives of our free
+ software and of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+ WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+ EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+ OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
+ EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
+ YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+ NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+ AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+ DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
+ (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+ INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+ THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
+ OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+ possible use to the public, the best way to achieve this is to make it
+ free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest to
+ attach them to the start of each source file to most effectively convey
+ the exclusion of warranty; and each file should have at least the
+ "copyright" line and a pointer to where the full notice is found.
+
+ One line to give the program's name and a brief idea of what it does.
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+ Also add information on how to contact you by electronic and paper mail.
+
+ If the program is interactive, make it output a short notice like this
+ when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type
+ `show w'. This is free software, and you are welcome to redistribute
+ it under certain conditions; type `show c' for details.
+
+ The hypothetical commands `show w' and `show c' should show the
+ appropriate parts of the General Public License. Of course, the commands
+ you use may be called something other than `show w' and `show c'; they
+ could even be mouse-clicks or menu items--whatever suits your program.
+
+ You should also get your employer (if you work as a programmer) or your
+ school, if any, to sign a "copyright disclaimer" for the program, if
+ necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (which makes passes at compilers) written by
+ James Hacker.
+
+ signature of Ty Coon, 1 April 1989
+ Ty Coon, President of Vice
+
+ This General Public License does not permit incorporating your program
+ into proprietary programs. If your program is a subroutine library, you
+ may consider it more useful to permit linking proprietary applications
+ with the library. If this is what you want to do, use the GNU Library
+ General Public License instead of this License.
+
+---
+
+ Certain source files distributed by Oracle America, Inc. and/or its
+ affiliates are subject to the following clarification and special
+ exception to the GPLv2, based on the GNU Project exception for its
+ Classpath libraries, known as the GNU Classpath Exception, but only
+ where Oracle has expressly included in the particular source file's
+ header the words "Oracle designates this particular file as subject to
+ the "Classpath" exception as provided by Oracle in the LICENSE file
+ that accompanied this code."
+
+ You should also note that Oracle includes multiple, independent
+ programs in this software package. Some of those programs are provided
+ under licenses deemed incompatible with the GPLv2 by the Free Software
+ Foundation and others. For example, the package includes programs
+ licensed under the Apache License, Version 2.0. Such programs are
+ licensed to you under their original licenses.
+
+ Oracle facilitates your further distribution of this package by adding
+ the Classpath Exception to the necessary parts of its GPLv2 code, which
+ permits you to use that code in combination with other independent
+ modules not licensed under the GPLv2. However, note that this would
+ not permit you to commingle code under an incompatible license with
+ Oracle's GPLv2 licensed code by, for example, cutting and pasting such
+ code into a file also containing Oracle's GPLv2 licensed code and then
+ distributing the result. Additionally, if you were to remove the
+ Classpath Exception from any of the files to which it applies and
+ distribute the result, you would likely be required to license some or
+ all of the other code in that distribution under the GPLv2 as well, and
+ since the GPLv2 is incompatible with the license terms of some items
+ included in the distribution by Oracle, removing the Classpath
+ Exception could therefore effectively compromise your ability to
+ further distribute the package.
+
+ Proceed with caution and we recommend that you obtain the advice of a
+ lawyer skilled in open source matters before removing the Classpath
+ Exception or making modifications to this package which may
+ subsequently be redistributed and/or involve the use of third party
+ software.
+
+ CLASSPATH EXCEPTION
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License version 2 cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from or
+ based on this library. If you modify this library, you may extend this
+ exception to your version of the library, but you are not obligated to
+ do so. If you do not wish to do so, delete this exception statement
+ from your version.
diff --git a/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebEndpoint.java b/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebEndpoint.java
new file mode 100644
index 00000000000..9a149cde585
--- /dev/null
+++ b/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebEndpoint.java
@@ -0,0 +1,73 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2005-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.xml.ws;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used to annotate the getPortName()
+ * methods of a generated service interface.
+ *
+ *
The information specified in this annotation is sufficient
+ * to uniquely identify a {@code wsdl:port} element
+ * inside a {@code wsdl:service}. The latter is
+ * determined based on the value of the {@code WebServiceClient}
+ * annotation on the generated service interface itself.
+ *
+ * @since 1.6, JAX-WS 2.0
+ *
+ * @see javax.xml.ws.WebServiceClient
+**/
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebEndpoint {
+ /**
+ * The local name of the endpoint.
+ *
+ * @return ocal name of the endpoint
+ **/
+ String name() default "";
+}
diff --git a/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceClient.java b/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceClient.java
new file mode 100644
index 00000000000..635a86440da
--- /dev/null
+++ b/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceClient.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2005-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.xml.ws;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used to annotate a generated service interface.
+ *
+ *
The information specified in this annotation is sufficient
+ * to uniquely identify a {@code wsdl:service}
+ * element inside a WSDL document. This {@code wsdl:service}
+ * element represents the Web service for which the generated
+ * service interface provides a client view.
+ *
+ * @since 1.6, JAX-WS 2.0
+**/
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebServiceClient {
+ /**
+ * The local name of the Web service.
+ *
+ * @return local name
+ */
+ String name() default "";
+
+ /**
+ * The namespace for the Web service.
+ *
+ * @return target namespace name
+ */
+ String targetNamespace() default "";
+
+ /**
+ * The location of the WSDL document for the service (a URL).
+ *
+ * @return location of the WSDL document (a URL)
+ */
+ String wsdlLocation() default "";
+}
diff --git a/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceProvider.java b/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceProvider.java
new file mode 100644
index 00000000000..f54713fed23
--- /dev/null
+++ b/java/ql/test/stubs/jaxws-api-2.0/javax/xml/ws/WebServiceProvider.java
@@ -0,0 +1,85 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2005-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.xml.ws;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+/**
+ * Used to annotate a Provider implementation class.
+ *
+ * @since 1.6, JAX-WS 2.0
+ * @see javax.xml.ws.Provider
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebServiceProvider {
+ /**
+ * Location of the WSDL description for the service.
+ *
+ * @return location of the WSDL description
+ */
+ String wsdlLocation() default "";
+
+ /**
+ * Service name.
+ *
+ * @return service name
+ */
+ String serviceName() default "";
+
+ /**
+ * Target namespace for the service
+ *
+ * @return target namespace
+ */
+ String targetNamespace() default "";
+
+ /**
+ * Port name.
+ *
+ * @return port name
+ */
+ String portName() default "";
+}
diff --git a/java/ql/test/stubs/jsr181-api/LICENSE b/java/ql/test/stubs/jsr181-api/LICENSE
new file mode 100644
index 00000000000..b1c74f95ede
--- /dev/null
+++ b/java/ql/test/stubs/jsr181-api/LICENSE
@@ -0,0 +1,759 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
+
+1. Definitions.
+
+ 1.1. "Contributor" means each individual or entity that creates or
+ contributes to the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Software, prior Modifications used by a Contributor (if any), and
+ the Modifications made by that particular Contributor.
+
+ 1.3. "Covered Software" means (a) the Original Software, or (b)
+ Modifications, or (c) the combination of files containing Original
+ Software with files containing Modifications, in each case including
+ portions thereof.
+
+ 1.4. "Executable" means the Covered Software in any form other than
+ Source Code.
+
+ 1.5. "Initial Developer" means the individual or entity that first
+ makes Original Software available under this License.
+
+ 1.6. "Larger Work" means a work which combines Covered Software or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.7. "License" means this document.
+
+ 1.8. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means the Source Code and Executable form of
+ any of the following:
+
+ A. Any file that results from an addition to, deletion from or
+ modification of the contents of a file containing Original Software
+ or previous Modifications;
+
+ B. Any new file that contains any part of the Original Software or
+ previous Modification; or
+
+ C. Any new file that is contributed or otherwise made available
+ under the terms of this License.
+
+ 1.10. "Original Software" means the Source Code and Executable form
+ of computer software code that is originally released under this
+ License.
+
+ 1.11. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.12. "Source Code" means (a) the common form of computer software
+ code in which modifications are made and (b) associated
+ documentation included in or with such code.
+
+ 1.13. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of,
+ this License. For legal entities, "You" includes any entity which
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and subject
+ to third party intellectual property claims, the Initial Developer
+ hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer, to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Software (or portions thereof), with or without Modifications,
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using or selling of
+ Original Software, to make, have made, use, practice, sell, and
+ offer for sale, and/or otherwise dispose of the Original Software
+ (or portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b) are effective on
+ the date Initial Developer first distributes or otherwise makes the
+ Original Software available to a third party under the terms of this
+ License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: (1) for code that You delete from the Original Software, or
+ (2) for infringements caused by: (i) the modification of the
+ Original Software, or (ii) the combination of the Original Software
+ with other software or devices.
+
+ 2.2. Contributor Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and subject
+ to third party intellectual property claims, each Contributor hereby
+ grants You a world-wide, royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof), either on an
+ unmodified basis, with other Modifications, as Covered Software
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or selling
+ of Modifications made by that Contributor either alone and/or in
+ combination with its Contributor Version (or portions of such
+ combination), to make, use, sell, offer for sale, have made, and/or
+ otherwise dispose of: (1) Modifications made by that Contributor (or
+ portions thereof); and (2) the combination of Modifications made by
+ that Contributor with its Contributor Version (or portions of such
+ combination).
+
+ (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective
+ on the date Contributor first distributes or otherwise makes the
+ Modifications available to a third party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: (1) for any code that Contributor has deleted from the
+ Contributor Version; (2) for infringements caused by: (i) third
+ party modifications of Contributor Version, or (ii) the combination
+ of Modifications made by that Contributor with other software
+ (except as part of the Contributor Version) or other devices; or (3)
+ under Patent Claims infringed by Covered Software in the absence of
+ Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+
+ Any Covered Software that You distribute or otherwise make available
+ in Executable form must also be made available in Source Code form
+ and that Source Code form must be distributed only under the terms
+ of this License. You must include a copy of this License with every
+ copy of the Source Code form of the Covered Software You distribute
+ or otherwise make available. You must inform recipients of any such
+ Covered Software in Executable form as to how they can obtain such
+ Covered Software in Source Code form in a reasonable manner on or
+ through a medium customarily used for software exchange.
+
+ 3.2. Modifications.
+
+ The Modifications that You create or to which You contribute are
+ governed by the terms of this License. You represent that You
+ believe Your Modifications are Your original creation(s) and/or You
+ have sufficient rights to grant the rights conveyed by this License.
+
+ 3.3. Required Notices.
+
+ You must include a notice in each of Your Modifications that
+ identifies You as the Contributor of the Modification. You may not
+ remove or alter any copyright, patent or trademark notices contained
+ within the Covered Software, or any notices of licensing or any
+ descriptive text giving attribution to any Contributor or the
+ Initial Developer.
+
+ 3.4. Application of Additional Terms.
+
+ You may not offer or impose any terms on any Covered Software in
+ Source Code form that alters or restricts the applicable version of
+ this License or the recipients' rights hereunder. You may choose to
+ offer, and to charge a fee for, warranty, support, indemnity or
+ liability obligations to one or more recipients of Covered Software.
+ However, you may do so only on Your own behalf, and not on behalf of
+ the Initial Developer or any Contributor. You must make it
+ absolutely clear that any such warranty, support, indemnity or
+ liability obligation is offered by You alone, and You hereby agree
+ to indemnify the Initial Developer and every Contributor for any
+ liability incurred by the Initial Developer or such Contributor as a
+ result of warranty, support, indemnity or liability terms You offer.
+
+ 3.5. Distribution of Executable Versions.
+
+ You may distribute the Executable form of the Covered Software under
+ the terms of this License or under the terms of a license of Your
+ choice, which may contain terms different from this License,
+ provided that You are in compliance with the terms of this License
+ and that the license for the Executable form does not attempt to
+ limit or alter the recipient's rights in the Source Code form from
+ the rights set forth in this License. If You distribute the Covered
+ Software in Executable form under a different license, You must make
+ it absolutely clear that any terms which differ from this License
+ are offered by You alone, not by the Initial Developer or
+ Contributor. You hereby agree to indemnify the Initial Developer and
+ every Contributor for any liability incurred by the Initial
+ Developer or such Contributor as a result of any such terms You offer.
+
+ 3.6. Larger Works.
+
+ You may create a Larger Work by combining Covered Software with
+ other code not governed by the terms of this License and distribute
+ the Larger Work as a single product. In such a case, You must make
+ sure the requirements of this License are fulfilled for the Covered
+ Software.
+
+4. Versions of the License.
+
+ 4.1. New Versions.
+
+ Oracle is the initial license steward and may publish revised and/or
+ new versions of this License from time to time. Each version will be
+ given a distinguishing version number. Except as provided in Section
+ 4.3, no one other than the license steward has the right to modify
+ this License.
+
+ 4.2. Effect of New Versions.
+
+ You may always continue to use, distribute or otherwise make the
+ Covered Software available under the terms of the version of the
+ License under which You originally received the Covered Software. If
+ the Initial Developer includes a notice in the Original Software
+ prohibiting it from being distributed or otherwise made available
+ under any subsequent version of the License, You must distribute and
+ make the Covered Software available under the terms of the version
+ of the License under which You originally received the Covered
+ Software. Otherwise, You may also choose to use, distribute or
+ otherwise make the Covered Software available under the terms of any
+ subsequent version of the License published by the license steward.
+
+ 4.3. Modified Versions.
+
+ When You are an Initial Developer and You want to create a new
+ license for Your Original Software, You may create and use a
+ modified version of this License if You: (a) rename the license and
+ remove any references to the name of the license steward (except to
+ note that the license differs from this License); and (b) otherwise
+ make it clear that the license contains terms which differ from this
+ License.
+
+5. DISCLAIMER OF WARRANTY.
+
+ COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE
+ IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
+ NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF
+ THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE
+ DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY
+ OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING,
+ REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
+ ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS
+ AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to
+ cure such breach within 30 days of becoming aware of the breach.
+ Provisions which, by their nature, must remain in effect beyond the
+ termination of this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding
+ declaratory judgment actions) against Initial Developer or a
+ Contributor (the Initial Developer or Contributor against whom You
+ assert such claim is referred to as "Participant") alleging that the
+ Participant Software (meaning the Contributor Version where the
+ Participant is a Contributor or the Original Software where the
+ Participant is the Initial Developer) directly or indirectly
+ infringes any patent, then any and all rights granted directly or
+ indirectly to You by such Participant, the Initial Developer (if the
+ Initial Developer is not the Participant) and all Contributors under
+ Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice
+ from Participant terminate prospectively and automatically at the
+ expiration of such 60 day notice period, unless if within such 60
+ day period You withdraw Your claim with respect to the Participant
+ Software against such Participant either unilaterally or pursuant to
+ a written agreement with Participant.
+
+ 6.3. If You assert a patent infringement claim against Participant
+ alleging that the Participant Software directly or indirectly
+ infringes any patent where such claim is resolved (such as by
+ license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 6.4. In the event of termination under Sections 6.1 or 6.2 above,
+ all end user licenses that have been validly granted by You or any
+ distributor hereunder prior to termination (excluding licenses
+ granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+ INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+ COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE
+ TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+ LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER
+ FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR
+ LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE
+ POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT
+ APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
+ PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
+ LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
+ LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION
+ AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+ The Covered Software is a "commercial item," as that term is defined
+ in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" (as that term is defined at 48 C.F.R. §
+ 252.227-7014(a)(1)) and "commercial computer software documentation"
+ as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent
+ with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4
+ (June 1995), all U.S. Government End Users acquire Covered Software
+ with only those rights set forth herein. This U.S. Government Rights
+ clause is in lieu of, and supersedes, any other FAR, DFAR, or other
+ clause or provision that addresses Government rights in computer
+ software under this License.
+
+9. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ the law of the jurisdiction specified in a notice contained within
+ the Original Software (except to the extent applicable law, if any,
+ provides otherwise), excluding such jurisdiction's conflict-of-law
+ provisions. Any litigation relating to this License shall be subject
+ to the jurisdiction of the courts located in the jurisdiction and
+ venue specified in a notice contained within the Original Software,
+ with the losing party responsible for costs, including, without
+ limitation, court costs and reasonable attorneys' fees and expenses.
+ The application of the United Nations Convention on Contracts for
+ the International Sale of Goods is expressly excluded. Any law or
+ regulation which provides that the language of a contract shall be
+ construed against the drafter shall not apply to this License. You
+ agree that You alone are responsible for compliance with the United
+ States export administration regulations (and the export control
+ laws and regulation of any other countries) when You use, distribute
+ or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+------------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION
+LICENSE (CDDL)
+
+The code released under the CDDL shall be governed by the laws of the
+State of California (excluding conflict-of-law provisions). Any
+litigation relating to this License shall be subject to the jurisdiction
+of the Federal Courts of the Northern District of California and the
+state courts of the State of California, with venue lying in Santa Clara
+County, California.
+
+
+
+ The GNU General Public License (GPL) Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor
+Boston, MA 02110-1335
+USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users. This General Public
+License applies to most of the Free Software Foundation's software and
+to any other program whose authors commit to using it. (Some other Free
+Software Foundation software is covered by the GNU Library General
+Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.
+Our General Public Licenses are designed to make sure that you have the
+freedom to distribute copies of free software (and charge for this
+service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone
+to deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis
+or for a fee, you must give the recipients all the rights that you have.
+You must make sure that they, too, receive or can get the source code.
+And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software patents.
+We wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program
+proprietary. To prevent this, we have made it clear that any patent must
+be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a
+notice placed by the copyright holder saying it may be distributed under
+the terms of this General Public License. The "Program", below, refers
+to any such program or work, and a "work based on the Program" means
+either the Program or any derivative work under copyright law: that is
+to say, a work containing the Program or a portion of it, either
+verbatim or with modifications and/or translated into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of running
+the Program is not restricted, and the output from the Program is
+covered only if its contents constitute a work based on the Program
+(independent of having been made by running the Program). Whether that
+is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice
+and disclaimer of warranty; keep intact all the notices that refer to
+this License and to the absence of any warranty; and give any other
+recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of
+it, thus forming a work based on the Program, and copy and distribute
+such modifications or work under the terms of Section 1 above, provided
+that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any part
+ thereof, to be licensed as a whole at no charge to all third parties
+ under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a notice
+ that there is no warranty (or else, saying that you provide a
+ warranty) and that users may redistribute the program under these
+ conditions, and telling the user how to view a copy of this License.
+ (Exception: if the Program itself is interactive but does not
+ normally print such an announcement, your work based on the Program
+ is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program, and
+can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based on
+the Program, the distribution of the whole must be on the terms of this
+License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of a
+storage or distribution medium does not bring the other work under the
+scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your cost
+ of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer to
+ distribute corresponding source code. (This alternative is allowed
+ only for noncommercial distribution and only if you received the
+ program in object code or executable form with such an offer, in
+ accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source code
+means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to control
+compilation and installation of the executable. However, as a special
+exception, the source code distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies the
+executable.
+
+If distribution of executable or object code is made by offering access
+to copy from a designated place, then offering equivalent access to copy
+the source code from the same place counts as distribution of the source
+code, even though third parties are not compelled to copy the source
+along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt otherwise
+to copy, modify, sublicense or distribute the Program is void, and will
+automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will
+not have their licenses terminated so long as such parties remain in
+full compliance.
+
+5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and all
+its terms and conditions for copying, distributing or modifying the
+Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further restrictions
+on the recipients' exercise of the rights granted herein. You are not
+responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute
+so as to satisfy simultaneously your obligations under this License and
+any other pertinent obligations, then as a consequence you may not
+distribute the Program at all. For example, if a patent license would
+not permit royalty-free redistribution of the Program by all those who
+receive copies directly or indirectly through you, then the only way you
+could satisfy both it and this License would be to refrain entirely from
+distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is implemented
+by public license practices. Many people have made generous
+contributions to the wide range of software distributed through that
+system in reliance on consistent application of that system; it is up to
+the author/donor to decide if he or she is willing to distribute
+software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be
+a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License may
+add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among countries
+not thus excluded. In such case, this License incorporates the
+limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new
+versions of the General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Program does not specify a version
+number of this License, you may choose any version ever published by the
+Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the
+author to ask for permission. For software which is copyrighted by the
+Free Software Foundation, write to the Free Software Foundation; we
+sometimes make exceptions for this. Our decision will be guided by the
+two goals of preserving the free status of all derivatives of our free
+software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
+YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
+OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ One line to give the program's name and a brief idea of what it does.
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type
+ `show w'. This is free software, and you are welcome to redistribute
+ it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the commands
+you use may be called something other than `show w' and `show c'; they
+could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (which makes passes at compilers) written by
+ James Hacker.
+
+ signature of Ty Coon, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications
+with the library. If this is what you want to do, use the GNU Library
+General Public License instead of this License.
+
+#
+
+Certain source files distributed by Oracle America, Inc. and/or its
+affiliates are subject to the following clarification and special
+exception to the GPLv2, based on the GNU Project exception for its
+Classpath libraries, known as the GNU Classpath Exception, but only
+where Oracle has expressly included in the particular source file's
+header the words "Oracle designates this particular file as subject to
+the "Classpath" exception as provided by Oracle in the LICENSE file
+that accompanied this code."
+
+You should also note that Oracle includes multiple, independent
+programs in this software package. Some of those programs are provided
+under licenses deemed incompatible with the GPLv2 by the Free Software
+Foundation and others. For example, the package includes programs
+licensed under the Apache License, Version 2.0. Such programs are
+licensed to you under their original licenses.
+
+Oracle facilitates your further distribution of this package by adding
+the Classpath Exception to the necessary parts of its GPLv2 code, which
+permits you to use that code in combination with other independent
+modules not licensed under the GPLv2. However, note that this would
+not permit you to commingle code under an incompatible license with
+Oracle's GPLv2 licensed code by, for example, cutting and pasting such
+code into a file also containing Oracle's GPLv2 licensed code and then
+distributing the result. Additionally, if you were to remove the
+Classpath Exception from any of the files to which it applies and
+distribute the result, you would likely be required to license some or
+all of the other code in that distribution under the GPLv2 as well, and
+since the GPLv2 is incompatible with the license terms of some items
+included in the distribution by Oracle, removing the Classpath
+Exception could therefore effectively compromise your ability to
+further distribute the package.
+
+Proceed with caution and we recommend that you obtain the advice of a
+lawyer skilled in open source matters before removing the Classpath
+Exception or making modifications to this package which may
+subsequently be redistributed and/or involve the use of third party
+software.
+
+CLASSPATH EXCEPTION
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License version 2 cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from or
+based on this library. If you modify this library, you may extend this
+exception to your version of the library, but you are not obligated to
+do so. If you do not wish to do so, delete this exception statement
+from your version.
diff --git a/java/ql/test/stubs/jsr181-api/javax/jws/WebMethod.java b/java/ql/test/stubs/jsr181-api/javax/jws/WebMethod.java
new file mode 100644
index 00000000000..92813b5a255
--- /dev/null
+++ b/java/ql/test/stubs/jsr181-api/javax/jws/WebMethod.java
@@ -0,0 +1,48 @@
+package javax.jws;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Customizes a method that is exposed as a Web Service operation.
+ * The associated method must be public and its parameters return value,
+ * and exceptions must follow the rules defined in JAX-RPC 1.1, section 5.
+ *
+ * The method is not required to throw java.rmi.RemoteException.
+ *
+ * @author Copyright (c) 2004 by BEA Systems, Inc. All Rights Reserved.
+ *
+ * @since 1.6
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface WebMethod {
+
+ /**
+ * Name of the wsdl:operation matching this method.
+ *
+ * @specdefault Name of the Java method.
+ */
+ String operationName() default "";
+
+ /**
+ * The action for this operation.
+ *
+ * For SOAP bindings, this determines the value of the soap action.
+ */
+ String action() default "";
+
+ /**
+ * Marks a method to NOT be exposed as a web method.
+ *
+ * Used to stop an inherited method from being exposed as part of this web service.
+ * If this element is specified, other elements MUST NOT be specified for the @WebMethod.
+ *
+ * This member-value is not allowed on endpoint interfaces.
+ *
+ * @since 2.0
+ */
+ boolean exclude() default false;
+};
diff --git a/java/ql/test/stubs/jsr181-api/javax/jws/WebService.java b/java/ql/test/stubs/jsr181-api/javax/jws/WebService.java
new file mode 100644
index 00000000000..67eebee9ca3
--- /dev/null
+++ b/java/ql/test/stubs/jsr181-api/javax/jws/WebService.java
@@ -0,0 +1,97 @@
+package javax.jws;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.ElementType;
+
+/**
+ * Marks a Java class as implementing a Web Service, or a Java interface as defining a Web Service interface.
+ *
+ * @author Copyright (c) 2004 by BEA Systems, Inc. All Rights Reserved.
+ *
+ * @since 1.6
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE})
+public @interface WebService {
+
+ /**
+ * The name of the Web Service.
+ *
+ * Used as the name of the wsdl:portType when mapped to WSDL 1.1.
+ *
+ * @specdefault The simple name of the Java class or interface.
+ */
+ String name() default "";
+
+ /**
+ * If the @WebService.targetNamespace annotation is on a service endpoint interface, the targetNamespace is used
+ * for the namespace for the wsdl:portType (and associated XML elements).
+ *
+ * If the @WebService.targetNamespace annotation is on a service implementation bean that does NOT reference a
+ * service endpoint interface (through the endpointInterface attribute), the targetNamespace is used for both the
+ * wsdl:portType and the wsdl:service (and associated XML elements).
+ *
+ * If the @WebService.targetNamespace annotation is on a service implementation bean that does reference a service
+ * endpoint interface (through the endpointInterface attribute), the targetNamespace is used for only the
+ * wsdl:service (and associated XML elements).
+ *
+ * @specdefault Implementation-defined, as described in JAX-WS 2.0 [5], section 3.2.
+ */
+ String targetNamespace() default "";
+
+ /**
+ * The service name of the Web Service.
+ *
+ * Used as the name of the wsdl:service when mapped to WSDL 1.1.
+ *
+ * This member-value is not allowed on endpoint interfaces.
+ *
+ * @specdefault The simple name of the Java class + Service".
+ */
+ String serviceName() default "";
+
+ /**
+ * The port name of the Web Service.
+ *
+ * Used as the name of the wsdl:port when mapped to WSDL 1.1.
+ *
+ * This member-value is not allowed on endpoint interfaces.
+ *
+ * @specdefault {@code @WebService.name}+Port.
+ *
+ * @since 2.0
+ */
+ String portName() default "";
+
+ /**
+ * The location of a pre-defined WSDL describing the service.
+ *
+ * The wsdlLocation is a URL (relative or absolute) that refers to a pre-existing WSDL file. The presence of a
+ * wsdlLocation value indicates that the service implementation bean is implementing a pre-defined WSDL contract.
+ * The JSR-181 tool MUST provide feedback if the service implementation bean is inconsistent with the portType and
+ * bindings declared in this WSDL. Note that a single WSDL file might contain multiple portTypes and multiple
+ * bindings. The annotations on the service implementation bean determine the specific portType and bindings that
+ * correspond to the Web Service.
+ */
+ String wsdlLocation() default "";
+
+ /**
+ * The complete name of the service endpoint interface defining the service's abstract Web Service contract.
+ *
+ * This annotation allows the developer to separate the interface contract from the implementation. If this
+ * annotation is present, the service endpoint interface is used to determine the abstract WSDL contract (portType
+ * and bindings). The service endpoint interface MAY include JSR-181 annotations to customize the mapping from
+ * Java to WSDL.
+ *
+ * The service implementation bean MAY implement the service endpoint interface, but is not REQUIRED to do so.
+ *
+ * If this member-value is not present, the Web Service contract is generated from annotations on the service
+ * implementation bean. If a service endpoint interface is required by the target environment, it will be
+ * generated into an implementation-defined package with an implementation- defined name
+ *
+ * This member-value is not allowed on endpoint interfaces.
+ */
+ String endpointInterface() default "";
+};
From 2cb76fe4071ae1011764054c5447f31780a54096 Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Wed, 24 Mar 2021 16:32:51 +0000
Subject: [PATCH 026/153] Test JAX-WS endpoints
---
.../frameworks/JaxWs/JaxWsEndpoint.expected | 0
.../frameworks/JaxWs/JaxWsEndpoint.java | 44 +++++++++++++++++++
.../frameworks/JaxWs/JaxWsEndpoint.ql | 27 ++++++++++++
.../library-tests/frameworks/JaxWs/options | 1 +
4 files changed, 72 insertions(+)
create mode 100644 java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected
create mode 100644 java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.java
create mode 100644 java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.ql
create mode 100644 java/ql/test/library-tests/frameworks/JaxWs/options
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.java b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.java
new file mode 100644
index 00000000000..5817f433aaf
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.java
@@ -0,0 +1,44 @@
+import javax.jws.WebMethod;
+import javax.jws.WebService;
+import javax.xml.ws.WebEndpoint;
+import javax.xml.ws.WebServiceClient;
+import javax.xml.ws.WebServiceProvider;
+
+@WebService
+class WebServiceClass { // $JaxWsEndpoint
+
+ @WebMethod
+ void WebMethodMethod() { // $JaxWsEndpointRemoteMethod
+ }
+
+ @WebEndpoint
+ void WebEndpointMethod() { // $JaxWsEndpointRemoteMethod
+ }
+
+}
+
+@WebServiceProvider
+class WebServiceProviderClass { // $JaxWsEndpoint
+
+ @WebMethod
+ void WebMethodMethod() { // $JaxWsEndpointRemoteMethod
+ }
+
+ @WebEndpoint
+ void WebEndpointMethod() { // $JaxWsEndpointRemoteMethod
+ }
+
+}
+
+@WebServiceClient
+class WebServiceClientClass { // $JaxWsEndpoint
+
+ @WebMethod
+ void WebMethodMethod() { // $JaxWsEndpointRemoteMethod
+ }
+
+ @WebEndpoint
+ void WebEndpointMethod() { // $JaxWsEndpointRemoteMethod
+ }
+
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.ql b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.ql
new file mode 100644
index 00000000000..6ebd597bb0a
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.ql
@@ -0,0 +1,27 @@
+import java
+import semmle.code.java.frameworks.JaxWS
+import TestUtilities.InlineExpectationsTest
+
+class JaxWsEndpointTest extends InlineExpectationsTest {
+ JaxWsEndpointTest() { this = "JaxWsEndpointTest" }
+
+ override string getARelevantTag() { result = ["JaxWsEndpoint", "JaxWsEndpointRemoteMethod"] }
+
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ tag = "JaxWsEndpoint" and
+ exists(JaxWsEndpoint jaxWsEndpoint |
+ jaxWsEndpoint.getLocation() = location and
+ element = jaxWsEndpoint.toString() and
+ value = ""
+ )
+ or
+ tag = "JaxWsEndpointRemoteMethod" and
+ exists(Callable remoteMethod |
+ remoteMethod = any(JaxWsEndpoint jaxWsEndpoint).getARemoteMethod()
+ |
+ remoteMethod.getLocation() = location and
+ element = remoteMethod.toString() and
+ value = ""
+ )
+ }
+}
diff --git a/java/ql/test/library-tests/frameworks/JaxWs/options b/java/ql/test/library-tests/frameworks/JaxWs/options
new file mode 100644
index 00000000000..e64ee74d9bc
--- /dev/null
+++ b/java/ql/test/library-tests/frameworks/JaxWs/options
@@ -0,0 +1 @@
+//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jsr311-api-1.1.1:${testdir}/../../../stubs/jsr181-api:${testdir}/../../../stubs/jaxws-api-2.0
From 49190615a72405dad8fe9becd77aef45cd8822c2 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Fri, 4 Jun 2021 08:26:00 +0200
Subject: [PATCH 027/153] Cleanup CSV coverage report generator
---
.github/workflows/csv-coverage.yml | 22 +---------------------
1 file changed, 1 insertion(+), 21 deletions(-)
diff --git a/.github/workflows/csv-coverage.yml b/.github/workflows/csv-coverage.yml
index 54c172d66d3..e4df6da8642 100644
--- a/.github/workflows/csv-coverage.yml
+++ b/.github/workflows/csv-coverage.yml
@@ -1,4 +1,4 @@
-name: Build/check CSV flow coverage report
+name: Build CSV flow coverage report
on:
workflow_dispatch:
@@ -6,22 +6,6 @@ on:
qlModelShaOverride:
description: 'github/codeql repo SHA used for looking up the CSV models'
required: false
- push:
- branches:
- - main
- - 'rc/**'
- pull_request:
- paths:
- - '.github/workflows/csv-coverage.yml'
- - '*/ql/src/**/*.ql'
- - '*/ql/src/**/*.qll'
- - 'misc/scripts/library-coverage/*.py'
- # input data files
- - '*/documentation/library-coverage/cwe-sink.csv'
- - '*/documentation/library-coverage/frameworks.csv'
- # coverage report files
- - '*/documentation/library-coverage/flow-model-coverage.csv'
- - '*/documentation/library-coverage/flow-model-coverage.rst'
jobs:
build:
@@ -70,8 +54,4 @@ jobs:
with:
name: rst-flow-model-coverage
path: flow-model-coverage-*.rst
- # - name: Check coverage files
- # if: github.event.pull_request
- # run: |
- # python script/misc/scripts/library-coverage/compare-files.py codeqlModels
From 270cf62f08e50134fecee73b8651573c639a8ffc Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Fri, 4 Jun 2021 08:32:24 +0200
Subject: [PATCH 028/153] Fix variable reference
---
.github/workflows/csv-coverage.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/csv-coverage.yml b/.github/workflows/csv-coverage.yml
index e4df6da8642..1a5816816b4 100644
--- a/.github/workflows/csv-coverage.yml
+++ b/.github/workflows/csv-coverage.yml
@@ -22,7 +22,7 @@ jobs:
uses: actions/checkout@v2
with:
path: codeqlModels
- ref: github.event.inputs.qlModelShaOverride
+ ref: ${{ github.event.inputs.qlModelShaOverride }}
- name: Clone self (github/codeql) for analysis
if: github.event.inputs.qlModelShaOverride == ''
uses: actions/checkout@v2
From 4de4277a8df2de9aff1917d2feb4162bea04acc3 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Fri, 4 Jun 2021 11:57:31 +0200
Subject: [PATCH 029/153] Add timeseries CSV generator script
---
.../library-coverage/generate-report.py | 32 +----
.../library-coverage/generate-time-series.py | 114 ++++++++++++++++++
misc/scripts/library-coverage/utils.py | 26 ++++
3 files changed, 144 insertions(+), 28 deletions(-)
create mode 100644 misc/scripts/library-coverage/generate-time-series.py
create mode 100644 misc/scripts/library-coverage/utils.py
diff --git a/misc/scripts/library-coverage/generate-report.py b/misc/scripts/library-coverage/generate-report.py
index ffcc654a728..a86e4af823c 100644
--- a/misc/scripts/library-coverage/generate-report.py
+++ b/misc/scripts/library-coverage/generate-report.py
@@ -1,9 +1,9 @@
-import subprocess
import csv
import sys
import os
import shutil
import settings
+import utils
"""
This script runs the CSV coverage report QL query, and transforms it to a more readable format.
@@ -12,30 +12,6 @@ data.
"""
-def subprocess_run(cmd):
- """Runs a command through subprocess.run, with a few tweaks. Raises an Exception if exit code != 0."""
- return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True)
-
-
-def create_empty_database(lang, extension, database):
- """Creates an empty database for the given language."""
- subprocess_run(["codeql", "database", "init", "--language=" + lang,
- "--source-root=/tmp/empty", "--allow-missing-source-root", database])
- subprocess_run(["mkdir", "-p", database + "/src/tmp/empty"])
- subprocess_run(["touch", database + "/src/tmp/empty/empty" + extension])
- subprocess_run(["codeql", "database", "finalize",
- database, "--no-pre-finalize"])
-
-
-def run_codeql_query(query, database, output):
- """Runs a codeql query on the given database."""
- subprocess_run(["codeql", "query", "run", query,
- "--database", database, "--output", output + ".bqrs"])
- subprocess_run(["codeql", "bqrs", "decode", output + ".bqrs",
- "--format=csv", "--no-titles", "--output", output])
- os.remove(output + ".bqrs")
-
-
def append_csv_number(list, value):
"""Adds a number to the list or None if the value is not greater than 0."""
if value > 0:
@@ -117,7 +93,7 @@ class LanguageConfig:
try: # Check for `codeql` on path
- subprocess_run(["codeql", "--version"])
+ utils.subprocess_run(["codeql", "--version"])
except Exception as e:
print("Error: couldn't invoke CodeQL CLI 'codeql'. Is it on the path? Aborting.", file=sys.stderr)
raise e
@@ -165,8 +141,8 @@ for config in configs:
lang = config.lang
db = "empty-" + lang
ql_output = output_ql_csv.format(language=lang)
- create_empty_database(lang, config.ext, db)
- run_codeql_query(config.ql_path, db, ql_output)
+ utils.create_empty_database(lang, config.ext, db)
+ utils.run_codeql_query(config.ql_path, db, ql_output)
shutil.rmtree(db)
packages = {}
diff --git a/misc/scripts/library-coverage/generate-time-series.py b/misc/scripts/library-coverage/generate-time-series.py
new file mode 100644
index 00000000000..00719c63a0b
--- /dev/null
+++ b/misc/scripts/library-coverage/generate-time-series.py
@@ -0,0 +1,114 @@
+import subprocess
+import csv
+import sys
+import os
+import shutil
+from datetime import date
+import datetime
+import utils
+
+"""
+ Gets the sink/source/summary statistics for different days.
+"""
+
+# the distance between commits to include in the output
+day_distance = 1
+
+# the directory where codeql is. This is the directory where we change the SHAs
+working_dir = sys.argv[1]
+
+lang = "java"
+db = "empty-java"
+ql_output = "output-java.csv"
+csv_output = "timeseries-java.csv"
+
+
+def get_str_output(arr):
+ r = subprocess.check_output(arr)
+ return r.decode("utf-8").strip("\n'")
+
+
+def get_date(sha):
+ d = get_str_output(
+ ["git", "show", "--no-patch", "--no-notes", "--pretty='%cd'", "--date=short", sha])
+ return date.fromisoformat(d)
+
+
+def get_parent(sha, date):
+ parent_sha = get_str_output(
+ ["git", "rev-parse", sha + "^"])
+ parent_date = get_date(parent_sha)
+ return (parent_sha, parent_date)
+
+
+def get_previous_sha(sha, date):
+ parent_sha, parent_date = get_parent(sha, date)
+ while parent_date > date + datetime.timedelta(days=-1 * day_distance):
+ parent_sha, parent_date = get_parent(parent_sha, parent_date)
+
+ return (parent_sha, parent_date)
+
+
+def get_stats():
+ if os.path.isdir(db):
+ shutil.rmtree(db)
+ utils.create_empty_database(lang, ".java", db)
+ utils.run_codeql_query(
+ "java/ql/src/meta/frameworks/Coverage.ql", db, ql_output)
+ shutil.rmtree(db)
+
+ sources = 0
+ sinks = 0
+ summaries = 0
+
+ with open(ql_output) as csvfile:
+ reader = csv.reader(csvfile)
+ for row in reader:
+ # row: "android.util",1,"remote","source",16
+ if row[3] == "source":
+ sources += int(row[4])
+ if row[3] == "sink":
+ sinks += int(row[4])
+ if row[3] == "summary":
+ summaries += int(row[4])
+
+ os.remove(ql_output)
+
+ return (sources, sinks, summaries)
+
+
+with open(csv_output, 'w', newline='') as csvfile:
+ csvwriter = csv.writer(csvfile)
+ csvwriter.writerow(["SHA", "Date", "Sources", "Sinks", "Summaries"])
+
+ os.chdir(working_dir)
+
+ utils.subprocess_run(["git", "checkout", "main"])
+
+ current_sha = get_str_output(["git", "rev-parse", "HEAD"])
+ current_date = get_date(current_sha)
+
+ while True:
+ print("Getting stats for " + current_sha)
+ utils.subprocess_run(["git", "checkout", current_sha])
+
+ try:
+ stats = get_stats()
+
+ csvwriter.writerow(
+ [current_sha, current_date, stats[0], stats[1], stats[2]])
+
+ print("Collected stats for " + current_sha +
+ " at " + current_date.isoformat())
+ except:
+ print("Unexpected error:", sys.exc_info()[0])
+
+ if os.path.isdir(db):
+ shutil.rmtree(db)
+ print("Error getting stats for " +
+ current_sha + ". Stopping iteration.")
+ break
+
+ current_sha, current_date = get_previous_sha(current_sha, current_date)
+
+utils.subprocess_run(["git", "checkout", "main"])
diff --git a/misc/scripts/library-coverage/utils.py b/misc/scripts/library-coverage/utils.py
new file mode 100644
index 00000000000..122c8bdac0b
--- /dev/null
+++ b/misc/scripts/library-coverage/utils.py
@@ -0,0 +1,26 @@
+import subprocess
+import os
+
+
+def subprocess_run(cmd):
+ """Runs a command through subprocess.run, with a few tweaks. Raises an Exception if exit code != 0."""
+ return subprocess.run(cmd, capture_output=True, text=True, env=os.environ.copy(), check=True)
+
+
+def create_empty_database(lang, extension, database):
+ """Creates an empty database for the given language."""
+ subprocess_run(["codeql", "database", "init", "--language=" + lang,
+ "--source-root=/tmp/empty", "--allow-missing-source-root", database])
+ subprocess_run(["mkdir", "-p", database + "/src/tmp/empty"])
+ subprocess_run(["touch", database + "/src/tmp/empty/empty" + extension])
+ subprocess_run(["codeql", "database", "finalize",
+ database, "--no-pre-finalize"])
+
+
+def run_codeql_query(query, database, output):
+ """Runs a codeql query on the given database."""
+ subprocess_run(["codeql", "query", "run", query,
+ "--database", database, "--output", output + ".bqrs"])
+ subprocess_run(["codeql", "bqrs", "decode", output + ".bqrs",
+ "--format=csv", "--no-titles", "--output", output])
+ os.remove(output + ".bqrs")
From 3353c3ecdd00668365c57ade1d6e4c67e57934b8 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Fri, 4 Jun 2021 16:06:05 +0200
Subject: [PATCH 030/153] Add workflow to generate timeseries CSV coverage
report
---
.github/workflows/csv-coverage-timeseries.yml | 41 ++++++
.../library-coverage/generate-report.py | 10 +-
.../library-coverage/generate-time-series.py | 132 ++++++++++--------
misc/scripts/library-coverage/utils.py | 8 ++
4 files changed, 120 insertions(+), 71 deletions(-)
create mode 100644 .github/workflows/csv-coverage-timeseries.yml
diff --git a/.github/workflows/csv-coverage-timeseries.yml b/.github/workflows/csv-coverage-timeseries.yml
new file mode 100644
index 00000000000..46287e7892f
--- /dev/null
+++ b/.github/workflows/csv-coverage-timeseries.yml
@@ -0,0 +1,41 @@
+name: Build CSV timeseries flow coverage report
+
+on:
+ workflow_dispatch:
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Clone self (github/codeql)
+ uses: actions/checkout@v2
+ with:
+ path: script
+ - name: Clone self (github/codeql) for analysis
+ uses: actions/checkout@v2
+ with:
+ path: codeqlModels
+ - name: Set up Python 3.8
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.8
+ - name: Download CodeQL CLI
+ uses: dsaltares/fetch-gh-release-asset@aa37ae5c44d3c9820bc12fe675e8670ecd93bd1c
+ with:
+ repo: "github/codeql-cli-binaries"
+ version: "latest"
+ file: "codeql-linux64.zip"
+ token: ${{ secrets.GITHUB_TOKEN }}
+ - name: Unzip CodeQL CLI
+ run: unzip -d codeql-cli codeql-linux64.zip
+ - name: Build modeled package list
+ run: |
+ PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-time-series.py codeqlModels
+ - name: Upload timeseries CSV
+ uses: actions/upload-artifact@v2
+ with:
+ name: csv-flow-model-coverage-timeseries
+ path: timeseries-*.csv
+
diff --git a/misc/scripts/library-coverage/generate-report.py b/misc/scripts/library-coverage/generate-report.py
index a86e4af823c..bb692088a46 100644
--- a/misc/scripts/library-coverage/generate-report.py
+++ b/misc/scripts/library-coverage/generate-report.py
@@ -84,14 +84,6 @@ def add_package_stats_to_row(row, sorted_cwes, collect):
return row, processed_packages
-class LanguageConfig:
- def __init__(self, lang, capitalized_lang, ext, ql_path):
- self.lang = lang
- self.capitalized_lang = capitalized_lang
- self.ext = ext
- self.ql_path = ql_path
-
-
try: # Check for `codeql` on path
utils.subprocess_run(["codeql", "--version"])
except Exception as e:
@@ -121,7 +113,7 @@ if len(sys.argv) > 2:
# Languages for which we want to generate coverage reports.
configs = [
- LanguageConfig(
+ utils.LanguageConfig(
"java", "Java", ".java", query_prefix + "java/ql/src/meta/frameworks/Coverage.ql")
]
diff --git a/misc/scripts/library-coverage/generate-time-series.py b/misc/scripts/library-coverage/generate-time-series.py
index 00719c63a0b..e76a159c7c0 100644
--- a/misc/scripts/library-coverage/generate-time-series.py
+++ b/misc/scripts/library-coverage/generate-time-series.py
@@ -14,14 +14,6 @@ import utils
# the distance between commits to include in the output
day_distance = 1
-# the directory where codeql is. This is the directory where we change the SHAs
-working_dir = sys.argv[1]
-
-lang = "java"
-db = "empty-java"
-ql_output = "output-java.csv"
-csv_output = "timeseries-java.csv"
-
def get_str_output(arr):
r = subprocess.check_output(arr)
@@ -49,66 +41,82 @@ def get_previous_sha(sha, date):
return (parent_sha, parent_date)
-def get_stats():
- if os.path.isdir(db):
- shutil.rmtree(db)
- utils.create_empty_database(lang, ".java", db)
- utils.run_codeql_query(
- "java/ql/src/meta/frameworks/Coverage.ql", db, ql_output)
- shutil.rmtree(db)
+def get_stats(lang, query):
+ try:
+ db = "empty_" + lang
+ ql_output = "output-" + lang + ".csv"
+ if os.path.isdir(db):
+ shutil.rmtree(db)
+ utils.create_empty_database(lang, ".java", db)
+ utils.run_codeql_query(query, db, ql_output)
- sources = 0
- sinks = 0
- summaries = 0
+ sources = 0
+ sinks = 0
+ summaries = 0
- with open(ql_output) as csvfile:
- reader = csv.reader(csvfile)
- for row in reader:
- # row: "android.util",1,"remote","source",16
- if row[3] == "source":
- sources += int(row[4])
- if row[3] == "sink":
- sinks += int(row[4])
- if row[3] == "summary":
- summaries += int(row[4])
+ with open(ql_output) as csvfile:
+ reader = csv.reader(csvfile)
+ for row in reader:
+ # row: "android.util",1,"remote","source",16
+ if row[3] == "source":
+ sources += int(row[4])
+ if row[3] == "sink":
+ sinks += int(row[4])
+ if row[3] == "summary":
+ summaries += int(row[4])
- os.remove(ql_output)
+ os.remove(ql_output)
- return (sources, sinks, summaries)
+ return (sources, sinks, summaries)
+ except:
+ print("Unexpected error:", sys.exc_info()[0])
+ raise Exception()
+ finally:
+ if os.path.isdir(db):
+ shutil.rmtree(db)
-with open(csv_output, 'w', newline='') as csvfile:
- csvwriter = csv.writer(csvfile)
- csvwriter.writerow(["SHA", "Date", "Sources", "Sinks", "Summaries"])
+working_dir = ""
+if len(sys.argv) > 1:
+ working_dir = sys.argv[1]
- os.chdir(working_dir)
+configs = [
+ utils.LanguageConfig(
+ "java", "Java", ".java", "java/ql/src/meta/frameworks/Coverage.ql")
+]
+
+# todo: change this when we cover multiple languages. We should compute the SHAs
+# only once and not per language
+for config in configs:
+ with open("timeseries-" + config.lang + ".csv", 'w', newline='') as csvfile:
+ csvwriter = csv.writer(csvfile)
+ csvwriter.writerow(["SHA", "Date", "Sources", "Sinks", "Summaries"])
+
+ os.chdir(working_dir)
+
+ utils.subprocess_run(["git", "checkout", "main"])
+
+ current_sha = get_str_output(["git", "rev-parse", "HEAD"])
+ current_date = get_date(current_sha)
+
+ while True:
+ print("Getting stats for " + current_sha)
+ utils.subprocess_run(["git", "checkout", current_sha])
+
+ try:
+ stats = get_stats(config.lang, config.ql_path)
+
+ csvwriter.writerow(
+ [current_sha, current_date, stats[0], stats[1], stats[2]])
+
+ print("Collected stats for " + current_sha +
+ " at " + current_date.isoformat())
+ except:
+ print("Error getting stats for " +
+ current_sha + ". Stopping iteration.")
+ break
+
+ current_sha, current_date = get_previous_sha(
+ current_sha, current_date)
utils.subprocess_run(["git", "checkout", "main"])
-
- current_sha = get_str_output(["git", "rev-parse", "HEAD"])
- current_date = get_date(current_sha)
-
- while True:
- print("Getting stats for " + current_sha)
- utils.subprocess_run(["git", "checkout", current_sha])
-
- try:
- stats = get_stats()
-
- csvwriter.writerow(
- [current_sha, current_date, stats[0], stats[1], stats[2]])
-
- print("Collected stats for " + current_sha +
- " at " + current_date.isoformat())
- except:
- print("Unexpected error:", sys.exc_info()[0])
-
- if os.path.isdir(db):
- shutil.rmtree(db)
- print("Error getting stats for " +
- current_sha + ". Stopping iteration.")
- break
-
- current_sha, current_date = get_previous_sha(current_sha, current_date)
-
-utils.subprocess_run(["git", "checkout", "main"])
diff --git a/misc/scripts/library-coverage/utils.py b/misc/scripts/library-coverage/utils.py
index 122c8bdac0b..773874ac593 100644
--- a/misc/scripts/library-coverage/utils.py
+++ b/misc/scripts/library-coverage/utils.py
@@ -24,3 +24,11 @@ def run_codeql_query(query, database, output):
subprocess_run(["codeql", "bqrs", "decode", output + ".bqrs",
"--format=csv", "--no-titles", "--output", output])
os.remove(output + ".bqrs")
+
+
+class LanguageConfig:
+ def __init__(self, lang, capitalized_lang, ext, ql_path):
+ self.lang = lang
+ self.capitalized_lang = capitalized_lang
+ self.ext = ext
+ self.ql_path = ql_path
From d0ec1e2f37f3fe41581b74c76b639bcb4c1bed45 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Fri, 4 Jun 2021 16:32:51 +0200
Subject: [PATCH 031/153] Generate file with package info
---
.../library-coverage/generate-time-series.py | 68 ++++++++++++-------
1 file changed, 45 insertions(+), 23 deletions(-)
diff --git a/misc/scripts/library-coverage/generate-time-series.py b/misc/scripts/library-coverage/generate-time-series.py
index e76a159c7c0..924167474f6 100644
--- a/misc/scripts/library-coverage/generate-time-series.py
+++ b/misc/scripts/library-coverage/generate-time-series.py
@@ -54,20 +54,33 @@ def get_stats(lang, query):
sinks = 0
summaries = 0
+ packages = {}
+
with open(ql_output) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
# row: "android.util",1,"remote","source",16
+ package = row[0]
+ if package not in packages:
+ packages[package] = {
+ "sources": 0,
+ "sinks": 0,
+ "summaries": 0
+ }
+
if row[3] == "source":
sources += int(row[4])
+ packages[package]["sources"] += int(row[4])
if row[3] == "sink":
sinks += int(row[4])
+ packages[package]["sinks"] += int(row[4])
if row[3] == "summary":
summaries += int(row[4])
+ packages[package]["summaries"] += int(row[4])
os.remove(ql_output)
- return (sources, sinks, summaries)
+ return (sources, sinks, summaries, packages)
except:
print("Unexpected error:", sys.exc_info()[0])
raise Exception()
@@ -88,35 +101,44 @@ configs = [
# todo: change this when we cover multiple languages. We should compute the SHAs
# only once and not per language
for config in configs:
- with open("timeseries-" + config.lang + ".csv", 'w', newline='') as csvfile:
- csvwriter = csv.writer(csvfile)
- csvwriter.writerow(["SHA", "Date", "Sources", "Sinks", "Summaries"])
+ with open("timeseries-" + config.lang + ".csv", 'w', newline='') as csvfile_total:
+ with open("timeseries-" + config.lang + "-packages.csv", 'w', newline='') as csvfile_packages:
+ csvwriter_total = csv.writer(csvfile_total)
+ csvwriter_packages = csv.writer(csvfile_packages)
+ csvwriter_total.writerow(
+ ["SHA", "Date", "Sources", "Sinks", "Summaries"])
+ csvwriter_packages.writerow(
+ ["SHA", "Date", "Package", "Sources", "Sinks", "Summaries"])
- os.chdir(working_dir)
+ os.chdir(working_dir)
- utils.subprocess_run(["git", "checkout", "main"])
+ utils.subprocess_run(["git", "checkout", "main"])
- current_sha = get_str_output(["git", "rev-parse", "HEAD"])
- current_date = get_date(current_sha)
+ current_sha = get_str_output(["git", "rev-parse", "HEAD"])
+ current_date = get_date(current_sha)
- while True:
- print("Getting stats for " + current_sha)
- utils.subprocess_run(["git", "checkout", current_sha])
+ while True:
+ print("Getting stats for " + current_sha)
+ utils.subprocess_run(["git", "checkout", current_sha])
- try:
- stats = get_stats(config.lang, config.ql_path)
+ try:
+ stats = get_stats(config.lang, config.ql_path)
- csvwriter.writerow(
- [current_sha, current_date, stats[0], stats[1], stats[2]])
+ csvwriter_total.writerow(
+ [current_sha, current_date, stats[0], stats[1], stats[2]])
- print("Collected stats for " + current_sha +
- " at " + current_date.isoformat())
- except:
- print("Error getting stats for " +
- current_sha + ". Stopping iteration.")
- break
+ for package in stats[3]:
+ csvwriter_packages.writerow(
+ [current_sha, current_date, package, stats[3][package]["sources"], stats[3][package]["sinks"], stats[3][package]["summaries"]])
- current_sha, current_date = get_previous_sha(
- current_sha, current_date)
+ print("Collected stats for " + current_sha +
+ " at " + current_date.isoformat())
+ except:
+ print("Error getting stats for " +
+ current_sha + ". Stopping iteration.")
+ break
+
+ current_sha, current_date = get_previous_sha(
+ current_sha, current_date)
utils.subprocess_run(["git", "checkout", "main"])
From c6cb7c6eed0a75beddfccbb1e23eab87cdfe4155 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Tue, 8 Jun 2021 08:50:32 +0200
Subject: [PATCH 032/153] Rename time-series file to timeseries
---
.github/workflows/csv-coverage-timeseries.yml | 2 +-
.../{generate-time-series.py => generate-timeseries.py} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename misc/scripts/library-coverage/{generate-time-series.py => generate-timeseries.py} (100%)
diff --git a/.github/workflows/csv-coverage-timeseries.yml b/.github/workflows/csv-coverage-timeseries.yml
index 46287e7892f..ab87e6fb651 100644
--- a/.github/workflows/csv-coverage-timeseries.yml
+++ b/.github/workflows/csv-coverage-timeseries.yml
@@ -32,7 +32,7 @@ jobs:
run: unzip -d codeql-cli codeql-linux64.zip
- name: Build modeled package list
run: |
- PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-time-series.py codeqlModels
+ PATH="$PATH:codeql-cli/codeql" python script/misc/scripts/library-coverage/generate-timeseries.py codeqlModels
- name: Upload timeseries CSV
uses: actions/upload-artifact@v2
with:
diff --git a/misc/scripts/library-coverage/generate-time-series.py b/misc/scripts/library-coverage/generate-timeseries.py
similarity index 100%
rename from misc/scripts/library-coverage/generate-time-series.py
rename to misc/scripts/library-coverage/generate-timeseries.py
From ba9c2e0702781014140255be36d992c21309d78d Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Tue, 8 Jun 2021 14:51:49 +0200
Subject: [PATCH 033/153] Rework CSV report generator and change timeseries
report to use framework.csv
---
misc/scripts/library-coverage/frameworks.py | 72 ++++++++
.../library-coverage/generate-report.py | 124 ++++----------
.../library-coverage/generate-timeseries.py | 159 ++++++++++--------
misc/scripts/library-coverage/packages.py | 110 ++++++++++++
misc/scripts/library-coverage/utils.py | 18 ++
5 files changed, 323 insertions(+), 160 deletions(-)
create mode 100644 misc/scripts/library-coverage/frameworks.py
create mode 100644 misc/scripts/library-coverage/packages.py
diff --git a/misc/scripts/library-coverage/frameworks.py b/misc/scripts/library-coverage/frameworks.py
new file mode 100644
index 00000000000..a7f79098544
--- /dev/null
+++ b/misc/scripts/library-coverage/frameworks.py
@@ -0,0 +1,72 @@
+import csv
+import sys
+import packages
+
+
+class Framework:
+ """
+ Frameworks are the aggregation units in the RST and timeseries report. These are read from the frameworks.csv file.
+ """
+
+ def __init__(self, name, url, package_pattern):
+ self.name = name
+ self.url = url
+ self.package_pattern = package_pattern
+
+
+class FrameworkCollection:
+ """
+ A (sorted) list of frameworks.
+ """
+
+ def __init__(self, path):
+ self.frameworks: list[Framework] = []
+ self.package_patterns = set()
+
+ with open(path) as csvfile:
+ reader = csv.reader(csvfile)
+ next(reader)
+ for row in reader:
+ # row: Hibernate,https://hibernate.org/,org.hibernate
+ self.__add(Framework(row[0], row[1], row[2]))
+ self.__sort()
+
+ def __add(self, framework: Framework):
+ if framework.package_pattern not in self.package_patterns:
+ self.package_patterns.add(framework.package_pattern)
+ self.frameworks.append(framework)
+ else:
+ print("Package pattern already exists: " +
+ framework.package_pattern, file=sys.stderr)
+
+ def __sort(self):
+ self.frameworks.sort(key=lambda f: f.name)
+
+ def get(self, framework_name):
+ for framework in self.frameworks:
+ if framework.name == framework_name:
+ return framework
+ return None
+
+ def get_patterns(self):
+ return self.package_patterns
+
+ def get_frameworks(self):
+ return self.frameworks
+
+ def __package_match(self, package: packages.Package, pattern):
+ return (pattern.endswith("*") and package.name.startswith(pattern[:-1])) or (not pattern.endswith("*") and pattern == package.name)
+
+ def get_package_filter(self, framework: Framework):
+ """
+ Returns a lambda filter that holds for packages that match the current framework.
+
+ The pattern is either full name, such as "org.hibernate", or a prefix, such as "java.*"
+ Package patterns might overlap, in case of 'org.apache.commons.io' and 'org.apache.*', the statistics for
+ the latter will not include the statistics for the former.
+ """
+ return lambda p: \
+ self.__package_match(p, framework.package_pattern) and \
+ all(
+ len(framework.package_pattern) >= len(pattern) or
+ not self.__package_match(p, pattern) for pattern in self.get_patterns())
diff --git a/misc/scripts/library-coverage/generate-report.py b/misc/scripts/library-coverage/generate-report.py
index bb692088a46..2df4e1e9409 100644
--- a/misc/scripts/library-coverage/generate-report.py
+++ b/misc/scripts/library-coverage/generate-report.py
@@ -4,6 +4,8 @@ import os
import shutil
import settings
import utils
+import packages as pack
+import frameworks as fr
"""
This script runs the CSV coverage report QL query, and transforms it to a more readable format.
@@ -28,14 +30,7 @@ def append_csv_dict_item(list, dictionary, key):
list.append(None)
-def increment_dict_item(value, dictionary, key):
- """Increments the value of the dictionary[key] by value."""
- if key not in dictionary:
- dictionary[key] = 0
- dictionary[key] += int(value)
-
-
-def collect_package_stats(packages, cwes, filter):
+def collect_package_stats(packages: pack.PackageCollection, cwes, filter):
"""
Collects coverage statistics for packages matching the given filter. `filter` is a `lambda` that for example (i) matches
packages to frameworks, or (2) matches packages that were previously not processed.
@@ -48,20 +43,21 @@ def collect_package_stats(packages, cwes, filter):
framework_cwes = {}
processed_packages = set()
- for package in packages:
+ for package in packages.get_packages():
+ package: pack.Package = package
if filter(package):
processed_packages.add(package)
- sources += int(packages[package]["kind"].get("source:remote", 0))
- steps += int(packages[package]["part"].get("summary", 0))
- sinks += int(packages[package]["part"].get("sink", 0))
+ sources += package.get_kind_count("source:remote")
+ steps += package.get_part_count("summary")
+ sinks += package.get_part_count("sink")
for cwe in cwes:
sink = "sink:" + cwes[cwe]["sink"]
- if sink in packages[package]["kind"]:
+ count = package.get_kind_count(sink)
+ if count > 0:
if cwe not in framework_cwes:
framework_cwes[cwe] = 0
- framework_cwes[cwe] += int(
- packages[package]["kind"][sink])
+ framework_cwes[cwe] += count
return sources, steps, sinks, framework_cwes, processed_packages
@@ -137,37 +133,12 @@ for config in configs:
utils.run_codeql_query(config.ql_path, db, ql_output)
shutil.rmtree(db)
- packages = {}
- parts = set()
- kinds = set()
-
- # Read the generated CSV file, and collect package statistics.
- with open(ql_output) as csvfile:
- reader = csv.reader(csvfile)
- for row in reader:
- # row: "android.util",1,"remote","source",16
- package = row[0]
- if package not in packages:
- packages[package] = {
- "count": row[1],
- # part: "summary", "sink", or "source"
- "part": {},
- # kind: "source:remote", "sink:create-file", ...
- "kind": {}
- }
-
- part = row[3]
- parts.add(part)
- increment_dict_item(row[4], packages[package]["part"], part)
-
- kind = part + ":" + row[2]
- kinds.add(kind)
- increment_dict_item(row[4], packages[package]["kind"], kind)
+ packages = pack.PackageCollection(ql_output)
os.remove(ql_output)
- parts = sorted(parts)
- kinds = sorted(kinds)
+ parts = packages.get_parts()
+ kinds = packages.get_kinds()
# Write the denormalized package statistics to a CSV file.
with open(output_csv.format(language=lang), 'w', newline='') as csvfile:
@@ -179,44 +150,21 @@ for config in configs:
csvwriter.writerow(headers)
- for package in sorted(packages):
- row = [package]
+ for package in packages.get_packages():
+ package: pack.Package = package
+ row = [package.name]
for part in parts:
- append_csv_dict_item(row, packages[package]["part"], part)
+ append_csv_number(row, package.get_part_count(part))
for kind in kinds:
- append_csv_dict_item(row, packages[package]["kind"], kind)
+ append_csv_number(row, package.get_kind_count(kind))
csvwriter.writerow(row)
# Read the additional framework data, such as URL, friendly name
- frameworks = {}
-
- with open(input_framework_csv.format(language=lang)) as csvfile:
- reader = csv.reader(csvfile)
- next(reader)
- for row in reader:
- # row: Hibernate,https://hibernate.org/,org.hibernate
- framwork = row[0]
- if framwork not in frameworks:
- frameworks[framwork] = {
- "package": row[2],
- "url": row[1]
- }
+ frameworks = fr.FrameworkCollection(
+ input_framework_csv.format(language=lang))
# Read the additional CWE data
- cwes = {}
-
- with open(input_cwe_sink_csv.format(language=lang)) as csvfile:
- reader = csv.reader(csvfile)
- next(reader)
- for row in reader:
- # row: CWE-89,sql,SQL injection
- cwe = row[0]
- if cwe not in cwes:
- cwes[cwe] = {
- "sink": row[1],
- "label": row[2]
- }
-
+ cwes = utils.read_cwes(input_cwe_sink_csv.format(language=lang))
sorted_cwes = sorted(cwes)
with open(output_rst.format(language=lang), 'w', newline='') as rst_file:
@@ -246,34 +194,24 @@ for config in configs:
processed_packages = set()
- all_package_patterns = set(
- (frameworks[fr]["package"] for fr in frameworks))
-
# Write a row for each framework.
- for framework in sorted(frameworks):
+ for framework in frameworks.get_frameworks():
+ framework: fr.Framework = framework
row = []
# Add the framework name to the row
- if not frameworks[framework]["url"]:
- row.append(row_prefix + framework)
+ if not framework.url:
+ row.append(row_prefix + framework.name)
else:
row.append(
- row_prefix + "`" + framework + " <" + frameworks[framework]["url"] + ">`_")
+ row_prefix + "`" + framework.name + " <" + framework.url + ">`_")
# Add the package name to the row
- row.append("``" + frameworks[framework]["package"] + "``")
-
- current_package_pattern = frameworks[framework]["package"]
+ row.append("``" + framework.package_pattern + "``")
# Collect statistics on the current framework
- # current_package_pattern is either full name, such as "org.hibernate", or a prefix, such as "java.*"
- # Package patterns might overlap, in case of 'org.apache.commons.io' and 'org.apache.*', the statistics for
- # the latter will not include the statistics for the former.
- def package_match(package_name, pattern): return (pattern.endswith(
- "*") and package_name.startswith(pattern[:-1])) or (not pattern.endswith("*") and pattern == package_name)
-
def collect_framework(): return collect_package_stats(
- packages, cwes, lambda p: package_match(p, current_package_pattern) and all(len(current_package_pattern) >= len(pattern) or not package_match(p, pattern) for pattern in all_package_patterns))
+ packages, cwes, frameworks.get_package_filter(framework))
row, f_processed_packages = add_package_stats_to_row(
row, sorted_cwes, collect_framework)
@@ -290,8 +228,8 @@ for config in configs:
row, other_packages = add_package_stats_to_row(
row, sorted_cwes, collect_others)
- row[1] = ", ".join("``{0}``".format(p)
- for p in sorted(other_packages))
+ row[1] = ", ".join("``{0}``".format(p.name)
+ for p in sorted(other_packages, key=lambda x: x.name))
csvwriter.writerow(row)
diff --git a/misc/scripts/library-coverage/generate-timeseries.py b/misc/scripts/library-coverage/generate-timeseries.py
index 924167474f6..12c2af95ee4 100644
--- a/misc/scripts/library-coverage/generate-timeseries.py
+++ b/misc/scripts/library-coverage/generate-timeseries.py
@@ -6,42 +6,43 @@ import shutil
from datetime import date
import datetime
import utils
+import settings
+import packages as pack
+import frameworks as fr
"""
- Gets the sink/source/summary statistics for different days.
+Gets the sink/source/summary statistics for different days.
"""
# the distance between commits to include in the output
day_distance = 1
-def get_str_output(arr):
- r = subprocess.check_output(arr)
- return r.decode("utf-8").strip("\n'")
+class Git:
+ def get_output(arr):
+ r = subprocess.check_output(arr, text=True, env=os.environ.copy())
+ return r.strip("\n'")
+
+ def get_date(sha):
+ d = Git.get_output(
+ ["git", "show", "--no-patch", "--no-notes", "--pretty='%cd'", "--date=short", sha])
+ return date.fromisoformat(d)
+
+ def get_parent(sha):
+ parent_sha = Git.get_output(
+ ["git", "rev-parse", sha + "^"])
+ parent_date = Git.get_date(parent_sha)
+ return (parent_sha, parent_date)
+
+ def get_previous_sha(sha, date):
+ parent_sha, parent_date = Git.get_parent(sha)
+ while parent_date > date + datetime.timedelta(days=-1 * day_distance):
+ parent_sha, parent_date = Git.get_parent(parent_sha)
+
+ return (parent_sha, parent_date)
-def get_date(sha):
- d = get_str_output(
- ["git", "show", "--no-patch", "--no-notes", "--pretty='%cd'", "--date=short", sha])
- return date.fromisoformat(d)
-
-
-def get_parent(sha, date):
- parent_sha = get_str_output(
- ["git", "rev-parse", sha + "^"])
- parent_date = get_date(parent_sha)
- return (parent_sha, parent_date)
-
-
-def get_previous_sha(sha, date):
- parent_sha, parent_date = get_parent(sha, date)
- while parent_date > date + datetime.timedelta(days=-1 * day_distance):
- parent_sha, parent_date = get_parent(parent_sha, parent_date)
-
- return (parent_sha, parent_date)
-
-
-def get_stats(lang, query):
+def get_packages(lang, query):
try:
db = "empty_" + lang
ql_output = "output-" + lang + ".csv"
@@ -50,41 +51,14 @@ def get_stats(lang, query):
utils.create_empty_database(lang, ".java", db)
utils.run_codeql_query(query, db, ql_output)
- sources = 0
- sinks = 0
- summaries = 0
-
- packages = {}
-
- with open(ql_output) as csvfile:
- reader = csv.reader(csvfile)
- for row in reader:
- # row: "android.util",1,"remote","source",16
- package = row[0]
- if package not in packages:
- packages[package] = {
- "sources": 0,
- "sinks": 0,
- "summaries": 0
- }
-
- if row[3] == "source":
- sources += int(row[4])
- packages[package]["sources"] += int(row[4])
- if row[3] == "sink":
- sinks += int(row[4])
- packages[package]["sinks"] += int(row[4])
- if row[3] == "summary":
- summaries += int(row[4])
- packages[package]["summaries"] += int(row[4])
-
- os.remove(ql_output)
-
- return (sources, sinks, summaries, packages)
+ return pack.PackageCollection(ql_output)
except:
print("Unexpected error:", sys.exc_info()[0])
raise Exception()
finally:
+ if os.path.isfile(ql_output):
+ os.remove(ql_output)
+
if os.path.isdir(db):
shutil.rmtree(db)
@@ -108,28 +82,79 @@ for config in configs:
csvwriter_total.writerow(
["SHA", "Date", "Sources", "Sinks", "Summaries"])
csvwriter_packages.writerow(
- ["SHA", "Date", "Package", "Sources", "Sinks", "Summaries"])
+ ["SHA", "Date", "Framework", "Package", "Sources", "Sinks", "Summaries"])
os.chdir(working_dir)
utils.subprocess_run(["git", "checkout", "main"])
- current_sha = get_str_output(["git", "rev-parse", "HEAD"])
- current_date = get_date(current_sha)
+ current_sha = Git.get_output(["git", "rev-parse", "HEAD"])
+ current_date = Git.get_date(current_sha)
+
+ # Read the additional framework data, such as URL, friendly name from the latest commit
+ input_framework_csv = settings.documentation_folder_no_prefix + "frameworks.csv"
+ frameworks = fr.FrameworkCollection(
+ input_framework_csv.format(language=config.lang))
while True:
print("Getting stats for " + current_sha)
utils.subprocess_run(["git", "checkout", current_sha])
try:
- stats = get_stats(config.lang, config.ql_path)
+ packages = get_packages(config.lang, config.ql_path)
- csvwriter_total.writerow(
- [current_sha, current_date, stats[0], stats[1], stats[2]])
+ csvwriter_total.writerow([
+ current_sha,
+ current_date,
+ packages.get_part_count("source"),
+ packages.get_part_count("sink"),
+ packages.get_part_count("summary")])
- for package in stats[3]:
- csvwriter_packages.writerow(
- [current_sha, current_date, package, stats[3][package]["sources"], stats[3][package]["sinks"], stats[3][package]["summaries"]])
+ matched_packages = set()
+
+ for framework in frameworks.get_frameworks():
+ framework: fr.Framework = framework
+
+ row = [current_sha, current_date,
+ framework.name, framework.package_pattern]
+
+ sources = 0
+ sinks = 0
+ summaries = 0
+
+ for package in packages.get_packages():
+ if frameworks.get_package_filter(framework)(package):
+ sources += package.get_part_count("source")
+ sinks += package.get_part_count("sink")
+ summaries += package.get_part_count("summary")
+ matched_packages.add(package.name)
+
+ row.append(sources)
+ row.append(sinks)
+ row.append(summaries)
+
+ csvwriter_packages.writerow(row)
+
+ row = [current_sha, current_date, "Others"]
+
+ sources = 0
+ sinks = 0
+ summaries = 0
+ other_packages = set()
+
+ for package in packages.get_packages():
+ if not package.name in matched_packages:
+ sources += package.get_part_count("source")
+ sinks += package.get_part_count("sink")
+ summaries += package.get_part_count("summary")
+ other_packages.add(package.name)
+
+ row.append(", ".join(sorted(other_packages)))
+ row.append(sources)
+ row.append(sinks)
+ row.append(summaries)
+
+ csvwriter_packages.writerow(row)
print("Collected stats for " + current_sha +
" at " + current_date.isoformat())
@@ -138,7 +163,7 @@ for config in configs:
current_sha + ". Stopping iteration.")
break
- current_sha, current_date = get_previous_sha(
+ current_sha, current_date = Git.get_previous_sha(
current_sha, current_date)
utils.subprocess_run(["git", "checkout", "main"])
diff --git a/misc/scripts/library-coverage/packages.py b/misc/scripts/library-coverage/packages.py
new file mode 100644
index 00000000000..f0292b867cf
--- /dev/null
+++ b/misc/scripts/library-coverage/packages.py
@@ -0,0 +1,110 @@
+import csv
+
+
+class PackagePart:
+ """
+ Represents a single package part with its count returned from the QL query, such as:
+ "android.util",1,"remote","source",16
+ """
+
+ def __init__(self, package, kind, part, count):
+ self.package = package
+ # "summary", "sink", or "source"
+ self.part = part
+ # "source:remote", "sink:create-file", ...
+ self.kind = part + ":" + kind
+ self.count = int(count)
+
+
+class Package:
+ """
+ Represents an entire package with multiple parts returned from the QL query.
+ """
+
+ def __init__(self, name, package_count):
+ self.parts: list[PackagePart] = []
+
+ self.name = name
+ self.package_count = int(package_count)
+
+ def add_part(self, part: PackagePart):
+ self.parts.append(part)
+
+ def get_part_count(self, p):
+ count = 0
+ for part in self.parts:
+ if part.part == p:
+ count += part.count
+ return count
+
+ def get_kind_count(self, k):
+ count = 0
+ for part in self.parts:
+ if part.kind == k:
+ count += part.count
+ return count
+
+
+class PackageCollection:
+ """
+ A (sorted) list of packages. Packages are returned by the QL query in the form:
+ "android.util",1,"remote","source",16
+
+ And then the denormalized rows are aggregated by packages.
+ """
+
+ def __init__(self, ql_output_path):
+ self.packages: list[Package] = []
+ self.package_names = set()
+
+ # Read the generated CSV file, and collect package statistics.
+ with open(ql_output_path) as csvfile:
+ reader = csv.reader(csvfile)
+ for row in reader:
+ # row: "android.util",1,"remote","source",16
+
+ package = self.__get_or_create_package(row[0], row[1])
+
+ packagePart = PackagePart(
+ package, row[2], row[3], row[4])
+
+ package.add_part(packagePart)
+ self.__sort()
+
+ def __sort(self):
+ self.packages.sort(key=lambda f: f.name)
+
+ def get_packages(self):
+ return self.packages
+
+ def __get_or_create_package(self, package_name, package_count):
+ if package_name not in self.package_names:
+ self.package_names.add(package_name)
+ package = Package(package_name, package_count)
+ self.packages.append(package)
+ return package
+ else:
+ for package in self.packages:
+ if package.name == package_name:
+ return package
+ return None
+
+ def get_parts(self):
+ parts = set()
+ for package in self.packages:
+ for part in package.parts:
+ parts.add(part.part)
+ return sorted(parts)
+
+ def get_kinds(self):
+ kinds = set()
+ for package in self.packages:
+ for part in package.parts:
+ kinds.add(part.kind)
+ return sorted(kinds)
+
+ def get_part_count(self, p):
+ count = 0
+ for package in self.packages:
+ count += package.get_part_count(p)
+ return count
diff --git a/misc/scripts/library-coverage/utils.py b/misc/scripts/library-coverage/utils.py
index 773874ac593..e9dc6b12472 100644
--- a/misc/scripts/library-coverage/utils.py
+++ b/misc/scripts/library-coverage/utils.py
@@ -1,5 +1,7 @@
import subprocess
import os
+import csv
+import sys
def subprocess_run(cmd):
@@ -32,3 +34,19 @@ class LanguageConfig:
self.capitalized_lang = capitalized_lang
self.ext = ext
self.ql_path = ql_path
+
+
+def read_cwes(path):
+ cwes = {}
+ with open(path) as csvfile:
+ reader = csv.reader(csvfile)
+ next(reader)
+ for row in reader:
+ # row: CWE-89,sql,SQL injection
+ cwe = row[0]
+ if cwe not in cwes:
+ cwes[cwe] = {
+ "sink": row[1],
+ "label": row[2]
+ }
+ return cwes
From 3605b9f720e2bf087872480295c9d6aa2c41c3bc Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Wed, 9 Jun 2021 09:59:01 +0200
Subject: [PATCH 034/153] Update java framework data
---
java/documentation/library-coverage/frameworks.csv | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/java/documentation/library-coverage/frameworks.csv b/java/documentation/library-coverage/frameworks.csv
index 0e39bc51836..a99e9618457 100644
--- a/java/documentation/library-coverage/frameworks.csv
+++ b/java/documentation/library-coverage/frameworks.csv
@@ -1,8 +1,11 @@
Framework name,URL,Package prefix
Java Standard Library,,java.*
-Google,,com.google.common.*
-Apache,,org.apache.*
+Java extensions,,javax.*
+Google Guava,https://guava.dev/,com.google.common.*
Apache Commons IO,https://commons.apache.org/proper/commons-io/,org.apache.commons.io
+Apache Commons Lang,https://commons.apache.org/proper/commons-lang/,org.apache.commons.lang3
+Apache Commons Text,https://commons.apache.org/proper/commons-text/,org.apache.commons.text
+Apache HttpComponents,https://hc.apache.org/,org.apache.hc.core5.*
+Apache HttpComponents,https://hc.apache.org/,org.apache.http
Android,,android.*
-Spring,https://spring.io/,org.springframework.*
-Java extensions,,javax.*
\ No newline at end of file
+Spring,https://spring.io/,org.springframework.*
\ No newline at end of file
From 74c00383d279d4853d05ea44bc9b22380de4b553 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Thu, 10 Jun 2021 10:26:34 +0200
Subject: [PATCH 035/153] Update java framework coverage reports
---
.../library-coverage/flow-model-coverage.csv | 86 ++++++++++---------
.../library-coverage/flow-model-coverage.rst | 13 +--
2 files changed, 52 insertions(+), 47 deletions(-)
diff --git a/java/documentation/library-coverage/flow-model-coverage.csv b/java/documentation/library-coverage/flow-model-coverage.csv
index 464228bb022..b7b83a6c217 100644
--- a/java/documentation/library-coverage/flow-model-coverage.csv
+++ b/java/documentation/library-coverage/flow-model-coverage.csv
@@ -1,42 +1,44 @@
-package,sink,source,summary,sink:bean-validation,sink:create-file,sink:header-splitting,sink:information-leak,sink:ldap,sink:open-url,sink:set-hostname-verifier,sink:url-open-stream,sink:xpath,sink:xss,source:remote,summary:taint,summary:value
-android.util,,16,,,,,,,,,,,,16,,
-android.webkit,3,2,,,,,,,,,,,3,2,,
-com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,1,
-com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,1,
-com.fasterxml.jackson.databind,,,2,,,,,,,,,,,,2,
-com.google.common.base,,,28,,,,,,,,,,,,22,6
-com.google.common.io,6,,69,,,,,,,,6,,,,68,1
-com.unboundid.ldap.sdk,17,,,,,,,17,,,,,,,,
-java.beans,,,1,,,,,,,,,,,,1,
-java.io,3,,20,,3,,,,,,,,,,20,
-java.lang,,,1,,,,,,,,,,,,1,
-java.net,2,3,4,,,,,,2,,,,,3,4,
-java.nio,10,,2,,10,,,,,,,,,,2,
-java.util,,,13,,,,,,,,,,,,13,
-javax.naming.directory,1,,,,,,,1,,,,,,,,
-javax.net.ssl,2,,,,,,,,,2,,,,,,
-javax.servlet,4,21,2,,,3,1,,,,,,,21,2,
-javax.validation,1,1,,1,,,,,,,,,,1,,
-javax.ws.rs.core,1,,,,,1,,,,,,,,,,
-javax.xml.transform.sax,,,4,,,,,,,,,,,,4,
-javax.xml.transform.stream,,,2,,,,,,,,,,,,2,
-javax.xml.xpath,3,,,,,,,,,,,3,,,,
-org.apache.commons.codec,,,2,,,,,,,,,,,,2,
-org.apache.commons.io,,,22,,,,,,,,,,,,22,
-org.apache.commons.lang3,,,313,,,,,,,,,,,,299,14
-org.apache.commons.text,,,203,,,,,,,,,,,,203,
-org.apache.directory.ldap.client.api,1,,,,,,,1,,,,,,,,
-org.apache.hc.core5.function,,,1,,,,,,,,,,,,1,
-org.apache.hc.core5.http,1,2,39,,,,,,,,,,1,2,39,
-org.apache.hc.core5.net,,,2,,,,,,,,,,,,2,
-org.apache.hc.core5.util,,,22,,,,,,,,,,,,18,4
-org.apache.http,2,3,66,,,,,,,,,,2,3,59,7
-org.dom4j,20,,,,,,,,,,,20,,,,
-org.springframework.ldap.core,14,,,,,,,14,,,,,,,,
-org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,6,,
-org.springframework.web.client,,3,,,,,,,,,,,,3,,
-org.springframework.web.context.request,,8,,,,,,,,,,,,8,,
-org.springframework.web.multipart,,12,,,,,,,,,,,,12,,
-org.xml.sax,,,1,,,,,,,,,,,,1,
-org.xmlpull.v1,,3,,,,,,,,,,,,3,,
-play.mvc,,4,,,,,,,,,,,,4,,
+package,sink,source,summary,sink:bean-validation,sink:create-file,sink:header-splitting,sink:information-leak,sink:jexl,sink:ldap,sink:open-url,sink:set-hostname-verifier,sink:url-open-stream,sink:xpath,sink:xss,source:remote,summary:taint,summary:value
+android.util,,16,,,,,,,,,,,,,16,,
+android.webkit,3,2,,,,,,,,,,,,3,2,,
+com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,1,
+com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,1,
+com.fasterxml.jackson.databind,,,3,,,,,,,,,,,,,3,
+com.google.common.base,,,34,,,,,,,,,,,,,28,6
+com.google.common.io,6,,73,,,,,,,,,6,,,,72,1
+com.unboundid.ldap.sdk,17,,,,,,,,17,,,,,,,,
+java.beans,,,1,,,,,,,,,,,,,1,
+java.io,3,,20,,3,,,,,,,,,,,20,
+java.lang,,,3,,,,,,,,,,,,,1,2
+java.net,2,3,4,,,,,,,2,,,,,3,4,
+java.nio,10,,2,,10,,,,,,,,,,,2,
+java.util,,,283,,,,,,,,,,,,,15,268
+javax.naming.directory,1,,,,,,,,1,,,,,,,,
+javax.net.ssl,2,,,,,,,,,,2,,,,,,
+javax.servlet,4,21,2,,,3,1,,,,,,,,21,2,
+javax.validation,1,1,,1,,,,,,,,,,,1,,
+javax.ws.rs.core,1,,,,,1,,,,,,,,,,,
+javax.xml.transform.sax,,,4,,,,,,,,,,,,,4,
+javax.xml.transform.stream,,,2,,,,,,,,,,,,,2,
+javax.xml.xpath,3,,,,,,,,,,,,3,,,,
+org.apache.commons.codec,,,2,,,,,,,,,,,,,2,
+org.apache.commons.io,,,22,,,,,,,,,,,,,22,
+org.apache.commons.jexl2,15,,,,,,,15,,,,,,,,,
+org.apache.commons.jexl3,15,,,,,,,15,,,,,,,,,
+org.apache.commons.lang3,,,370,,,,,,,,,,,,,324,46
+org.apache.commons.text,,,272,,,,,,,,,,,,,220,52
+org.apache.directory.ldap.client.api,1,,,,,,,,1,,,,,,,,
+org.apache.hc.core5.function,,,1,,,,,,,,,,,,,1,
+org.apache.hc.core5.http,1,2,39,,,,,,,,,,,1,2,39,
+org.apache.hc.core5.net,,,2,,,,,,,,,,,,,2,
+org.apache.hc.core5.util,,,24,,,,,,,,,,,,,18,6
+org.apache.http,2,3,67,,,,,,,,,,,2,3,59,8
+org.dom4j,20,,,,,,,,,,,,20,,,,
+org.springframework.ldap.core,14,,,,,,,,14,,,,,,,,
+org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,6,,
+org.springframework.web.client,,3,,,,,,,,,,,,,3,,
+org.springframework.web.context.request,,8,,,,,,,,,,,,,8,,
+org.springframework.web.multipart,,12,,,,,,,,,,,,,12,,
+org.xml.sax,,,1,,,,,,,,,,,,,1,
+org.xmlpull.v1,,3,,,,,,,,,,,,,3,,
+play.mvc,,4,,,,,,,,,,,,,4,,
diff --git a/java/documentation/library-coverage/flow-model-coverage.rst b/java/documentation/library-coverage/flow-model-coverage.rst
index b9b54aad158..cc71ab0aac2 100644
--- a/java/documentation/library-coverage/flow-model-coverage.rst
+++ b/java/documentation/library-coverage/flow-model-coverage.rst
@@ -8,12 +8,15 @@ Java framework & library support
Framework / library,Package,Remote flow sources,Taint & value steps,Sinks (total),`CWE‑022` :sub:`Path injection`,`CWE‑036` :sub:`Path traversal`,`CWE‑079` :sub:`Cross-site scripting`,`CWE‑089` :sub:`SQL injection`,`CWE‑090` :sub:`LDAP injection`,`CWE‑094` :sub:`Code injection`,`CWE‑319` :sub:`Cleartext transmission`
Android,``android.*``,18,,3,,,3,,,,
- Apache,``org.apache.*``,5,648,4,,,3,,1,,
`Apache Commons IO `_,``org.apache.commons.io``,,22,,,,,,,,
- Google,``com.google.common.*``,,97,6,,6,,,,,
- Java Standard Library,``java.*``,3,41,15,13,,,,,,2
+ `Apache Commons Lang `_,``org.apache.commons.lang3``,,370,,,,,,,,
+ `Apache Commons Text `_,``org.apache.commons.text``,,272,,,,,,,,
+ `Apache HttpComponents `_,``org.apache.hc.core5.*``,2,66,1,,,1,,,,
+ `Apache HttpComponents `_,``org.apache.http``,3,67,2,,,2,,,,
+ `Google Guava `_,``com.google.common.*``,,107,6,,6,,,,,
+ Java Standard Library,``java.*``,3,313,15,13,,,,,,2
Java extensions,``javax.*``,22,8,12,,,,,1,1,
`Spring `_,``org.springframework.*``,29,,14,,,,,14,,
- Others,"``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.databind``, ``com.unboundid.ldap.sdk``, ``org.dom4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``",7,5,37,,,,,17,,
- Totals,,84,821,91,13,6,6,,33,1,2
+ Others,"``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.databind``, ``com.unboundid.ldap.sdk``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.directory.ldap.client.api``, ``org.dom4j``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``",7,8,68,,,,,18,,
+ Totals,,84,1233,121,13,6,6,,33,1,2
From 55dd6ed3d1cf4f374b943fa89d05f670ca0c0fe8 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Thu, 10 Jun 2021 10:54:12 +0200
Subject: [PATCH 036/153] Allow space separated package patterns in
framework-aggregated reports
---
.../library-coverage/flow-model-coverage.rst | 3 +--
.../documentation/library-coverage/frameworks.csv | 5 ++---
misc/scripts/library-coverage/frameworks.py | 15 +++++++++------
misc/scripts/library-coverage/generate-report.py | 3 ++-
4 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/java/documentation/library-coverage/flow-model-coverage.rst b/java/documentation/library-coverage/flow-model-coverage.rst
index cc71ab0aac2..c99a41d3be2 100644
--- a/java/documentation/library-coverage/flow-model-coverage.rst
+++ b/java/documentation/library-coverage/flow-model-coverage.rst
@@ -11,8 +11,7 @@ Java framework & library support
`Apache Commons IO `_,``org.apache.commons.io``,,22,,,,,,,,
`Apache Commons Lang `_,``org.apache.commons.lang3``,,370,,,,,,,,
`Apache Commons Text `_,``org.apache.commons.text``,,272,,,,,,,,
- `Apache HttpComponents `_,``org.apache.hc.core5.*``,2,66,1,,,1,,,,
- `Apache HttpComponents `_,``org.apache.http``,3,67,2,,,2,,,,
+ `Apache HttpComponents `_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,133,3,,,3,,,,
`Google Guava `_,``com.google.common.*``,,107,6,,6,,,,,
Java Standard Library,``java.*``,3,313,15,13,,,,,,2
Java extensions,``javax.*``,22,8,12,,,,,1,1,
diff --git a/java/documentation/library-coverage/frameworks.csv b/java/documentation/library-coverage/frameworks.csv
index a99e9618457..751883eaf4b 100644
--- a/java/documentation/library-coverage/frameworks.csv
+++ b/java/documentation/library-coverage/frameworks.csv
@@ -1,11 +1,10 @@
-Framework name,URL,Package prefix
+Framework name,URL,Package prefixes
Java Standard Library,,java.*
Java extensions,,javax.*
Google Guava,https://guava.dev/,com.google.common.*
Apache Commons IO,https://commons.apache.org/proper/commons-io/,org.apache.commons.io
Apache Commons Lang,https://commons.apache.org/proper/commons-lang/,org.apache.commons.lang3
Apache Commons Text,https://commons.apache.org/proper/commons-text/,org.apache.commons.text
-Apache HttpComponents,https://hc.apache.org/,org.apache.hc.core5.*
-Apache HttpComponents,https://hc.apache.org/,org.apache.http
+Apache HttpComponents,https://hc.apache.org/,org.apache.hc.core5.* org.apache.http
Android,,android.*
Spring,https://spring.io/,org.springframework.*
\ No newline at end of file
diff --git a/misc/scripts/library-coverage/frameworks.py b/misc/scripts/library-coverage/frameworks.py
index a7f79098544..d37e59ddb74 100644
--- a/misc/scripts/library-coverage/frameworks.py
+++ b/misc/scripts/library-coverage/frameworks.py
@@ -48,20 +48,23 @@ class FrameworkCollection:
return framework
return None
- def get_patterns(self):
- return self.package_patterns
-
def get_frameworks(self):
return self.frameworks
- def __package_match(self, package: packages.Package, pattern):
+ def __package_match_single(self, package: packages.Package, pattern):
return (pattern.endswith("*") and package.name.startswith(pattern[:-1])) or (not pattern.endswith("*") and pattern == package.name)
+ def __package_match(self, package: packages.Package, pattern):
+ patterns = pattern.split(" ")
+ return any(self.__package_match_single(package, pattern) for pattern in patterns)
+
def get_package_filter(self, framework: Framework):
"""
Returns a lambda filter that holds for packages that match the current framework.
- The pattern is either full name, such as "org.hibernate", or a prefix, such as "java.*"
+ The pattern is either full name, such as "org.hibernate", or a prefix, such as "java.*".
+ Patterns can also contain a space separated list of patterns, such as "java.sql javax.swing".
+
Package patterns might overlap, in case of 'org.apache.commons.io' and 'org.apache.*', the statistics for
the latter will not include the statistics for the former.
"""
@@ -69,4 +72,4 @@ class FrameworkCollection:
self.__package_match(p, framework.package_pattern) and \
all(
len(framework.package_pattern) >= len(pattern) or
- not self.__package_match(p, pattern) for pattern in self.get_patterns())
+ not self.__package_match(p, pattern) for pattern in self.package_patterns)
diff --git a/misc/scripts/library-coverage/generate-report.py b/misc/scripts/library-coverage/generate-report.py
index 2df4e1e9409..bb5dc694fd5 100644
--- a/misc/scripts/library-coverage/generate-report.py
+++ b/misc/scripts/library-coverage/generate-report.py
@@ -207,7 +207,8 @@ for config in configs:
row_prefix + "`" + framework.name + " <" + framework.url + ">`_")
# Add the package name to the row
- row.append("``" + framework.package_pattern + "``")
+ row.append(", ".join("``{0}``".format(p)
+ for p in framework.package_pattern.split(" ")))
# Collect statistics on the current framework
def collect_framework(): return collect_package_stats(
From 73aaeb4c0d77dc0e16366fc48c9e4a0b41af00ce Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Thu, 10 Jun 2021 11:01:45 +0200
Subject: [PATCH 037/153] Change workflow names
---
.github/workflows/csv-coverage-timeseries.yml | 2 +-
.github/workflows/csv-coverage.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/csv-coverage-timeseries.yml b/.github/workflows/csv-coverage-timeseries.yml
index ab87e6fb651..f959a45837a 100644
--- a/.github/workflows/csv-coverage-timeseries.yml
+++ b/.github/workflows/csv-coverage-timeseries.yml
@@ -1,4 +1,4 @@
-name: Build CSV timeseries flow coverage report
+name: Build framework coverage timeseries reports
on:
workflow_dispatch:
diff --git a/.github/workflows/csv-coverage.yml b/.github/workflows/csv-coverage.yml
index 1a5816816b4..0efb895b152 100644
--- a/.github/workflows/csv-coverage.yml
+++ b/.github/workflows/csv-coverage.yml
@@ -1,4 +1,4 @@
-name: Build CSV flow coverage report
+name: Build framework coverage reports
on:
workflow_dispatch:
From b0673099092d8eb671e0eb34902f1c86f9d15ce5 Mon Sep 17 00:00:00 2001
From: Tamas Vajk
Date: Thu, 10 Jun 2021 11:26:07 +0200
Subject: [PATCH 038/153] Change artifact names
---
.github/workflows/csv-coverage-timeseries.yml | 4 ++--
.github/workflows/csv-coverage.yml | 8 ++++----
.../{flow-model-coverage.csv => coverage.csv} | 0
.../{flow-model-coverage.rst => coverage.rst} | 0
misc/scripts/library-coverage/generate-timeseries.py | 5 +++--
misc/scripts/library-coverage/settings.py | 8 ++++----
6 files changed, 13 insertions(+), 12 deletions(-)
rename java/documentation/library-coverage/{flow-model-coverage.csv => coverage.csv} (100%)
rename java/documentation/library-coverage/{flow-model-coverage.rst => coverage.rst} (100%)
diff --git a/.github/workflows/csv-coverage-timeseries.yml b/.github/workflows/csv-coverage-timeseries.yml
index f959a45837a..42f00d6bbae 100644
--- a/.github/workflows/csv-coverage-timeseries.yml
+++ b/.github/workflows/csv-coverage-timeseries.yml
@@ -36,6 +36,6 @@ jobs:
- name: Upload timeseries CSV
uses: actions/upload-artifact@v2
with:
- name: csv-flow-model-coverage-timeseries
- path: timeseries-*.csv
+ name: framework-coverage-timeseries
+ path: framework-coverage-timeseries-*.csv
diff --git a/.github/workflows/csv-coverage.yml b/.github/workflows/csv-coverage.yml
index 0efb895b152..3c551ae02df 100644
--- a/.github/workflows/csv-coverage.yml
+++ b/.github/workflows/csv-coverage.yml
@@ -47,11 +47,11 @@ jobs:
- name: Upload CSV package list
uses: actions/upload-artifact@v2
with:
- name: csv-flow-model-coverage
- path: flow-model-coverage-*.csv
+ name: framework-coverage-csv
+ path: framework-coverage-*.csv
- name: Upload RST package list
uses: actions/upload-artifact@v2
with:
- name: rst-flow-model-coverage
- path: flow-model-coverage-*.rst
+ name: framework-coverage-rst
+ path: framework-coverage-*.rst
diff --git a/java/documentation/library-coverage/flow-model-coverage.csv b/java/documentation/library-coverage/coverage.csv
similarity index 100%
rename from java/documentation/library-coverage/flow-model-coverage.csv
rename to java/documentation/library-coverage/coverage.csv
diff --git a/java/documentation/library-coverage/flow-model-coverage.rst b/java/documentation/library-coverage/coverage.rst
similarity index 100%
rename from java/documentation/library-coverage/flow-model-coverage.rst
rename to java/documentation/library-coverage/coverage.rst
diff --git a/misc/scripts/library-coverage/generate-timeseries.py b/misc/scripts/library-coverage/generate-timeseries.py
index 12c2af95ee4..8bd745f561d 100644
--- a/misc/scripts/library-coverage/generate-timeseries.py
+++ b/misc/scripts/library-coverage/generate-timeseries.py
@@ -74,9 +74,10 @@ configs = [
# todo: change this when we cover multiple languages. We should compute the SHAs
# only once and not per language
+output_prefix = "framework-coverage-timeseries-"
for config in configs:
- with open("timeseries-" + config.lang + ".csv", 'w', newline='') as csvfile_total:
- with open("timeseries-" + config.lang + "-packages.csv", 'w', newline='') as csvfile_packages:
+ with open(output_prefix + config.lang + ".csv", 'w', newline='') as csvfile_total:
+ with open(output_prefix + config.lang + "-packages.csv", 'w', newline='') as csvfile_packages:
csvwriter_total = csv.writer(csvfile_total)
csvwriter_packages = csv.writer(csvfile_packages)
csvwriter_total.writerow(
diff --git a/misc/scripts/library-coverage/settings.py b/misc/scripts/library-coverage/settings.py
index 787f7253bba..ae43a0666da 100644
--- a/misc/scripts/library-coverage/settings.py
+++ b/misc/scripts/library-coverage/settings.py
@@ -1,7 +1,7 @@
import sys
-generated_output_rst = "flow-model-coverage-{language}.rst"
-generated_output_csv = "flow-model-coverage-{language}.csv"
+generated_output_rst = "framework-coverage-{language}.rst"
+generated_output_csv = "framework-coverage-{language}.csv"
# The CI job checks out the codebase to a subfolder
data_prefix = ""
@@ -16,7 +16,7 @@ if len(sys.argv) > index:
documentation_folder_no_prefix = "{language}/documentation/library-coverage/"
documentation_folder = data_prefix + documentation_folder_no_prefix
-output_rst_file_name = "flow-model-coverage.rst"
-output_csv_file_name = "flow-model-coverage.csv"
+output_rst_file_name = "coverage.rst"
+output_csv_file_name = "coverage.csv"
repo_output_rst = documentation_folder + output_rst_file_name
repo_output_csv = documentation_folder + output_csv_file_name
From 07f7fd0342cbab3f708cefbd81787e3174a4ac8d Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Sun, 25 Apr 2021 06:27:55 +0100
Subject: [PATCH 039/153] Add missing QLDocs in JaxWS.qll
And correct one QLDoc
---
java/ql/src/semmle/code/java/frameworks/JaxWS.qll | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index 4c2627f85f8..982ef463729 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -30,6 +30,7 @@ class JaxWsEndpoint extends Class {
)
}
+ /** Gets a method annotated with `@WebMethod` or `@WebEndpoint`. */
Callable getARemoteMethod() {
result = this.getACallable() and
exists(AnnotationType a | a = result.getAnAnnotation().getType() |
@@ -210,10 +211,16 @@ class JaxRsInjectionAnnotation extends JaxRSAnnotation {
}
}
+/**
+ * The class `javax.ws.rs.core.Response`.
+ */
class JaxRsResponse extends Class {
JaxRsResponse() { this.hasQualifiedName(getAJaxRsPackage("core"), "Response") }
}
+/**
+ * The class `javax.ws.rs.core.Response$ResponseBuilder`.
+ */
class JaxRsResponseBuilder extends Class {
JaxRsResponseBuilder() {
this.hasQualifiedName(getAJaxRsPackage("core"), "Response$ResponseBuilder")
@@ -408,7 +415,7 @@ private class HttpHeadersModel extends SummaryModelCsv {
}
/**
- * Model MultivaluedMap, which extends Map, V> and provides a few extra helper methods.
+ * Model MultivaluedMap, which extends Map> and provides a few extra helper methods.
*/
private class MultivaluedMapModel extends SummaryModelCsv {
override predicate row(string row) {
From 7b3acd8b459ac6e226f1f7147e852f9850c89dab Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Thu, 29 Apr 2021 10:52:47 +0100
Subject: [PATCH 040/153] (Minor) Add missing `this.`
---
.../src/semmle/code/java/frameworks/JaxWS.qll | 49 +++++++++----------
1 file changed, 24 insertions(+), 25 deletions(-)
diff --git a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
index 982ef463729..25fcdab3ad7 100644
--- a/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
+++ b/java/ql/src/semmle/code/java/frameworks/JaxWS.qll
@@ -71,23 +71,23 @@ class JaxRsResourceMethod extends Method {
or
// A JaxRS resource method can also inherit these annotations from a supertype, but only if
// there are no JaxRS annotations on the method itself
- getAnOverride() instanceof JaxRsResourceMethod and
- not exists(getAnAnnotation().(JaxRSAnnotation))
+ this.getAnOverride() instanceof JaxRsResourceMethod and
+ not exists(this.getAnAnnotation().(JaxRSAnnotation))
}
/** Gets an `@Produces` annotation that applies to this method */
JaxRSProducesAnnotation getProducesAnnotation() {
- result = getAnAnnotation()
+ result = this.getAnAnnotation()
or
// No direct annotations
- not exists(getAnAnnotation().(JaxRSProducesAnnotation)) and
+ not exists(this.getAnAnnotation().(JaxRSProducesAnnotation)) and
(
// Annotations on a method we've overridden
- result = getAnOverride().getAnAnnotation()
+ result = this.getAnOverride().getAnAnnotation()
or
// No annotations on this method, or a method we've overridden, so look to the class
- not exists(getAnOverride().getAnAnnotation().(JaxRSProducesAnnotation)) and
- result = getDeclaringType().getAnAnnotation()
+ not exists(this.getAnOverride().getAnAnnotation().(JaxRSProducesAnnotation)) and
+ result = this.getDeclaringType().getAnAnnotation()
)
}
}
@@ -120,7 +120,7 @@ class JaxRsResourceClass extends Class {
* annotations leading to this resource method.
*/
JaxRsResourceMethod getAResourceMethod() {
- isPublic() and
+ this.isPublic() and
result = this.getACallable()
}
@@ -129,7 +129,7 @@ class JaxRsResourceClass extends Class {
* but is not a resource method e.g. it is not annotated with `@GET` etc.
*/
Callable getASubResourceLocator() {
- result = getAMethod() and
+ result = this.getAMethod() and
not result instanceof JaxRsResourceMethod and
hasPathAnnotation(result)
}
@@ -148,10 +148,10 @@ class JaxRsResourceClass extends Class {
* (existence of particular parameters).
*/
Constructor getAnInjectableConstructor() {
- result = getAConstructor() and
+ result = this.getAConstructor() and
// JaxRs Spec v2.0 - 3.12
// Only root resources are constructed by the JaxRS container.
- isRootResource() and
+ this.isRootResource() and
// JaxRS can only construct the class using constructors that are public, and where the
// container can provide all of the parameters. This includes the no-arg constructor.
result.isPublic() and
@@ -164,16 +164,16 @@ class JaxRsResourceClass extends Class {
* Gets a Callable that may be executed by the JaxRs container, injecting parameters as required.
*/
Callable getAnInjectableCallable() {
- result = getAResourceMethod() or
- result = getAnInjectableConstructor() or
- result = getASubResourceLocator()
+ result = this.getAResourceMethod() or
+ result = this.getAnInjectableConstructor() or
+ result = this.getASubResourceLocator()
}
/**
* Gets a Field that may be injected with a value by the JaxRs container.
*/
Field getAnInjectableField() {
- result = getAField() and
+ result = this.getAField() and
result.getAnAnnotation() instanceof JaxRsInjectionAnnotation
}
}
@@ -182,7 +182,7 @@ class JaxRsResourceClass extends Class {
class JaxRSAnnotation extends Annotation {
JaxRSAnnotation() {
exists(AnnotationType a |
- a = getType() and
+ a = this.getType() and
a.getPackage().getName().regexpMatch("javax\\.ws\\.rs(\\..*)?")
)
}
@@ -195,7 +195,7 @@ class JaxRSAnnotation extends Annotation {
class JaxRsInjectionAnnotation extends JaxRSAnnotation {
JaxRsInjectionAnnotation() {
exists(AnnotationType a |
- a = getType() and
+ a = this.getType() and
a.getPackage().getName() = getAJaxRsPackage()
|
a.hasName("BeanParam") or
@@ -207,7 +207,7 @@ class JaxRsInjectionAnnotation extends JaxRSAnnotation {
a.hasName("QueryParam")
)
or
- getType().hasQualifiedName(getAJaxRsPackage("core"), "Context")
+ this.getType().hasQualifiedName(getAJaxRsPackage("core"), "Context")
}
}
@@ -241,13 +241,12 @@ class JaxRsClient extends RefType {
class JaxRsBeanParamConstructor extends Constructor {
JaxRsBeanParamConstructor() {
exists(JaxRsResourceClass resourceClass, Callable c, Parameter p |
- c = resourceClass.getAnInjectableCallable()
- |
+ c = resourceClass.getAnInjectableCallable() and
p = c.getAParameter() and
p.getAnAnnotation().getType().hasQualifiedName(getAJaxRsPackage(), "BeanParam") and
this.getDeclaringType().getSourceDeclaration() = p.getType().(RefType).getSourceDeclaration()
) and
- forall(Parameter p | p = getAParameter() |
+ forall(Parameter p | p = this.getAParameter() |
p.getAnAnnotation() instanceof JaxRsInjectionAnnotation
)
}
@@ -283,19 +282,19 @@ class MessageBodyReaderRead extends Method {
/** An `@Produces` annotation that describes which content types can be produced by this resource. */
class JaxRSProducesAnnotation extends JaxRSAnnotation {
- JaxRSProducesAnnotation() { getType().hasQualifiedName(getAJaxRsPackage(), "Produces") }
+ JaxRSProducesAnnotation() { this.getType().hasQualifiedName(getAJaxRsPackage(), "Produces") }
/**
* Gets a declared content type that can be produced by this resource.
*/
string getADeclaredContentType() {
- result = getAValue().(CompileTimeConstantExpr).getStringValue()
+ result = this.getAValue().(CompileTimeConstantExpr).getStringValue()
or
exists(Field jaxMediaType |
// Accesses to static fields on `MediaType` class do not have constant strings in the database
// so convert the field name to a content type string
jaxMediaType.getDeclaringType().hasQualifiedName(getAJaxRsPackage("core"), "MediaType") and
- jaxMediaType.getAnAccess() = getAValue() and
+ jaxMediaType.getAnAccess() = this.getAValue() and
// e.g. MediaType.TEXT_PLAIN => text/plain
result = jaxMediaType.getName().toLowerCase().replaceAll("_", "/")
)
@@ -304,7 +303,7 @@ class JaxRSProducesAnnotation extends JaxRSAnnotation {
/** An `@Consumes` annotation that describes content types can be consumed by this resource. */
class JaxRSConsumesAnnotation extends JaxRSAnnotation {
- JaxRSConsumesAnnotation() { getType().hasQualifiedName(getAJaxRsPackage(), "Consumes") }
+ JaxRSConsumesAnnotation() { this.getType().hasQualifiedName(getAJaxRsPackage(), "Consumes") }
}
/**
From caf96b01e1c29c61e2bcb015e5257120fe83f28b Mon Sep 17 00:00:00 2001
From: Owen Mansel-Chan
Date: Thu, 8 Apr 2021 16:54:54 +0100
Subject: [PATCH 041/153] Stubs in javax-ws-rs-api-2.1.1
Generated using java-autostub
---
.../javax/ws/rs/BeanParam.java | 20 ++
.../javax/ws/rs/Consumes.java | 21 ++
.../javax/ws/rs/CookieParam.java | 22 ++
.../javax/ws/rs/DELETE.java | 20 ++
.../javax/ws/rs/FormParam.java | 22 ++
.../javax/ws/rs/GET.java | 20 ++
.../javax/ws/rs/HEAD.java | 20 ++
.../javax/ws/rs/HeaderParam.java | 22 ++
.../javax/ws/rs/MatrixParam.java | 22 ++
.../javax/ws/rs/OPTIONS.java | 20 ++
.../javax/ws/rs/POST.java | 20 ++
.../javax/ws/rs/PUT.java | 20 ++
.../javax/ws/rs/Path.java | 22 ++
.../javax/ws/rs/PathParam.java | 22 ++
.../javax/ws/rs/Produces.java | 21 ++
.../javax/ws/rs/QueryParam.java | 22 ++
.../javax/ws/rs/client/Client.java | 42 +++
.../javax/ws/rs/core/CacheControl.java | 112 +++++++
.../javax/ws/rs/core/Configurable.java | 41 +++
.../javax/ws/rs/core/Context.java | 20 ++
.../javax/ws/rs/core/Cookie.java | 71 +++++
.../javax/ws/rs/core/EntityTag.java | 53 ++++
.../javax/ws/rs/core/Form.java | 37 +++
.../javax/ws/rs/core/GenericEntity.java | 55 ++++
.../javax/ws/rs/core/HttpHeaders.java | 44 +++
.../javax/ws/rs/core/Link.java | 143 +++++++++
.../javax/ws/rs/core/MediaType.java | 108 +++++++
.../javax/ws/rs/core/MultivaluedMap.java | 36 +++
.../javax/ws/rs/core/NewCookie.java | 117 ++++++++
.../javax/ws/rs/core/PathSegment.java | 24 ++
.../javax/ws/rs/core/Response.java | 281 ++++++++++++++++++
.../javax/ws/rs/core/UriBuilder.java | 122 ++++++++
.../javax/ws/rs/core/UriBuilderException.java | 32 ++
.../javax/ws/rs/core/UriInfo.java | 60 ++++
.../javax/ws/rs/core/Variant.java | 93 ++++++
.../javax/ws/rs/ext/MessageBodyReader.java | 33 ++
36 files changed, 1860 insertions(+)
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/BeanParam.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Consumes.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/CookieParam.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/DELETE.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/FormParam.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/GET.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HEAD.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HeaderParam.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/MatrixParam.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/OPTIONS.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/POST.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PUT.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Path.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PathParam.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Produces.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/QueryParam.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/client/Client.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/CacheControl.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Configurable.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Context.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Cookie.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/EntityTag.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Form.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/GenericEntity.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/HttpHeaders.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Link.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MediaType.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MultivaluedMap.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/NewCookie.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/PathSegment.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Response.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilder.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilderException.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriInfo.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Variant.java
create mode 100644 java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/ext/MessageBodyReader.java
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/BeanParam.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/BeanParam.java
new file mode 100644
index 00000000000..9d0e62bf127
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/BeanParam.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface BeanParam {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Consumes.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Consumes.java
new file mode 100644
index 00000000000..9aef14670fd
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Consumes.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface Consumes {
+ String[] value() default "*/*";
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/CookieParam.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/CookieParam.java
new file mode 100644
index 00000000000..d8c9ced5ae0
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/CookieParam.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface CookieParam {
+ String value();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/DELETE.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/DELETE.java
new file mode 100644
index 00000000000..a0db648c970
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/DELETE.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface DELETE {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/FormParam.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/FormParam.java
new file mode 100644
index 00000000000..f811e756462
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/FormParam.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface FormParam {
+ String value();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/GET.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/GET.java
new file mode 100644
index 00000000000..da2fae0883d
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/GET.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface GET {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HEAD.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HEAD.java
new file mode 100644
index 00000000000..300d85bdd06
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HEAD.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface HEAD {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HeaderParam.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HeaderParam.java
new file mode 100644
index 00000000000..4d91be981d3
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/HeaderParam.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface HeaderParam {
+ String value();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/MatrixParam.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/MatrixParam.java
new file mode 100644
index 00000000000..193fdaccfae
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/MatrixParam.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface MatrixParam {
+ String value();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/OPTIONS.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/OPTIONS.java
new file mode 100644
index 00000000000..6f796d32300
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/OPTIONS.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface OPTIONS {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/POST.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/POST.java
new file mode 100644
index 00000000000..b7069865714
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/POST.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface POST {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PUT.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PUT.java
new file mode 100644
index 00000000000..68f6ecfc66e
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PUT.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface PUT {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Path.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Path.java
new file mode 100644
index 00000000000..506a7140d27
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Path.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface Path {
+ String value();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PathParam.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PathParam.java
new file mode 100644
index 00000000000..cf363361b48
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/PathParam.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface PathParam {
+ String value();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Produces.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Produces.java
new file mode 100644
index 00000000000..2cf426effaa
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/Produces.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface Produces {
+ String[] value() default "*/*";
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/QueryParam.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/QueryParam.java
new file mode 100644
index 00000000000..81b2143902a
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/QueryParam.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs;
+
+public @interface QueryParam {
+ String value();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/client/Client.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/client/Client.java
new file mode 100644
index 00000000000..a5fa9671b54
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/client/Client.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.client;
+import java.net.URI;
+import javax.ws.rs.core.Configurable;
+import javax.ws.rs.core.Link;
+import javax.ws.rs.core.UriBuilder;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+
+public interface Client extends Configurable {
+ public void close();
+
+ public WebTarget target(String uri);
+
+ public WebTarget target(URI uri);
+
+ public WebTarget target(UriBuilder uriBuilder);
+
+ public WebTarget target(Link link);
+
+ public Invocation.Builder invocation(Link link);
+
+ public SSLContext getSslContext();
+
+ public HostnameVerifier getHostnameVerifier();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/CacheControl.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/CacheControl.java
new file mode 100644
index 00000000000..21f6f14b343
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/CacheControl.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.util.List;
+import java.util.Map;
+
+public class CacheControl {
+ public CacheControl() {
+ }
+
+ public static CacheControl valueOf(final String value) {
+ return null;
+ }
+
+ public boolean isMustRevalidate() {
+ return false;
+ }
+
+ public void setMustRevalidate(final boolean mustRevalidate) {
+ }
+
+ public boolean isProxyRevalidate() {
+ return false;
+ }
+
+ public void setProxyRevalidate(final boolean proxyRevalidate) {
+ }
+
+ public int getMaxAge() {
+ return 0;
+ }
+
+ public void setMaxAge(final int maxAge) {
+ }
+
+ public int getSMaxAge() {
+ return 0;
+ }
+
+ public void setSMaxAge(final int sMaxAge) {
+ }
+
+ public List getNoCacheFields() {
+ return null;
+ }
+
+ public void setNoCache(final boolean noCache) {
+ }
+
+ public boolean isNoCache() {
+ return false;
+ }
+
+ public boolean isPrivate() {
+ return false;
+ }
+
+ public List getPrivateFields() {
+ return null;
+ }
+
+ public void setPrivate(final boolean flag) {
+ }
+
+ public boolean isNoTransform() {
+ return false;
+ }
+
+ public void setNoTransform(final boolean noTransform) {
+ }
+
+ public boolean isNoStore() {
+ return false;
+ }
+
+ public void setNoStore(final boolean noStore) {
+ }
+
+ public Map getCacheExtension() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return false;
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Configurable.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Configurable.java
new file mode 100644
index 00000000000..9d32b9d0c61
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Configurable.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.util.Map;
+
+public interface Configurable {
+ public Configuration getConfiguration();
+
+ public C property(String name, Object value);
+
+ public C register(Class> componentClass);
+
+ public C register(Class> componentClass, int priority);
+
+ public C register(Class> componentClass, Class>... contracts);
+
+ public C register(Class> componentClass, Map, Integer> contracts);
+
+ public C register(Object component);
+
+ public C register(Object component, int priority);
+
+ public C register(Object component, Class>... contracts);
+
+ public C register(Object component, Map, Integer> contracts);
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Context.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Context.java
new file mode 100644
index 00000000000..765e0bb7301
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Context.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+
+public @interface Context {
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Cookie.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Cookie.java
new file mode 100644
index 00000000000..7d69fb2bf9a
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Cookie.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+
+public class Cookie {
+ public Cookie(final String name, final String value, final String path, final String domain, final int version)
+ throws IllegalArgumentException {
+ }
+
+ public Cookie(final String name, final String value, final String path, final String domain)
+ throws IllegalArgumentException {
+ }
+
+ public Cookie(final String name, final String value)
+ throws IllegalArgumentException {
+ }
+
+ public static Cookie valueOf(final String value) {
+ return null;
+ }
+
+ public String getName() {
+ return null;
+ }
+
+ public String getValue() {
+ return null;
+ }
+
+ public int getVersion() {
+ return 0;
+ }
+
+ public String getDomain() {
+ return null;
+ }
+
+ public String getPath() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return false;
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/EntityTag.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/EntityTag.java
new file mode 100644
index 00000000000..7d21487c774
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/EntityTag.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+
+public class EntityTag {
+ public EntityTag(final String value) {
+ }
+
+ public EntityTag(final String value, final boolean weak) {
+ }
+
+ public static EntityTag valueOf(final String value) {
+ return null;
+ }
+
+ public boolean isWeak() {
+ return false;
+ }
+
+ public String getValue() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Form.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Form.java
new file mode 100644
index 00000000000..e14c6f30b13
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Form.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+
+public class Form {
+ public Form() {
+ }
+
+ public Form(final String parameterName, final String parameterValue) {
+ }
+
+ public Form(final MultivaluedMap store) {
+ }
+
+ public Form param(final String name, final String value) {
+ return null;
+ }
+
+ public MultivaluedMap asMap() {
+ return null;
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/GenericEntity.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/GenericEntity.java
new file mode 100644
index 00000000000..b3ea7c8553f
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/GenericEntity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright (c) 2006 Google Inc.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package javax.ws.rs.core;
+import java.lang.reflect.Type;
+
+public class GenericEntity {
+ public GenericEntity(final T entity, final Type genericType) {
+ }
+
+ public final Class> getRawType() {
+ return null;
+ }
+
+ public final Type getType() {
+ return null;
+ }
+
+ public final T getEntity() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/HttpHeaders.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/HttpHeaders.java
new file mode 100644
index 00000000000..f375bcb2a9a
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/HttpHeaders.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public interface HttpHeaders {
+ public List getRequestHeader(String name);
+
+ public String getHeaderString(String name);
+
+ public MultivaluedMap getRequestHeaders();
+
+ public List getAcceptableMediaTypes();
+
+ public List getAcceptableLanguages();
+
+ public MediaType getMediaType();
+
+ public Locale getLanguage();
+
+ public Map getCookies();
+
+ public Date getDate();
+
+ public int getLength();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Link.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Link.java
new file mode 100644
index 00000000000..7d16e33c757
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Link.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2011, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.namespace.QName;
+
+public abstract class Link {
+ public abstract URI getUri();
+
+ public abstract UriBuilder getUriBuilder();
+
+ public abstract String getRel();
+
+ public abstract List getRels();
+
+ public abstract String getTitle();
+
+ public abstract String getType();
+
+ public abstract Map getParams();
+
+ @Override
+ public abstract String toString();
+
+ public static Link valueOf(String value) {
+ return null;
+ }
+
+ public static Builder fromUri(URI uri) {
+ return null;
+ }
+
+ public static Builder fromUri(String uri) {
+ return null;
+ }
+
+ public static Builder fromUriBuilder(UriBuilder uriBuilder) {
+ return null;
+ }
+
+ public static Builder fromLink(Link link) {
+ return null;
+ }
+
+ public static Builder fromPath(String path) {
+ return null;
+ }
+
+ public static Builder fromResource(Class> resource) {
+ return null;
+ }
+
+ public static Builder fromMethod(Class> resource, String method) {
+ return null;
+ }
+
+ public interface Builder {
+ public Builder link(Link link);
+
+ public Builder link(String link);
+
+ public Builder uri(URI uri);
+
+ public Builder uri(String uri);
+
+ public Builder baseUri(URI uri);
+
+ public Builder baseUri(String uri);
+
+ public Builder uriBuilder(UriBuilder uriBuilder);
+
+ public Builder rel(String rel);
+
+ public Builder title(String title);
+
+ public Builder type(String type);
+
+ public Builder param(String name, String value);
+
+ public Link build(Object... values);
+
+ public Link buildRelativized(URI uri, Object... values);
+
+ }
+ public static class JaxbLink {
+ public JaxbLink() {
+ }
+
+ public JaxbLink(URI uri) {
+ }
+
+ public JaxbLink(URI uri, Map params) {
+ }
+
+ public URI getUri() {
+ return null;
+ }
+
+ public Map getParams() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ }
+ public static class JaxbAdapter extends XmlAdapter {
+ @Override
+ public Link unmarshal(JaxbLink v) {
+ return null;
+ }
+
+ @Override
+ public JaxbLink marshal(Link v) {
+ return null;
+ }
+
+ }
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MediaType.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MediaType.java
new file mode 100644
index 00000000000..7cb06b36d78
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MediaType.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.util.Map;
+
+public class MediaType {
+ public final static MediaType WILDCARD_TYPE = new MediaType();
+
+ public final static MediaType APPLICATION_XML_TYPE = new MediaType("application", "xml");
+
+ public final static MediaType APPLICATION_ATOM_XML_TYPE = new MediaType("application", "atom+xml");
+
+ public final static MediaType APPLICATION_XHTML_XML_TYPE = new MediaType("application", "xhtml+xml");
+
+ public final static MediaType APPLICATION_SVG_XML_TYPE = new MediaType("application", "svg+xml");
+
+ public final static MediaType APPLICATION_JSON_TYPE = new MediaType("application", "json");
+
+ public final static MediaType APPLICATION_FORM_URLENCODED_TYPE = new MediaType("application", "x-www-form-urlencoded");
+
+ public final static MediaType MULTIPART_FORM_DATA_TYPE = new MediaType("multipart", "form-data");
+
+ public final static MediaType APPLICATION_OCTET_STREAM_TYPE = new MediaType("application", "octet-stream");
+
+ public final static MediaType TEXT_PLAIN_TYPE = new MediaType("text", "plain");
+
+ public final static MediaType TEXT_XML_TYPE = new MediaType("text", "xml");
+
+ public final static MediaType TEXT_HTML_TYPE = new MediaType("text", "html");
+
+ public static final MediaType SERVER_SENT_EVENTS_TYPE = new MediaType("text", "event-stream");
+
+ public static final MediaType APPLICATION_JSON_PATCH_JSON_TYPE = new MediaType("application", "json-patch+json");
+
+ public static MediaType valueOf(String type){
+ return null;
+ }
+
+ public MediaType(String type, String subtype, Map parameters) {
+ }
+
+ public MediaType(String type, String subtype) {
+ }
+
+ public MediaType(String type, String subtype, String charset) {
+ }
+
+ public MediaType() {
+ }
+
+ public String getType() {
+ return null;
+ }
+
+ public boolean isWildcardType() {
+ return false;
+ }
+
+ public String getSubtype() {
+ return null;
+ }
+
+ public boolean isWildcardSubtype() {
+ return false;
+ }
+
+ public Map getParameters() {
+ return null;
+ }
+
+ public MediaType withCharset(String charset) {
+ return null;
+ }
+
+ public boolean isCompatible(MediaType other) {
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MultivaluedMap.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MultivaluedMap.java
new file mode 100644
index 00000000000..e34f32328cc
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/MultivaluedMap.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.util.List;
+import java.util.Map;
+
+public interface MultivaluedMap extends Map> {
+ void putSingle(K key, V value);
+
+ void add(K key, V value);
+
+ V getFirst(K key);
+
+ void addAll(K key, V... newValues);
+
+ void addAll(K key, List valueList);
+
+ void addFirst(K key, V value);
+
+ boolean equalsIgnoreValueOrder(MultivaluedMap otherMap);
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/NewCookie.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/NewCookie.java
new file mode 100644
index 00000000000..60b257cd9b7
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/NewCookie.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.util.Date;
+
+public class NewCookie extends Cookie {
+ public NewCookie(String name, String value) {
+ }
+
+ public NewCookie(String name,
+ String value,
+ String path,
+ String domain,
+ String comment,
+ int maxAge,
+ boolean secure) {
+ }
+
+ public NewCookie(String name,
+ String value,
+ String path,
+ String domain,
+ String comment,
+ int maxAge,
+ boolean secure,
+ boolean httpOnly) {
+ }
+
+ public NewCookie(String name,
+ String value,
+ String path,
+ String domain,
+ int version,
+ String comment,
+ int maxAge,
+ boolean secure) {
+ }
+
+ public NewCookie(String name,
+ String value,
+ String path,
+ String domain,
+ int version,
+ String comment,
+ int maxAge,
+ Date expiry,
+ boolean secure,
+ boolean httpOnly) {
+ }
+
+ public NewCookie(Cookie cookie) {
+ }
+
+ public NewCookie(Cookie cookie, String comment, int maxAge, boolean secure) {
+ }
+
+ public NewCookie(Cookie cookie, String comment, int maxAge, Date expiry, boolean secure, boolean httpOnly) {
+ }
+
+ public static NewCookie valueOf(String value) {
+ return null;
+ }
+
+ public String getComment() {
+ return null;
+ }
+
+ public int getMaxAge() {
+ return 0;
+ }
+
+ public Date getExpiry() {
+ return null;
+ }
+
+ public boolean isSecure() {
+ return false;
+ }
+
+ public boolean isHttpOnly() {
+ return false;
+ }
+
+ public Cookie toCookie() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return false;
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/PathSegment.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/PathSegment.java
new file mode 100644
index 00000000000..b34e059e68e
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/PathSegment.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+
+public interface PathSegment {
+ String getPath();
+
+ MultivaluedMap getMatrixParameters();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Response.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Response.java
new file mode 100644
index 00000000000..416d016d201
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/Response.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.lang.annotation.Annotation;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class Response implements AutoCloseable {
+ public abstract int getStatus();
+
+ public abstract StatusType getStatusInfo();
+
+ public abstract Object getEntity();
+
+ public abstract T readEntity(Class entityType);
+
+ public abstract T readEntity(GenericType entityType);
+
+ public abstract T readEntity(Class entityType, Annotation[] annotations);
+
+ public abstract T readEntity(GenericType entityType, Annotation[] annotations);
+
+ public abstract boolean hasEntity();
+
+ public abstract boolean bufferEntity();
+
+ @Override
+ public abstract void close();
+
+ public abstract MediaType getMediaType();
+
+ public abstract Locale getLanguage();
+
+ public abstract int getLength();
+
+ public abstract Set getAllowedMethods();
+
+ public abstract Map getCookies();
+
+ public abstract EntityTag getEntityTag();
+
+ public abstract Date getDate();
+
+ public abstract Date getLastModified();
+
+ public abstract URI getLocation();
+
+ public abstract Set getLinks();
+
+ public abstract boolean hasLink(String relation);
+
+ public abstract Link getLink(String relation);
+
+ public abstract Link.Builder getLinkBuilder(String relation);
+
+ public abstract MultivaluedMap getMetadata();
+
+ public MultivaluedMap getHeaders() {
+ return null;
+ }
+
+ public abstract MultivaluedMap getStringHeaders();
+
+ public abstract String getHeaderString(String name);
+
+ public static ResponseBuilder fromResponse(Response response) {
+ return null;
+ }
+
+ public static ResponseBuilder status(StatusType status) {
+ return null;
+ }
+
+ public static ResponseBuilder status(Status status) {
+ return null;
+ }
+
+ public static ResponseBuilder status(int status) {
+ return null;
+ }
+
+ public static ResponseBuilder status(int status, String reasonPhrase) {
+ return null;
+ }
+
+ public static ResponseBuilder ok() {
+ return null;
+ }
+
+ public static ResponseBuilder ok(Object entity) {
+ return null;
+ }
+
+ public static ResponseBuilder ok(Object entity, MediaType type) {
+ return null;
+ }
+
+ public static ResponseBuilder ok(Object entity, String type) {
+ return null;
+ }
+
+ public static ResponseBuilder ok(Object entity, Variant variant) {
+ return null;
+ }
+
+ public static ResponseBuilder serverError() {
+ return null;
+ }
+
+ public static ResponseBuilder created(URI location) {
+ return null;
+ }
+
+ public static ResponseBuilder accepted() {
+ return null;
+ }
+
+ public static ResponseBuilder accepted(Object entity) {
+ return null;
+ }
+
+ public static ResponseBuilder noContent() {
+ return null;
+ }
+
+ public static ResponseBuilder notModified() {
+ return null;
+ }
+
+ public static ResponseBuilder notModified(EntityTag tag) {
+ return null;
+ }
+
+ public static ResponseBuilder notModified(String tag) {
+ return null;
+ }
+
+ public static ResponseBuilder seeOther(URI location) {
+ return null;
+ }
+
+ public static ResponseBuilder temporaryRedirect(URI location) {
+ return null;
+ }
+
+ public static ResponseBuilder notAcceptable(List variants) {
+ return null;
+ }
+
+ public static abstract class ResponseBuilder {
+ public abstract Response build();
+
+ @Override
+ public abstract ResponseBuilder clone();
+
+ public abstract ResponseBuilder status(int status);
+
+ public abstract ResponseBuilder status(int status, String reasonPhrase);
+
+ public ResponseBuilder status(StatusType status) {
+ return null;
+ }
+
+ public ResponseBuilder status(Status status) {
+ return null;
+ }
+
+ public abstract ResponseBuilder entity(Object entity);
+
+ public abstract ResponseBuilder entity(Object entity, Annotation[] annotations);
+
+ public abstract ResponseBuilder allow(String... methods);
+
+ public abstract ResponseBuilder allow(Set methods);
+
+ public abstract ResponseBuilder cacheControl(CacheControl cacheControl);
+
+ public abstract ResponseBuilder encoding(String encoding);
+
+ public abstract ResponseBuilder header(String name, Object value);
+
+ public abstract ResponseBuilder replaceAll(MultivaluedMap headers);
+
+ public abstract ResponseBuilder language(String language);
+
+ public abstract ResponseBuilder language(Locale language);
+
+ public abstract ResponseBuilder type(MediaType type);
+
+ public abstract ResponseBuilder type(String type);
+
+ public abstract ResponseBuilder variant(Variant variant);
+
+ public abstract ResponseBuilder contentLocation(URI location);
+
+ public abstract ResponseBuilder cookie(NewCookie... cookies);
+
+ public abstract ResponseBuilder expires(Date expires);
+
+ public abstract ResponseBuilder lastModified(Date lastModified);
+
+ public abstract ResponseBuilder location(URI location);
+
+ public abstract ResponseBuilder tag(EntityTag tag);
+
+ public abstract ResponseBuilder tag(String tag);
+
+ public abstract ResponseBuilder variants(Variant... variants);
+
+ public abstract ResponseBuilder variants(List variants);
+
+ public abstract ResponseBuilder links(Link... links);
+
+ public abstract ResponseBuilder link(URI uri, String rel);
+
+ public abstract ResponseBuilder link(String uri, String rel);
+
+ }
+ public interface StatusType {
+ public int getStatusCode();
+
+ public Status.Family getFamily();
+
+ public String getReasonPhrase();
+
+ public default Status toEnum() {
+ return null;
+ }
+
+ }
+ public enum Status implements StatusType {
+ public enum Family {
+ public static Family familyOf(final int statusCode) {
+ return null;
+ }
+
+ }
+ @Override
+ public Family getFamily() {
+ return null;
+ }
+
+ @Override
+ public int getStatusCode() {
+ return 0;
+ }
+
+ @Override
+ public String getReasonPhrase() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+ public static Status fromStatusCode(final int statusCode) {
+ return null;
+ }
+
+ }
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilder.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilder.java
new file mode 100644
index 00000000000..0a5685c32c0
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.Map;
+
+public abstract class UriBuilder {
+ public static UriBuilder fromUri(URI uri) {
+ return null;
+ }
+
+ public static UriBuilder fromUri(String uriTemplate) {
+ return null;
+ }
+
+ public static UriBuilder fromLink(Link link) {
+ return null;
+ }
+
+ public static UriBuilder fromPath(String path) throws IllegalArgumentException {
+ return null;
+ }
+
+ public static UriBuilder fromResource(Class> resource) {
+ return null;
+ }
+
+ public static UriBuilder fromMethod(Class> resource, String method) {
+ return null;
+ }
+
+ @Override
+ public abstract UriBuilder clone();
+
+ public abstract UriBuilder uri(URI uri);
+
+ public abstract UriBuilder uri(String uriTemplate);
+
+ public abstract UriBuilder scheme(String scheme);
+
+ public abstract UriBuilder schemeSpecificPart(String ssp);
+
+ public abstract UriBuilder userInfo(String ui);
+
+ public abstract UriBuilder host(String host);
+
+ public abstract UriBuilder port(int port);
+
+ public abstract UriBuilder replacePath(String path);
+
+ public abstract UriBuilder path(String path);
+
+ public abstract UriBuilder path(Class resource);
+
+ public abstract UriBuilder path(Class resource, String method);
+
+ public abstract UriBuilder path(Method method);
+
+ public abstract UriBuilder segment(String... segments);
+
+ public abstract UriBuilder replaceMatrix(String matrix);
+
+ public abstract UriBuilder matrixParam(String name, Object... values);
+
+ public abstract UriBuilder replaceMatrixParam(String name, Object... values);
+
+ public abstract UriBuilder replaceQuery(String query);
+
+ public abstract UriBuilder queryParam(String name, Object... values);
+
+ public abstract UriBuilder replaceQueryParam(String name, Object... values);
+
+ public abstract UriBuilder fragment(String fragment);
+
+ public abstract UriBuilder resolveTemplate(String name, Object value);
+
+ public abstract UriBuilder resolveTemplate(String name, Object value, boolean encodeSlashInPath);
+
+ public abstract UriBuilder resolveTemplateFromEncoded(String name, Object value);
+
+ public abstract UriBuilder resolveTemplates(Map templateValues);
+
+ public abstract UriBuilder resolveTemplates(Map templateValues, boolean encodeSlashInPath)
+ throws IllegalArgumentException;
+
+ public abstract UriBuilder resolveTemplatesFromEncoded(Map templateValues);
+
+ public abstract URI buildFromMap(Map values);
+
+ public abstract URI buildFromMap(Map values, boolean encodeSlashInPath)
+ throws IllegalArgumentException, UriBuilderException;
+
+ public abstract URI buildFromEncodedMap(Map values)
+ throws IllegalArgumentException, UriBuilderException;
+
+ public abstract URI build(Object... values)
+ throws IllegalArgumentException, UriBuilderException;
+
+ public abstract URI build(Object[] values, boolean encodeSlashInPath)
+ throws IllegalArgumentException, UriBuilderException;
+
+ public abstract URI buildFromEncoded(Object... values)
+ throws IllegalArgumentException, UriBuilderException;
+
+ public abstract String toTemplate();
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilderException.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilderException.java
new file mode 100644
index 00000000000..05f6ad1a4bc
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriBuilderException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+
+public class UriBuilderException extends java.lang.RuntimeException {
+ public UriBuilderException() {
+ }
+
+ public UriBuilderException(String msg) {
+ }
+
+ public UriBuilderException(String msg, Throwable cause) {
+ }
+
+ public UriBuilderException(Throwable cause) {
+ }
+
+}
diff --git a/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriInfo.java b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriInfo.java
new file mode 100644
index 00000000000..9903e7f6b97
--- /dev/null
+++ b/java/ql/test/stubs/javax-ws-rs-api-2.1.1/javax/ws/rs/core/UriInfo.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package javax.ws.rs.core;
+import java.net.URI;
+import java.util.List;
+
+public interface UriInfo {
+ public String getPath();
+
+ public String getPath(boolean decode);
+
+ public List getPathSegments();
+
+ public List getPathSegments(boolean decode);
+
+ public URI getRequestUri();
+
+ public UriBuilder getRequestUriBuilder();
+
+ public URI getAbsolutePath();
+
+ public UriBuilder getAbsolutePathBuilder();
+
+ public URI getBaseUri();
+
+ public UriBuilder getBaseUriBuilder();
+
+ public MultivaluedMap getPathParameters();
+
+ public MultivaluedMap getPathParameters(boolean decode);
+
+ public MultivaluedMap getQueryParameters();
+
+ public MultivaluedMap getQueryParameters(boolean decode);
+
+ public List getMatchedURIs();
+
+ public List getMatchedURIs(boolean decode);
+
+ public List