mirror of
https://github.com/github/codeql.git
synced 2026-04-26 01:05:15 +02:00
Merge pull request #15393 from erik-krogh/deps-jan-2024
All: delete outdated deprecations
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted many deprecated predicates and classes with uppercase `LDAP`, `HTTP`, `URL`, `CGI` etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `localSourceStoreStep` predicate, use `flowsToStoreStep` instead.
|
||||
* Deleted the deprecated `iteration_defined_variable` predicate from the `SSA` library.
|
||||
* Deleted various deprecated predicates from the points-to libraries.
|
||||
* Deleted the deprecated `semmle/python/security/OverlyLargeRangeQuery.qll`, `semmle/python/security/regexp/ExponentialBackTracking.qll`, `semmle/python/security/regexp/NfaUtils.qll`, and `semmle/python/security/regexp/NfaUtils.qll` files.
|
||||
@@ -26,7 +26,6 @@ import semmle.python.types.FunctionObject
|
||||
import semmle.python.types.ModuleObject
|
||||
import semmle.python.types.Version
|
||||
import semmle.python.types.Descriptors
|
||||
import semmle.python.protocols
|
||||
import semmle.python.SSA
|
||||
import semmle.python.SelfAttribute
|
||||
import semmle.python.types.Properties
|
||||
|
||||
@@ -685,9 +685,6 @@ module Ldap {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Ldap */
|
||||
deprecated module LDAP = Ldap;
|
||||
|
||||
/**
|
||||
* A data-flow node that escapes meta-characters, which could be used to prevent
|
||||
* injection attacks.
|
||||
@@ -1157,9 +1154,6 @@ module Http {
|
||||
// remote-flow-sources in general.
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Http */
|
||||
deprecated module HTTP = Http;
|
||||
|
||||
/**
|
||||
* Provides models for cryptographic things.
|
||||
*
|
||||
|
||||
@@ -386,8 +386,6 @@ deprecated module StepSummary {
|
||||
smallstepCall(nodeFrom, nodeTo, summary)
|
||||
}
|
||||
|
||||
deprecated predicate localSourceStoreStep = flowsToStoreStep/3;
|
||||
|
||||
/** Gets the step summary for a level step. */
|
||||
StepSummary levelStep() { result = LevelStep() }
|
||||
|
||||
|
||||
@@ -88,15 +88,6 @@ module SsaSource {
|
||||
lhs.getBasicBlock().dominates(defn.getBasicBlock())
|
||||
}
|
||||
|
||||
/** Holds if `v` is defined by a `for` statement, the definition being `defn` */
|
||||
cached
|
||||
deprecated predicate iteration_defined_variable(
|
||||
Variable v, ControlFlowNode defn, ControlFlowNode sequence
|
||||
) {
|
||||
exists(ForNode for | for.iterates(defn, sequence)) and
|
||||
defn.(NameNode).defines(v)
|
||||
}
|
||||
|
||||
/** Holds if `v` is a parameter variable and `defn` is the CFG node for that parameter. */
|
||||
cached
|
||||
predicate parameter_definition(Variable v, ControlFlowNode defn) {
|
||||
|
||||
@@ -1154,9 +1154,6 @@ module PrivateDjango {
|
||||
/** Gets a reference to the `django.http` module. */
|
||||
API::Node http() { result = django().getMember("http") }
|
||||
|
||||
/** DEPRECATED: Alias for `DjangoHttp` */
|
||||
deprecated module http = DjangoHttp;
|
||||
|
||||
/** Provides models for the `django.http` module */
|
||||
module DjangoHttp {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -166,9 +166,6 @@ module Starlette {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for Url */
|
||||
deprecated module URL = Url;
|
||||
|
||||
/**
|
||||
* A call to the `starlette.responses.FileResponse` constructor as a sink for Filesystem access.
|
||||
*/
|
||||
|
||||
@@ -1967,14 +1967,8 @@ module StdlibPrivate {
|
||||
result = cgiHttpServer().getMember("CGIHTTPRequestHandler")
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for CgiHttpRequestHandler */
|
||||
deprecated module CGIHTTPRequestHandler = CgiHttpRequestHandler;
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for CgiHttpServer */
|
||||
deprecated module CGIHTTPServer = CgiHttpServer;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// http (Python 3 only)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -2042,9 +2036,6 @@ module StdlibPrivate {
|
||||
*/
|
||||
deprecated API::Node classRef() { result = server().getMember("CGIHTTPRequestHandler") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for CgiHttpRequestHandler */
|
||||
deprecated module CGIHTTPRequestHandler = CgiHttpRequestHandler;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2233,9 +2224,6 @@ module StdlibPrivate {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for WsgiEnvirontParameter */
|
||||
deprecated class WSGIEnvirontParameter = WsgiEnvirontParameter;
|
||||
|
||||
/**
|
||||
* Gets a reference to the parameter of a `WsgirefSimpleServerApplication` that
|
||||
* takes the `start_response` function.
|
||||
|
||||
@@ -333,36 +333,6 @@ predicate call3(
|
||||
arg2 = call.getArg(2)
|
||||
}
|
||||
|
||||
bindingset[self, function]
|
||||
deprecated predicate method_binding(
|
||||
AttrNode instantiation, ObjectInternal self, CallableObjectInternal function,
|
||||
PointsToContext context
|
||||
) {
|
||||
exists(ObjectInternal obj, string name | receiver(instantiation, context, obj, name) |
|
||||
exists(ObjectInternal cls |
|
||||
cls = obj.getClass() and
|
||||
cls != ObjectInternal::superType() and
|
||||
cls.attribute(name, function, _) and
|
||||
self = obj
|
||||
)
|
||||
or
|
||||
exists(SuperInstance sup, ClassObjectInternal decl |
|
||||
sup = obj and
|
||||
decl = Types::getMro(self.getClass()).startingAt(sup.getStartClass()).findDeclaringClass(name) and
|
||||
Types::declaredAttribute(decl, name, function, _) and
|
||||
self = sup.getSelf()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Helper for method_binding */
|
||||
pragma[noinline]
|
||||
deprecated predicate receiver(
|
||||
AttrNode instantiation, PointsToContext context, ObjectInternal obj, string name
|
||||
) {
|
||||
PointsToInternal::pointsTo(instantiation.getObject(name), context, obj, _)
|
||||
}
|
||||
|
||||
/** Helper self parameters: `def meth(self, ...): ...`. */
|
||||
pragma[noinline]
|
||||
private predicate self_parameter(
|
||||
|
||||
@@ -13,123 +13,6 @@ import semmle.python.essa.SsaDefinitions
|
||||
private import semmle.python.types.Builtins
|
||||
private import semmle.python.internal.CachedStages
|
||||
|
||||
deprecated module BasePointsTo {
|
||||
/** INTERNAL -- Use n.refersTo(value, _, origin) instead */
|
||||
pragma[noinline]
|
||||
predicate points_to(ControlFlowNode f, Object value, ControlFlowNode origin) {
|
||||
(
|
||||
f.isLiteral() and value = f and not f.getNode() instanceof ImmutableLiteral
|
||||
or
|
||||
f.isFunction() and value = f
|
||||
) and
|
||||
origin = f
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the kwargs parameter (`**kwargs`). In a function definition this is always a dict. */
|
||||
deprecated predicate kwargs_points_to(ControlFlowNode f, ClassObject cls) {
|
||||
exists(Function func | func.getKwarg() = f.getNode()) and
|
||||
cls = theDictType()
|
||||
}
|
||||
|
||||
/** Gets the varargs parameter (`*varargs`). In a function definition this is always a tuple. */
|
||||
deprecated predicate varargs_points_to(ControlFlowNode f, ClassObject cls) {
|
||||
exists(Function func | func.getVararg() = f.getNode()) and
|
||||
cls = theTupleType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class of the object for simple cases, namely constants, functions,
|
||||
* comprehensions and built-in objects.
|
||||
*
|
||||
* This exists primarily for internal use. Use getAnInferredType() instead.
|
||||
*/
|
||||
pragma[noinline]
|
||||
deprecated ClassObject simple_types(Object obj) {
|
||||
result = comprehension(obj.getOrigin())
|
||||
or
|
||||
result = collection_literal(obj.getOrigin())
|
||||
or
|
||||
obj.getOrigin() instanceof CallableExpr and result = thePyFunctionType()
|
||||
or
|
||||
obj.getOrigin() instanceof Module and result = theModuleType()
|
||||
or
|
||||
result.asBuiltin() = obj.asBuiltin().getClass()
|
||||
or
|
||||
obj = unknownValue() and result = theUnknownType()
|
||||
}
|
||||
|
||||
deprecated private ClassObject comprehension(Expr e) {
|
||||
e instanceof ListComp and result = theListType()
|
||||
or
|
||||
e instanceof SetComp and result = theSetType()
|
||||
or
|
||||
e instanceof DictComp and result = theDictType()
|
||||
or
|
||||
e instanceof GeneratorExp and result = theGeneratorType()
|
||||
}
|
||||
|
||||
deprecated private ClassObject collection_literal(Expr e) {
|
||||
e instanceof List and result = theListType()
|
||||
or
|
||||
e instanceof Set and result = theSetType()
|
||||
or
|
||||
e instanceof Dict and result = theDictType()
|
||||
or
|
||||
e instanceof Tuple and result = theTupleType()
|
||||
}
|
||||
|
||||
deprecated private int tuple_index_value(Object t, int i) {
|
||||
result = t.(TupleNode).getElement(i).getNode().(Num).getN().toInt()
|
||||
or
|
||||
exists(Object item |
|
||||
py_citems(t, i, item) and
|
||||
result = item.(NumericObject).intValue()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
deprecated int version_tuple_value(Object t) {
|
||||
not exists(tuple_index_value(t, 1)) and result = tuple_index_value(t, 0) * 10
|
||||
or
|
||||
not exists(tuple_index_value(t, 2)) and
|
||||
result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1)
|
||||
or
|
||||
tuple_index_value(t, 2) = 0 and result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1)
|
||||
or
|
||||
tuple_index_value(t, 2) > 0 and
|
||||
result = tuple_index_value(t, 0) * 10 + tuple_index_value(t, 1) + 1
|
||||
}
|
||||
|
||||
/** Choose a version numbers that represent the extreme of supported versions. */
|
||||
deprecated private int major_minor() {
|
||||
if major_version() = 3
|
||||
then (
|
||||
result = 33 or result = 37
|
||||
) else (
|
||||
// 3.3 to 3.7
|
||||
result = 25 or result = 27
|
||||
) // 2.5 to 2.7
|
||||
}
|
||||
|
||||
/** Compares the given tuple object to both the maximum and minimum possible sys.version_info values */
|
||||
deprecated int version_tuple_compare(Object t) {
|
||||
version_tuple_value(t) < major_minor() and result = -1
|
||||
or
|
||||
version_tuple_value(t) = major_minor() and result = 0
|
||||
or
|
||||
version_tuple_value(t) > major_minor() and result = 1
|
||||
}
|
||||
|
||||
/** Holds if `cls` is a new-style class if it were to have no explicit base classes */
|
||||
deprecated predicate baseless_is_new_style(ClassObject cls) {
|
||||
cls.isBuiltin()
|
||||
or
|
||||
major_version() = 3 and exists(cls)
|
||||
or
|
||||
exists(cls.declaredMetaClass())
|
||||
}
|
||||
|
||||
/*
|
||||
* The following predicates exist in order to provide
|
||||
* more precise type information than the underlying
|
||||
@@ -159,49 +42,6 @@ private predicate class_defines_name(Class cls, string name) {
|
||||
exists(SsaVariable var | name = var.getId() and var.getAUse() = cls.getANormalExit())
|
||||
}
|
||||
|
||||
/** Gets a return value CFG node, provided that is safe to track across returns */
|
||||
deprecated ControlFlowNode safe_return_node(PyFunctionObject func) {
|
||||
result = func.getAReturnedNode() and
|
||||
// Not a parameter
|
||||
not exists(Parameter p, SsaVariable pvar |
|
||||
p.asName().getAFlowNode() = pvar.getDefinition() and
|
||||
result = pvar.getAUse()
|
||||
) and
|
||||
// No alternatives
|
||||
not exists(ControlFlowNode branch | branch.isBranch() and branch.getScope() = func.getFunction())
|
||||
}
|
||||
|
||||
/** Holds if it can be determined from the control flow graph alone that this function can never return */
|
||||
deprecated predicate function_can_never_return(FunctionObject func) {
|
||||
/*
|
||||
* A Python function never returns if it has no normal exits that are not dominated by a
|
||||
* call to a function which itself never returns.
|
||||
*/
|
||||
|
||||
exists(Function f |
|
||||
f = func.getFunction() and
|
||||
not exists(f.getAnExitNode())
|
||||
)
|
||||
or
|
||||
func = ModuleObject::named("sys").attr("exit")
|
||||
}
|
||||
|
||||
/** Hold if outer contains inner, both are contained within a test and inner is a use is a plain use or an attribute lookup */
|
||||
pragma[noinline]
|
||||
deprecated predicate contains_interesting_expression_within_test(
|
||||
ControlFlowNode outer, ControlFlowNode inner
|
||||
) {
|
||||
inner.isLoad() and
|
||||
exists(ControlFlowNode test |
|
||||
outer.getAChild*() = inner and
|
||||
test_contains(test, outer) and
|
||||
test_contains(test, inner)
|
||||
|
|
||||
inner instanceof NameNode or
|
||||
inner instanceof AttrNode
|
||||
)
|
||||
}
|
||||
|
||||
/** Hold if `expr` is a test (a branch) and `use` is within that test */
|
||||
predicate test_contains(ControlFlowNode expr, ControlFlowNode use) {
|
||||
expr.getNode() instanceof Expr and
|
||||
@@ -209,31 +49,6 @@ predicate test_contains(ControlFlowNode expr, ControlFlowNode use) {
|
||||
expr.getAChild*() = use
|
||||
}
|
||||
|
||||
/** Holds if `test` is a test (a branch), `use` is within that test and `def` is an edge from that test with `sense` */
|
||||
deprecated predicate refinement_test(
|
||||
ControlFlowNode test, ControlFlowNode use, boolean sense, PyEdgeRefinement def
|
||||
) {
|
||||
/*
|
||||
* Because calls such as `len` may create a new variable, we need to go via the source variable
|
||||
* That is perfectly safe as we are only dealing with calls that do not mutate their arguments.
|
||||
*/
|
||||
|
||||
use = def.getInput().getSourceVariable().(Variable).getAUse() and
|
||||
test = def.getPredecessor().getLastNode() and
|
||||
test_contains(test, use) and
|
||||
sense = def.getSense()
|
||||
}
|
||||
|
||||
/** Holds if `f` is an import of the form `from .[...] import name` and the enclosing scope is an __init__ module */
|
||||
pragma[noinline]
|
||||
deprecated predicate live_import_from_dot_in_init(ImportMemberNode f, EssaVariable var) {
|
||||
exists(string name |
|
||||
import_from_dot_in_init(f.getModule(name)) and
|
||||
var.getSourceVariable().getName() = name and
|
||||
var.getAUse() = f
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `f` is an import of the form `from .[...] import ...` and the enclosing scope is an __init__ module */
|
||||
predicate import_from_dot_in_init(ImportExprNode f) {
|
||||
f.getScope() = any(Module m).getInitModule() and
|
||||
@@ -251,30 +66,6 @@ Object undefinedVariable() { py_special_objects(result, "_semmle_undefined_value
|
||||
/** Gets the pseudo-object representing an unknown value */
|
||||
Object unknownValue() { result.asBuiltin() = Builtin::unknown() }
|
||||
|
||||
deprecated BuiltinCallable theTypeNewMethod() {
|
||||
result.asBuiltin() = theTypeType().asBuiltin().getMember("__new__")
|
||||
}
|
||||
|
||||
/** Gets the `value, cls, origin` that `f` would refer to if it has not been assigned some other value */
|
||||
pragma[noinline]
|
||||
deprecated predicate potential_builtin_points_to(
|
||||
NameNode f, Object value, ClassObject cls, ControlFlowNode origin
|
||||
) {
|
||||
f.isGlobal() and
|
||||
f.isLoad() and
|
||||
origin = f and
|
||||
(
|
||||
builtin_name_points_to(f.getId(), value, cls)
|
||||
or
|
||||
not exists(Object::builtin(f.getId())) and value = unknownValue() and cls = theUnknownType()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
deprecated predicate builtin_name_points_to(string name, Object value, ClassObject cls) {
|
||||
value = Object::builtin(name) and cls.asBuiltin() = value.asBuiltin().getClass()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate essa_var_scope(SsaSourceVariable var, Scope pred_scope, EssaVariable pred_var) {
|
||||
BaseFlow::reaches_exit(pred_var) and
|
||||
@@ -331,48 +122,3 @@ module BaseFlow {
|
||||
scope_entry_value_transfer_through_init(pred_var, pred_scope, succ_def, succ_scope)
|
||||
}
|
||||
}
|
||||
|
||||
/** Points-to for syntactic elements where context is not relevant */
|
||||
deprecated predicate simple_points_to(
|
||||
ControlFlowNode f, Object value, ClassObject cls, ControlFlowNode origin
|
||||
) {
|
||||
kwargs_points_to(f, cls) and value = f and origin = f
|
||||
or
|
||||
varargs_points_to(f, cls) and value = f and origin = f
|
||||
or
|
||||
BasePointsTo::points_to(f, value, origin) and cls = simple_types(value)
|
||||
or
|
||||
value = f.getNode().(ImmutableLiteral).getLiteralObject() and
|
||||
cls = simple_types(value) and
|
||||
origin = f
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bit` is a binary expression node with a bitwise operator.
|
||||
* Helper for `this_binary_expr_points_to`.
|
||||
*/
|
||||
deprecated predicate bitwise_expression_node(
|
||||
BinaryExprNode bit, ControlFlowNode left, ControlFlowNode right
|
||||
) {
|
||||
exists(Operator op | op = bit.getNode().getOp() |
|
||||
op instanceof BitAnd or
|
||||
op instanceof BitOr or
|
||||
op instanceof BitXor
|
||||
) and
|
||||
left = bit.getLeft() and
|
||||
right = bit.getRight()
|
||||
}
|
||||
|
||||
deprecated private Module theCollectionsAbcModule() {
|
||||
result.getName() = "_abcoll"
|
||||
or
|
||||
result.getName() = "_collections_abc"
|
||||
}
|
||||
|
||||
deprecated ClassObject collectionsAbcClass(string name) {
|
||||
exists(Class cls |
|
||||
result.getPyClass() = cls and
|
||||
cls.getName() = name and
|
||||
cls.getScope() = theCollectionsAbcModule()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,12 +12,6 @@ predicate hasattr(CallNode c, ControlFlowNode obj, string attr) {
|
||||
c.getArg(1).getNode().(StrConst).getText() = attr
|
||||
}
|
||||
|
||||
/** Holds if `c` is a call to `callable(obj)`. */
|
||||
deprecated predicate is_callable(CallNode c, ControlFlowNode obj) {
|
||||
c.getFunction().(NameNode).getId() = "callable" and
|
||||
obj = c.getArg(0)
|
||||
}
|
||||
|
||||
/** Holds if `c` is a call to `isinstance(use, cls)`. */
|
||||
predicate isinstance(CallNode fc, ControlFlowNode cls, ControlFlowNode use) {
|
||||
fc.getFunction().(NameNode).getId() = "isinstance" and
|
||||
@@ -25,13 +19,6 @@ predicate isinstance(CallNode fc, ControlFlowNode cls, ControlFlowNode use) {
|
||||
fc.getArg(0) = use
|
||||
}
|
||||
|
||||
/** Holds if `c` is a call to `issubclass(use, cls)`. */
|
||||
deprecated predicate issubclass(CallNode fc, ControlFlowNode cls, ControlFlowNode use) {
|
||||
fc.getFunction().(NameNode).getId() = "issubclass" and
|
||||
fc.getArg(0) = use and
|
||||
cls = fc.getArg(1)
|
||||
}
|
||||
|
||||
/** Holds if `c` is a test comparing `x` and `y`. `is` is true if the operator is `is` or `==`, it is false if the operator is `is not` or `!=`. */
|
||||
predicate equality_test(CompareNode c, ControlFlowNode x, boolean is, ControlFlowNode y) {
|
||||
exists(Cmpop op |
|
||||
|
||||
@@ -122,10 +122,6 @@ private newtype TPointsToContext =
|
||||
} or
|
||||
TObjectContext(SelfInstanceInternal object)
|
||||
|
||||
deprecated module Context {
|
||||
PointsToContext forObject(ObjectInternal object) { result = TObjectContext(object) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A points-to context. Context can be one of:
|
||||
* * "main": Used for scripts.
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import python
|
||||
|
||||
/** Retained for backwards compatibility use ClassObject.isIterator() instead. */
|
||||
deprecated predicate is_iterator(ClassObject c) { c.isIterator() }
|
||||
|
||||
/** Retained for backwards compatibility use ClassObject.isIterable() instead. */
|
||||
deprecated predicate is_iterable(ClassObject c) { c.isIterable() }
|
||||
|
||||
/** Retained for backwards compatibility use ClassObject.isCollection() instead. */
|
||||
deprecated predicate is_collection(ClassObject c) { c.isCollection() }
|
||||
|
||||
/** Retained for backwards compatibility use ClassObject.isMapping() instead. */
|
||||
deprecated predicate is_mapping(ClassObject c) { c.isMapping() }
|
||||
|
||||
/** Retained for backwards compatibility use ClassObject.isSequence() instead. */
|
||||
deprecated predicate is_sequence(ClassObject c) { c.isSequence() }
|
||||
|
||||
/** Retained for backwards compatibility use ClassObject.isContextManager() instead. */
|
||||
deprecated predicate is_context_manager(ClassObject c) { c.isContextManager() }
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Provides predicates for reasoning about bad tag filter vulnerabilities.
|
||||
*/
|
||||
|
||||
private import semmle.python.RegexTreeView::RegexTreeView as TreeView
|
||||
// BadTagFilterQuery should be used directly from the shared pack, and not from this file.
|
||||
deprecated import codeql.regex.nfa.BadTagFilterQuery::Make<TreeView> as Dep
|
||||
import Dep
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Classes and predicates for working with suspicious character ranges.
|
||||
*/
|
||||
|
||||
private import semmle.python.RegexTreeView::RegexTreeView as TreeView
|
||||
// OverlyLargeRangeQuery should be used directly from the shared pack, and not from this file.
|
||||
deprecated import codeql.regex.OverlyLargeRangeQuery::Make<TreeView> as Dep
|
||||
import Dep
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* This library implements the analysis described in the following two papers:
|
||||
*
|
||||
* James Kirrage, Asiri Rathnayake, Hayo Thielecke: Static Analysis for
|
||||
* Regular Expression Denial-of-Service Attacks. NSS 2013.
|
||||
* (https://arxiv.org/abs/1301.0849)
|
||||
* Asiri Rathnayake, Hayo Thielecke: Static Analysis for Regular Expression
|
||||
* Exponential Runtime via Substructural Logics. 2014.
|
||||
* (https://www.cs.bham.ac.uk/~hxt/research/redos_full.pdf)
|
||||
*
|
||||
* The basic idea is to search for overlapping cycles in the NFA, that is,
|
||||
* states `q` such that there are two distinct paths from `q` to itself
|
||||
* that consume the same word `w`.
|
||||
*
|
||||
* For any such state `q`, an attack string can be constructed as follows:
|
||||
* concatenate a prefix `v` that takes the NFA to `q` with `n` copies of
|
||||
* the word `w` that leads back to `q` along two different paths, followed
|
||||
* by a suffix `x` that is _not_ accepted in state `q`. A backtracking
|
||||
* implementation will need to explore at least 2^n different ways of going
|
||||
* from `q` back to itself while trying to match the `n` copies of `w`
|
||||
* before finally giving up.
|
||||
*
|
||||
* Now in order to identify overlapping cycles, all we have to do is find
|
||||
* pumpable forks, that is, states `q` that can transition to two different
|
||||
* states `r1` and `r2` on the same input symbol `c`, such that there are
|
||||
* paths from both `r1` and `r2` to `q` that consume the same word. The latter
|
||||
* condition is equivalent to saying that `(q, q)` is reachable from `(r1, r2)`
|
||||
* in the product NFA.
|
||||
*
|
||||
* This is what the library does. It makes a simple attempt to construct a
|
||||
* prefix `v` leading into `q`, but only to improve the alert message.
|
||||
* And the library tries to prove the existence of a suffix that ensures
|
||||
* rejection. This check might fail, which can cause false positives.
|
||||
*
|
||||
* Finally, sometimes it depends on the translation whether the NFA generated
|
||||
* for a regular expression has a pumpable fork or not. We implement one
|
||||
* particular translation, which may result in false positives or negatives
|
||||
* relative to some particular JavaScript engine.
|
||||
*
|
||||
* More precisely, the library constructs an NFA from a regular expression `r`
|
||||
* as follows:
|
||||
*
|
||||
* * Every sub-term `t` gives rise to an NFA state `Match(t,i)`, representing
|
||||
* the state of the automaton before attempting to match the `i`th character in `t`.
|
||||
* * There is one accepting state `Accept(r)`.
|
||||
* * There is a special `AcceptAnySuffix(r)` state, which accepts any suffix string
|
||||
* by using an epsilon transition to `Accept(r)` and an any transition to itself.
|
||||
* * Transitions between states may be labelled with epsilon, or an abstract
|
||||
* input symbol.
|
||||
* * Each abstract input symbol represents a set of concrete input characters:
|
||||
* either a single character, a set of characters represented by a
|
||||
* character class, or the set of all characters.
|
||||
* * The product automaton is constructed lazily, starting with pair states
|
||||
* `(q, q)` where `q` is a fork, and proceeding along an over-approximate
|
||||
* step relation.
|
||||
* * The over-approximate step relation allows transitions along pairs of
|
||||
* abstract input symbols where the symbols have overlap in the characters they accept.
|
||||
* * Once a trace of pairs of abstract input symbols that leads from a fork
|
||||
* back to itself has been identified, we attempt to construct a concrete
|
||||
* string corresponding to it, which may fail.
|
||||
* * Lastly we ensure that any state reached by repeating `n` copies of `w` has
|
||||
* a suffix `x` (possible empty) that is most likely __not__ accepted.
|
||||
*/
|
||||
|
||||
private import semmle.python.RegexTreeView::RegexTreeView as TreeView
|
||||
// ExponentialBackTracking should be used directly from the shared pack, and not from this file.
|
||||
deprecated private import codeql.regex.nfa.ExponentialBackTracking::Make<TreeView> as Dep
|
||||
import Dep
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Provides classes and predicates for constructing an NFA from
|
||||
* a regular expression, and various utilities for reasoning about
|
||||
* the resulting NFA.
|
||||
*
|
||||
* These utilities are used both by the ReDoS queries and by
|
||||
* other queries that benefit from reasoning about NFAs.
|
||||
*/
|
||||
|
||||
private import semmle.python.RegexTreeView::RegexTreeView as TreeView
|
||||
// NfaUtils should be used directly from the shared pack, and not from this file.
|
||||
deprecated private import codeql.regex.nfa.NfaUtils::Make<TreeView> as Dep
|
||||
import Dep
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Provides predicates for reasoning about which strings are matched by a regular expression,
|
||||
* and for testing which capture groups are filled when a particular regexp matches a string.
|
||||
*/
|
||||
|
||||
private import semmle.python.RegexTreeView::RegexTreeView as TreeView
|
||||
// RegexpMatching should be used directly from the shared pack, and not from this file.
|
||||
deprecated import codeql.regex.nfa.RegexpMatching::Make<TreeView> as Dep
|
||||
import Dep
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* This module implements the analysis described in the paper:
|
||||
* Valentin Wustholz, Oswaldo Olivo, Marijn J. H. Heule, and Isil Dillig:
|
||||
* Static Detection of DoS Vulnerabilities in
|
||||
* Programs that use Regular Expressions
|
||||
* (Extended Version).
|
||||
* (https://arxiv.org/pdf/1701.04045.pdf)
|
||||
*
|
||||
* Theorem 3 from the paper describes the basic idea.
|
||||
*
|
||||
* The following explains the idea using variables and predicate names that are used in the implementation:
|
||||
* We consider a pair of repetitions, which we will call `pivot` and `succ`.
|
||||
*
|
||||
* We create a product automaton of 3-tuples of states (see `StateTuple`).
|
||||
* There exists a transition `(a,b,c) -> (d,e,f)` in the product automaton
|
||||
* iff there exists three transitions in the NFA `a->d, b->e, c->f` where those three
|
||||
* transitions all match a shared character `char`. (see `getAThreewayIntersect`)
|
||||
*
|
||||
* We start a search in the product automaton at `(pivot, pivot, succ)`,
|
||||
* and search for a series of transitions (a `Trace`), such that we end
|
||||
* at `(pivot, succ, succ)` (see `isReachableFromStartTuple`).
|
||||
*
|
||||
* For example, consider the regular expression `/^\d*5\w*$/`.
|
||||
* The search will start at the tuple `(\d*, \d*, \w*)` and search
|
||||
* for a path to `(\d*, \w*, \w*)`.
|
||||
* This path exists, and consists of a single transition in the product automaton,
|
||||
* where the three corresponding NFA edges all match the character `"5"`.
|
||||
*
|
||||
* The start-state in the NFA has an any-transition to itself, this allows us to
|
||||
* flag regular expressions such as `/a*$/` - which does not have a start anchor -
|
||||
* and can thus start matching anywhere.
|
||||
*
|
||||
* The implementation is not perfect.
|
||||
* It has the same suffix detection issue as the `js/redos` query, which can cause false positives.
|
||||
* It also doesn't find all transitions in the product automaton, which can cause false negatives.
|
||||
*/
|
||||
|
||||
private import semmle.python.RegexTreeView::RegexTreeView as TreeView
|
||||
// SuperlinearBackTracking should be used directly from the shared pack, and not from this file.
|
||||
deprecated private import codeql.regex.nfa.SuperlinearBackTracking::Make<TreeView> as Dep
|
||||
import Dep
|
||||
@@ -32,9 +32,6 @@ class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlLocatable */
|
||||
deprecated class XMLLocatable = XmlLocatable;
|
||||
|
||||
/**
|
||||
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
|
||||
* both of which can contain other elements.
|
||||
@@ -95,9 +92,6 @@ class XmlParent extends @xmlparent {
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlParent */
|
||||
deprecated class XMLParent = XmlParent;
|
||||
|
||||
/** An XML file. */
|
||||
class XmlFile extends XmlParent, File {
|
||||
XmlFile() { xmlEncoding(this, _) }
|
||||
@@ -119,14 +113,8 @@ class XmlFile extends XmlParent, File {
|
||||
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
|
||||
|
||||
/** DEPRECATED: Alias for getADtd */
|
||||
deprecated XmlDtd getADTD() { result = this.getADtd() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlFile */
|
||||
deprecated class XMLFile = XmlFile;
|
||||
|
||||
/**
|
||||
* An XML document type definition (DTD).
|
||||
*
|
||||
@@ -163,9 +151,6 @@ class XmlDtd extends XmlLocatable, @xmldtd {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlDtd */
|
||||
deprecated class XMLDTD = XmlDtd;
|
||||
|
||||
/**
|
||||
* An XML element in an XML file.
|
||||
*
|
||||
@@ -221,9 +206,6 @@ class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
|
||||
override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlElement */
|
||||
deprecated class XMLElement = XmlElement;
|
||||
|
||||
/**
|
||||
* An attribute that occurs inside an XML element.
|
||||
*
|
||||
@@ -254,9 +236,6 @@ class XmlAttribute extends @xmlattribute, XmlLocatable {
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlAttribute */
|
||||
deprecated class XMLAttribute = XmlAttribute;
|
||||
|
||||
/**
|
||||
* A namespace used in an XML file.
|
||||
*
|
||||
@@ -273,9 +252,6 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||
/** Gets the URI of this namespace. */
|
||||
string getUri() { xmlNs(this, _, result, _) }
|
||||
|
||||
/** DEPRECATED: Alias for getUri */
|
||||
deprecated string getURI() { result = this.getUri() }
|
||||
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
@@ -286,9 +262,6 @@ class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlNamespace */
|
||||
deprecated class XMLNamespace = XmlNamespace;
|
||||
|
||||
/**
|
||||
* A comment in an XML file.
|
||||
*
|
||||
@@ -309,9 +282,6 @@ class XmlComment extends @xmlcomment, XmlLocatable {
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlComment */
|
||||
deprecated class XMLComment = XmlComment;
|
||||
|
||||
/**
|
||||
* A sequence of characters that occurs between opening and
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
@@ -335,6 +305,3 @@ class XmlCharacters extends @xmlcharacters, XmlLocatable {
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlCharacters */
|
||||
deprecated class XMLCharacters = XmlCharacters;
|
||||
|
||||
@@ -27,9 +27,6 @@ private module ExperimentalPrivateDjango {
|
||||
|
||||
override string getSourceType() { result = "django.http.request.GET.get" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for DjangoGetParameter */
|
||||
deprecated class DjangoGETParameter = DjangoGetParameter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,9 +124,6 @@ private module Ldap {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for useSsl */
|
||||
deprecated override predicate useSSL() { this.useSsl() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,9 +216,6 @@ private module Ldap {
|
||||
startTls.getObject().getALocalSource() = this
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for useSsl */
|
||||
deprecated override predicate useSSL() { this.useSsl() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,3 @@ query predicate missingAnnotationOnSink(Location location, string error, string
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for missingAnnotationOnSink */
|
||||
deprecated predicate missingAnnotationOnSINK = missingAnnotationOnSink/3;
|
||||
|
||||
@@ -10,18 +10,12 @@ class XmlRecordedCall extends XmlElement {
|
||||
/** Gets the XML data for the call. */
|
||||
XmlCall getXmlCall() { result.getParent() = this }
|
||||
|
||||
/** DEPRECATED: Alias for getXmlCall */
|
||||
deprecated XMLCall getXMLCall() { result = this.getXmlCall() }
|
||||
|
||||
/** Gets a call matching the recorded information. */
|
||||
Call getACall() { result = this.getXmlCall().getACall() }
|
||||
|
||||
/** Gets the XML data for the callee. */
|
||||
XmlCallee getXmlCallee() { result.getParent() = this }
|
||||
|
||||
/** DEPRECATED: Alias for getXmlCallee */
|
||||
deprecated XMLCallee getXMLCallee() { result = this.getXmlCallee() }
|
||||
|
||||
/** Gets a python function matching the recorded information of the callee. */
|
||||
Function getAPythonCallee() { result = this.getXmlCallee().(XmlPythonCallee).getACallee() }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user