mirror of
https://github.com/github/codeql.git
synced 2026-06-30 09:05:28 +02:00
Flips the Python dataflow trunk from the legacy CFG (semmle/python/Flow.qll) and legacy ESSA SSA (semmle/python/essa/*) to the new shared CFG facade (semmle.python.controlflow.internal.Cfg) and the new SSA adapter (semmle.python.dataflow.new.internal.SsaImpl), both introduced additively in the preceding PRs in this stack. This is the trunk-flip equivalent of the original draft PR #21894 (kept around as documentation), rebased on top of the four preparatory PRs: P1: Remove AstNode.getAFlowNode() and rewrite callers (#21919). P2: Qualify Flow.qll's AST references with Py:: prefix (#21920). P3: Add new shared-CFG-backed control flow graph (#21921). P4: Add new shared-SSA-backed SSA adapter (#21923). The Python dataflow library (semmle/python/dataflow/new/) now imports the new CFG facade and SSA adapter. All CFG-typed predicates (ControlFlowNode, CallNode, BasicBlock, NameNode, AttrNode, ...) are qualified with the Cfg:: prefix; SSA references switch from EssaVariable/EssaDefinition to SsaImpl::Definition/SourceVariable. GuardNode is redesigned to use the new CFG's outcome-node model (isAfterTrue / isAfterFalse) instead of the legacy ConditionBlock + flipped indirection. Only BarrierGuard<...> is preserved as public API. Framework files (Bottle, FastApi, Django, Tornado, Pyramid, Stdlib, ...) are updated to take CFG nodes from the new facade. A handful of dataflow consistency tweaks for the new CFG: - Augmented-assignment targets are treated as both load and store. - 'from X import *' produces uncertain SSA writes for unknown names. - CFG nodes are canonicalised so dataflow does not see equivalent pre/post-order pairs as distinct nodes. Two AST tweaks for the new CFG: - AstNodeImpl: omit PEP 695 type-parameter names from FunctionDefExpr / ClassDefExpr children. - ImportResolution: drop the legacy essa import. Test churn (~175 files): reblessed library- and query-test .expected files reflect slightly different CFG granularity, different toString output, and a handful of true alert deltas in security queries. Verification: all 367 lib + src + consistency-queries compile clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
90 lines
3.1 KiB
Plaintext
90 lines
3.1 KiB
Plaintext
/**
|
|
* Provides modeling of SSL/TLS functionality of the `OpenSSL` module from the `pyOpenSSL` PyPI package.
|
|
* See https://www.pyopenssl.org/en/stable/
|
|
*/
|
|
|
|
private import python
|
|
private import semmle.python.ApiGraphs
|
|
private import semmle.python.controlflow.internal.Cfg as Cfg
|
|
import TlsLibraryModel
|
|
|
|
class PyOpenSslContextCreation extends ContextCreation, DataFlow::CallCfgNode {
|
|
PyOpenSslContextCreation() {
|
|
this = API::moduleImport("OpenSSL").getMember("SSL").getMember("Context").getACall()
|
|
}
|
|
|
|
override ProtocolVersion getProtocol() {
|
|
exists(DataFlow::Node protocolArg, PyOpenSsl pyo |
|
|
protocolArg in [this.getArg(0), this.getArgByName("method")]
|
|
|
|
|
protocolArg = pyo.specific_version(result).getAValueReachableFromSource()
|
|
or
|
|
protocolArg = pyo.unspecific_version().getAValueReachableFromSource() and
|
|
result = any(ProtocolVersion pv)
|
|
)
|
|
}
|
|
}
|
|
|
|
class ConnectionCall extends ConnectionCreation, DataFlow::CallCfgNode {
|
|
ConnectionCall() {
|
|
this = API::moduleImport("OpenSSL").getMember("SSL").getMember("Connection").getACall()
|
|
}
|
|
|
|
override DataFlow::CfgNode getContext() {
|
|
result in [this.getArg(0), this.getArgByName("context")]
|
|
}
|
|
}
|
|
|
|
// This cannot be used to unrestrict,
|
|
// see https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.set_options
|
|
class SetOptionsCall extends ProtocolRestriction, DataFlow::CallCfgNode {
|
|
SetOptionsCall() { node.getFunction().(Cfg::AttrNode).getName() = "set_options" }
|
|
|
|
override DataFlow::CfgNode getContext() {
|
|
result.getNode() = node.getFunction().(Cfg::AttrNode).getObject()
|
|
}
|
|
|
|
override ProtocolVersion getRestriction() {
|
|
API::moduleImport("OpenSSL")
|
|
.getMember("SSL")
|
|
.getMember("OP_NO_" + result)
|
|
.getAValueReachableFromSource() in [this.getArg(0), this.getArgByName("options")]
|
|
}
|
|
}
|
|
|
|
class PyOpenSsl extends TlsLibrary {
|
|
PyOpenSsl() { this = "pyOpenSSL" }
|
|
|
|
override string specific_version_name(ProtocolVersion version) { result = version + "_METHOD" }
|
|
|
|
override string unspecific_version_name() {
|
|
// See
|
|
// - https://www.pyopenssl.org/en/23.0.0/api/ssl.html#module-OpenSSL.SSL
|
|
// - https://www.openssl.org/docs/manmaster/man3/DTLS_server_method.html#NOTES
|
|
//
|
|
// PyOpenSSL also allows DTLS
|
|
// see https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context
|
|
// although they are not mentioned here:
|
|
// https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.TLS_METHOD
|
|
result = ["TLS", "SSLv23"] + "_METHOD"
|
|
or
|
|
result = "TLS_" + ["CLIENT", "SERVER"] + "_METHOD"
|
|
}
|
|
|
|
override API::Node version_constants() { result = API::moduleImport("OpenSSL").getMember("SSL") }
|
|
|
|
override ContextCreation default_context_creation() { none() }
|
|
|
|
override ContextCreation specific_context_creation() {
|
|
result instanceof PyOpenSslContextCreation
|
|
}
|
|
|
|
override DataFlow::Node insecure_connection_creation(ProtocolVersion version) { none() }
|
|
|
|
override ConnectionCreation connection_creation() { result instanceof ConnectionCall }
|
|
|
|
override ProtocolRestriction protocol_restriction() { result instanceof SetOptionsCall }
|
|
|
|
override ProtocolUnrestriction protocol_unrestriction() { none() }
|
|
}
|