Merge pull request #13235 from atorralba/atorralba/java/hudson-models

Java: Add Hudson models
This commit is contained in:
Tony Torralba
2023-06-14 12:33:18 +02:00
committed by GitHub
13 changed files with 201 additions and 39 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added more models for the Hudson framework.

View File

@@ -16,3 +16,9 @@ extensions:
data:
- ["hudson.model", "Node", True, "createPath", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson.model", "DirectoryBrowserSupport$Path", False, "Path", "(String,String,boolean,long,boolean,long)", "", "Argument[0]", "Argument[this].SyntheticField[hudson.model.DirectoryBrowserSupport$Path.href]", "taint", "ai-manual"]
- addsTo:
pack: codeql/java-all
extensible: sourceModel
data:
- ["hudson.model", "Descriptor", True, "configure", "", "", "Parameter", "remote", "manual"]
- ["hudson.model", "Descriptor", True, "newInstance", "", "", "Parameter", "remote", "manual"]

View File

@@ -3,24 +3,68 @@ extensions:
pack: codeql/java-all
extensible: sinkModel
data:
- ["hudson", "FilePath", False, "copyFrom", "(FilePath)", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", False, "copyFrom", "(URL)", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", False, "copyFrom", "(FileItem)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", False, "copyRecursiveTo", "(DirScanner,FilePath,String,TarCompression)", "", "Argument[1]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", False, "copyRecursiveTo", "(DirScanner,FilePath,String)", "", "Argument[1]", "file-content-store", "ai-manual"]
- ["hudson", "FilePath", False, "copyRecursiveTo", "(String,FilePath)", "", "Argument[1]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", False, "copyRecursiveTo", "(String,String,FilePath)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", False, "copyRecursiveTo", "(String,String,FilePath)", "", "Argument[2]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", False, "copyTo", "(FilePath)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", False, "installIfNecessaryFrom", "(URL,TaskListener,String)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["hudson", "FilePath", False, "newInputStreamDenyingSymlinkAsNeeded", "(File,String,boolean)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyFrom", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "copyFrom", "(FilePath)", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "copyFrom", "(URL)", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "copyFrom", "(FileItem)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyRecursiveTo", "", "", "Argument[this]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyRecursiveTo", "(DirScanner,FilePath,String,TarCompression)", "", "Argument[1]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyRecursiveTo", "(DirScanner,FilePath,String)", "", "Argument[1]", "file-content-store", "ai-manual"]
- ["hudson", "FilePath", True, "copyRecursiveTo", "(String,FilePath)", "", "Argument[1]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyRecursiveTo", "(String,String,FilePath)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyRecursiveTo", "(String,String,FilePath)", "", "Argument[2]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyTo", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "copyTo", "(FilePath)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "copyToWithPermission", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "copyToWithPermission", "(FilePath)", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "installIfNecessaryFrom", "(URL,TaskListener,String)", "", "Argument[0]", "request-forgery", "ai-manual"]
- ["hudson", "FilePath", True, "newInputStreamDenyingSymlinkAsNeeded", "(File,String,boolean)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson", "FilePath", True, "openInputStream", "(File,OpenOption[])", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "read", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "read", "(FilePath,OpenOption[])", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "readFromOffset", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "readToString", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "renameTo", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "renameTo", "", "", "Argument[0]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "write", "", "", "Argument[this]", "path-injection", "manual"]
- ["hudson", "FilePath", True, "write", "(String,String)", "", "Argument[0]", "file-content-store", "manual"]
- ["hudson", "Launcher$ProcStarter", False, "cmds", "", "", "Argument[0]", "command-injection", "manual"]
- ["hudson", "Launcher$ProcStarter", False, "cmdAsSingleString", "", "", "Argument[0]", "command-injection", "manual"]
- ["hudson", "Launcher", True, "launch", "", "", "Argument[0]", "command-injection", "manual"]
- ["hudson", "Launcher", True, "launchChannel", "", "", "Argument[0]", "command-injection", "manual"]
- addsTo:
pack: codeql/java-all
extensible: sourceModel
data:
- ["hudson", "Plugin", True, "configure", "", "", "Parameter", "remote", "manual"]
- ["hudson", "Plugin", True, "newInstance", "", "", "Parameter", "remote", "manual"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["hudson", "FilePath", False, "child", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", False, "list", "(String,String,boolean)", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", False, "list", "(String,String)", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", False, "list", "(String)", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", False, "normalize", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", False, "sibling", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", True, "FilePath", "(String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["hudson", "FilePath", True, "FilePath", "(FilePath,String)", "", "Argument[0..1]", "Argument[this]", "taint", "manual"]
- ["hudson", "FilePath", True, "FilePath", "(VirtualChannel,String)", "", "Argument[1]", "Argument[this]", "taint", "manual"]
- ["hudson", "FilePath", True, "child", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", True, "list", "(String,String,boolean)", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", True, "list", "(String,String)", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", True, "list", "(String)", "", "Argument[this]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", True, "normalize", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "FilePath", True, "sibling", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson", "Util", True, "nullify", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "fixNull", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "fixEmpty", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "fixEmptyAndTrim", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "getFileName", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "join", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "encodeRFC2396", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "wrapToErrorSpan", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "fileToPath", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "xmlEscape", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "escape", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "singleQuote", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "rawEncode", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "encode", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "fromHexString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "toHexString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["hudson", "Util", True, "tokenize", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]

View File

@@ -7,6 +7,10 @@ extensions:
- ["hudson.util", "AtomicFileWriter", True, "AtomicFileWriter", "(Path,Charset,boolean,boolean)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson.util", "AtomicFileWriter", True, "AtomicFileWriter", "(Path,Charset)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson.util", "ClasspathBuilder", True, "add", "(FilePath)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson.util", "FormValidation", True, "errorWithMarkup", "", "", "Argument[0]", "html-injection", "manual"]
- ["hudson.util", "FormValidation", True, "okWithMarkup", "", "", "Argument[0]", "html-injection", "manual"]
- ["hudson.util", "FormValidation", True, "respond", "", "", "Argument[1]", "html-injection", "manual"]
- ["hudson.util", "FormValidation", True, "warningWithMarkup", "", "", "Argument[0]", "html-injection", "manual"]
- ["hudson.util", "IOUtils", True, "mkdirs", "(File)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson.util", "StreamTaskListener", True, "StreamTaskListener", "(File,boolean,Charset)", "", "Argument[0]", "path-injection", "ai-manual"]
- ["hudson.util", "TextFile", True, "delete", "()", "", "Argument[this]", "path-injection", "manual"]
@@ -15,10 +19,28 @@ extensions:
- ["hudson.util", "TextFile", True, "lines", "()", "", "Argument[this]", "path-injection", "manual"]
- ["hudson.util", "TextFile", True, "read", "()", "", "Argument[this]", "path-injection", "manual"]
- ["hudson.util", "TextFile", True, "readTrim", "()", "", "Argument[this]", "path-injection", "manual"]
- ["hudson.util", "TextFile", True, "write", "(String)", "", "Argument[this]", "path-injection", "manual"]
- ["hudson.util", "TextFile", True, "write", "(String)", "", "Argument[0]", "file-content-store", "manual"]
- ["hudson.util", "HttpResponses", True, "staticResource", "(File)", "", "Argument[0]", "path-injection", "manual"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["hudson.util", "ArgumentListBuilder", True, "ArgumentListBuilder", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "add", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "clone", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "prepend", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "toCommandArray", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "toList", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "toWindowsCommand", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
# ArgumentListBuilder fluent methods
- ["hudson.util", "ArgumentListBuilder", True, "add", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "addKeyValuePair", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "addKeyValuePairs", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "addKeyValuePairsFromPropertyString", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "addMasked", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "addQuoted", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "addTokenized", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "ArgumentListBuilder", True, "prepend", "", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["hudson.util", "QuotedStringTokenizer", True, "tokenize", "(String)", "", "Argument[0]", "ReturnValue", "taint", "ai-manual"]
- ["hudson.util", "TextFile", True, "TextFile", "(File)", "", "Argument[0]", "Argument[this]", "taint", "ai-manual"]

View File

@@ -36,6 +36,13 @@ abstract class RemoteFlowSource extends DataFlow::Node {
abstract string getSourceType();
}
/**
* A module for importing frameworks that define flow sources.
*/
private module FlowSources {
private import semmle.code.java.frameworks.hudson.Hudson
}
private class ExternalRemoteFlowSource extends RemoteFlowSource {
ExternalRemoteFlowSource() { sourceNode(this, "remote") }

View File

@@ -0,0 +1,29 @@
/** Provides classes and predicates related to the Hudson framework. */
import java
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.security.XSS
private class FilePathRead extends LocalUserInput {
FilePathRead() {
this.asExpr()
.(MethodAccess)
.getMethod()
.hasQualifiedName("hudson", "FilePath",
[
"newInputStreamDenyingSymlinkAsNeeded", "openInputStream", "read", "readFromOffset",
"readToString"
])
}
}
private class HudsonUtilXssSanitizer extends XssSanitizer {
HudsonUtilXssSanitizer() {
this.asExpr()
.(MethodAccess)
.getMethod()
// Not including xmlEscape because it only accounts for >, <, and &.
// It does not account for ", or ', which makes it an incomplete XSS sanitizer.
.hasQualifiedName("hudson", "Util", "escape")
}
}

View File

@@ -6,6 +6,7 @@ import semmle.code.java.frameworks.android.WebView
import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.frameworks.spring.SpringHttp
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
private import semmle.code.java.frameworks.hudson.Hudson
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.ExternalFlow

View File

@@ -0,0 +1,16 @@
import hudson.FilePath;
public class Hudson {
private static void sink(Object o) {}
public static void test() throws Exception {
FilePath fp = null;
sink(FilePath.newInputStreamDenyingSymlinkAsNeeded(null, null, null)); // $hasLocalValueFlow
sink(FilePath.openInputStream(null, null)); // $hasLocalValueFlow
sink(fp.read()); // $hasLocalValueFlow
sink(fp.read(null)); // $hasLocalValueFlow
sink(fp.readFromOffset(-1)); // $hasLocalValueFlow
sink(fp.readToString()); // $hasLocalValueFlow
}
}

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x:${testdir}/../../../stubs/jwtk-jjwt-0.11.2
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/springframework-5.3.8:${testdir}/../../../stubs/google-android-9.0.0:${testdir}/../../../stubs/playframework-2.6.x:${testdir}/../../../stubs/jackson-databind-2.12:${testdir}/../../../stubs/jackson-core-2.12:${testdir}/../../../stubs/akka-2.6.x:${testdir}/../../../stubs/jwtk-jjwt-0.11.2:${testdir}/../../../stubs/jenkins

View File

@@ -4,9 +4,6 @@
package test.cwe079.cwe.examples;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
@@ -14,13 +11,12 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class XSS extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
throws ServletException, IOException {
// BAD: a request parameter is written directly to the Servlet response stream
response.getWriter().print(
"The page \"" + request.getParameter("page") + "\" was not found."); // $xss
response.getWriter()
.print("The page \"" + request.getParameter("page") + "\" was not found."); // $xss
// GOOD: servlet API encodes the error message HTML for the HTML context
response.sendError(HttpServletResponse.SC_NOT_FOUND,
@@ -29,35 +25,31 @@ public class XSS extends HttpServlet {
// GOOD: escape HTML characters first
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"The page \"" + encodeForHtml(request.getParameter("page")) + "\" was not found.");
// GOOD: servlet API encodes the error message HTML for the HTML context
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"The page \"" + capitalizeName(request.getParameter("page")) + "\" was not found.");
// BAD: outputting the path of the resource
response.getWriter().print("The path section of the URL was " + request.getPathInfo()); // $xss
// BAD: typical XSS, this time written to an OutputStream instead of a Writer
// BAD: typical XSS, this time written to an OutputStream instead of a Writer
response.getOutputStream().write(request.getPathInfo().getBytes()); // $xss
// GOOD: sanitizer
response.getOutputStream().write(hudson.Util.escape(request.getPathInfo()).getBytes()); // safe
}
/**
* Replace special characters in the given text such that it can
* be inserted into an HTML file and not be interpreted as including
* any HTML tags.
* Replace special characters in the given text such that it can be inserted into an HTML file
* and not be interpreted as including any HTML tags.
*/
static String encodeForHtml(String text) {
// This is just a stub. For an example of a real implementation, see
// the OWASP Java Encoder Project.
return text.replace("<", "&lt;");
}
static String capitalizeName(String text) {
return text.replace("foo inc", "Foo, Inc.");
}

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/javax-ws-rs-api-2.1.1/:${testdir}/../../../../../stubs/springframework-5.3.8:${testdir}/../../../../../stubs/javax-faces-2.3/:${testdir}/../../../../../stubs/google-android-9.0.0
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/servlet-api-2.4:${testdir}/../../../../../stubs/javax-ws-rs-api-2.1.1/:${testdir}/../../../../../stubs/springframework-5.3.8:${testdir}/../../../../../stubs/javax-faces-2.3/:${testdir}/../../../../../stubs/google-android-9.0.0:${testdir}/../../../../../stubs/jenkins

View File

@@ -0,0 +1,34 @@
package hudson;
import java.io.File;
import java.io.InputStream;
import java.nio.file.OpenOption;
public class FilePath {
public static InputStream newInputStreamDenyingSymlinkAsNeeded(File file,
String verificationRoot, OpenOption... openOption) {
return null;
}
public static InputStream openInputStream(File file, OpenOption[] openOptions) {
return null;
}
public InputStream read() {
return null;
}
public InputStream read(FilePath rootPath, OpenOption... openOptions) {
return null;
}
public InputStream readFromOffset(long offset) {
return null;
}
public String readToString() {
return null;
}
}

View File

@@ -0,0 +1,7 @@
package hudson;
public class Util {
public static String escape(String text) {
return null;
}
}