mirror of
https://github.com/github/codeql.git
synced 2026-02-23 10:23:41 +01:00
Merge branch 'main' of github.com:github/codeql into python/support-match
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -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"))
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
|
||||
Reference in New Issue
Block a user