Merge branch 'main' of github.com:github/codeql into python/support-match

This commit is contained in:
Rasmus Lerchedahl Petersen
2022-01-26 11:39:46 +01:00
635 changed files with 40719 additions and 11029 deletions

View File

@@ -40,7 +40,7 @@ class Comment extends @py_comment {
private predicate comment_block_part(Comment start, Comment part, int i) {
not exists(Comment prev | prev.getFollowing() = part) and
exists(Comment following | part.getFollowing() = following) and
exists(part.getFollowing()) and
start = part and
i = 1
or

View File

@@ -18,7 +18,7 @@ class Function extends Function_, Scope, AstNode {
override Scope getScope() { result = this.getEnclosingScope() }
/** Whether this function is declared in a class */
predicate isMethod() { exists(Class cls | this.getEnclosingScope() = cls) }
predicate isMethod() { this.getEnclosingScope() instanceof Class }
/** Whether this is a special method, that is does its name have the form `__xxx__` (except `__init__`) */
predicate isSpecialMethod() {

View File

@@ -57,7 +57,7 @@ class LocalVariable extends Variable {
override string toString() { result = "Local Variable " + this.getId() }
/** Whether this variable is a parameter */
override predicate isParameter() { exists(Parameter p | this.getAnAccess() = p) }
override predicate isParameter() { this.getAnAccess() instanceof Parameter }
/** Holds if this variable is the first parameter of a method. It is not necessarily called "self" */
override predicate isSelf() {
@@ -87,7 +87,7 @@ class NameLocalVariable extends LocalVariable {
/** A global (module-level) variable */
class GlobalVariable extends Variable {
GlobalVariable() { exists(Module m | m = this.getScope()) }
GlobalVariable() { this.getScope() instanceof Module }
override string toString() { result = "Global Variable " + this.getId() }
}

View File

@@ -67,6 +67,6 @@ string prettyNodeForInlineTest(DataFlow::Node node) {
)
or
not exists(node.asExpr()) and
not exists(Expr e | e = node.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()) and
not exists(node.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()) and
result = node.toString()
}

View File

@@ -163,7 +163,7 @@ private module FastApi {
exists(Class cls, API::Node base |
base = getModeledResponseClass(_).getASubclass*() and
cls.getABase() = base.getAUse().asExpr() and
responseClass.getAnImmediateUse().asExpr().(ClassExpr) = cls.getParent()
responseClass.getAnImmediateUse().asExpr() = cls.getParent()
|
exists(Assign assign | assign = cls.getAStmt() |
assign.getATarget().(Name).getId() = "media_type" and

View File

@@ -2942,6 +2942,90 @@ private module StdlibPrivate {
]
}
}
// ---------------------------------------------------------------------------
// shutil
// ---------------------------------------------------------------------------
/** Gets a reference to the `shutil` module. */
private API::Node shutil() { result = API::moduleImport("shutil") }
/**
* A call to the `shutil.rmtree` function.
*
* See https://docs.python.org/3/library/shutil.html#shutil.rmtree
*/
private class ShutilRmtreeCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
ShutilRmtreeCall() { this = shutil().getMember("rmtree").getACall() }
override DataFlow::Node getAPathArgument() {
result in [this.getArg(0), this.getArgByName("path")]
}
}
/**
* The `shutil` module provides methods to copy, move files or copy file attributes.
* See:
* - https://docs.python.org/3/library/shutil.html#shutil.copyfile
* - https://docs.python.org/3/library/shutil.html#shutil.copymode
* - https://docs.python.org/3/library/shutil.html#shutil.copystat
* - https://docs.python.org/3/library/shutil.html#shutil.copy
* - https://docs.python.org/3/library/shutil.html#shutil.copy2
* - https://docs.python.org/3/library/shutil.html#shutil.copytree
* - https://docs.python.org/3/library/shutil.html#shutil.move
*/
private class ShutilCopyCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
ShutilCopyCall() {
this =
shutil()
.getMember([
// these are used to copy files
"copyfile", "copy", "copy2", "copytree",
// these are used to move files
"move",
// these are used to copy some attributes of the file
"copymode", "copystat"
])
.getACall()
}
override DataFlow::Node getAPathArgument() {
result in [this.getArg(0), this.getArgByName("src"), this.getArg(1), this.getArgByName("dst")]
}
}
// TODO: once we have flow summaries, model `shutil.copyfileobj` which copies the content between its' file-like arguments.
// See https://docs.python.org/3/library/shutil.html#shutil.copyfileobj
private class ShutilCopyfileobjCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
ShutilCopyfileobjCall() { this = shutil().getMember("copyfileobj").getACall() }
override DataFlow::Node getAPathArgument() { none() }
}
/**
* A call to the `shutil.disk_usage` function.
*
* See https://docs.python.org/3/library/shutil.html#shutil.disk_usage
*/
private class ShutilDiskUsageCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
ShutilDiskUsageCall() { this = shutil().getMember("disk_usage").getACall() }
override DataFlow::Node getAPathArgument() {
result in [this.getArg(0), this.getArgByName("path")]
}
}
/**
* A call to the `shutil.chown` function.
*
* See https://docs.python.org/3/library/shutil.html#shutil.chown
*/
private class ShutilChownCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
ShutilChownCall() { this = shutil().getMember("chown").getACall() }
override DataFlow::Node getAPathArgument() {
result in [this.getArg(0), this.getArgByName("path")]
}
}
}
// ---------------------------------------------------------------------------

View File

@@ -916,7 +916,7 @@ private module InterModulePointsTo {
private predicate exportsSubmodule(Folder folder, string name) {
name.regexpMatch("\\p{L}(\\p{L}|\\d|_)*") and
(
exists(Folder child | child = folder.getChildContainer(name))
folder.getChildContainer(name) instanceof Folder
or
exists(folder.getFile(name + ".py"))
)

View File

@@ -40,6 +40,10 @@ module CleartextLogging {
* A source of sensitive data, considered as a flow source.
*/
class SensitiveDataSourceAsSource extends Source, SensitiveDataSource {
SensitiveDataSourceAsSource() {
not SensitiveDataSource.super.getClassification() = SensitiveDataClassification::id()
}
override SensitiveDataClassification getClassification() {
result = SensitiveDataSource.super.getClassification()
}

View File

@@ -39,6 +39,10 @@ module CleartextStorage {
* A source of sensitive data, considered as a flow source.
*/
class SensitiveDataSourceAsSource extends Source, SensitiveDataSource {
SensitiveDataSourceAsSource() {
not SensitiveDataSource.super.getClassification() = SensitiveDataClassification::id()
}
override SensitiveDataClassification getClassification() {
result = SensitiveDataSource.super.getClassification()
}

View File

@@ -0,0 +1,37 @@
/**
* Provides a taint-tracking configuration for detecting regular expression injection
* vulnerabilities.
*
* Note, for performance reasons: only import this file if
* `RegexInjection::Configuration` is needed, otherwise
* `RegexInjectionCustomizations` should be imported instead.
*/
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/**
* Provides a taint-tracking configuration for detecting regular expression injection
* vulnerabilities.
*/
module RegexInjection {
import RegexInjectionCustomizations::RegexInjection
/**
* A taint-tracking configuration for detecting "reflected server-side cross-site scripting" vulnerabilities.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "RegexInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
}

View File

@@ -0,0 +1,62 @@
/**
* Provides default sources, sinks and sanitizers for detecting
* "regular expression injection"
* vulnerabilities, as well as extension points for adding your own.
*/
private import python
private import semmle.python.Concepts
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
/**
* Provides default sources, sinks and sanitizers for detecting
* "regular expression injection"
* vulnerabilities, as well as extension points for adding your own.
*/
module RegexInjection {
/**
* A data flow source for "regular expression injection" vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A sink for "regular expression injection" vulnerabilities is the execution of a regular expression.
* If you have a custom way to execute regular expressions, you can extend `RegexExecution::Range`.
*/
class Sink extends DataFlow::Node {
RegexExecution regexExecution;
Sink() { this = regexExecution.getRegex() }
/** Gets the call that executes the regular expression marked by this sink. */
RegexExecution getRegexExecution() { result = regexExecution }
}
/**
* A sanitizer for "regular expression injection" vulnerabilities.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A sanitizer guard for "regular expression injection" vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A source of remote user input, considered as a flow source.
*/
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
/**
* A regex escaping, considered as a sanitizer.
*/
class RegexEscapingAsSanitizer extends Sanitizer {
RegexEscapingAsSanitizer() {
// Due to use-use flow, we want the output rather than an input
// (so the input can still flow to other sinks).
this = any(RegexEscaping esc).getOutput()
}
}
}

View File

@@ -1,37 +1,6 @@
/**
* Provides a taint-tracking configuration for detecting regular expression injection
* vulnerabilities.
*
* Note, for performance reasons: only import this file if
* `RegexInjection::Configuration` is needed, otherwise
* `RegexInjectionCustomizations` should be imported instead.
*/
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjection instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
private import semmle.python.security.dataflow.RegexInjection as New
/**
* Provides a taint-tracking configuration for detecting regular expression injection
* vulnerabilities.
*/
module RegexInjection {
import RegexInjectionCustomizations::RegexInjection
/**
* A taint-tracking configuration for detecting "reflected server-side cross-site scripting" vulnerabilities.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "RegexInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
}
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjection instead. */
deprecated module RegexInjection = New::RegexInjection;

View File

@@ -1,62 +1,6 @@
/**
* Provides default sources, sinks and sanitizers for detecting
* "regular expression injection"
* vulnerabilities, as well as extension points for adding your own.
*/
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjectionCustomizations instead. */
private import python
private import semmle.python.Concepts
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.security.dataflow.RegexInjectionCustomizations as New
/**
* Provides default sources, sinks and sanitizers for detecting
* "regular expression injection"
* vulnerabilities, as well as extension points for adding your own.
*/
module RegexInjection {
/**
* A data flow source for "regular expression injection" vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A sink for "regular expression injection" vulnerabilities is the execution of a regular expression.
* If you have a custom way to execute regular expressions, you can extend `RegexExecution::Range`.
*/
class Sink extends DataFlow::Node {
RegexExecution regexExecution;
Sink() { this = regexExecution.getRegex() }
/** Gets the call that executes the regular expression marked by this sink. */
RegexExecution getRegexExecution() { result = regexExecution }
}
/**
* A sanitizer for "regular expression injection" vulnerabilities.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A sanitizer guard for "regular expression injection" vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A source of remote user input, considered as a flow source.
*/
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
/**
* A regex escaping, considered as a sanitizer.
*/
class RegexEscapingAsSanitizer extends Sanitizer {
RegexEscapingAsSanitizer() {
// Due to use-use flow, we want the output rather than an input
// (so the input can still flow to other sinks).
this = any(RegexEscaping esc).getOutput()
}
}
}
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjectionCustomizations instead. */
deprecated module RegexInjection = New::RegexInjection;

View File

@@ -83,7 +83,7 @@ class RaisingNode extends ControlFlowNode {
result = this.innateException_objectapi()
)
or
not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and
not this.getAnExceptionalSuccessor() instanceof ExceptFlowNode and
sequence_or_mapping(this) and
result = theLookupErrorType()
or
@@ -110,7 +110,7 @@ class RaisingNode extends ControlFlowNode {
result = this.innateException()
)
or
not exists(ExceptFlowNode except | except = this.getAnExceptionalSuccessor()) and
not this.getAnExceptionalSuccessor() instanceof ExceptFlowNode and
sequence_or_mapping(this) and
result = ClassValue::lookupError()
or

View File

@@ -15,12 +15,7 @@ class CherryPyRequest extends TaintKind {
}
override TaintKind getTaintOfMethodResult(string name) {
(
name = "getHeader" or
name = "getCookie" or
name = "getUser" or
name = "getPassword"
) and
name in ["getHeader", "getCookie", "getUser", "getPassword"] and
result instanceof ExternalStringKind
}
}

View File

@@ -16,10 +16,7 @@ class FlaskRequestData extends HttpRequestTaintSource {
FlaskRequestData() {
not this instanceof FlaskRequestArgs and
exists(string name | flask_request_attr(this, name) |
name = "path" or
name = "full_path" or
name = "base_url" or
name = "url"
name in ["path", "full_path", "base_url", "url"]
)
}

View File

@@ -41,10 +41,7 @@ class TornadoRequestSource extends HttpRequestTaintSource {
class TornadoExternalInputSource extends HttpRequestTaintSource {
TornadoExternalInputSource() {
exists(string name |
name = "get_argument" or
name = "get_query_argument" or
name = "get_body_argument" or
name = "decode_argument"
name in ["get_argument", "get_query_argument", "get_body_argument", "decode_argument"]
|
this = callToNamedTornadoRequestHandlerMethod(name)
)

View File

@@ -16,12 +16,7 @@ class TwistedRequest extends TaintKind {
}
override TaintKind getTaintOfMethodResult(string name) {
(
name = "getHeader" or
name = "getCookie" or
name = "getUser" or
name = "getPassword"
) and
name in ["getHeader", "getCookie", "getUser", "getPassword"] and
result instanceof ExternalStringKind
}
}

View File

@@ -233,7 +233,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
/** Holds if this XML element has an attribute with the specified `name`. */
predicate hasAttribute(string name) { exists(XMLAttribute a | a = this.getAttribute(name)) }
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
/** Gets the value of the attribute with the specified `name`, if any. */
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }