mirror of
https://github.com/github/codeql.git
synced 2026-03-05 07:06:47 +01:00
Merge branch 'main' into jcogs33/shared-sink-kind-validation
This commit is contained in:
@@ -1809,9 +1809,6 @@ class LValue extends VarAccess {
|
||||
* are source expressions of the assignment.
|
||||
*/
|
||||
Expr getRhs() { exists(Assignment e | e.getDest() = this and e.getSource() = result) }
|
||||
|
||||
/** DEPRECATED: Alias for getRhs */
|
||||
deprecated Expr getRHS() { result = this.getRhs() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -987,6 +987,17 @@ private string getAPublicObjectMethodSignature() {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate interfaceInheritsOverridingNonAbstractMethod(Interface interface, Method m) {
|
||||
interface.inherits(m) and
|
||||
not m.isAbstract() and
|
||||
m.overrides(_)
|
||||
}
|
||||
|
||||
bindingset[m]
|
||||
pragma[inline_late]
|
||||
private Method getAnOverridden(Method m) { m.overrides(result) }
|
||||
|
||||
private Method getAnAbstractMethod(Interface interface) {
|
||||
interface.inherits(result) and
|
||||
result.isAbstract() and
|
||||
@@ -995,9 +1006,8 @@ private Method getAnAbstractMethod(Interface interface) {
|
||||
// Make sure that there is no other non-abstract method
|
||||
// (e.g. `default`) which overrides the abstract one
|
||||
not exists(Method m |
|
||||
interface.inherits(m) and
|
||||
not m.isAbstract() and
|
||||
m.overrides(result)
|
||||
interfaceInheritsOverridingNonAbstractMethod(interface, m) and
|
||||
result = getAnOverridden(m)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,15 +6,6 @@
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `conditionCheckMethodArgument` instead.
|
||||
* Holds if `m` is a non-overridable method that checks that its first argument
|
||||
* is equal to `checkTrue` and throws otherwise.
|
||||
*/
|
||||
deprecated predicate conditionCheckMethod(Method m, boolean checkTrue) {
|
||||
conditionCheckMethodArgument(m, 0, checkTrue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `m` is a non-overridable method that checks that its zero-indexed `argument`
|
||||
* is equal to `checkTrue` and throws otherwise.
|
||||
|
||||
@@ -36,6 +36,13 @@ abstract class RemoteFlowSource extends DataFlow::Node {
|
||||
abstract string getSourceType();
|
||||
}
|
||||
|
||||
/**
|
||||
* A module for importing frameworks that define flow sources.
|
||||
*/
|
||||
private module FlowSources {
|
||||
private import semmle.code.java.frameworks.hudson.Hudson
|
||||
}
|
||||
|
||||
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
||||
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
|
||||
|
||||
|
||||
@@ -149,8 +149,9 @@ class SummarizedCallableBase extends TSummarizedCallableBase {
|
||||
or
|
||||
result = this.asSyntheticCallable().getParameterType(pos)
|
||||
or
|
||||
exists(SyntheticCallable sc | sc = this.asSyntheticCallable() |
|
||||
Impl::Private::summaryParameterNodeRange(this, pos) and
|
||||
exists(SyntheticCallable sc, Impl::Private::SummaryNode p | sc = this.asSyntheticCallable() |
|
||||
Impl::Private::summaryParameterNode(p, pos) and
|
||||
this = p.getSummarizedCallable() and
|
||||
not exists(sc.getParameterType(pos)) and
|
||||
result instanceof TypeObject
|
||||
)
|
||||
|
||||
@@ -931,9 +931,6 @@ class SsaVariable extends TSsaVariable {
|
||||
this = TSsaUntracked(_, result)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getCfgNode */
|
||||
deprecated ControlFlowNode getCFGNode() { result = this.getCfgNode() }
|
||||
|
||||
/** Gets a textual representation of this SSA variable. */
|
||||
string toString() { none() }
|
||||
|
||||
|
||||
@@ -483,9 +483,6 @@ class BaseSsaVariable extends TBaseSsaVariable {
|
||||
this = TSsaEntryDef(_, result)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getCfgNode */
|
||||
deprecated ControlFlowNode getCFGNode() { result = this.getCfgNode() }
|
||||
|
||||
string toString() { none() }
|
||||
|
||||
Location getLocation() { result = this.getCfgNode().getLocation() }
|
||||
|
||||
@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
|
||||
);
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
|
||||
|
||||
bindingset[typ, contentType]
|
||||
predicate typecheckStore(Typ typ, DataFlowType contentType);
|
||||
@@ -1199,17 +1199,21 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t, ap)
|
||||
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
private predicate fwdFlow1(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap
|
||||
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t0, ap, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
|
||||
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
@@ -1339,6 +1343,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
|
||||
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
|
||||
cons = apCons(c, t1, tail)
|
||||
or
|
||||
exists(Typ t0 |
|
||||
typeStrengthen(t0, cons, t2) and
|
||||
fwdFlowConsCand(t0, cons, c, t1, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1359,7 +1368,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
|
||||
) {
|
||||
exists(ApHeadContent apc |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
|
||||
apc = getHeadContent(ap) and
|
||||
readStepCand0(node1, apc, c, node2)
|
||||
)
|
||||
@@ -1520,14 +1529,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
revFlow0(node, state, returnCtx, returnAp, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap)
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlow0(
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
fwdFlow(node, state, _, _, _, _, _, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _) and
|
||||
sinkNode(node, state) and
|
||||
(
|
||||
if hasSinkCallCtx()
|
||||
@@ -1780,13 +1789,13 @@ module Impl<FullStateConfigSig Config> {
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
|
||||
) {
|
||||
fwd = true and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
|
||||
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
|
||||
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
|
||||
@@ -1963,10 +1972,10 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
PrevStage::revFlowState(state) and
|
||||
exists(t) and
|
||||
t0 = t and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state) and
|
||||
(
|
||||
@@ -2197,8 +2206,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import BooleanCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
exists(lcc)
|
||||
@@ -2218,10 +2227,16 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
exists(state) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
// We can get away with not using type strengthening here, since we aren't
|
||||
// going to use the tracked types in the construction of Stage 4 access
|
||||
// paths. For Stage 4 and onwards, the tracked types must be consistent as
|
||||
// the cons candidates including types are used to construct subsequent
|
||||
// access path approximations.
|
||||
t0 = t and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2241,6 +2256,16 @@ module Impl<FullStateConfigSig Config> {
|
||||
import MkStage<Stage2>::Stage<Stage3Param>
|
||||
}
|
||||
|
||||
bindingset[node, t0]
|
||||
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
|
||||
if castingNodeEx(node)
|
||||
then
|
||||
exists(DataFlowType nt | nt = node.getDataFlowType() |
|
||||
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
|
||||
)
|
||||
else t = t0
|
||||
}
|
||||
|
||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
private module PrevStage = Stage3;
|
||||
|
||||
@@ -2274,8 +2299,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2333,11 +2358,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
exists(state) and
|
||||
not clear(node, ap) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
strengthenType(node, t0, t) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2365,7 +2390,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
exists(AccessPathFront apf |
|
||||
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
|
||||
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
|
||||
apf)
|
||||
apf, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2579,8 +2604,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import LocalCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2609,9 +2634,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
strengthenType(node, t0, t) and
|
||||
exists(state) and
|
||||
exists(ap)
|
||||
}
|
||||
@@ -2632,7 +2657,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
Stage5::parameterMayFlowThrough(p, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
|
||||
TAccessPathApproxSome(apa), _, apa0)
|
||||
TAccessPathApproxSome(apa), _, apa0, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2649,7 +2674,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
|
||||
exists(AccessPathApprox apa | ap.getApprox() = apa |
|
||||
Stage5::parameterMayFlowThrough(p, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
|
||||
Stage5::revFlow(p, state, _)
|
||||
)
|
||||
}
|
||||
@@ -2820,9 +2845,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TAccessPathNil()
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
pathStep(_, node, state, cc, sc, t, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
|
||||
pathStep(_, node, state, cc, sc, t, ap)
|
||||
} or
|
||||
TPathNodeSink(NodeEx node, FlowState state) {
|
||||
exists(PathNodeMid sink |
|
||||
@@ -3340,13 +3363,24 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = mid.getAp()
|
||||
}
|
||||
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
exists(DataFlowType t0 |
|
||||
pathStep0(mid, node, state, cc, sc, t0, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
strengthenType(node, t0, t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
private predicate pathStep0(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
@@ -3964,7 +3998,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TPartialNil() and
|
||||
exists(explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
distSrc(node.getEnclosingCallable()) <= explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
@@ -3990,11 +4024,20 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathNodeMk0(
|
||||
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep1(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
|
||||
PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
|
||||
not fullBarrier(node) and
|
||||
not stateBarrier(node, state) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
@@ -4002,9 +4045,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), t)
|
||||
else any()
|
||||
strengthenType(node, t0, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathTypeStrengthen(
|
||||
DataFlowType t0, PartialAccessPath ap, DataFlowType t
|
||||
) {
|
||||
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4183,7 +4231,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate partialPathStep(
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep0(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
@@ -4309,6 +4358,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
|
||||
) {
|
||||
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
|
||||
or
|
||||
exists(DataFlowType t0 |
|
||||
partialPathTypeStrengthen(t0, ap2, t2) and
|
||||
apConsFwd(t1, ap1, c, t0, ap2)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -54,12 +54,7 @@ private module Cached {
|
||||
fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa)
|
||||
)
|
||||
} or
|
||||
TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
FlowSummaryImpl::Private::summaryNodeRange(c, state)
|
||||
} or
|
||||
TSummaryParameterNode(SummarizedCallable c, int pos) {
|
||||
FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos)
|
||||
} or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
||||
TFieldValueNode(Field f)
|
||||
|
||||
cached
|
||||
@@ -132,8 +127,6 @@ module Public {
|
||||
or
|
||||
result = this.(ImplicitPostUpdateNode).getPreUpdateNode().getType()
|
||||
or
|
||||
result = this.(SummaryParameterNode).getTypeImpl()
|
||||
or
|
||||
result = this.(FieldValueNode).getField().getType()
|
||||
}
|
||||
|
||||
@@ -378,8 +371,7 @@ module Private {
|
||||
result.asCallable() = n.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or
|
||||
result.asCallable() = n.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or
|
||||
result = nodeGetEnclosingCallable(n.(ImplicitPostUpdateNode).getPreUpdateNode()) or
|
||||
n = TSummaryInternalNode(result.asSummarizedCallable(), _) or
|
||||
n = TSummaryParameterNode(result.asSummarizedCallable(), _) or
|
||||
result.asSummarizedCallable() = n.(FlowSummaryNode).getSummarizedCallable() or
|
||||
result.asFieldScope() = n.(FieldValueNode).getField()
|
||||
}
|
||||
|
||||
@@ -407,7 +399,7 @@ module Private {
|
||||
or
|
||||
this = getInstanceArgument(_)
|
||||
or
|
||||
this.(SummaryNode).isArgumentOf(_, _)
|
||||
this.(FlowSummaryNode).isArgumentOf(_, _)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,7 +416,7 @@ module Private {
|
||||
or
|
||||
pos = -1 and this = getInstanceArgument(call.asCall())
|
||||
or
|
||||
this.(SummaryNode).isArgumentOf(call, pos)
|
||||
this.(FlowSummaryNode).isArgumentOf(call, pos)
|
||||
}
|
||||
|
||||
/** Gets the call in which this node is an argument. */
|
||||
@@ -435,7 +427,7 @@ module Private {
|
||||
class ReturnNode extends Node {
|
||||
ReturnNode() {
|
||||
exists(ReturnStmt ret | this.asExpr() = ret.getResult()) or
|
||||
this.(SummaryNode).isReturn()
|
||||
this.(FlowSummaryNode).isReturn()
|
||||
}
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
@@ -447,61 +439,57 @@ module Private {
|
||||
OutNode() {
|
||||
this.asExpr() instanceof MethodAccess
|
||||
or
|
||||
this.(SummaryNode).isOut(_)
|
||||
this.(FlowSummaryNode).isOut(_)
|
||||
}
|
||||
|
||||
/** Gets the underlying call. */
|
||||
DataFlowCall getCall() {
|
||||
result.asCall() = this.asExpr()
|
||||
or
|
||||
this.(SummaryNode).isOut(result)
|
||||
this.(FlowSummaryNode).isOut(result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node used to model flow summaries.
|
||||
*/
|
||||
class SummaryNode extends Node, TSummaryInternalNode {
|
||||
private SummarizedCallable c;
|
||||
private FlowSummaryImpl::Private::SummaryNodeState state;
|
||||
class FlowSummaryNode extends Node, TFlowSummaryNode {
|
||||
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
|
||||
|
||||
SummaryNode() { this = TSummaryInternalNode(c, state) }
|
||||
SummarizedCallable getSummarizedCallable() {
|
||||
result = this.getSummaryNode().getSummarizedCallable()
|
||||
}
|
||||
|
||||
override Location getLocation() { result = c.getLocation() }
|
||||
override Location getLocation() { result = this.getSummarizedCallable().getLocation() }
|
||||
|
||||
override string toString() { result = "[summary] " + state + " in " + c }
|
||||
override string toString() { result = this.getSummaryNode().toString() }
|
||||
|
||||
/** Holds if this summary node is the `i`th argument of `call`. */
|
||||
predicate isArgumentOf(DataFlowCall call, int i) {
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call, this, i)
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call, this.getSummaryNode(), i)
|
||||
}
|
||||
|
||||
/** Holds if this summary node is a return node. */
|
||||
predicate isReturn() { FlowSummaryImpl::Private::summaryReturnNode(this, _) }
|
||||
predicate isReturn() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), _) }
|
||||
|
||||
/** Holds if this summary node is an out node for `call`. */
|
||||
predicate isOut(DataFlowCall call) { FlowSummaryImpl::Private::summaryOutNode(call, this, _) }
|
||||
predicate isOut(DataFlowCall call) {
|
||||
FlowSummaryImpl::Private::summaryOutNode(call, this.getSummaryNode(), _)
|
||||
}
|
||||
}
|
||||
|
||||
SummaryNode getSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
result = TSummaryInternalNode(c, state)
|
||||
}
|
||||
|
||||
class SummaryParameterNode extends ParameterNode, TSummaryParameterNode {
|
||||
private SummarizedCallable sc;
|
||||
private int pos_;
|
||||
|
||||
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos_) }
|
||||
|
||||
override Location getLocation() { result = sc.getLocation() }
|
||||
|
||||
override string toString() { result = "[summary param] " + pos_ + " in " + sc }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int pos) {
|
||||
c.asSummarizedCallable() = sc and pos = pos_
|
||||
class SummaryParameterNode extends ParameterNode, FlowSummaryNode {
|
||||
SummaryParameterNode() {
|
||||
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
|
||||
}
|
||||
|
||||
Type getTypeImpl() { result = sc.getParameterType(pos_) }
|
||||
private int getPosition() {
|
||||
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
|
||||
}
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int pos) {
|
||||
c.asSummarizedCallable() = this.getSummarizedCallable() and pos = this.getPosition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,10 +511,12 @@ private class MallocNode extends Node, TMallocNode {
|
||||
ClassInstanceExpr getClassInstanceExpr() { result = cie }
|
||||
}
|
||||
|
||||
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
|
||||
private Node pre;
|
||||
private class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode {
|
||||
private FlowSummaryNode pre;
|
||||
|
||||
SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) }
|
||||
SummaryPostUpdateNode() {
|
||||
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), pre.getSummaryNode())
|
||||
}
|
||||
|
||||
override Node getPreUpdateNode() { result = pre }
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ predicate jumpStep(Node node1, Node node2) {
|
||||
any(AdditionalValueStep a).step(node1, node2) and
|
||||
node1.getEnclosingCallable() != node2.getEnclosingCallable()
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(node1, node2)
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +115,8 @@ predicate storeStep(Node node1, Content f, Node node2) {
|
||||
or
|
||||
f instanceof ArrayContent and arrayStoreStep(node1, node2)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, f, node2)
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), f,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +147,8 @@ predicate readStep(Node node1, Content f, Node node2) {
|
||||
or
|
||||
f instanceof CollectionContent and collectionReadStep(node1, node2)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1, f, node2)
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), f,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +163,7 @@ predicate clearsContent(Node n, Content c) {
|
||||
c.(FieldContent).getField() = fa.getField()
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c)
|
||||
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,7 +171,7 @@ predicate clearsContent(Node n, Content c) {
|
||||
* at node `n`.
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) {
|
||||
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n, c)
|
||||
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,7 +179,7 @@ predicate expectsContent(Node n, ContentSet c) {
|
||||
* possible flow. A single type is used for all numeric types to account for
|
||||
* numeric conversions, and otherwise the erasure is used.
|
||||
*/
|
||||
DataFlowType getErasedRepr(Type t) {
|
||||
RefType getErasedRepr(Type t) {
|
||||
exists(Type e | e = t.getErasure() |
|
||||
if e instanceof NumericOrCharType
|
||||
then result.(BoxedType).getPrimitiveType().getName() = "double"
|
||||
@@ -189,11 +192,18 @@ DataFlowType getErasedRepr(Type t) {
|
||||
t instanceof NullType and result instanceof TypeObject
|
||||
}
|
||||
|
||||
class DataFlowType extends SrcRefType {
|
||||
DataFlowType() { this = getErasedRepr(_) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { t1.getASourceSupertype+() = t2 }
|
||||
|
||||
pragma[noinline]
|
||||
DataFlowType getNodeType(Node n) {
|
||||
result = getErasedRepr(n.getTypeBound())
|
||||
or
|
||||
result = FlowSummaryImpl::Private::summaryNodeType(n)
|
||||
result = FlowSummaryImpl::Private::summaryNodeType(n.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getErasedRepr`. */
|
||||
@@ -259,11 +269,9 @@ class DataFlowCallable extends TDataFlowCallable {
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = RefType;
|
||||
|
||||
private newtype TDataFlowCall =
|
||||
TCall(Call c) or
|
||||
TSummaryCall(SummarizedCallable c, Node receiver) {
|
||||
TSummaryCall(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
@@ -313,12 +321,12 @@ class SrcCall extends DataFlowCall, TCall {
|
||||
/** A synthesized call inside a `SummarizedCallable`. */
|
||||
class SummaryCall extends DataFlowCall, TSummaryCall {
|
||||
private SummarizedCallable c;
|
||||
private Node receiver;
|
||||
private FlowSummaryImpl::Private::SummaryNode receiver;
|
||||
|
||||
SummaryCall() { this = TSummaryCall(c, receiver) }
|
||||
|
||||
/** Gets the data flow node that this call targets. */
|
||||
Node getReceiver() { result = receiver }
|
||||
FlowSummaryImpl::Private::SummaryNode getReceiver() { result = receiver }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() { result.asSummarizedCallable() = c }
|
||||
|
||||
@@ -378,10 +386,7 @@ predicate forceHighPrecision(Content c) {
|
||||
}
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) {
|
||||
n instanceof SummaryNode or
|
||||
n instanceof SummaryParameterNode
|
||||
}
|
||||
predicate nodeIsHidden(Node n) { n instanceof FlowSummaryNode }
|
||||
|
||||
class LambdaCallKind = Method; // the "apply" method in the functional interface
|
||||
|
||||
@@ -399,7 +404,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
|
||||
|
||||
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
receiver = call.(SummaryCall).getReceiver() and
|
||||
receiver.(FlowSummaryNode).getSummaryNode() = call.(SummaryCall).getReceiver() and
|
||||
getNodeDataFlowType(receiver)
|
||||
.getSourceDeclaration()
|
||||
.(FunctionalInterface)
|
||||
|
||||
@@ -183,7 +183,8 @@ private predicate simpleLocalFlowStep0(Node node1, Node node2) {
|
||||
node1.(ArgumentNode).argumentOf(any(DataFlowCall c | c.asCall() = ma), argNo)
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1, node2, true)
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode(), true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -180,6 +180,11 @@ module Public {
|
||||
result = "Argument[" + getParameterPosition(pos) + "]"
|
||||
)
|
||||
or
|
||||
exists(string synthetic |
|
||||
sc = TSyntheticGlobalSummaryComponent(synthetic) and
|
||||
result = "SyntheticGlobal[" + synthetic + "]"
|
||||
)
|
||||
or
|
||||
sc = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
|
||||
}
|
||||
|
||||
@@ -505,6 +510,9 @@ module Private {
|
||||
or
|
||||
// Add the post-update node corresponding to the requested argument node
|
||||
outputState(c, s) and isCallbackParameter(s)
|
||||
or
|
||||
// Add the parameter node for parameter side-effects
|
||||
outputState(c, s) and s = SummaryComponentStack::argument(_)
|
||||
}
|
||||
|
||||
private newtype TSummaryNodeState =
|
||||
@@ -530,7 +538,7 @@ module Private {
|
||||
* this state represents that the components in `s` _remain to be written_ to
|
||||
* the output.
|
||||
*/
|
||||
class SummaryNodeState extends TSummaryNodeState {
|
||||
private class SummaryNodeState extends TSummaryNodeState {
|
||||
/** Holds if this state is a valid input state for `c`. */
|
||||
pragma[nomagic]
|
||||
predicate isInputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
@@ -559,6 +567,42 @@ module Private {
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TSummaryNode =
|
||||
TSummaryInternalNode(SummarizedCallable c, SummaryNodeState state) {
|
||||
summaryNodeRange(c, state)
|
||||
} or
|
||||
TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) {
|
||||
summaryParameterNodeRange(c, pos)
|
||||
}
|
||||
|
||||
abstract class SummaryNode extends TSummaryNode {
|
||||
abstract string toString();
|
||||
|
||||
abstract SummarizedCallable getSummarizedCallable();
|
||||
}
|
||||
|
||||
private class SummaryInternalNode extends SummaryNode, TSummaryInternalNode {
|
||||
private SummarizedCallable c;
|
||||
private SummaryNodeState state;
|
||||
|
||||
SummaryInternalNode() { this = TSummaryInternalNode(c, state) }
|
||||
|
||||
override string toString() { result = "[summary] " + state + " in " + c }
|
||||
|
||||
override SummarizedCallable getSummarizedCallable() { result = c }
|
||||
}
|
||||
|
||||
private class SummaryParamNode extends SummaryNode, TSummaryParameterNode {
|
||||
private SummarizedCallable c;
|
||||
private ParameterPosition pos;
|
||||
|
||||
SummaryParamNode() { this = TSummaryParameterNode(c, pos) }
|
||||
|
||||
override string toString() { result = "[summary param] " + pos + " in " + c }
|
||||
|
||||
override SummarizedCallable getSummarizedCallable() { result = c }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `state` represents having read from a parameter at position
|
||||
* `pos` in `c`. In this case we are not synthesizing a data-flow node,
|
||||
@@ -574,7 +618,7 @@ module Private {
|
||||
* Holds if a synthesized summary node is needed for the state `state` in summarized
|
||||
* callable `c`.
|
||||
*/
|
||||
predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) {
|
||||
private predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) {
|
||||
state.isInputState(c, _) and
|
||||
not parameterReadState(c, state, _)
|
||||
or
|
||||
@@ -582,22 +626,22 @@ module Private {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Node summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
private SummaryNode summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
exists(SummaryNodeState state | state.isInputState(c, s) |
|
||||
result = summaryNode(c, state)
|
||||
result = TSummaryInternalNode(c, state)
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
parameterReadState(c, state, pos) and
|
||||
result.(ParamNode).isParameterOf(inject(c), pos)
|
||||
result = TSummaryParameterNode(c, pos)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Node summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
private SummaryNode summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
exists(SummaryNodeState state |
|
||||
state.isOutputState(c, s) and
|
||||
result = summaryNode(c, state)
|
||||
result = TSummaryInternalNode(c, state)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -605,12 +649,14 @@ module Private {
|
||||
* Holds if a write targets `post`, which is a post-update node for a
|
||||
* parameter at position `pos` in `c`.
|
||||
*/
|
||||
private predicate isParameterPostUpdate(Node post, SummarizedCallable c, ParameterPosition pos) {
|
||||
private predicate isParameterPostUpdate(
|
||||
SummaryNode post, SummarizedCallable c, ParameterPosition pos
|
||||
) {
|
||||
post = summaryNodeOutputState(c, SummaryComponentStack::argument(pos))
|
||||
}
|
||||
|
||||
/** Holds if a parameter node at position `pos` is required for `c`. */
|
||||
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||
private predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
|
||||
parameterReadState(c, _, pos)
|
||||
or
|
||||
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
|
||||
@@ -618,7 +664,7 @@ module Private {
|
||||
}
|
||||
|
||||
private predicate callbackOutput(
|
||||
SummarizedCallable c, SummaryComponentStack s, Node receiver, ReturnKind rk
|
||||
SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ReturnKind rk
|
||||
) {
|
||||
any(SummaryNodeState state).isInputState(c, s) and
|
||||
s.head() = TReturnSummaryComponent(rk) and
|
||||
@@ -626,7 +672,7 @@ module Private {
|
||||
}
|
||||
|
||||
private predicate callbackInput(
|
||||
SummarizedCallable c, SummaryComponentStack s, Node receiver, ArgumentPosition pos
|
||||
SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ArgumentPosition pos
|
||||
) {
|
||||
any(SummaryNodeState state).isOutputState(c, s) and
|
||||
s.head() = TParameterSummaryComponent(pos) and
|
||||
@@ -634,7 +680,7 @@ module Private {
|
||||
}
|
||||
|
||||
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
|
||||
predicate summaryCallbackRange(SummarizedCallable c, Node receiver) {
|
||||
predicate summaryCallbackRange(SummarizedCallable c, SummaryNode receiver) {
|
||||
callbackOutput(c, _, receiver, _)
|
||||
or
|
||||
callbackInput(c, _, receiver, _)
|
||||
@@ -647,10 +693,10 @@ module Private {
|
||||
* `getContentType()`, `getReturnType()`, `getCallbackParameterType()`, and
|
||||
* `getCallbackReturnType()`.
|
||||
*/
|
||||
DataFlowType summaryNodeType(Node n) {
|
||||
exists(Node pre |
|
||||
DataFlowType summaryNodeType(SummaryNode n) {
|
||||
exists(SummaryNode pre |
|
||||
summaryPostUpdateNode(n, pre) and
|
||||
result = getNodeType(pre)
|
||||
result = summaryNodeType(pre)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() |
|
||||
@@ -662,12 +708,12 @@ module Private {
|
||||
)
|
||||
or
|
||||
head = TWithoutContentSummaryComponent(_) and
|
||||
result = getNodeType(summaryNodeInputState(c, s.tail()))
|
||||
result = summaryNodeType(summaryNodeInputState(c, s.tail()))
|
||||
or
|
||||
exists(ReturnKind rk |
|
||||
head = TReturnSummaryComponent(rk) and
|
||||
result =
|
||||
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
getCallbackReturnType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
s.tail())), rk)
|
||||
)
|
||||
or
|
||||
@@ -675,6 +721,11 @@ module Private {
|
||||
head = TSyntheticGlobalSummaryComponent(sg) and
|
||||
result = getSyntheticGlobalType(sg)
|
||||
)
|
||||
or
|
||||
exists(ParameterPosition pos |
|
||||
head = TArgumentSummaryComponent(pos) and
|
||||
result = getParameterType(c, pos)
|
||||
)
|
||||
)
|
||||
or
|
||||
n = summaryNodeOutputState(c, s) and
|
||||
@@ -691,7 +742,7 @@ module Private {
|
||||
or
|
||||
exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) |
|
||||
result =
|
||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
getCallbackParameterType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
s.tail())), pos)
|
||||
)
|
||||
or
|
||||
@@ -703,9 +754,14 @@ module Private {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if summary node `p` is a parameter with position `pos`. */
|
||||
predicate summaryParameterNode(SummaryNode p, ParameterPosition pos) {
|
||||
p = TSummaryParameterNode(_, pos)
|
||||
}
|
||||
|
||||
/** Holds if summary node `out` contains output of kind `rk` from call `c`. */
|
||||
predicate summaryOutNode(DataFlowCall c, Node out, ReturnKind rk) {
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver |
|
||||
predicate summaryOutNode(DataFlowCall c, SummaryNode out, ReturnKind rk) {
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s, SummaryNode receiver |
|
||||
callbackOutput(callable, s, receiver, rk) and
|
||||
out = summaryNodeInputState(callable, s) and
|
||||
c = summaryDataFlowCall(receiver)
|
||||
@@ -713,8 +769,8 @@ module Private {
|
||||
}
|
||||
|
||||
/** Holds if summary node `arg` is at position `pos` in the call `c`. */
|
||||
predicate summaryArgumentNode(DataFlowCall c, Node arg, ArgumentPosition pos) {
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver |
|
||||
predicate summaryArgumentNode(DataFlowCall c, SummaryNode arg, ArgumentPosition pos) {
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s, SummaryNode receiver |
|
||||
callbackInput(callable, s, receiver, pos) and
|
||||
arg = summaryNodeOutputState(callable, s) and
|
||||
c = summaryDataFlowCall(receiver)
|
||||
@@ -722,10 +778,10 @@ module Private {
|
||||
}
|
||||
|
||||
/** Holds if summary node `post` is a post-update node with pre-update node `pre`. */
|
||||
predicate summaryPostUpdateNode(Node post, Node pre) {
|
||||
predicate summaryPostUpdateNode(SummaryNode post, SummaryNode pre) {
|
||||
exists(SummarizedCallable c, ParameterPosition pos |
|
||||
isParameterPostUpdate(post, c, pos) and
|
||||
pre.(ParamNode).isParameterOf(inject(c), pos)
|
||||
pre = TSummaryParameterNode(c, pos)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s |
|
||||
@@ -736,7 +792,7 @@ module Private {
|
||||
}
|
||||
|
||||
/** Holds if summary node `ret` is a return node of kind `rk`. */
|
||||
predicate summaryReturnNode(Node ret, ReturnKind rk) {
|
||||
predicate summaryReturnNode(SummaryNode ret, ReturnKind rk) {
|
||||
exists(SummaryComponentStack s |
|
||||
ret = summaryNodeOutputState(_, s) and
|
||||
s = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk))
|
||||
@@ -748,7 +804,9 @@ module Private {
|
||||
* node, and back out to `p`.
|
||||
*/
|
||||
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
|
||||
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(inject(c), ppos) |
|
||||
exists(SummarizedCallable c, ParameterPosition ppos |
|
||||
p.isParameterOf(inject(c), pragma[only_bind_into](ppos))
|
||||
|
|
||||
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
|
||||
summary(c, inputContents, outputContents, _) and
|
||||
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
|
||||
@@ -763,7 +821,7 @@ module Private {
|
||||
* Holds if there is a local step from `pred` to `succ`, which is synthesized
|
||||
* from a flow summary.
|
||||
*/
|
||||
predicate summaryLocalStep(Node pred, Node succ, boolean preservesValue) {
|
||||
predicate summaryLocalStep(SummaryNode pred, SummaryNode succ, boolean preservesValue) {
|
||||
exists(
|
||||
SummarizedCallable c, SummaryComponentStack inputContents,
|
||||
SummaryComponentStack outputContents
|
||||
@@ -789,7 +847,7 @@ module Private {
|
||||
* Holds if there is a read step of content `c` from `pred` to `succ`, which
|
||||
* is synthesized from a flow summary.
|
||||
*/
|
||||
predicate summaryReadStep(Node pred, ContentSet c, Node succ) {
|
||||
predicate summaryReadStep(SummaryNode pred, ContentSet c, SummaryNode succ) {
|
||||
exists(SummarizedCallable sc, SummaryComponentStack s |
|
||||
pred = summaryNodeInputState(sc, s.tail()) and
|
||||
succ = summaryNodeInputState(sc, s) and
|
||||
@@ -801,7 +859,7 @@ module Private {
|
||||
* Holds if there is a store step of content `c` from `pred` to `succ`, which
|
||||
* is synthesized from a flow summary.
|
||||
*/
|
||||
predicate summaryStoreStep(Node pred, ContentSet c, Node succ) {
|
||||
predicate summaryStoreStep(SummaryNode pred, ContentSet c, SummaryNode succ) {
|
||||
exists(SummarizedCallable sc, SummaryComponentStack s |
|
||||
pred = summaryNodeOutputState(sc, s) and
|
||||
succ = summaryNodeOutputState(sc, s.tail()) and
|
||||
@@ -813,7 +871,7 @@ module Private {
|
||||
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
|
||||
* from a flow summary.
|
||||
*/
|
||||
predicate summaryJumpStep(Node pred, Node succ) {
|
||||
predicate summaryJumpStep(SummaryNode pred, SummaryNode succ) {
|
||||
exists(SummaryComponentStack s |
|
||||
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
|
||||
pred = summaryNodeOutputState(_, s) and
|
||||
@@ -840,9 +898,9 @@ module Private {
|
||||
* `a` on line 2 to the post-update node for `a` on that line (via an intermediate
|
||||
* node where field `b` is cleared).
|
||||
*/
|
||||
predicate summaryClearsContent(Node n, ContentSet c) {
|
||||
predicate summaryClearsContent(SummaryNode n, ContentSet c) {
|
||||
exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack |
|
||||
n = summaryNode(sc, state) and
|
||||
n = TSummaryInternalNode(sc, state) and
|
||||
state.isInputState(sc, stack) and
|
||||
stack.head() = SummaryComponent::withoutContent(c)
|
||||
)
|
||||
@@ -852,9 +910,9 @@ module Private {
|
||||
* Holds if the value that is being tracked is expected to be stored inside
|
||||
* content `c` at `n`.
|
||||
*/
|
||||
predicate summaryExpectsContent(Node n, ContentSet c) {
|
||||
predicate summaryExpectsContent(SummaryNode n, ContentSet c) {
|
||||
exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack |
|
||||
n = summaryNode(sc, state) and
|
||||
n = TSummaryInternalNode(sc, state) and
|
||||
state.isInputState(sc, stack) and
|
||||
stack.head() = SummaryComponent::withContent(c)
|
||||
)
|
||||
@@ -862,17 +920,17 @@ module Private {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate viableParam(
|
||||
DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, ParamNode p
|
||||
DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, SummaryParamNode p
|
||||
) {
|
||||
exists(DataFlowCallable c |
|
||||
c = inject(sc) and
|
||||
p.isParameterOf(c, ppos) and
|
||||
p = TSummaryParameterNode(sc, ppos) and
|
||||
c = viableCallable(call)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg, SummarizedCallable sc) {
|
||||
private SummaryParamNode summaryArgParam(DataFlowCall call, ArgNode arg, SummarizedCallable sc) {
|
||||
exists(ParameterPosition ppos |
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
viableParam(call, sc, ppos, result)
|
||||
@@ -884,12 +942,12 @@ module Private {
|
||||
* local steps. `clearsOrExpects` records whether any node on the path from `p` to
|
||||
* `n` either clears or expects contents.
|
||||
*/
|
||||
private predicate paramReachesLocal(ParamNode p, Node n, boolean clearsOrExpects) {
|
||||
private predicate paramReachesLocal(SummaryParamNode p, SummaryNode n, boolean clearsOrExpects) {
|
||||
viableParam(_, _, _, p) and
|
||||
n = p and
|
||||
clearsOrExpects = false
|
||||
or
|
||||
exists(Node mid, boolean clearsOrExpectsMid |
|
||||
exists(SummaryNode mid, boolean clearsOrExpectsMid |
|
||||
paramReachesLocal(p, mid, clearsOrExpectsMid) and
|
||||
summaryLocalStep(mid, n, true) and
|
||||
if
|
||||
@@ -909,21 +967,33 @@ module Private {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate prohibitsUseUseFlow(ArgNode arg, SummarizedCallable sc) {
|
||||
exists(ParamNode p, ParameterPosition ppos, Node ret |
|
||||
exists(SummaryParamNode p, ParameterPosition ppos, SummaryNode ret |
|
||||
paramReachesLocal(p, ret, true) and
|
||||
p = summaryArgParam0(_, arg, sc) and
|
||||
p.isParameterOf(_, pragma[only_bind_into](ppos)) and
|
||||
p = summaryArgParam(_, arg, sc) and
|
||||
p = TSummaryParameterNode(_, pragma[only_bind_into](ppos)) and
|
||||
isParameterPostUpdate(ret, _, pragma[only_bind_into](ppos))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate summaryReturnNodeExt(SummaryNode ret, ReturnKindExt rk) {
|
||||
summaryReturnNode(ret, rk.(ValueReturnKind).getKind())
|
||||
or
|
||||
exists(SummaryParamNode p, SummaryNode pre, ParameterPosition pos |
|
||||
paramReachesLocal(p, pre, _) and
|
||||
summaryPostUpdateNode(ret, pre) and
|
||||
p = TSummaryParameterNode(_, pos) and
|
||||
rk.(ParamUpdateReturnKind).getPosition() = pos
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[ret]
|
||||
private ParamNode summaryArgParam(
|
||||
ArgNode arg, ReturnNodeExt ret, OutNodeExt out, SummarizedCallable sc
|
||||
private SummaryParamNode summaryArgParamRetOut(
|
||||
ArgNode arg, SummaryNode ret, OutNodeExt out, SummarizedCallable sc
|
||||
) {
|
||||
exists(DataFlowCall call, ReturnKindExt rk |
|
||||
result = summaryArgParam0(call, arg, sc) and
|
||||
ret.getKind() = pragma[only_bind_into](rk) and
|
||||
result = summaryArgParam(call, arg, sc) and
|
||||
summaryReturnNodeExt(ret, pragma[only_bind_into](rk)) and
|
||||
out = pragma[only_bind_into](rk).getAnOutNode(call)
|
||||
)
|
||||
}
|
||||
@@ -936,9 +1006,9 @@ module Private {
|
||||
* be useful to include in the exposed local data-flow/taint-tracking relations.
|
||||
*/
|
||||
predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) {
|
||||
exists(ReturnKind rk, ReturnNode ret, DataFlowCall call |
|
||||
summaryLocalStep(summaryArgParam0(call, arg, sc), ret, true) and
|
||||
ret.getKind() = pragma[only_bind_into](rk) and
|
||||
exists(ReturnKind rk, SummaryNode ret, DataFlowCall call |
|
||||
summaryLocalStep(summaryArgParam(call, arg, sc), ret, true) and
|
||||
summaryReturnNode(ret, pragma[only_bind_into](rk)) and
|
||||
out = getAnOutNode(call, pragma[only_bind_into](rk))
|
||||
)
|
||||
}
|
||||
@@ -951,7 +1021,9 @@ module Private {
|
||||
* be useful to include in the exposed local data-flow/taint-tracking relations.
|
||||
*/
|
||||
predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) {
|
||||
exists(ReturnNodeExt ret | summaryLocalStep(summaryArgParam(arg, ret, out, sc), ret, false))
|
||||
exists(SummaryNode ret |
|
||||
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -962,8 +1034,8 @@ module Private {
|
||||
* be useful to include in the exposed local data-flow/taint-tracking relations.
|
||||
*/
|
||||
predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
|
||||
exists(Node mid, ReturnNodeExt ret |
|
||||
summaryReadStep(summaryArgParam(arg, ret, out, sc), c, mid) and
|
||||
exists(SummaryNode mid, SummaryNode ret |
|
||||
summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and
|
||||
summaryLocalStep(mid, ret, _)
|
||||
)
|
||||
}
|
||||
@@ -976,8 +1048,8 @@ module Private {
|
||||
* be useful to include in the exposed local data-flow/taint-tracking relations.
|
||||
*/
|
||||
predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
|
||||
exists(Node mid, ReturnNodeExt ret |
|
||||
summaryLocalStep(summaryArgParam(arg, ret, out, sc), mid, _) and
|
||||
exists(SummaryNode mid, SummaryNode ret |
|
||||
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), mid, _) and
|
||||
summaryStoreStep(mid, c, ret)
|
||||
)
|
||||
}
|
||||
@@ -1344,11 +1416,11 @@ module Private {
|
||||
}
|
||||
|
||||
private newtype TNodeOrCall =
|
||||
MkNode(Node n) {
|
||||
MkNode(SummaryNode n) {
|
||||
exists(RelevantSummarizedCallable c |
|
||||
n = summaryNode(c, _)
|
||||
n = TSummaryInternalNode(c, _)
|
||||
or
|
||||
n.(ParamNode).isParameterOf(inject(c), _)
|
||||
n = TSummaryParameterNode(c, _)
|
||||
)
|
||||
} or
|
||||
MkCall(DataFlowCall call) {
|
||||
@@ -1357,7 +1429,7 @@ module Private {
|
||||
}
|
||||
|
||||
private class NodeOrCall extends TNodeOrCall {
|
||||
Node asNode() { this = MkNode(result) }
|
||||
SummaryNode asNode() { this = MkNode(result) }
|
||||
|
||||
DataFlowCall asCall() { this = MkCall(result) }
|
||||
|
||||
@@ -1377,9 +1449,11 @@ module Private {
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
or
|
||||
this.asCall().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
filepath = "" and
|
||||
startline = 0 and
|
||||
startcolumn = 0 and
|
||||
endline = 0 and
|
||||
endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,15 +26,17 @@ DataFlowCallable inject(SummarizedCallable c) { result.asSummarizedCallable() =
|
||||
/** Gets the parameter position of the instance parameter. */
|
||||
ArgumentPosition callbackSelfParameterPosition() { result = -1 }
|
||||
|
||||
/** Gets the synthesized summary data-flow node for the given values. */
|
||||
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = getSummaryNode(c, state) }
|
||||
|
||||
/** Gets the synthesized data-flow call for `receiver`. */
|
||||
SummaryCall summaryDataFlowCall(Node receiver) { result.getReceiver() = receiver }
|
||||
SummaryCall summaryDataFlowCall(SummaryNode receiver) { result.getReceiver() = receiver }
|
||||
|
||||
/** Gets the type of content `c`. */
|
||||
DataFlowType getContentType(Content c) { result = c.getType() }
|
||||
|
||||
/** Gets the type of the parameter at the given position. */
|
||||
DataFlowType getParameterType(SummarizedCallable c, ParameterPosition pos) {
|
||||
result = getErasedRepr(c.getParameterType(pos))
|
||||
}
|
||||
|
||||
/** Gets the return type of kind `rk` for callable `c`. */
|
||||
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
|
||||
result = getErasedRepr(c.getReturnType()) and
|
||||
|
||||
@@ -86,6 +86,7 @@ module LocalTaintFlow<nodeSig/1 source, nodeSig/1 sink> {
|
||||
cached
|
||||
private module Cached {
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import DataFlowPrivate as DataFlowPrivate
|
||||
|
||||
cached
|
||||
predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
|
||||
@@ -136,7 +137,8 @@ private module Cached {
|
||||
)
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(src.(DataFlowPrivate::FlowSummaryNode)
|
||||
.getSummaryNode(), sink.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -456,9 +456,6 @@ class ArbitraryXmlEntryPoint extends ReflectivelyConstructedClass {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ArbitraryXmlEntryPoint */
|
||||
deprecated class ArbitraryXMLEntryPoint = ArbitraryXmlEntryPoint;
|
||||
|
||||
/** A Selenium PageObject, created by a call to PageFactory.initElements(..). */
|
||||
class SeleniumPageObjectEntryPoint extends ReflectivelyConstructedClass instanceof SeleniumPageObject
|
||||
{ }
|
||||
|
||||
@@ -38,9 +38,6 @@ class UrlConnectionGetInputStreamMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UrlConnectionGetInputStreamMethod */
|
||||
deprecated class URLConnectionGetInputStreamMethod = UrlConnectionGetInputStreamMethod;
|
||||
|
||||
/** The method `java.net.Socket::getInputStream`. */
|
||||
class SocketGetInputStreamMethod extends Method {
|
||||
SocketGetInputStreamMethod() {
|
||||
|
||||
@@ -128,9 +128,6 @@ class HttpServletRequestGetRequestUrlMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for HttpServletRequestGetRequestUrlMethod */
|
||||
deprecated class HttpServletRequestGetRequestURLMethod = HttpServletRequestGetRequestUrlMethod;
|
||||
|
||||
/**
|
||||
* The method `getRequestURI()` declared in `javax.servlet.http.HttpServletRequest`.
|
||||
*/
|
||||
@@ -339,9 +336,6 @@ class ServletWebXmlListenerType extends RefType {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ServletWebXmlListenerType */
|
||||
deprecated class ServletWebXMLListenerType = ServletWebXmlListenerType;
|
||||
|
||||
/** Holds if `m` is a request handler method (for example `doGet` or `doPost`). */
|
||||
predicate isServletRequestMethod(Method m) {
|
||||
m.getDeclaringType() instanceof ServletClass and
|
||||
|
||||
@@ -29,9 +29,6 @@ class TypeUnboundIdLdapConnection extends Class {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for TypeUnboundIdLdapConnection */
|
||||
deprecated class TypeUnboundIdLDAPConnection = TypeUnboundIdLdapConnection;
|
||||
|
||||
/*--- Methods ---*/
|
||||
/** A method with the name `setBaseDN` declared in `com.unboundid.ldap.sdk.SearchRequest`. */
|
||||
class MethodUnboundIdSearchRequestSetBaseDN extends Method {
|
||||
@@ -103,9 +100,6 @@ class MethodUnboundIdLdapConnectionSearch extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for MethodUnboundIdLdapConnectionSearch */
|
||||
deprecated class MethodUnboundIdLDAPConnectionSearch = MethodUnboundIdLdapConnectionSearch;
|
||||
|
||||
/** A method with the name `asyncSearch` declared in `com.unboundid.ldap.sdk.LDAPConnection`. */
|
||||
class MethodUnboundIdLdapConnectionAsyncSearch extends Method {
|
||||
MethodUnboundIdLdapConnectionAsyncSearch() {
|
||||
@@ -114,10 +108,6 @@ class MethodUnboundIdLdapConnectionAsyncSearch extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for MethodUnboundIdLdapConnectionAsyncSearch */
|
||||
deprecated class MethodUnboundIdLDAPConnectionAsyncSearch =
|
||||
MethodUnboundIdLdapConnectionAsyncSearch;
|
||||
|
||||
/** A method with the name `searchForEntry` declared in `com.unboundid.ldap.sdk.LDAPConnection`. */
|
||||
class MethodUnboundIdLdapConnectionSearchForEntry extends Method {
|
||||
MethodUnboundIdLdapConnectionSearchForEntry() {
|
||||
@@ -125,7 +115,3 @@ class MethodUnboundIdLdapConnectionSearchForEntry extends Method {
|
||||
this.hasName("searchForEntry")
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for MethodUnboundIdLdapConnectionSearchForEntry */
|
||||
deprecated class MethodUnboundIdLDAPConnectionSearchForEntry =
|
||||
MethodUnboundIdLdapConnectionSearchForEntry;
|
||||
|
||||
29
java/ql/lib/semmle/code/java/frameworks/hudson/Hudson.qll
Normal file
29
java/ql/lib/semmle/code/java/frameworks/hudson/Hudson.qll
Normal file
@@ -0,0 +1,29 @@
|
||||
/** Provides classes and predicates related to the Hudson framework. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.security.XSS
|
||||
|
||||
private class FilePathRead extends LocalUserInput {
|
||||
FilePathRead() {
|
||||
this.asExpr()
|
||||
.(MethodAccess)
|
||||
.getMethod()
|
||||
.hasQualifiedName("hudson", "FilePath",
|
||||
[
|
||||
"newInputStreamDenyingSymlinkAsNeeded", "openInputStream", "read", "readFromOffset",
|
||||
"readToString"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
private class HudsonUtilXssSanitizer extends XssSanitizer {
|
||||
HudsonUtilXssSanitizer() {
|
||||
this.asExpr()
|
||||
.(MethodAccess)
|
||||
.getMethod()
|
||||
// Not including xmlEscape because it only accounts for >, <, and &.
|
||||
// It does not account for ", or ', which makes it an incomplete XSS sanitizer.
|
||||
.hasQualifiedName("hudson", "Util", "escape")
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,6 @@ class JacksonJsonIgnoreAnnotation extends NonReflectiveAnnotation {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for JacksonJsonIgnoreAnnotation */
|
||||
deprecated class JacksonJSONIgnoreAnnotation = JacksonJsonIgnoreAnnotation;
|
||||
|
||||
/** A type whose values may be serialized using the Jackson JSON framework. */
|
||||
abstract class JacksonSerializableType extends Type { }
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ class PersistenceXmlFile extends XmlFile {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PersistenceXmlFile */
|
||||
deprecated class PersistenceXMLFile = PersistenceXmlFile;
|
||||
|
||||
/** The root `persistence` XML element in a `persistence.xml` file. */
|
||||
class PersistenceXmlRoot extends XmlElement {
|
||||
PersistenceXmlRoot() {
|
||||
|
||||
@@ -35,9 +35,6 @@ class EjbJarXmlFile extends XmlFile {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for EjbJarXmlFile */
|
||||
deprecated class EjbJarXMLFile = EjbJarXmlFile;
|
||||
|
||||
/** The root `ejb-jar` XML element in an `ejb-jar.xml` file. */
|
||||
class EjbJarRootElement extends XmlElement {
|
||||
EjbJarRootElement() {
|
||||
|
||||
@@ -16,9 +16,6 @@ class FacesConfigXmlFile extends XmlFile {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for FacesConfigXmlFile */
|
||||
deprecated class FacesConfigXMLFile = FacesConfigXmlFile;
|
||||
|
||||
/**
|
||||
* An XML element in a `FacesConfigXMLFile`.
|
||||
*/
|
||||
@@ -31,9 +28,6 @@ class FacesConfigXmlElement extends XmlElement {
|
||||
string getValue() { result = this.allCharactersString().trim() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for FacesConfigXmlElement */
|
||||
deprecated class FacesConfigXMLElement = FacesConfigXmlElement;
|
||||
|
||||
/**
|
||||
* An element in a JSF config file that declares a managed bean.
|
||||
*/
|
||||
|
||||
@@ -100,9 +100,6 @@ class SpringBeanXmlAutowiredSetterMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringBeanXmlAutowiredSetterMethod */
|
||||
deprecated class SpringBeanXMLAutowiredSetterMethod = SpringBeanXmlAutowiredSetterMethod;
|
||||
|
||||
/**
|
||||
* A callable that is annotated with `@Autowired`.
|
||||
*
|
||||
|
||||
@@ -13,9 +13,6 @@ class SpringCamelXmlElement extends SpringXmlElement {
|
||||
SpringCamelXmlElement() { this.getNamespace().getUri() = "http://camel.apache.org/schema/spring" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlElement */
|
||||
deprecated class SpringCamelXMLElement = SpringCamelXmlElement;
|
||||
|
||||
/**
|
||||
* An element in a Spring beans file that defines an Apache Camel context.
|
||||
*
|
||||
@@ -25,9 +22,6 @@ class SpringCamelXmlContext extends SpringCamelXmlElement {
|
||||
SpringCamelXmlContext() { this.getName() = "camelContext" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlContext */
|
||||
deprecated class SpringCamelXMLContext = SpringCamelXmlContext;
|
||||
|
||||
/**
|
||||
* An element in a Spring beans file that defines an Apache Camel route context.
|
||||
*
|
||||
@@ -38,9 +32,6 @@ class SpringCamelXmlRouteContext extends SpringCamelXmlElement {
|
||||
SpringCamelXmlRouteContext() { this.getName() = "routeContext" }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlRouteContext */
|
||||
deprecated class SpringCamelXMLRouteContext = SpringCamelXmlRouteContext;
|
||||
|
||||
/**
|
||||
* An element in a Spring beans files that defines an Apache Camel route.
|
||||
*
|
||||
@@ -58,9 +49,6 @@ class SpringCamelXmlRoute extends SpringCamelXmlElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlRoute */
|
||||
deprecated class SpringCamelXMLRoute = SpringCamelXmlRoute;
|
||||
|
||||
/**
|
||||
* An element in a Spring bean file that is logically contained in an Apache Camel route.
|
||||
*/
|
||||
@@ -71,9 +59,6 @@ class SpringCamelXmlRouteElement extends SpringCamelXmlElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlRouteElement */
|
||||
deprecated class SpringCamelXMLRouteElement = SpringCamelXmlRouteElement;
|
||||
|
||||
/**
|
||||
* A reference to a Spring bean in an Apache Camel route defined in a Spring beans file.
|
||||
*
|
||||
@@ -98,9 +83,6 @@ class SpringCamelXmlBeanRef extends SpringCamelXmlRouteElement {
|
||||
RefType getBeanType() { result.getQualifiedName() = this.getAttribute("beanType").getValue() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlBeanRef */
|
||||
deprecated class SpringCamelXMLBeanRef = SpringCamelXmlBeanRef;
|
||||
|
||||
/**
|
||||
* A declaration of a target in an Apache Camel route defined in a Spring beans file.
|
||||
*
|
||||
@@ -120,9 +102,6 @@ class SpringCamelXmlToElement extends SpringCamelXmlRouteElement {
|
||||
deprecated string getURI() { result = this.getUri() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlToElement */
|
||||
deprecated class SpringCamelXMLToElement = SpringCamelXmlToElement;
|
||||
|
||||
/**
|
||||
* A declaration of a Apache Camel "method" expression defined in a Spring beans file.
|
||||
*
|
||||
@@ -147,6 +126,3 @@ class SpringCamelXmlMethodElement extends SpringCamelXmlElement {
|
||||
*/
|
||||
RefType getBeanType() { result.getQualifiedName() = this.getAttribute("beanType").getValue() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringCamelXmlMethodElement */
|
||||
deprecated class SpringCamelXMLMethodElement = SpringCamelXmlMethodElement;
|
||||
|
||||
@@ -23,9 +23,6 @@ class SpringXmlComponentScan extends SpringXmlElement {
|
||||
string getAProfileExpr() { result = this.getSpringBeanFile().getAProfileExpr() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringXmlComponentScan */
|
||||
deprecated class SpringXMLComponentScan = SpringXmlComponentScan;
|
||||
|
||||
/**
|
||||
* An annotation of a class that configures which packages are considered to be "base" packages
|
||||
* when performing the Spring component scan.
|
||||
|
||||
@@ -57,11 +57,6 @@ class SpringRemotingDestinationClass extends Class {
|
||||
*/
|
||||
SpringRemotingDestination getRemotingDestinationXml() { this = result.getSpringBean().getClass() }
|
||||
|
||||
/** DEPRECATED: Alias for getRemotingDestinationXml */
|
||||
deprecated SpringRemotingDestination getRemotingDestinationXML() {
|
||||
result = this.getRemotingDestinationXml()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the class is operating on an "include" or "exclude" basis.
|
||||
*
|
||||
|
||||
@@ -37,6 +37,3 @@ class SpringXmlElement extends XmlElement {
|
||||
|
||||
string getContentString() { result = this.allCharactersString() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SpringXmlElement */
|
||||
deprecated class SpringXMLElement = SpringXmlElement;
|
||||
|
||||
@@ -77,9 +77,6 @@ StrutsXmlFile getRootXmlFile(RefType refType) {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getRootXmlFile */
|
||||
deprecated StrutsXMLFile getRootXMLFile(RefType refType) { result = getRootXmlFile(refType) }
|
||||
|
||||
/**
|
||||
* Gets the suffix used for automatically identifying actions when using the convention plugin.
|
||||
*
|
||||
|
||||
@@ -5,9 +5,6 @@ import java
|
||||
*/
|
||||
predicate isStrutsXmlIncluded() { exists(StrutsXmlFile strutsXml) }
|
||||
|
||||
/** DEPRECATED: Alias for isStrutsXmlIncluded */
|
||||
deprecated predicate isStrutsXMLIncluded = isStrutsXmlIncluded/0;
|
||||
|
||||
/**
|
||||
* A struts 2 configuration file.
|
||||
*/
|
||||
@@ -51,9 +48,6 @@ abstract class StrutsXmlFile extends XmlFile {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StrutsXmlFile */
|
||||
deprecated class StrutsXMLFile = StrutsXmlFile;
|
||||
|
||||
/**
|
||||
* A Struts 2 "root" configuration XML file directly read by struts.
|
||||
*
|
||||
@@ -66,9 +60,6 @@ class StrutsRootXmlFile extends StrutsXmlFile {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StrutsRootXmlFile */
|
||||
deprecated class StrutsRootXMLFile = StrutsRootXmlFile;
|
||||
|
||||
/**
|
||||
* A Struts 2 configuration XML file included, directly or indirectly, by a root Struts configuration.
|
||||
*/
|
||||
@@ -76,9 +67,6 @@ class StrutsIncludedXmlFile extends StrutsXmlFile {
|
||||
StrutsIncludedXmlFile() { exists(StrutsXmlInclude include | this = include.getIncludedFile()) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StrutsIncludedXmlFile */
|
||||
deprecated class StrutsIncludedXMLFile = StrutsIncludedXmlFile;
|
||||
|
||||
/**
|
||||
* A Folder which has one or more Struts 2 root configurations.
|
||||
*/
|
||||
@@ -116,9 +104,6 @@ class StrutsXmlElement extends XmlElement {
|
||||
string getValue() { result = this.allCharactersString().trim() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StrutsXmlElement */
|
||||
deprecated class StrutsXMLElement = StrutsXmlElement;
|
||||
|
||||
/**
|
||||
* A `<include>` element within a `struts.xml` file.
|
||||
*
|
||||
@@ -141,9 +126,6 @@ class StrutsXmlInclude extends StrutsXmlElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StrutsXmlInclude */
|
||||
deprecated class StrutsXMLInclude = StrutsXmlInclude;
|
||||
|
||||
/**
|
||||
* Escape a string for use as the matcher in a string.match(..) call.
|
||||
*/
|
||||
@@ -192,9 +174,6 @@ class StrutsXmlAction extends StrutsXmlElement {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StrutsXmlAction */
|
||||
deprecated class StrutsXMLAction = StrutsXmlAction;
|
||||
|
||||
/**
|
||||
* A `<constant>` property, representing a configuration parameter to struts.
|
||||
*/
|
||||
@@ -205,6 +184,3 @@ class StrutsXmlConstant extends StrutsXmlElement {
|
||||
|
||||
string getConstantValue() { result = this.getAttribute("value").getValue() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StrutsXmlConstant */
|
||||
deprecated class StrutsXMLConstant = StrutsXmlConstant;
|
||||
|
||||
@@ -25,9 +25,6 @@ class HttpsUrlConnection extends RefType {
|
||||
HttpsUrlConnection() { this.hasQualifiedName("javax.net.ssl", "HttpsURLConnection") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for HttpsUrlConnection */
|
||||
deprecated class HttpsURLConnection = HttpsUrlConnection;
|
||||
|
||||
class SslSocketFactory extends RefType {
|
||||
SslSocketFactory() { this.hasQualifiedName("javax.net.ssl", "SSLSocketFactory") }
|
||||
}
|
||||
|
||||
@@ -12,9 +12,6 @@ import semmle.code.java.dataflow.TaintTracking
|
||||
*/
|
||||
abstract class SafeExternalApiMethod extends Method { }
|
||||
|
||||
/** DEPRECATED: Alias for SafeExternalApiMethod */
|
||||
deprecated class SafeExternalAPIMethod = SafeExternalApiMethod;
|
||||
|
||||
/** The default set of "safe" external APIs. */
|
||||
private class DefaultSafeExternalApiMethod extends SafeExternalApiMethod {
|
||||
DefaultSafeExternalApiMethod() {
|
||||
@@ -95,9 +92,6 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
string getMethodDescription() { result = this.getMethod().getQualifiedName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiDataNode */
|
||||
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `UntrustedDataToExternalApiFlow` instead.
|
||||
*
|
||||
@@ -125,9 +119,6 @@ module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
|
||||
*/
|
||||
module UntrustedDataToExternalApiFlow = TaintTracking::Global<UntrustedDataToExternalApiConfig>;
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||
|
||||
/** A node representing untrusted data being passed to an external API. */
|
||||
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flowTo(this) }
|
||||
@@ -136,9 +127,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
private newtype TExternalApi =
|
||||
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||
@@ -172,6 +160,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
|
||||
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;
|
||||
|
||||
@@ -46,16 +46,33 @@ private class LineBreaksLogInjectionSanitizer extends LogInjectionSanitizer {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate stringMethodAccess(
|
||||
MethodAccess ma, CompileTimeConstantExpr arg0, CompileTimeConstantExpr arg1
|
||||
) {
|
||||
ma.getMethod().getDeclaringType() instanceof TypeString and
|
||||
arg0 = ma.getArgument(0) and
|
||||
arg1 = ma.getArgument(1)
|
||||
}
|
||||
|
||||
private predicate stringMethodArgument(CompileTimeConstantExpr arg) {
|
||||
stringMethodAccess(_, arg, _) or stringMethodAccess(_, _, arg)
|
||||
}
|
||||
|
||||
bindingset[match]
|
||||
pragma[inline_late]
|
||||
private predicate stringMethodArgumentValueMatches(CompileTimeConstantExpr const, string match) {
|
||||
stringMethodArgument(const) and
|
||||
const.getStringValue().matches(match)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the return value of `ma` is sanitized against log injection attacks
|
||||
* by removing line breaks from it.
|
||||
*/
|
||||
private predicate logInjectionSanitizer(MethodAccess ma) {
|
||||
exists(CompileTimeConstantExpr target, CompileTimeConstantExpr replacement |
|
||||
ma.getMethod().getDeclaringType() instanceof TypeString and
|
||||
target = ma.getArgument(0) and
|
||||
replacement = ma.getArgument(1) and
|
||||
not replacement.getStringValue().matches(["%\n%", "%\r%"])
|
||||
stringMethodAccess(ma, target, replacement) and
|
||||
not stringMethodArgumentValueMatches(replacement, ["%\n%", "%\r%"])
|
||||
|
|
||||
ma.getMethod().hasName("replace") and
|
||||
not replacement.getIntValue() = [10, 13] and
|
||||
@@ -68,7 +85,7 @@ private predicate logInjectionSanitizer(MethodAccess ma) {
|
||||
(
|
||||
// Replace anything not in an allow list
|
||||
target.getStringValue().matches("[^%]") and
|
||||
not target.getStringValue().matches("%" + ["\n", "\r", "\\n", "\\r", "\\R"] + "%")
|
||||
not stringMethodArgumentValueMatches(target, "%" + ["\n", "\r", "\\n", "\\r", "\\R"] + "%")
|
||||
or
|
||||
// Replace line breaks
|
||||
target.getStringValue() = ["\n", "\r", "\\n", "\\r", "\\R"]
|
||||
|
||||
@@ -5,7 +5,6 @@ import semmle.code.java.frameworks.Networking
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.security.PathCreation
|
||||
import semmle.code.java.security.PathSanitizer
|
||||
|
||||
/**
|
||||
@@ -55,11 +54,7 @@ private class TaintPreservingUriCtorParam extends Parameter {
|
||||
module TaintedPathConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(PathCreation p).getAnInput()
|
||||
or
|
||||
sinkNode(sink, "path-injection")
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "path-injection") }
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
sanitizer.getType() instanceof BoxedType or
|
||||
@@ -82,11 +77,7 @@ module TaintedPathFlow = TaintTracking::Global<TaintedPathConfig>;
|
||||
module TaintedPathLocalConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(PathCreation p).getAnInput()
|
||||
or
|
||||
sinkNode(sink, "path-injection")
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "path-injection") }
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) {
|
||||
sanitizer.getType() instanceof BoxedType or
|
||||
|
||||
@@ -6,6 +6,7 @@ import semmle.code.java.frameworks.android.WebView
|
||||
import semmle.code.java.frameworks.spring.SpringController
|
||||
import semmle.code.java.frameworks.spring.SpringHttp
|
||||
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
|
||||
private import semmle.code.java.frameworks.hudson.Hudson
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
@@ -337,9 +337,6 @@ class SaxBuilder extends RefType {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxBuilder */
|
||||
deprecated class SAXBuilder = SaxBuilder;
|
||||
|
||||
/**
|
||||
* A call to `SAXBuilder.build.`
|
||||
*/
|
||||
@@ -359,9 +356,6 @@ class SaxBuilderParse extends XmlParserCall {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxBuilderParse */
|
||||
deprecated class SAXBuilderParse = SaxBuilderParse;
|
||||
|
||||
private module SafeSaxBuilderToSaxBuilderParseFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxBuilder }
|
||||
|
||||
@@ -386,9 +380,6 @@ class SaxBuilderConfig extends ParserConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxBuilderConfig */
|
||||
deprecated class SAXBuilderConfig = SaxBuilderConfig;
|
||||
|
||||
/** A safely configured `SaxBuilder`. */
|
||||
class SafeSaxBuilder extends VarAccess {
|
||||
SafeSaxBuilder() {
|
||||
@@ -404,9 +395,6 @@ class SafeSaxBuilder extends VarAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SafeSaxBuilder */
|
||||
deprecated class SafeSAXBuilder = SafeSaxBuilder;
|
||||
|
||||
/*
|
||||
* The case in
|
||||
* https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller
|
||||
@@ -420,17 +408,11 @@ class SaxParser extends RefType {
|
||||
SaxParser() { this.hasQualifiedName("javax.xml.parsers", "SAXParser") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxParser */
|
||||
deprecated class SAXParser = SaxParser;
|
||||
|
||||
/** The class `javax.xml.parsers.SAXParserFactory`. */
|
||||
class SaxParserFactory extends RefType {
|
||||
SaxParserFactory() { this.hasQualifiedName("javax.xml.parsers", "SAXParserFactory") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxParserFactory */
|
||||
deprecated class SAXParserFactory = SaxParserFactory;
|
||||
|
||||
/** A call to `SAXParser.parse`. */
|
||||
class SaxParserParse extends XmlParserCall {
|
||||
SaxParserParse() {
|
||||
@@ -446,9 +428,6 @@ class SaxParserParse extends XmlParserCall {
|
||||
override predicate isSafe() { SafeSaxParserFlow::flowToExpr(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxParserParse */
|
||||
deprecated class SAXParserParse = SaxParserParse;
|
||||
|
||||
/** A `ParserConfig` that is specific to `SaxParserFactory`. */
|
||||
class SaxParserFactoryConfig extends ParserConfig {
|
||||
SaxParserFactoryConfig() {
|
||||
@@ -460,9 +439,6 @@ class SaxParserFactoryConfig extends ParserConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxParserFactoryConfig */
|
||||
deprecated class SAXParserFactoryConfig = SaxParserFactoryConfig;
|
||||
|
||||
/**
|
||||
* A safely configured `SAXParserFactory`.
|
||||
*/
|
||||
@@ -496,9 +472,6 @@ class SafeSaxParserFactory extends VarAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SafeSaxParserFactory */
|
||||
deprecated class SafeSAXParserFactory = SafeSaxParserFactory;
|
||||
|
||||
private module SafeSaxParserFactoryToNewSaxParserFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxParserFactory }
|
||||
|
||||
@@ -540,9 +513,6 @@ class SafeSaxParser extends MethodAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SafeSaxParser */
|
||||
deprecated class SafeSAXParser = SafeSaxParser;
|
||||
|
||||
/* SAXReader: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#saxreader */
|
||||
/**
|
||||
* The class `org.dom4j.io.SAXReader`.
|
||||
@@ -551,9 +521,6 @@ class SaxReader extends RefType {
|
||||
SaxReader() { this.hasQualifiedName("org.dom4j.io", "SAXReader") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxReader */
|
||||
deprecated class SAXReader = SaxReader;
|
||||
|
||||
/** A call to `SAXReader.read`. */
|
||||
class SaxReaderRead extends XmlParserCall {
|
||||
SaxReaderRead() {
|
||||
@@ -569,9 +536,6 @@ class SaxReaderRead extends XmlParserCall {
|
||||
override predicate isSafe() { SafeSaxReaderFlow::flowToExpr(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxReaderRead */
|
||||
deprecated class SAXReaderRead = SaxReaderRead;
|
||||
|
||||
/** A `ParserConfig` specific to `SaxReader`. */
|
||||
class SaxReaderConfig extends ParserConfig {
|
||||
SaxReaderConfig() {
|
||||
@@ -583,9 +547,6 @@ class SaxReaderConfig extends ParserConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxReaderConfig */
|
||||
deprecated class SAXReaderConfig = SaxReaderConfig;
|
||||
|
||||
private module SafeSaxReaderFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSaxReader }
|
||||
|
||||
@@ -626,9 +587,6 @@ class SafeSaxReader extends VarAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SafeSaxReader */
|
||||
deprecated class SafeSAXReader = SafeSaxReader;
|
||||
|
||||
/* https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#xmlreader */
|
||||
/** The class `org.xml.sax.XMLReader`. */
|
||||
class XmlReader extends RefType {
|
||||
@@ -640,9 +598,6 @@ class InputSource extends Class {
|
||||
InputSource() { this.hasQualifiedName("org.xml.sax", "InputSource") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlReader */
|
||||
deprecated class XMLReader = XmlReader;
|
||||
|
||||
/** A call to `XMLReader.read`. */
|
||||
class XmlReaderParse extends XmlParserCall {
|
||||
XmlReaderParse() {
|
||||
@@ -661,9 +616,6 @@ class XmlReaderParse extends XmlParserCall {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlReaderParse */
|
||||
deprecated class XMLReaderParse = XmlReaderParse;
|
||||
|
||||
/** A `ParserConfig` specific to the `XmlReader`. */
|
||||
class XmlReaderConfig extends ParserConfig {
|
||||
XmlReaderConfig() {
|
||||
@@ -675,9 +627,6 @@ class XmlReaderConfig extends ParserConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlReaderConfig */
|
||||
deprecated class XMLReaderConfig = XmlReaderConfig;
|
||||
|
||||
private module ExplicitlySafeXmlReaderFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ExplicitlySafeXmlReader }
|
||||
|
||||
@@ -697,9 +646,6 @@ class SafeXmlReaderFlowSink extends Expr {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SafeXmlReaderFlowSink */
|
||||
deprecated class SafeXMLReaderFlowSink = SafeXmlReaderFlowSink;
|
||||
|
||||
/** An `XmlReader` that is explicitly configured to be safe. */
|
||||
class ExplicitlySafeXmlReader extends VarAccess {
|
||||
ExplicitlySafeXmlReader() {
|
||||
@@ -739,9 +685,6 @@ class ExplicitlySafeXmlReader extends VarAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExplicitlySafeXmlReader */
|
||||
deprecated class ExplicitlySafeXMLReader = ExplicitlySafeXmlReader;
|
||||
|
||||
private module CreatedSafeXmlReaderFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CreatedSafeXmlReader }
|
||||
|
||||
@@ -778,9 +721,6 @@ class CreatedSafeXmlReader extends Call {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for CreatedSafeXmlReader */
|
||||
deprecated class CreatedSafeXMLReader = CreatedSafeXmlReader;
|
||||
|
||||
/*
|
||||
* SAXSource in
|
||||
* https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller
|
||||
@@ -791,9 +731,6 @@ class SaxSource extends RefType {
|
||||
SaxSource() { this.hasQualifiedName("javax.xml.transform.sax", "SAXSource") }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxSource */
|
||||
deprecated class SAXSource = SaxSource;
|
||||
|
||||
/** A call to the constructor of `SAXSource` with `XmlReader` and `InputSource`. */
|
||||
class ConstructedSaxSource extends ClassInstanceExpr {
|
||||
ConstructedSaxSource() {
|
||||
@@ -814,9 +751,6 @@ class ConstructedSaxSource extends ClassInstanceExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ConstructedSaxSource */
|
||||
deprecated class ConstructedSAXSource = ConstructedSaxSource;
|
||||
|
||||
/** A call to the `SAXSource.setXMLReader` method. */
|
||||
class SaxSourceSetReader extends MethodAccess {
|
||||
SaxSourceSetReader() {
|
||||
@@ -828,9 +762,6 @@ class SaxSourceSetReader extends MethodAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxSourceSetReader */
|
||||
deprecated class SAXSourceSetReader = SaxSourceSetReader;
|
||||
|
||||
/** A `SaxSource` that is safe to use. */
|
||||
class SafeSaxSource extends Expr {
|
||||
SafeSaxSource() {
|
||||
@@ -847,9 +778,6 @@ class SafeSaxSource extends Expr {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SafeSaxSource */
|
||||
deprecated class SafeSAXSource = SafeSaxSource;
|
||||
|
||||
/* Transformer: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#transformerfactory */
|
||||
/** An access to a method use for configuring a transformer or schema. */
|
||||
abstract class TransformerConfig extends MethodAccess {
|
||||
@@ -1063,9 +991,6 @@ class SaxTransformerFactoryNewXmlFilter extends XmlParserCall {
|
||||
override predicate isSafe() { SafeTransformerFactoryFlow::flowToExpr(this.getQualifier()) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SaxTransformerFactoryNewXmlFilter */
|
||||
deprecated class SAXTransformerFactoryNewXMLFilter = SaxTransformerFactoryNewXmlFilter;
|
||||
|
||||
/* Schema: https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#schemafactory */
|
||||
/** The class `javax.xml.validation.SchemaFactory`. */
|
||||
class SchemaFactory extends RefType {
|
||||
@@ -1197,9 +1122,6 @@ class SimpleXmlPersisterCall extends XmlParserCall {
|
||||
override predicate isSafe() { none() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SimpleXmlPersisterCall */
|
||||
deprecated class SimpleXMLPersisterCall = SimpleXmlPersisterCall;
|
||||
|
||||
/** A call to `provide` in `Provider`. */
|
||||
class SimpleXmlProviderCall extends XmlParserCall {
|
||||
SimpleXmlProviderCall() {
|
||||
@@ -1218,9 +1140,6 @@ class SimpleXmlProviderCall extends XmlParserCall {
|
||||
override predicate isSafe() { none() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SimpleXmlProviderCall */
|
||||
deprecated class SimpleXMLProviderCall = SimpleXmlProviderCall;
|
||||
|
||||
/** A call to `read` in `NodeBuilder`. */
|
||||
class SimpleXmlNodeBuilderCall extends XmlParserCall {
|
||||
SimpleXmlNodeBuilderCall() {
|
||||
@@ -1236,9 +1155,6 @@ class SimpleXmlNodeBuilderCall extends XmlParserCall {
|
||||
override predicate isSafe() { none() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SimpleXmlNodeBuilderCall */
|
||||
deprecated class SimpleXMLNodeBuilderCall = SimpleXmlNodeBuilderCall;
|
||||
|
||||
/** A call to the `format` method of the `Formatter`. */
|
||||
class SimpleXmlFormatterCall extends XmlParserCall {
|
||||
SimpleXmlFormatterCall() {
|
||||
@@ -1254,9 +1170,6 @@ class SimpleXmlFormatterCall extends XmlParserCall {
|
||||
override predicate isSafe() { none() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SimpleXmlFormatterCall */
|
||||
deprecated class SimpleXMLFormatterCall = SimpleXmlFormatterCall;
|
||||
|
||||
/** A configuration for secure processing. */
|
||||
Expr configSecureProcessing() {
|
||||
result.(ConstantStringExpr).getStringValue() =
|
||||
|
||||
@@ -4,6 +4,7 @@ import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.PathSanitizer
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.security.PathCreation
|
||||
|
||||
/**
|
||||
* A method that returns the name of an archive entry.
|
||||
@@ -40,5 +41,28 @@ module ZipSlipFlow = TaintTracking::Global<ZipSlipConfig>;
|
||||
* A sink that represents a file creation, such as a file write, copy or move operation.
|
||||
*/
|
||||
private class FileCreationSink extends DataFlow::Node {
|
||||
FileCreationSink() { sinkNode(this, "path-injection") }
|
||||
FileCreationSink() {
|
||||
sinkNode(this, "path-injection") and
|
||||
not isPathCreation(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a path creation node that doesn't imply a read/write filesystem operation.
|
||||
* This is to avoid creating new spurious alerts, since `PathCreation` sinks weren't
|
||||
* previously part of this query.
|
||||
*/
|
||||
private predicate isPathCreation(DataFlow::Node sink) {
|
||||
exists(PathCreation pc |
|
||||
pc.getAnInput() = sink.asExpr()
|
||||
or
|
||||
pc.getAnInput().(Argument).isVararg() and sink.(DataFlow::ImplicitVarargsArray).getCall() = pc
|
||||
|
|
||||
// exclude actual read/write operations included in `PathCreation`
|
||||
not pc.(Call)
|
||||
.getCallee()
|
||||
.getDeclaringType()
|
||||
.hasQualifiedName("java.io",
|
||||
["FileInputStream", "FileOutputStream", "FileReader", "FileWriter"])
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user