mirror of
https://github.com/github/codeql.git
synced 2026-03-30 20:28:15 +02:00
Merge branch 'main' of https://github.com/github/codeql into oscarsj/merge-back-rc-3.21
This commit is contained in:
@@ -177,6 +177,9 @@ module Make<LocationSig Location, InputSig<Location> Input> implements CfgSig<Lo
|
||||
/** Gets the CFG scope of this basic block. */
|
||||
CfgScope getScope() { result = nodeGetCfgScope(this.getFirstNode()) }
|
||||
|
||||
/** Gets the enclosing callable of this basic block. */
|
||||
CfgScope getEnclosingCallable() { result = nodeGetCfgScope(this.getFirstNode()) }
|
||||
|
||||
/** Gets the location of this basic block. */
|
||||
Location getLocation() { result = this.getFirstNode().getLocation() }
|
||||
|
||||
|
||||
1857
shared/controlflow/codeql/controlflow/ControlFlowGraph.qll
Normal file
1857
shared/controlflow/codeql/controlflow/ControlFlowGraph.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -597,6 +597,12 @@ module Make<
|
||||
module Logic<LogicInputSig LogicInput> {
|
||||
private import LogicInput
|
||||
|
||||
bindingset[bb1, bb2]
|
||||
pragma[inline_late]
|
||||
private predicate strictlyDominatesCheck(BasicBlock bb1, BasicBlock bb2) {
|
||||
bb1.strictlyDominates(bb2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` evaluating to `v` directly controls `phi` taking the value
|
||||
* `inp`. This means that `guard` evaluating to `v` must control all the input
|
||||
@@ -614,7 +620,7 @@ module Make<
|
||||
exists(BasicBlock bbPhi |
|
||||
phi.hasInputFromBlock(inp, _) and
|
||||
phi.getBasicBlock() = bbPhi and
|
||||
guard.getBasicBlock().strictlyDominates(bbPhi) and
|
||||
strictlyDominatesCheck(guard.getBasicBlock(), bbPhi) and
|
||||
not guard.directlyValueControls(bbPhi, _) and
|
||||
forex(BasicBlock bbInput | phi.hasInputFromBlock(inp, bbInput) |
|
||||
guard.directlyValueControls(bbInput, v) or
|
||||
@@ -634,7 +640,11 @@ module Make<
|
||||
Guard guard, GuardValue v, SsaPhiDefinition phi, Expr input
|
||||
) {
|
||||
exists(GuardValue dv, SsaExplicitWrite inp |
|
||||
guardControlsPhiBranch(guard, v, phi, inp) and
|
||||
// The `forall` below implies that there's only one `inp` guarded by
|
||||
// `guard == v`, but checking this upfront using `unique` as opposed to
|
||||
// merely stating `guardControlsPhiBranch(guard, v, phi, inp)` improves
|
||||
// performance of the `forall` check.
|
||||
inp = unique(SsaDefinition inp0 | guardControlsPhiBranch(guard, v, phi, inp0)) and
|
||||
inp.getValue() = input and
|
||||
dv = v.getDualValue() and
|
||||
forall(SsaDefinition other | phi.hasInputFromBlock(other, _) and other != inp |
|
||||
@@ -735,7 +745,7 @@ module Make<
|
||||
possibleValue(v, false, e, k) and
|
||||
not possibleValue(v, true, e, k) and
|
||||
// there's only one expression with the value `k`
|
||||
1 = strictcount(Expr e0 | possibleValue(v, _, e0, k)) and
|
||||
e = unique(Expr e0 | possibleValue(v, _, e0, k)) and
|
||||
// and `v` has at least two possible values
|
||||
2 <= strictcount(GuardValue k0 | possibleValue(v, _, _, k0))
|
||||
}
|
||||
|
||||
@@ -28,6 +28,38 @@ module;
|
||||
|
||||
private import codeql.util.Boolean
|
||||
|
||||
private newtype TConditionKind =
|
||||
TBooleanCondition() or
|
||||
TNullnessCondition() or
|
||||
TMatchingCondition() or
|
||||
TEmptinessCondition()
|
||||
|
||||
/** A condition kind. This is used to classify different `ConditionalSuccessor`s. */
|
||||
class ConditionKind extends TConditionKind {
|
||||
/** Gets a textual representation of this condition kind. */
|
||||
string toString() {
|
||||
this instanceof TBooleanCondition and result = "Boolean"
|
||||
or
|
||||
this instanceof TNullnessCondition and result = "Nullness"
|
||||
or
|
||||
this instanceof TMatchingCondition and result = "Matching"
|
||||
or
|
||||
this instanceof TEmptinessCondition and result = "Emptiness"
|
||||
}
|
||||
|
||||
/** Holds if this condition kind identifies `BooleanSuccessor`s. */
|
||||
predicate isBoolean() { this instanceof TBooleanCondition }
|
||||
|
||||
/** Holds if this condition kind identifies `NullnessSuccessor`s. */
|
||||
predicate isNullness() { this instanceof TNullnessCondition }
|
||||
|
||||
/** Holds if this condition kind identifies `MatchingSuccessor`s. */
|
||||
predicate isMatching() { this instanceof TMatchingCondition }
|
||||
|
||||
/** Holds if this condition kind identifies `EmptinessSuccessor`s. */
|
||||
predicate isEmptiness() { this instanceof TEmptinessCondition }
|
||||
}
|
||||
|
||||
private newtype TSuccessorType =
|
||||
TDirectSuccessor() or
|
||||
TBooleanSuccessor(Boolean branch) or
|
||||
@@ -83,6 +115,18 @@ private class TConditionalSuccessor =
|
||||
abstract private class ConditionalSuccessorImpl extends NormalSuccessorImpl, TConditionalSuccessor {
|
||||
/** Gets the Boolean value of this successor. */
|
||||
abstract boolean getValue();
|
||||
|
||||
/** Gets the condition kind of this conditional successor. */
|
||||
abstract ConditionKind getKind();
|
||||
|
||||
/**
|
||||
* Gets the dual of this conditional successor. That is, the conditional
|
||||
* successor of the same kind but with the opposite value.
|
||||
*/
|
||||
ConditionalSuccessor getDual() {
|
||||
this.getValue().booleanNot() = result.getValue() and
|
||||
this.getKind() = result.getKind()
|
||||
}
|
||||
}
|
||||
|
||||
final class ConditionalSuccessor = ConditionalSuccessorImpl;
|
||||
@@ -116,6 +160,8 @@ final class ConditionalSuccessor = ConditionalSuccessorImpl;
|
||||
class BooleanSuccessor extends ConditionalSuccessorImpl, TBooleanSuccessor {
|
||||
override boolean getValue() { this = TBooleanSuccessor(result) }
|
||||
|
||||
override ConditionKind getKind() { result = TBooleanCondition() }
|
||||
|
||||
override string toString() { result = this.getValue().toString() }
|
||||
}
|
||||
|
||||
@@ -151,6 +197,8 @@ class NullnessSuccessor extends ConditionalSuccessorImpl, TNullnessSuccessor {
|
||||
|
||||
override boolean getValue() { this = TNullnessSuccessor(result) }
|
||||
|
||||
override ConditionKind getKind() { result = TNullnessCondition() }
|
||||
|
||||
override string toString() { if this.isNull() then result = "null" else result = "non-null" }
|
||||
}
|
||||
|
||||
@@ -192,6 +240,8 @@ class MatchingSuccessor extends ConditionalSuccessorImpl, TMatchingSuccessor {
|
||||
|
||||
override boolean getValue() { this = TMatchingSuccessor(result) }
|
||||
|
||||
override ConditionKind getKind() { result = TMatchingCondition() }
|
||||
|
||||
override string toString() { if this.isMatch() then result = "match" else result = "no-match" }
|
||||
}
|
||||
|
||||
@@ -233,6 +283,8 @@ class EmptinessSuccessor extends ConditionalSuccessorImpl, TEmptinessSuccessor {
|
||||
|
||||
override boolean getValue() { this = TEmptinessSuccessor(result) }
|
||||
|
||||
override ConditionKind getKind() { result = TEmptinessCondition() }
|
||||
|
||||
override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" }
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Two new flow features `FeatureEscapesSourceCallContext` and `FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext` have been added. The former implies that the sink must be reached from the source by escaping the source call context, that is, flow must either return from the callable containing the source or use a jump-step before reaching the sink. The latter is the disjunction of the former and the existing `FeatureEqualSourceSinkCallContext` flow feature.
|
||||
@@ -567,7 +567,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
) {
|
||||
sourceNode(node) and
|
||||
(if hasSourceCallCtx() then cc = ccSomeCall() else cc = ccNone()) and
|
||||
summaryCtx = TSummaryCtxNone() and
|
||||
summaryCtx.isSourceCtx() and
|
||||
t = getNodeTyp(node) and
|
||||
ap instanceof ApNil and
|
||||
apa = getApprox(ap) and
|
||||
@@ -602,18 +602,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
apa = getApprox(ap)
|
||||
or
|
||||
// flow into a callable without summary context
|
||||
fwdFlowInNoFlowThrough(node, cc, t, ap, stored) and
|
||||
fwdFlowInNoFlowThrough(node, cc, summaryCtx, t, ap, stored) and
|
||||
apa = getApprox(ap) and
|
||||
summaryCtx = TSummaryCtxNone() and
|
||||
// When the call contexts of source and sink needs to match then there's
|
||||
// never any reason to enter a callable except to find a summary. See also
|
||||
// the comment in `PathNodeMid::isAtSink`.
|
||||
not Config::getAFeature() instanceof FeatureEqualSourceSinkCallContext
|
||||
or
|
||||
// flow into a callable with summary context (non-linear recursion)
|
||||
fwdFlowInFlowThrough(node, cc, t, ap, stored) and
|
||||
apa = getApprox(ap) and
|
||||
summaryCtx = TSummaryCtxSome(node, t, ap, stored)
|
||||
exists(boolean mustReturn |
|
||||
fwdFlowInFlowThrough(node, cc, t, ap, stored, mustReturn) and
|
||||
apa = getApprox(ap) and
|
||||
summaryCtx = TSummaryCtxSome(node, t, ap, stored, mustReturn)
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
fwdFlowOut(_, _, node, cc, summaryCtx, t, ap, stored) and
|
||||
@@ -630,9 +631,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParamNd p, Typ t, Ap ap, TypOption stored) {
|
||||
fwdFlowInFlowThrough(p, _, t, ap, stored)
|
||||
}
|
||||
TSummaryCtxSome(ParamNd p, Typ t, Ap ap, TypOption stored, boolean mustReturn) {
|
||||
fwdFlowInFlowThrough(p, _, t, ap, stored, mustReturn)
|
||||
} or
|
||||
TSummaryCtxSource(Boolean mustEscape)
|
||||
|
||||
/**
|
||||
* A context for generating flow summaries. This represents flow entry through
|
||||
@@ -644,6 +646,69 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
abstract string toString();
|
||||
|
||||
abstract Location getLocation();
|
||||
|
||||
/**
|
||||
* Holds if this context is the unique context used at flow sources.
|
||||
*/
|
||||
predicate isSourceCtx() {
|
||||
exists(boolean strict |
|
||||
Stage1::hasFeatureEscapesSourceCallContext(strict) and
|
||||
this = TSummaryCtxSource(strict)
|
||||
)
|
||||
or
|
||||
not Stage1::hasFeatureEscapesSourceCallContext(_) and
|
||||
this = TSummaryCtxNone()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isSome(boolean mustReturn) {
|
||||
this = TSummaryCtxSome(_, _, _, _, mustReturn)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this context is valid as a flow-in context when no flow-through is possible,
|
||||
* in which case `innerSummaryCtx` is the summary context to be used when entering the
|
||||
* callable.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate isValidForFlowInNoThrough(SummaryCtx innerSummaryCtx) {
|
||||
this = TSummaryCtxNone() and
|
||||
innerSummaryCtx = TSummaryCtxNone()
|
||||
or
|
||||
this.isSome(false) and
|
||||
innerSummaryCtx = TSummaryCtxNone()
|
||||
or
|
||||
// Even if we must escape the source call context, we can still allow for flow-in
|
||||
// without flow-through, as long as the inner context is escaped (which must then
|
||||
// necessarily be via a jump-step -- possibly after even more flow-in
|
||||
// without-flow-through steps).
|
||||
this = TSummaryCtxSource(_) and
|
||||
innerSummaryCtx = TSummaryCtxSource(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this context is valid as a flow-in context when flow-through is possible.
|
||||
*
|
||||
* The boolean `mustReturn` indicates whether flow must return.
|
||||
*/
|
||||
predicate isValidForFlowThrough(boolean mustReturn) {
|
||||
this = TSummaryCtxSource(_) and
|
||||
mustReturn = true
|
||||
or
|
||||
this = TSummaryCtxNone() and
|
||||
mustReturn = false
|
||||
or
|
||||
this.isSome(mustReturn)
|
||||
}
|
||||
|
||||
/** Holds if this context is valid as a sink context. */
|
||||
predicate isASinkCtx() {
|
||||
this = TSummaryCtxNone()
|
||||
or
|
||||
this.isSome(false)
|
||||
or
|
||||
this = TSummaryCtxSource(false)
|
||||
}
|
||||
}
|
||||
|
||||
/** A summary context from which no flow summary can be generated. */
|
||||
@@ -659,20 +724,43 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private Typ t;
|
||||
private Ap ap;
|
||||
private TypOption stored;
|
||||
private boolean mustReturn;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, t, ap, stored) }
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, t, ap, stored, mustReturn) }
|
||||
|
||||
ParamNd getParamNode() { result = p }
|
||||
|
||||
private string ppTyp() { result = t.toString() and result != "" }
|
||||
|
||||
private string ppMustReturn() {
|
||||
if mustReturn = true then result = " <mustReturn>" else result = ""
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = p + concat(" : " + this.ppTyp()) + " " + ap + ppStored(stored)
|
||||
result =
|
||||
p + concat(" : " + this.ppTyp()) + " " + ap + ppStored(stored) + this.ppMustReturn()
|
||||
}
|
||||
|
||||
override Location getLocation() { result = p.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A special summary context that is used when the flow feature
|
||||
* `FeatureEscapesSourceCallContext(OrEqualSourceSinkCallContext)`
|
||||
* is enabled.
|
||||
*/
|
||||
private class SummaryCtxSource extends SummaryCtx, TSummaryCtxSource {
|
||||
private boolean mustEscape;
|
||||
|
||||
SummaryCtxSource() { this = TSummaryCtxSource(mustEscape) }
|
||||
|
||||
override string toString() {
|
||||
if mustEscape = true then result = "<source-must-escape>" else result = "<source>"
|
||||
}
|
||||
|
||||
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
|
||||
}
|
||||
|
||||
private predicate fwdFlowJump(Nd node, Typ t, Ap ap, TypOption stored) {
|
||||
exists(Nd mid |
|
||||
fwdFlow(mid, _, _, t, ap, stored) and
|
||||
@@ -915,9 +1003,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInNoFlowThrough(
|
||||
ParamNd p, CcCall innercc, Typ t, Ap ap, TypOption stored
|
||||
ParamNd p, CcCall innercc, SummaryCtx innerSummaryCtx, Typ t, Ap ap, TypOption stored
|
||||
) {
|
||||
FwdFlowInNoThrough::fwdFlowIn(_, _, _, p, _, innercc, _, t, ap, stored, _)
|
||||
exists(SummaryCtx summaryCtx |
|
||||
FwdFlowInNoThrough::fwdFlowIn(_, _, _, p, _, innercc, summaryCtx, t, ap, stored, _) and
|
||||
summaryCtx.isValidForFlowInNoThrough(innerSummaryCtx)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate top() { any() }
|
||||
@@ -926,9 +1017,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowInFlowThrough(
|
||||
ParamNd p, CcCall innercc, Typ t, Ap ap, TypOption stored
|
||||
ParamNd p, CcCall innercc, Typ t, Ap ap, TypOption stored, boolean mustReturn
|
||||
) {
|
||||
FwdFlowInThrough::fwdFlowIn(_, _, _, p, _, innercc, _, t, ap, stored, _)
|
||||
exists(SummaryCtx summaryCtx |
|
||||
FwdFlowInThrough::fwdFlowIn(_, _, _, p, _, innercc, summaryCtx, t, ap, stored, _) and
|
||||
summaryCtx.isValidForFlowThrough(mustReturn)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -999,7 +1093,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
TypOption stored
|
||||
) {
|
||||
exists(RetNd ret, CcNoCall innercc, boolean allowsFieldFlow |
|
||||
fwdFlowIntoRet(ret, innercc, summaryCtx, t, ap, stored) and
|
||||
fwdFlowIntoRet(ret, innercc, _, t, ap, stored) and
|
||||
summaryCtx = TSummaryCtxNone() and
|
||||
fwdFlowOutValidEdge(call, ret, innercc, inner, out, outercc, allowsFieldFlow) and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
@@ -1090,7 +1185,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
instanceofCcCall(ccc) and
|
||||
fwdFlow(pragma[only_bind_into](ret), ccc, summaryCtx, t, ap, stored) and
|
||||
summaryCtx =
|
||||
TSummaryCtxSome(pragma[only_bind_into](p), _, pragma[only_bind_into](argAp), _) and
|
||||
TSummaryCtxSome(pragma[only_bind_into](p), _, pragma[only_bind_into](argAp), _, _) and
|
||||
kind = ret.getKind() and
|
||||
Stage1::parameterFlowThroughAllowed(p, kind) and
|
||||
PrevStage::returnMayFlowThrough(ret, kind)
|
||||
@@ -1116,9 +1211,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered0(
|
||||
Call call, ArgNd arg, Cc cc, CcCall innerCc, SummaryCtx summaryCtx, ParamNd p, Typ t,
|
||||
Ap ap, TypOption stored
|
||||
Ap ap, TypOption stored, boolean mustReturn
|
||||
) {
|
||||
FwdFlowInThrough::fwdFlowIn(call, arg, _, p, cc, innerCc, summaryCtx, t, ap, stored, _)
|
||||
FwdFlowInThrough::fwdFlowIn(call, arg, _, p, cc, innerCc, summaryCtx, t, ap, stored, _) and
|
||||
summaryCtx.isValidForFlowThrough(mustReturn)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1130,9 +1226,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
Call call, ArgNd arg, Cc cc, CcCall innerCc, SummaryCtx summaryCtx,
|
||||
SummaryCtxSome innerSummaryCtx
|
||||
) {
|
||||
exists(ParamNd p, Typ t, Ap ap, TypOption stored |
|
||||
fwdFlowIsEntered0(call, arg, cc, innerCc, summaryCtx, p, t, ap, stored) and
|
||||
innerSummaryCtx = TSummaryCtxSome(p, t, ap, stored)
|
||||
exists(ParamNd p, Typ t, Ap ap, TypOption stored, boolean mustReturn |
|
||||
fwdFlowIsEntered0(call, arg, cc, innerCc, summaryCtx, p, t, ap, stored, mustReturn) and
|
||||
innerSummaryCtx = TSummaryCtxSome(p, t, ap, stored, mustReturn)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1160,7 +1256,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
TypOption argStored, Ap ap
|
||||
) {
|
||||
exists(Call call, boolean allowsFieldFlow |
|
||||
returnFlowsThrough0(call, ccc, ap, ret, TSummaryCtxSome(p, argT, argAp, argStored)) and
|
||||
returnFlowsThrough0(call, ccc, ap, ret, TSummaryCtxSome(p, argT, argAp, argStored, _)) and
|
||||
flowThroughOutOfCall(call, ret, _, allowsFieldFlow) and
|
||||
pos = ret.getReturnPosition() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
@@ -1216,7 +1312,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlow0(Nd node, ReturnCtx returnCtx, ApOption returnAp, Ap ap) {
|
||||
fwdFlow(node, _, _, _, ap, _) and
|
||||
fwdFlow(node, _, any(SummaryCtx sinkCtx | sinkCtx.isASinkCtx()), _, ap, _) and
|
||||
sinkNode(node) and
|
||||
(
|
||||
if hasSinkCallCtx()
|
||||
@@ -1490,7 +1586,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
exists(Ap ap0 |
|
||||
parameterMayFlowThrough(p, _) and
|
||||
revFlow(n, TReturnCtxMaybeFlowThrough(_), _, ap0) and
|
||||
fwdFlow(n, any(CcCall ccc), TSummaryCtxSome(p, _, ap, _), _, ap0, _)
|
||||
fwdFlow(n, any(CcCall ccc), TSummaryCtxSome(p, _, ap, _, _), _, ap0, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1962,6 +2058,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private string ppSummaryCtx() {
|
||||
summaryCtx instanceof SummaryCtxNone and result = ""
|
||||
or
|
||||
result = " " + summaryCtx.(SummaryCtxSource)
|
||||
or
|
||||
summaryCtx instanceof SummaryCtxSome and
|
||||
result = " <" + summaryCtx + ">"
|
||||
}
|
||||
@@ -1983,7 +2081,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
override predicate isSource() {
|
||||
sourceNode(node) and
|
||||
(if hasSourceCallCtx() then cc = ccSomeCall() else cc = ccNone()) and
|
||||
summaryCtx = TSummaryCtxNone() and
|
||||
summaryCtx.isSourceCtx() and
|
||||
t = getNodeTyp(node) and
|
||||
ap instanceof ApNil
|
||||
}
|
||||
@@ -1991,6 +2089,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
predicate isAtSink() {
|
||||
sinkNode(node) and
|
||||
ap instanceof ApNil and
|
||||
summaryCtx.isASinkCtx() and
|
||||
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
|
||||
// is exactly what we need to check.
|
||||
// For `FeatureEqualSourceSinkCallContext` the initial call
|
||||
@@ -2042,10 +2141,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
override predicate isSource() { sourceNode(node) }
|
||||
}
|
||||
|
||||
bindingset[p, t, ap, stored]
|
||||
bindingset[p, t, ap, stored, mustReturn]
|
||||
pragma[inline_late]
|
||||
private SummaryCtxSome mkSummaryCtxSome(ParamNd p, Typ t, Ap ap, TypOption stored) {
|
||||
result = TSummaryCtxSome(p, t, ap, stored)
|
||||
private SummaryCtxSome mkSummaryCtxSome(
|
||||
ParamNd p, Typ t, Ap ap, TypOption stored, boolean mustReturn
|
||||
) {
|
||||
result = TSummaryCtxSome(p, t, ap, stored, mustReturn)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2055,11 +2156,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
) {
|
||||
FwdFlowInNoThrough::fwdFlowIn(_, arg, _, p, outercc, innercc, outerSummaryCtx, t, ap,
|
||||
stored, _) and
|
||||
innerSummaryCtx = TSummaryCtxNone()
|
||||
outerSummaryCtx.isValidForFlowInNoThrough(innerSummaryCtx)
|
||||
or
|
||||
FwdFlowInThrough::fwdFlowIn(_, arg, _, p, outercc, innercc, outerSummaryCtx, t, ap,
|
||||
stored, _) and
|
||||
innerSummaryCtx = mkSummaryCtxSome(p, t, ap, stored)
|
||||
exists(boolean mustReturn |
|
||||
FwdFlowInThrough::fwdFlowIn(_, arg, _, p, outercc, innercc, outerSummaryCtx, t, ap,
|
||||
stored, _) and
|
||||
outerSummaryCtx.isValidForFlowThrough(mustReturn) and
|
||||
innerSummaryCtx = mkSummaryCtxSome(p, t, ap, stored, mustReturn)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2098,7 +2202,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
|
||||
fwdFlowThroughStep0(call, arg, cc, ccc, summaryCtx, t, ap, stored, ret,
|
||||
innerSummaryCtx) and
|
||||
innerSummaryCtx = TSummaryCtxSome(p, innerArgT, innerArgAp, innerArgStored) and
|
||||
innerSummaryCtx = TSummaryCtxSome(p, innerArgT, innerArgAp, innerArgStored, _) and
|
||||
pn1 = mkPathNode(arg, cc, summaryCtx, innerArgT, innerArgAp, innerArgStored) and
|
||||
pn2 =
|
||||
typeStrengthenToPathNode(p, ccc, innerSummaryCtx, innerArgT, innerArgAp,
|
||||
@@ -2212,11 +2316,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(RetNd ret, CcNoCall innercc, boolean allowsFieldFlow |
|
||||
pn1 = TPathNodeMid(ret, innercc, summaryCtx, t, ap, stored) and
|
||||
fwdFlowIntoRet(ret, innercc, summaryCtx, t, ap, stored) and
|
||||
exists(
|
||||
RetNd ret, CcNoCall innercc, SummaryCtx innerSummaryCtx, boolean allowsFieldFlow
|
||||
|
|
||||
pn1 = TPathNodeMid(ret, innercc, innerSummaryCtx, t, ap, stored) and
|
||||
fwdFlowIntoRet(ret, innercc, innerSummaryCtx, t, ap, stored) and
|
||||
fwdFlowOutValidEdge(_, ret, innercc, _, node, cc, allowsFieldFlow) and
|
||||
label = "" and
|
||||
summaryCtx = TSummaryCtxNone() and
|
||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ module;
|
||||
|
||||
private import codeql.dataflow.DataFlow
|
||||
private import codeql.typetracking.TypeTracking as Tt
|
||||
private import codeql.util.Boolean
|
||||
private import codeql.util.Location
|
||||
private import codeql.util.Option
|
||||
private import codeql.util.Unit
|
||||
@@ -49,7 +50,9 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
private newtype TFlowFeature =
|
||||
TFeatureHasSourceCallContext() or
|
||||
TFeatureHasSinkCallContext() or
|
||||
TFeatureEqualSourceSinkCallContext()
|
||||
TFeatureEqualSourceSinkCallContext() or
|
||||
TFeatureEscapesSourceCallContext() or
|
||||
TFeatureEscapesSourceCallContextOrEqualSourceSinkCallContext()
|
||||
|
||||
/** A flow configuration feature for use in `Configuration::getAFeature()`. */
|
||||
class FlowFeature extends TFlowFeature {
|
||||
@@ -80,6 +83,28 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
override string toString() { result = "FeatureEqualSourceSinkCallContext" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow configuration feature that implies that the sink must be reached from
|
||||
* the source by escaping the source call context, that is, flow must either
|
||||
* return from the callable containing the source or use a jump-step before reaching
|
||||
* the sink.
|
||||
*/
|
||||
class FeatureEscapesSourceCallContext extends FlowFeature, TFeatureEscapesSourceCallContext {
|
||||
override string toString() { result = "FeatureEscapesSourceCallContext" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow configuration feature that is the disjunction of `FeatureEscapesSourceCallContext`
|
||||
* and `FeatureEqualSourceSinkCallContext`.
|
||||
*/
|
||||
class FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext extends FlowFeature,
|
||||
TFeatureEscapesSourceCallContextOrEqualSourceSinkCallContext
|
||||
{
|
||||
override string toString() {
|
||||
result = "FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
|
||||
@@ -64,6 +64,8 @@ module MakeImplStage1<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
predicate hasSourceCallCtx();
|
||||
|
||||
predicate hasFeatureEscapesSourceCallContext(boolean strict);
|
||||
|
||||
predicate hasSinkCallCtx();
|
||||
|
||||
predicate jumpStepEx(Nd node1, Nd node2);
|
||||
@@ -1016,6 +1018,13 @@ module MakeImplStage1<LocationSig Location, InputSig<Location> Lang> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasFeatureEscapesSourceCallContext(boolean strict) {
|
||||
Config::getAFeature() instanceof FeatureEscapesSourceCallContext and strict = true
|
||||
or
|
||||
Config::getAFeature() instanceof FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext and
|
||||
strict = false
|
||||
}
|
||||
|
||||
predicate hasSinkCallCtx() {
|
||||
exists(FlowFeature feature | feature = Config::getAFeature() |
|
||||
feature instanceof FeatureHasSinkCallContext or
|
||||
|
||||
@@ -521,7 +521,7 @@ module Make<InlineExpectationsTestSig Impl> {
|
||||
* is treated as part of the expected results, except that the comment may contain a `//` sequence
|
||||
* to treat the remainder of the line as a regular (non-interpreted) comment.
|
||||
*/
|
||||
private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)(?://.*)?" }
|
||||
private string expectationCommentPattern() { result = "\\s*\\$ ((?:[^/]|/[^/])*)(?://.*)?" }
|
||||
|
||||
/**
|
||||
* The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first
|
||||
|
||||
Reference in New Issue
Block a user