mirror of
https://github.com/github/codeql.git
synced 2026-05-31 11:31:23 +02:00
Option 2: eliminates the AST→CFG bridge from the AST layer. Previously
'AstNode.getAFlowNode()' returned a 'ControlFlowNode' from the legacy
'Flow.qll' CFG via 'py_flow_bb_node' — this hardcoded the AST to know
about the legacy CFG, preventing files from cleanly switching to the
new shared CFG.
Removes:
* 'AstNode.getAFlowNode()' from 'AstExtended.qll'
* Type-narrowing overrides on 'Attribute' / 'Subscript' / 'Call' /
'IfExp' / 'Name' / 'NameConstant' / 'ImportMember' (in Exprs.qll
and Import.qll)
Rewrites ~130 call sites across 'python/ql/lib/' and 'python/ql/src/'
to bridge from the CFG side instead:
Before: node = expr.getAFlowNode()
After: node.getNode() = expr
Before: expr.getAFlowNode().(DefinitionNode).getValue()
After: exists(DefinitionNode d | d.getNode() = expr | d.getValue())
Before: cn.operands(const.getAFlowNode(), op, x)
After: exists(ControlFlowNode c | c.getNode() = const | cn.operands(c, op, x))
This is semantically a no-op — both forms are duals of the same predicate.
Verified by passing all library tests:
* 64 dataflow tests
* 28 ControlFlow + dataflow-new-ssa tests
* 1 essa SSA-compute test
* 93 tests total in the focused suite
Once committed, files that want to switch from the legacy 'Flow' CFG
to the new 'Cfg' facade only need to change their imports — the
bridge sites are CFG-side and respect whichever ControlFlowNode is in
scope.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
80 lines
2.7 KiB
Plaintext
80 lines
2.7 KiB
Plaintext
/**
|
|
* Provides classes modeling security-relevant aspects of the `Flask-Admin` PyPI package
|
|
* (imported as `flask_admin`).
|
|
*
|
|
* See
|
|
* - https://flask-admin.readthedocs.io/en/latest/
|
|
* - https://pypi.org/project/Flask-Admin/
|
|
*/
|
|
|
|
private import python
|
|
private import semmle.python.dataflow.new.DataFlow
|
|
private import semmle.python.dataflow.new.RemoteFlowSources
|
|
private import semmle.python.dataflow.new.TaintTracking
|
|
private import semmle.python.Concepts
|
|
private import semmle.python.frameworks.Flask
|
|
private import semmle.python.ApiGraphs
|
|
|
|
/**
|
|
* Provides models for the `Flask-Admin` PyPI package (imported as `flask_admin`).
|
|
*
|
|
* See
|
|
* - https://flask-admin.readthedocs.io/en/latest/
|
|
* - https://pypi.org/project/Flask-Admin/
|
|
*/
|
|
private module FlaskAdmin {
|
|
/**
|
|
* A call to `flask_admin.expose`, which is used as a decorator to make the
|
|
* function exposed in the admin interface (and make it a request handler)
|
|
*
|
|
* See https://flask-admin.readthedocs.io/en/latest/api/mod_base/#flask_admin.base.expose
|
|
*/
|
|
private class FlaskAdminExposeCall extends Flask::FlaskRouteSetup, DataFlow::CallCfgNode {
|
|
FlaskAdminExposeCall() {
|
|
this = API::moduleImport("flask_admin").getMember("expose").getACall()
|
|
}
|
|
|
|
override DataFlow::Node getUrlPatternArg() {
|
|
result in [this.getArg(0), this.getArgByName("url")]
|
|
}
|
|
|
|
override Function getARequestHandler() { node.getNode() = result.getADecorator() }
|
|
}
|
|
|
|
/**
|
|
* A call to `flask_admin.expose_plugview`, which is used as a decorator to make the
|
|
* class (which we expect to be a flask View class) exposed in the admin interface.
|
|
*
|
|
* See https://flask-admin.readthedocs.io/en/latest/api/mod_base/#flask_admin.base.expose_plugview
|
|
*/
|
|
private class FlaskAdminExposePlugviewCall extends Flask::FlaskRouteSetup, DataFlow::CallCfgNode {
|
|
FlaskAdminExposePlugviewCall() {
|
|
this = API::moduleImport("flask_admin").getMember("expose_plugview").getACall()
|
|
}
|
|
|
|
override DataFlow::Node getUrlPatternArg() {
|
|
result in [this.getArg(0), this.getArgByName("url")]
|
|
}
|
|
|
|
override Parameter getARoutedParameter() {
|
|
result = super.getARoutedParameter() and
|
|
(
|
|
exists(this.getUrlPattern())
|
|
or
|
|
// the first argument is `self`, and the second argument `cls` will receive the
|
|
// containing flask_admin View class -- this is only relevant if the URL pattern
|
|
// is not known
|
|
not exists(this.getUrlPattern()) and
|
|
not result = this.getARequestHandler().getArg([0, 1])
|
|
)
|
|
}
|
|
|
|
override Function getARequestHandler() {
|
|
exists(Flask::FlaskViewClass cls |
|
|
node.getNode() = cls.getADecorator() and
|
|
result = cls.getARequestHandler()
|
|
)
|
|
}
|
|
}
|
|
}
|