mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge branch 'main' into refacReDoS
This commit is contained in:
@@ -21,7 +21,7 @@ class File extends Container, @file {
|
||||
|
||||
/** Whether this file is a source code file. */
|
||||
predicate fromSource() {
|
||||
/* If we start to analyse .pyc files, then this will have to change. */
|
||||
/* If we start to analyze .pyc files, then this will have to change. */
|
||||
any()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Helper file that imports all framework modeling.
|
||||
*/
|
||||
|
||||
// If you add modeling of a new framework/library, remember to add it it to the docs in
|
||||
// If you add modeling of a new framework/library, remember to add it to the docs in
|
||||
// `docs/codeql/support/reusables/frameworks.rst`
|
||||
private import semmle.python.frameworks.Aioch
|
||||
private import semmle.python.frameworks.Aiohttp
|
||||
|
||||
@@ -71,7 +71,7 @@ deprecated Node importNode(string name) {
|
||||
// ```
|
||||
//
|
||||
// Where `foo_module_tracker` is a type tracker that tracks references to the `foo` module.
|
||||
// Because named imports are modelled as `AttrRead`s, the statement `from foo import bar as baz`
|
||||
// Because named imports are modeled as `AttrRead`s, the statement `from foo import bar as baz`
|
||||
// is interpreted as if it was an assignment `baz = foo.bar`, which means `baz` gets tracked as a
|
||||
// reference to `foo.bar`, as desired.
|
||||
exists(ImportExpr imp_expr |
|
||||
|
||||
@@ -333,7 +333,7 @@ abstract class Sanitizer extends string {
|
||||
/** Holds if `taint` cannot flow through `node`. */
|
||||
predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { none() }
|
||||
|
||||
/** Holds if `call` removes removes the `taint` */
|
||||
/** Holds if `call` removes the `taint` */
|
||||
predicate sanitizingCall(TaintKind taint, FunctionObject callee) { none() }
|
||||
|
||||
/** Holds if `test` shows value to be untainted with `taint` */
|
||||
|
||||
@@ -212,8 +212,8 @@ class EssaEdgeRefinement extends EssaDefinition, TEssaEdgeDefinition {
|
||||
/** Gets the SSA variable to which this refinement applies. */
|
||||
EssaVariable getInput() {
|
||||
exists(SsaSourceVariable var, EssaDefinition def |
|
||||
var = this.getSourceVariable() and
|
||||
var = def.getSourceVariable() and
|
||||
pragma[only_bind_into](var) = this.getSourceVariable() and
|
||||
pragma[only_bind_into](var) = def.getSourceVariable() and
|
||||
def.reachesEndOfBlock(this.getPredecessor()) and
|
||||
result.getDefinition() = def
|
||||
)
|
||||
|
||||
@@ -42,7 +42,7 @@ private module NotExposed {
|
||||
// Implementation below
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// We are looking to find all subclassed of the already modelled classes, and ideally
|
||||
// We are looking to find all subclassed of the already modeled classes, and ideally
|
||||
// we would identify an `API::Node` for each (then `toString` would give the API
|
||||
// path).
|
||||
//
|
||||
|
||||
@@ -273,6 +273,41 @@ 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
|
||||
pred_var.getScope() = pred_scope and
|
||||
var = pred_var.getSourceVariable()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate scope_entry_def_scope(
|
||||
SsaSourceVariable var, Scope succ_scope, ScopeEntryDefinition succ_def
|
||||
) {
|
||||
var = succ_def.getSourceVariable() and
|
||||
succ_def.getScope() = succ_scope
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate step_through_init(Scope succ_scope, Scope pred_scope, Scope init) {
|
||||
init.getName() = "__init__" and
|
||||
init.precedes(succ_scope) and
|
||||
pred_scope.precedes(init)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate scope_entry_value_transfer_through_init(
|
||||
EssaVariable pred_var, Scope pred_scope, ScopeEntryDefinition succ_def, Scope succ_scope
|
||||
) {
|
||||
exists(SsaSourceVariable var, Scope init |
|
||||
var instanceof GlobalVariable and
|
||||
essa_var_scope(var, pragma[only_bind_into](pred_scope), pred_var) and
|
||||
scope_entry_def_scope(var, succ_scope, succ_def) and
|
||||
step_through_init(succ_scope, pragma[only_bind_into](pred_scope), init) and
|
||||
not var.(Variable).getAStore().getScope() = init
|
||||
)
|
||||
}
|
||||
|
||||
module BaseFlow {
|
||||
predicate reaches_exit(EssaVariable var) { var.getAUse() = var.getScope().getANormalExit() }
|
||||
|
||||
@@ -283,27 +318,15 @@ module BaseFlow {
|
||||
) {
|
||||
Stages::DataFlow::ref() and
|
||||
exists(SsaSourceVariable var |
|
||||
reaches_exit(pred_var) and
|
||||
pred_var.getScope() = pred_scope and
|
||||
var = pred_var.getSourceVariable() and
|
||||
var = succ_def.getSourceVariable() and
|
||||
succ_def.getScope() = succ_scope
|
||||
essa_var_scope(var, pred_scope, pred_var) and
|
||||
scope_entry_def_scope(var, succ_scope, succ_def)
|
||||
|
|
||||
pred_scope.precedes(succ_scope)
|
||||
or
|
||||
/*
|
||||
* If an `__init__` method does not modify the global variable, then
|
||||
* we can skip it and take the value directly from the module.
|
||||
*/
|
||||
|
||||
exists(Scope init |
|
||||
init.getName() = "__init__" and
|
||||
init.precedes(succ_scope) and
|
||||
pred_scope.precedes(init) and
|
||||
not var.(Variable).getAStore().getScope() = init and
|
||||
var instanceof GlobalVariable
|
||||
)
|
||||
)
|
||||
or
|
||||
// If an `__init__` method does not modify the global variable, then
|
||||
// we can skip it and take the value directly from the module.
|
||||
scope_entry_value_transfer_through_init(pred_var, pred_scope, succ_def, succ_scope)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,8 @@ private int max_context_cost() {
|
||||
}
|
||||
|
||||
private int syntactic_call_count(Scope s) {
|
||||
exists(Function f | f = s and f.getName() != "__init__" |
|
||||
result =
|
||||
count(CallNode call |
|
||||
call.getFunction().(NameNode).getId() = f.getName()
|
||||
or
|
||||
call.getFunction().(AttrNode).getName() = f.getName()
|
||||
)
|
||||
exists(Function f, string name | f = s and name = f.getName() and name != "__init__" |
|
||||
result = count(function_call(name)) + count(method_call(name))
|
||||
)
|
||||
or
|
||||
s.getName() = "__init__" and result = 1
|
||||
@@ -37,6 +32,12 @@ private int syntactic_call_count(Scope s) {
|
||||
not s instanceof Function and result = 0
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private CallNode function_call(string name) { result.getFunction().(NameNode).getId() = name }
|
||||
|
||||
pragma[nomagic]
|
||||
private CallNode method_call(string name) { result.getFunction().(AttrNode).getName() = name }
|
||||
|
||||
private int incoming_call_cost(Scope s) {
|
||||
/*
|
||||
* Syntactic call count will often be a considerable overestimate
|
||||
|
||||
@@ -35,7 +35,7 @@ private import semmle.python.objects.ObjectInternal
|
||||
// functionality into `BuiltinFunctionValue` and `BuiltinMethodValue`, but will
|
||||
// probably require some more work: for this query, it's totally ok to use
|
||||
// `builtins.open` for the code `open(f)`, but well, it requires a bit of thinking to
|
||||
// figure out if that is desireable in general. I simply skipped a corner here!
|
||||
// figure out if that is desirable in general. I simply skipped a corner here!
|
||||
// 4. TaintTrackingPrivate: Nothing else gives us access to `defaultAdditionalTaintStep` :(
|
||||
/**
|
||||
* A callable that is considered a "safe" external API from a security perspective.
|
||||
|
||||
Reference in New Issue
Block a user