Ruby: Use FlowSummaryImpl from dataflow pack

This commit is contained in:
Tom Hvitved
2023-11-24 10:27:37 +01:00
parent adc4455f09
commit 0e81577269
38 changed files with 668 additions and 2564 deletions

View File

@@ -57,7 +57,6 @@
"java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll",
"go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll"
],
@@ -471,7 +470,6 @@
"go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/AccessPathSyntax.qll",
"swift/ql/lib/codeql/swift/dataflow/internal/AccessPathSyntax.qll"
],

View File

@@ -22,7 +22,7 @@ have no source code, so we include a flow summary for it:
private class ChompSummary extends SimpleSummarizedCallable {
ChompSummary() { this = "chomp" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = false

View File

@@ -8,7 +8,6 @@ private import internal.FlowSummaryImpl as Impl
private import internal.DataFlowDispatch
private import internal.DataFlowImplCommon as DataFlowImplCommon
private import internal.DataFlowPrivate
private import internal.FlowSummaryImplSpecific
// import all instances below
private module Summaries {
@@ -16,104 +15,13 @@ private module Summaries {
private import codeql.ruby.frameworks.data.ModelsAsData
}
class SummaryComponent = Impl::Public::SummaryComponent;
deprecated class SummaryComponent = Impl::Private::SummaryComponent;
/** Provides predicates for constructing summary components. */
module SummaryComponent {
private import Impl::Public::SummaryComponent as SC
deprecated module SummaryComponent = Impl::Private::SummaryComponent;
predicate parameter = SC::parameter/1;
deprecated class SummaryComponentStack = Impl::Private::SummaryComponentStack;
predicate argument = SC::argument/1;
predicate content = SC::content/1;
predicate withoutContent = SC::withoutContent/1;
predicate withContent = SC::withContent/1;
class SyntheticGlobal = SC::SyntheticGlobal;
/** Gets a summary component that represents a receiver. */
SummaryComponent receiver() { result = argument(any(ParameterPosition pos | pos.isSelf())) }
/** Gets a summary component that represents a block argument. */
SummaryComponent block() { result = argument(any(ParameterPosition pos | pos.isBlock())) }
/** Gets a summary component that represents an element in a collection at an unknown index. */
SummaryComponent elementUnknown() {
result = SC::content(TSingletonContent(TUnknownElementContent()))
}
/** Gets a summary component that represents an element in a collection at a known index. */
SummaryComponent elementKnown(ConstantValue cv) {
result = SC::content(TSingletonContent(DataFlow::Content::getElementContent(cv)))
}
/**
* Gets a summary component that represents an element in a collection at a specific
* known index `cv`, or an unknown index.
*/
SummaryComponent elementKnownOrUnknown(ConstantValue cv) {
result = SC::content(TKnownOrUnknownElementContent(TKnownElementContent(cv)))
or
not exists(TKnownElementContent(cv)) and
result = elementUnknown()
}
/**
* Gets a summary component that represents an element in a collection at either an unknown
* index or known index. This has the same semantics as
*
* ```ql
* elementKnown() or elementUnknown(_)
* ```
*
* but is more efficient, because it is represented by a single value.
*/
SummaryComponent elementAny() { result = SC::content(TAnyElementContent()) }
/**
* Gets a summary component that represents an element in a collection at known
* integer index `lower` or above.
*/
SummaryComponent elementLowerBound(int lower) {
result = SC::content(TElementLowerBoundContent(lower, false))
}
/**
* Gets a summary component that represents an element in a collection at known
* integer index `lower` or above, or possibly at an unknown index.
*/
SummaryComponent elementLowerBoundOrUnknown(int lower) {
result = SC::content(TElementLowerBoundContent(lower, true))
}
/** Gets a summary component that represents the return value of a call. */
SummaryComponent return() { result = SC::return(any(NormalReturnKind rk)) }
}
class SummaryComponentStack = Impl::Public::SummaryComponentStack;
/** Provides predicates for constructing stacks of summary components. */
module SummaryComponentStack {
private import Impl::Public::SummaryComponentStack as SCS
predicate singleton = SCS::singleton/1;
predicate push = SCS::push/2;
predicate argument = SCS::argument/1;
/** Gets a singleton stack representing a receiver. */
SummaryComponentStack receiver() { result = singleton(SummaryComponent::receiver()) }
/** Gets a singleton stack representing a block argument. */
SummaryComponentStack block() { result = singleton(SummaryComponent::block()) }
/** Gets a singleton stack representing the return value of a call. */
SummaryComponentStack return() { result = singleton(SummaryComponent::return()) }
}
deprecated module SummaryComponentStack = Impl::Private::SummaryComponentStack;
/** A callable with a flow summary, identified by a unique string. */
abstract class SummarizedCallable extends LibraryCallable, Impl::Public::SummarizedCallable {
@@ -121,18 +29,11 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari
SummarizedCallable() { any() }
/**
* Same as
*
* ```ql
* propagatesFlow(
* SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
* )
* ```
*
* but uses an external (string) representation of the input and output stacks.
* DEPRECATED: Use `propagatesFlow` instead.
*/
pragma[nomagic]
predicate propagatesFlowExt(string input, string output, boolean preservesValue) { none() }
deprecated predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
this.propagatesFlow(input, output, preservesValue)
}
/**
* Gets the synthesized parameter that results from an input specification
@@ -141,7 +42,7 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari
DataFlow::ParameterNode getParameter(string s) {
exists(ParameterPosition pos |
DataFlowImplCommon::parameterNode(result, TLibraryCallable(this), pos) and
s = getParameterPosition(pos)
s = Impl::Input::encodeParameterPosition(pos)
)
}
}
@@ -159,7 +60,7 @@ abstract class SimpleSummarizedCallable extends SummarizedCallable {
final override MethodCall getACallSimple() { result = mc }
}
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
deprecated class RequiredSummaryComponentStack = Impl::Private::RequiredSummaryComponentStack;
/**
* Provides a set of special flow summaries to ensure that callbacks passed into
@@ -199,7 +100,7 @@ private module LibraryCallbackSummaries {
libraryCallHasLambdaArg(result.getAControlFlowNode(), _)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[block]" and
output = "Argument[block].Parameter[lambda-self]"

View File

@@ -1,182 +0,0 @@
/**
* Module for parsing access paths from MaD models, both the identifying access path used
* by dynamic languages, and the input/output specifications for summary steps.
*
* This file is used by the shared data flow library and by the JavaScript libraries
* (which does not use the shared data flow libraries).
*/
/**
* Convenience-predicate for extracting two capture groups at once.
*/
bindingset[input, regexp]
private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) {
capture1 = input.regexpCapture(regexp, 1) and
capture2 = input.regexpCapture(regexp, 2)
}
/** Companion module to the `AccessPath` class. */
module AccessPath {
/** A string that should be parsed as an access path. */
abstract class Range extends string {
bindingset[this]
Range() { any() }
}
/**
* Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
* of the constant or any value contained in the interval.
*/
bindingset[arg]
int parseInt(string arg) {
result = arg.toInt()
or
// Match "n1..n2"
exists(string lo, string hi |
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and
result = [lo.toInt() .. hi.toInt()]
)
}
/**
* Parses a lower-bounded interval `n..` and gets the lower bound.
*/
bindingset[arg]
int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() }
/**
* Parses an integer constant or interval (bounded or unbounded) that explicitly
* references the arity, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
private int parseIntWithExplicitArity(string arg, int arity) {
result >= 0 and // do not allow N-1 to resolve to a negative index
exists(string lo |
// N-x
lo = arg.regexpCapture("N-(\\d+)", 1) and
result = arity - lo.toInt()
or
// N-x..
lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and
result = [arity - lo.toInt(), arity - 1]
)
or
exists(string lo, string hi |
// x..N-y
regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [lo.toInt() .. arity - hi.toInt()]
or
// N-x..N-y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. arity - hi.toInt()] and
result >= 0
or
// N-x..y
regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and
result = [arity - lo.toInt() .. hi.toInt()] and
result >= 0
)
}
/**
* Parses an integer constant or interval (bounded or unbounded) and gets any
* of the integers contained within (of which there may be infinitely many).
*
* Has no result for arguments involving an explicit arity, such as `N-1`.
*/
bindingset[arg, result]
int parseIntUnbounded(string arg) {
result = parseInt(arg)
or
result >= parseLowerBound(arg)
}
/**
* Parses an integer constant or interval (bounded or unbounded) that
* may reference the arity of a call, such as `N-1` or `N-3..N-1`.
*
* Note that expressions of form `N-x` will never resolve to a negative index,
* even if `N` is zero (it will have no result in that case).
*/
bindingset[arg, arity]
int parseIntWithArity(string arg, int arity) {
result = parseInt(arg)
or
result in [parseLowerBound(arg) .. arity - 1]
or
result = parseIntWithExplicitArity(arg, arity)
}
}
/** Gets the `n`th token on the access path as a string. */
private string getRawToken(AccessPath path, int n) {
// Avoid splitting by '.' since tokens may contain dots, e.g. `Field[foo.Bar.x]`.
// Instead use regexpFind to match valid tokens, and supplement with a final length
// check (in `AccessPath.hasSyntaxError`) to ensure all characters were included in a token.
result = path.regexpFind("\\w+(?:\\[[^\\]]*\\])?(?=\\.|$)", n, _)
}
/**
* A string that occurs as an access path (either identifying or input/output spec)
* which might be relevant for this database.
*/
class AccessPath extends string instanceof AccessPath::Range {
/** Holds if this string is not a syntactically valid access path. */
predicate hasSyntaxError() {
// If the lengths match, all characters must haven been included in a token
// or seen by the `.` lookahead pattern.
this != "" and
not this.length() = sum(int n | | getRawToken(this, n).length() + 1) - 1
}
/** Gets the `n`th token on the access path (if there are no syntax errors). */
AccessPathToken getToken(int n) {
result = getRawToken(this, n) and
not this.hasSyntaxError()
}
/** Gets the number of tokens on the path (if there are no syntax errors). */
int getNumToken() {
result = count(int n | exists(getRawToken(this, n))) and
not this.hasSyntaxError()
}
}
/**
* An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
*/
class AccessPathToken extends string {
AccessPathToken() { this = getRawToken(_, _) }
private string getPart(int part) {
result = this.regexpCapture("([^\\[]+)(?:\\[([^\\]]*)\\])?", part)
}
/** Gets the name of the token, such as `Member` from `Member[x]` */
string getName() { result = this.getPart(1) }
/**
* Gets the argument list, such as `1,2` from `Member[1,2]`,
* or has no result if there are no arguments.
*/
string getArgumentList() { result = this.getPart(2) }
/** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
string getArgument(int n) { result = this.getArgumentList().splitAt(",", n).trim() }
/** Gets the `n`th argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
pragma[nomagic]
string getArgument(string name, int n) { name = this.getName() and result = this.getArgument(n) }
/** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
string getAnArgument() { result = this.getArgument(_) }
/** Gets an argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
string getAnArgument(string name) { result = this.getArgument(name, _) }
/** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
int getNumArgument() { result = count(int n | exists(this.getArgument(n))) }
}

View File

@@ -4,7 +4,6 @@ private import DataFlowPrivate
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
private import codeql.ruby.ast.internal.Module
private import FlowSummaryImpl as FlowSummaryImpl
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.dataflow.FlowSummary
private import codeql.ruby.dataflow.SSA
private import codeql.util.Boolean
@@ -426,14 +425,14 @@ private module Cached {
TPositionalArgumentPosition(int pos) {
exists(Call c | exists(c.getArgument(pos)))
or
FlowSummaryImplSpecific::ParsePositions::isParsedParameterPosition(_, pos)
FlowSummaryImpl::ParsePositions::isParsedParameterPosition(_, pos)
} or
TKeywordArgumentPosition(string name) {
name = any(KeywordParameter kp).getName()
or
exists(any(Call c).getKeywordArgument(name))
or
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordParameterPosition(_, name)
FlowSummaryImpl::ParsePositions::isParsedKeywordParameterPosition(_, name)
} or
THashSplatArgumentPosition() or
TSynthHashSplatArgumentPosition() or
@@ -450,15 +449,17 @@ private module Cached {
TPositionalParameterPosition(int pos) {
pos = any(Parameter p).getPosition()
or
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentPosition(_, pos)
FlowSummaryImpl::ParsePositions::isParsedArgumentPosition(_, pos)
} or
TPositionalParameterLowerBoundPosition(int pos) {
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentLowerBoundPosition(_, pos)
FlowSummaryImpl::ParsePositions::isParsedArgumentLowerBoundPosition(_, pos)
} or
TKeywordParameterPosition(string name) {
name = any(KeywordParameter kp).getName()
or
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name)
exists(any(Call c).getKeywordArgument(name))
or
FlowSummaryImpl::ParsePositions::isParsedKeywordArgumentPosition(_, name)
} or
THashSplatParameterPosition() or
TSynthHashSplatParameterPosition() or

View File

@@ -8,7 +8,6 @@ private import DataFlowPublic
private import DataFlowDispatch
private import SsaImpl as SsaImpl
private import FlowSummaryImpl as FlowSummaryImpl
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.frameworks.data.ModelsAsData
/** Gets the callable in which this node occurs. */
@@ -629,8 +628,7 @@ private module Cached {
TAnyElementContent() or
TKnownOrUnknownElementContent(Content::KnownElementContent c) or
TElementLowerBoundContent(int lower, boolean includeUnknown) {
FlowSummaryImplSpecific::ParsePositions::isParsedElementLowerBoundPosition(_, includeUnknown,
lower)
FlowSummaryImpl::ParsePositions::isParsedElementLowerBoundPosition(_, includeUnknown, lower)
} or
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
type = any(Content::KnownElementContent content).getIndex().getValueType()
@@ -700,6 +698,21 @@ private module Cached {
THashSplatContentApprox(string approx) { approx = approxKnownElementIndex(_) } or
TNonElementContentApprox(Content c) { not c instanceof Content::ElementContent } or
TCapturedVariableContentApprox(VariableCapture::CapturedVariable v)
cached
newtype TDataFlowType =
TLambdaDataFlowType(Callable c) { c = any(LambdaSelfReferenceNode n).getCallable() } or
// In order to reduce the set of cons-candidates, we annotate all implicit (hash) splat
// creations with the name of the method that they are passed into. This includes
// array/hash literals as well (where the name is simply `[]`), because of how they
// are modeled (see `Array.qll` and `Hash.qll`).
TSynthHashSplatArgumentType(string methodName) {
methodName = any(SynthHashSplatArgumentNode n).getMethodName()
} or
TSynthSplatArgumentType(string methodName) {
methodName = any(SynthSplatArgumentNode n).getMethodName()
} or
TUnknownDataFlowType()
}
class TElementContent =
@@ -1254,11 +1267,11 @@ module ArgumentNodes {
}
private class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode {
private DataFlowCall call_;
private SummaryCall call_;
private ArgumentPosition pos_;
SummaryArgumentNode() {
FlowSummaryImpl::Private::summaryArgumentNode(call_, this.getSummaryNode(), pos_)
FlowSummaryImpl::Private::summaryArgumentNode(call_.getReceiver(), this.getSummaryNode(), pos_)
}
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
@@ -1641,11 +1654,11 @@ private module OutNodes {
}
private class SummaryOutNode extends FlowSummaryNode, OutNode {
private DataFlowCall call;
private SummaryCall call;
private ReturnKind kind_;
SummaryOutNode() {
FlowSummaryImpl::Private::summaryOutNode(call, this.getSummaryNode(), kind_)
FlowSummaryImpl::Private::summaryOutNode(call.getReceiver(), this.getSummaryNode(), kind_)
}
override DataFlowCall getCall(ReturnKind kind) { result = call and kind = kind_ }
@@ -1803,20 +1816,6 @@ predicate expectsContent(Node n, ContentSet c) {
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
}
private newtype TDataFlowType =
TLambdaDataFlowType(Callable c) { c = any(LambdaSelfReferenceNode n).getCallable() } or
// In order to reduce the set of cons-candidates, we annotate all implicit (hash) splat
// creations with the name of the method that they are passed into. This includes
// array/hash literals as well (where the name is simply `[]`), because of how they
// are modeled (see `Array.qll` and `Hash.qll`).
TSynthHashSplatArgumentType(string methodName) {
methodName = any(SynthHashSplatArgumentNode n).getMethodName()
} or
TSynthSplatArgumentType(string methodName) {
methodName = any(SynthSplatArgumentNode n).getMethodName()
} or
TUnknownDataFlowType()
class DataFlowType extends TDataFlowType {
string toString() { result = "" }
}
@@ -2043,7 +2042,10 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNodeImpl p) {
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
exists(DataFlowCallable c, ParameterPosition pos |
p.isParameterOf(c, pos) and
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(c.asLibraryCallable(), pos)
)
or
VariableCapture::Flow::heuristicAllowInstanceParameterReturnInSelf(p.(SelfParameterNode)
.getCallable())

File diff suppressed because it is too large Load Diff

View File

@@ -1,430 +0,0 @@
/**
* Provides Ruby specific classes and predicates for defining flow summaries.
*/
private import codeql.ruby.AST
private import DataFlowDispatch
private import DataFlowPrivate
private import DataFlowPublic
private import DataFlowImplCommon
private import FlowSummaryImpl::Private
private import FlowSummaryImpl::Public
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
/**
* A class of callables that are candidates for flow summary modeling.
*/
class SummarizedCallableBase = string;
/**
* A class of callables that are candidates for neutral modeling.
*/
class NeutralCallableBase = string;
DataFlowCallable inject(SummarizedCallable c) { result.asLibraryCallable() = c }
/** Gets the parameter position representing a callback itself, if any. */
ArgumentPosition callbackSelfParameterPosition() { result.isLambdaSelf() }
/** Gets the synthesized data-flow call for `receiver`. */
SummaryCall summaryDataFlowCall(SummaryNode receiver) { receiver = result.getReceiver() }
/** Gets the type of content `c`. */
DataFlowType getContentType(ContentSet c) { any() }
/** Gets the type of the parameter at the given position. */
DataFlowType getParameterType(SummarizedCallable c, ParameterPosition pos) { any() }
/** Gets the return type of kind `rk` for callable `c`. */
bindingset[c, rk]
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { any() }
/**
* Gets the type of the `i`th parameter in a synthesized call that targets a
* callback of type `t`.
*/
bindingset[t, pos]
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) { any() }
/**
* Gets the return type of kind `rk` in a synthesized call that targets a
* callback of type `t`.
*/
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) { any() }
/** Gets the type of synthetic global `sg`. */
DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any() }
/**
* Holds if an external flow summary exists for `c` with input specification
* `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
predicate summaryElement(
FlowSummary::SummarizedCallable c, string input, string output, string kind, string provenance
) {
exists(boolean preservesValue |
c.propagatesFlowExt(input, output, preservesValue) and
(if preservesValue = true then kind = "value" else kind = "taint") and
provenance = "manual"
)
}
/**
* Holds if a neutral model exists for `c` of kind `kind`
* and with provenance `provenance`.
* Note. Neutral models have not been implemented for Ruby.
*/
predicate neutralElement(NeutralCallableBase c, string kind, string provenance) { none() }
bindingset[arg]
private SummaryComponent interpretElementArg(string arg) {
arg = "?" and
result = FlowSummary::SummaryComponent::elementUnknown()
or
arg = "any" and
result = FlowSummary::SummaryComponent::elementAny()
or
exists(int lower, boolean includeUnknown |
ParsePositions::isParsedElementLowerBoundPosition(arg, includeUnknown, lower)
|
includeUnknown = false and
result = FlowSummary::SummaryComponent::elementLowerBound(lower)
or
includeUnknown = true and
result = FlowSummary::SummaryComponent::elementLowerBoundOrUnknown(lower)
)
or
exists(ConstantValue cv, string argAdjusted, boolean includeUnknown |
argAdjusted = ParsePositions::adjustElementArgument(arg, includeUnknown) and
(
includeUnknown = false and
result = FlowSummary::SummaryComponent::elementKnown(cv)
or
includeUnknown = true and
result = FlowSummary::SummaryComponent::elementKnownOrUnknown(cv)
)
|
cv.isInt(AccessPath::parseInt(argAdjusted))
or
not exists(AccessPath::parseInt(argAdjusted)) and
cv.serialize() = argAdjusted
)
}
/**
* Gets the summary component for specification component `c`, if any.
*
* This covers all the Ruby-specific components of a flow summary.
*/
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
exists(string arg, ParameterPosition ppos |
arg = c.getAnArgument("Argument") and
result = FlowSummary::SummaryComponent::argument(ppos)
|
arg = "any" and
ppos.isAny()
or
ppos.isPositionalLowerBound(AccessPath::parseLowerBound(arg))
or
arg = "hash-splat" and
ppos.isHashSplat()
or
arg = "splat" and
ppos.isSplat(0)
)
or
result = interpretElementArg(c.getAnArgument("Element"))
or
result =
FlowSummary::SummaryComponent::content(TSingletonContent(TFieldContent(c.getAnArgument("Field"))))
or
exists(ContentSet cs |
FlowSummary::SummaryComponent::content(cs) = interpretElementArg(c.getAnArgument("WithElement")) and
result = FlowSummary::SummaryComponent::withContent(cs)
)
or
exists(ContentSet cs |
FlowSummary::SummaryComponent::content(cs) =
interpretElementArg(c.getAnArgument("WithoutElement")) and
result = FlowSummary::SummaryComponent::withoutContent(cs)
)
}
private string getContentSpecific(Content c) {
exists(string name | c = TFieldContent(name) and result = "Field[" + name + "]")
or
exists(ConstantValue cv |
c = TKnownElementContent(cv) and result = "Element[" + cv.serialize() + "!]"
)
or
c = TUnknownElementContent() and result = "Element[?]"
}
private string getContentSetSpecific(ContentSet cs) {
exists(Content c | cs = TSingletonContent(c) and result = getContentSpecific(c))
or
cs = TAnyElementContent() and result = "Element[any]"
or
exists(Content::KnownElementContent kec |
cs = TKnownOrUnknownElementContent(kec) and
result = "Element[" + kec.getIndex().serialize() + "]"
)
or
exists(int lower, boolean includeUnknown, string unknown |
cs = TElementLowerBoundContent(lower, includeUnknown) and
(if includeUnknown = true then unknown = "" else unknown = "!") and
result = "Element[" + lower + ".." + unknown + "]"
)
}
/** Gets the textual representation of a summary component in the format used for MaD models. */
string getMadRepresentationSpecific(SummaryComponent sc) {
exists(ContentSet cs | sc = TContentSummaryComponent(cs) and result = getContentSetSpecific(cs))
or
exists(ContentSet cs |
sc = TWithoutContentSummaryComponent(cs) and
result = "WithoutElement[" + getContentSetSpecific(cs) + "]"
)
or
exists(ContentSet cs |
sc = TWithContentSummaryComponent(cs) and
result = "WithElement[" + getContentSetSpecific(cs) + "]"
)
or
exists(ReturnKind rk |
sc = TReturnSummaryComponent(rk) and
not rk = getReturnValueKind() and
result = "ReturnValue[" + rk + "]"
)
}
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
string getParameterPosition(ParameterPosition pos) {
exists(int i |
pos.isPositional(i) and
result = i.toString()
)
or
exists(int i |
pos.isPositionalLowerBound(i) and
result = i + ".."
)
or
exists(string name |
pos.isKeyword(name) and
result = name + ":"
)
or
pos.isSelf() and
result = "self"
or
pos.isLambdaSelf() and
result = "lambda-self"
or
pos.isBlock() and
result = "block"
or
pos.isAny() and
result = "any"
or
pos.isAnyNamed() and
result = "any-named"
or
pos.isHashSplat() and
result = "hash-splat"
or
pos.isSplat(0) and
result = "splat"
}
/** Gets the textual representation of an argument position in the format used for flow summaries. */
string getArgumentPosition(ArgumentPosition pos) {
pos.isSelf() and result = "self"
or
pos.isLambdaSelf() and result = "lambda-self"
or
pos.isBlock() and result = "block"
or
exists(int i |
pos.isPositional(i) and
result = i.toString()
)
or
exists(string name |
pos.isKeyword(name) and
result = name + ":"
)
}
/** Holds if input specification component `c` needs a reference. */
predicate inputNeedsReferenceSpecific(string c) { none() }
/** Holds if output specification component `c` needs a reference. */
predicate outputNeedsReferenceSpecific(string c) { none() }
/** Gets the return kind corresponding to specification `"ReturnValue"`. */
NormalReturnKind getReturnValueKind() { any() }
/**
* All definitions in this module are required by the shared implementation
* (for source/sink interpretation), but they are unused for Ruby, where
* we rely on API graphs instead.
*/
private module UnusedSourceSinkInterpretation {
/**
* Holds if an external source specification exists for `n` with output specification
* `output`, kind `kind`, and provenance `provenance`.
*/
predicate sourceElement(AstNode n, string output, string kind, string provenance) { none() }
/**
* Holds if an external sink specification exists for `n` with input specification
* `input`, kind `kind` and provenance `provenance`.
*/
predicate sinkElement(AstNode n, string input, string kind, string provenance) { none() }
class SourceOrSinkElement = AstNode;
/** An entity used to interpret a source/sink specification. */
class InterpretNode extends AstNode {
/** Gets the element that this node corresponds to, if any. */
SourceOrSinkElement asElement() { none() }
/** Gets the data-flow node that this node corresponds to, if any. */
Node asNode() { none() }
/** Gets the call that this node corresponds to, if any. */
DataFlowCall asCall() { none() }
/** Gets the callable that this node corresponds to, if any. */
DataFlowCallable asCallable() { none() }
/** Gets the target of this call, if any. */
Callable getCallTarget() { none() }
}
/** Provides additional sink specification logic. */
predicate interpretOutputSpecific(string c, InterpretNode mid, InterpretNode node) { none() }
/** Provides additional source specification logic. */
predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode node) { none() }
}
import UnusedSourceSinkInterpretation
module ParsePositions {
private import FlowSummaryImpl
private predicate isParamBody(string body) {
body = any(AccessPathToken tok).getAnArgument("Parameter")
}
private predicate isArgBody(string body) {
body = any(AccessPathToken tok).getAnArgument("Argument")
}
private predicate isElementBody(string body) {
body = any(AccessPathToken tok).getAnArgument(["Element", "WithElement", "WithoutElement"])
}
predicate isParsedParameterPosition(string c, int i) {
isParamBody(c) and
i = AccessPath::parseInt(c)
}
predicate isParsedArgumentPosition(string c, int i) {
isArgBody(c) and
i = AccessPath::parseInt(c)
}
predicate isParsedArgumentLowerBoundPosition(string c, int i) {
isArgBody(c) and
i = AccessPath::parseLowerBound(c)
}
predicate isParsedKeywordParameterPosition(string c, string paramName) {
isParamBody(c) and
c = paramName + ":"
}
predicate isParsedKeywordArgumentPosition(string c, string paramName) {
isArgBody(c) and
c = paramName + ":"
}
bindingset[arg]
string adjustElementArgument(string arg, boolean includeUnknown) {
result = arg.regexpCapture("(.*)!", 1) and
includeUnknown = false
or
result = arg and
not arg.matches("%!") and
includeUnknown = true
}
predicate isParsedElementLowerBoundPosition(string c, boolean includeUnknown, int lower) {
isElementBody(c) and
lower = AccessPath::parseLowerBound(adjustElementArgument(c, includeUnknown))
}
}
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
ArgumentPosition parseParamBody(string s) {
exists(int i |
ParsePositions::isParsedParameterPosition(s, i) and
result.isPositional(i)
)
or
exists(string name |
ParsePositions::isParsedKeywordParameterPosition(s, name) and
result.isKeyword(name)
)
or
s = "self" and
result.isSelf()
or
s = "lambda-self" and
result.isLambdaSelf()
or
s = "block" and
result.isBlock()
or
s = "any" and
result.isAny()
or
s = "any-named" and
result.isAnyNamed()
}
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
ParameterPosition parseArgBody(string s) {
exists(int i |
ParsePositions::isParsedArgumentPosition(s, i) and
result.isPositional(i)
)
or
exists(int i |
ParsePositions::isParsedArgumentLowerBoundPosition(s, i) and
result.isPositionalLowerBound(i)
)
or
exists(string name |
ParsePositions::isParsedKeywordArgumentPosition(s, name) and
result.isKeyword(name)
)
or
s = "self" and
result.isSelf()
or
s = "lambda-self" and
result.isLambdaSelf()
or
s = "block" and
result.isBlock()
or
s = "any" and
result.isAny()
or
s = "any-named" and
result.isAnyNamed()
}

View File

@@ -541,7 +541,7 @@ private module ParamsSummaries {
result = paramsInstance().getAMethodCall(methodReturnsTaintFromSelf()).asExpr().getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = false
@@ -564,7 +564,7 @@ private module ParamsSummaries {
[result.getReceiver(), result.getArgument(0)]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = ["Argument[self]", "Argument[0]"] and
output = "ReturnValue" and
preservesValue = false
@@ -588,7 +588,7 @@ private module ParamsSummaries {
[result.getReceiver(), result.getArgument(0)]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = ["Argument[self]", "Argument[0]"] and
output = ["ReturnValue", "Argument[self]"] and
preservesValue = false

View File

@@ -61,7 +61,7 @@ module ActiveSupport {
]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and output = "ReturnValue" and preservesValue = false
}
}
@@ -75,7 +75,7 @@ module ActiveSupport {
private class IdentitySummary extends SimpleSummarizedCallable {
IdentitySummary() { this = ["presence", "deep_dup"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = true
@@ -109,7 +109,7 @@ module ActiveSupport {
private class ToJsonSummary extends SimpleSummarizedCallable {
ToJsonSummary() { this = "to_json" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = ["Argument[self]", "Argument[self].Element[any]"] and
output = "ReturnValue" and
preservesValue = false
@@ -124,7 +124,7 @@ module ActiveSupport {
private class WithIndifferentAccessSummary extends SimpleSummarizedCallable {
WithIndifferentAccessSummary() { this = "with_indifferent_access" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[any]" and
preservesValue = true
@@ -137,7 +137,7 @@ module ActiveSupport {
private class ReverseMergeSummary extends SimpleSummarizedCallable {
ReverseMergeSummary() { this = ["reverse_merge", "with_defaults"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self,0].WithElement[any]" and
output = "ReturnValue" and
preservesValue = true
@@ -150,7 +150,7 @@ module ActiveSupport {
private class ReverseMergeBangSummary extends SimpleSummarizedCallable {
ReverseMergeBangSummary() { this = ["reverse_merge!", "with_defaults!", "reverse_update"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self,0].WithElement[any]" and
output = ["ReturnValue", "Argument[self]"] and
preservesValue = true
@@ -166,7 +166,7 @@ module ActiveSupport {
]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[?]" and
preservesValue = true
@@ -209,7 +209,7 @@ module ActiveSupport {
final override MethodCall getACall() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
exists(string s | s = getExtractComponent(mc, _) |
input = "Argument[self].Element[" + s + "!]" and
@@ -244,7 +244,7 @@ module ActiveSupport {
private class CompactBlankSummary extends SimpleSummarizedCallable {
CompactBlankSummary() { this = "compact_blank" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[?]" and
preservesValue = true
@@ -254,7 +254,7 @@ module ActiveSupport {
private class ExcludingSummary extends SimpleSummarizedCallable {
ExcludingSummary() { this = ["excluding", "without"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[?]" and
preservesValue = true
@@ -264,7 +264,7 @@ module ActiveSupport {
private class InOrderOfSummary extends SimpleSummarizedCallable {
InOrderOfSummary() { this = "in_order_of" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[?]" and
preservesValue = true
@@ -277,7 +277,7 @@ module ActiveSupport {
private class IncludingSummary extends SimpleSummarizedCallable {
IncludingSummary() { this = "including" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
exists(ArrayIndex i |
input = "Argument[self].Element[" + i + "]" and
@@ -299,7 +299,7 @@ module ActiveSupport {
private class IndexBySummary extends SimpleSummarizedCallable {
IndexBySummary() { this = "index_by" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = ["Argument[block].Parameter[0]", "ReturnValue.Element[?]"] and
preservesValue = true
@@ -309,7 +309,7 @@ module ActiveSupport {
private class IndexWithSummary extends SimpleSummarizedCallable {
IndexWithSummary() { this = "index_with" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "Argument[block].Parameter[0]" and
preservesValue = true
@@ -338,7 +338,7 @@ module ActiveSupport {
override MethodCall getACall() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[0].Element[" + key + "]" and
output = "ReturnValue" and
preservesValue = true
@@ -369,7 +369,7 @@ module ActiveSupport {
override MethodCall getACall() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
exists(string s, int i |
s = getKeyArgument(mc, i) and
input = "Argument[self].Element[0].Element[" + s + "]" and
@@ -392,7 +392,7 @@ module ActiveSupport {
override MethodCall getACall() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any].Element[" + key + "]" and
output = "ReturnValue.Element[any]" and
preservesValue = true
@@ -423,7 +423,7 @@ module ActiveSupport {
override MethodCall getACall() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
exists(string s, int i |
s = getKeyArgument(mc, i) and
input = "Argument[self].Element[any].Element[" + s + "]" and
@@ -436,7 +436,7 @@ module ActiveSupport {
private class SoleSummary extends SimpleSummarizedCallable {
SoleSummary() { this = "sole" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[0]" and
output = "ReturnValue" and
preservesValue = true
@@ -470,7 +470,7 @@ module ActiveSupport {
private class JsonEscapeSummary extends SimpleSummarizedCallable {
JsonEscapeSummary() { this = "json_escape" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false

View File

@@ -25,7 +25,7 @@ module Arel {
result = API::getTopLevelMember("Arel").getAMethodCall("sql").asExpr().getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}

View File

@@ -63,7 +63,7 @@ private class SplatSummary extends SummarizedCallable {
override SplatExpr getACallSimple() { any() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
// *1 = [1]
input = "Argument[self].WithoutElement[any]" and
@@ -82,7 +82,7 @@ private class HashSplatSummary extends SummarizedCallable {
override HashSplatExpr getACallSimple() { any() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].WithElement[any]" and
output = "ReturnValue" and
preservesValue = true

View File

@@ -18,7 +18,7 @@ module Erb {
override MethodCall getACall() { result = any(ErbTemplateNewCall c).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}

View File

@@ -115,7 +115,7 @@ module File {
result = API::getTopLevelMember("File").getAMethodCall(methodName).asExpr().getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false
@@ -133,7 +133,7 @@ module File {
result = API::getTopLevelMember("File").getAMethodCall("join").asExpr().getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0,1..]" and
output = "ReturnValue" and
preservesValue = false

View File

@@ -19,7 +19,7 @@ module NetLdap {
override MethodCall getACall() { result = any(NetLdapConnection l).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}
@@ -32,7 +32,7 @@ module NetLdap {
override MethodCall getACall() { result = any(NetLdapFilter l).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = ["Argument[0]", "Argument[1]"] and output = "ReturnValue" and preservesValue = false
}
}

View File

@@ -18,7 +18,7 @@ module Mysql2 {
override MethodCall getACall() { result = any(Mysql2Connection c).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}
@@ -66,7 +66,7 @@ module Mysql2 {
override MethodCall getACall() { result = any(Mysql2EscapeSanitization c).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}

View File

@@ -18,7 +18,7 @@ module Pg {
override MethodCall getACall() { result = any(PgConnection c).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}

View File

@@ -314,7 +314,7 @@ private predicate isPotentialRenderCall(MethodCall renderCall, Location loc, Erb
// TODO: initialization hooks, e.g. before_configuration, after_initialize...
// TODO: initializers
/** A synthetic global to represent the value passed to the `locals` argument of a render call for a specific ERB file. */
private class LocalAssignsHashSyntheticGlobal extends SummaryComponent::SyntheticGlobal {
private class LocalAssignsHashSyntheticGlobal extends string {
private ErbFile erbFile;
private string id;
// Note that we can't use an actual `Rails::RenderCall` here due to problems with non-monotonic recursion
@@ -346,7 +346,7 @@ private class RenderLocalsSummary extends SummarizedCallable {
override Rails::RenderCall getACall() { result = glob.getARenderCall() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[locals:]" and
output = "SyntheticGlobal[" + glob + "]" and
preservesValue = true
@@ -364,7 +364,7 @@ private class AccessLocalsSummary extends SummarizedCallable {
result.getMethodName() = "local_assigns"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "SyntheticGlobal[" + glob + "]" and
output = "ReturnValue" and
preservesValue = true
@@ -394,7 +394,7 @@ private class AccessLocalsKeySummary extends SummarizedCallable {
result.getReceiver() instanceof SelfVariableReadAccess
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "SyntheticGlobal[" + glob + "].Element[:" + methodName + "]" and
output = "ReturnValue" and
preservesValue = true

View File

@@ -19,7 +19,7 @@ module Sequel {
override MethodCall getACall() { result = any(SequelConnection c).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}

View File

@@ -133,7 +133,7 @@ module Sinatra {
/**
* A synthetic global representing the hash of local variables passed to an ERB template.
*/
class ErbLocalsHashSyntheticGlobal extends SummaryComponent::SyntheticGlobal {
class ErbLocalsHashSyntheticGlobal extends string {
private string id;
private MethodCall erbCall;
private ErbFile erbFile;
@@ -172,7 +172,7 @@ module Sinatra {
override MethodCall getACall() { result = any(ErbCall c).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[locals:]" and
output = "SyntheticGlobal[" + any(ErbLocalsHashSyntheticGlobal global) + "]" and
preservesValue = true
@@ -207,7 +207,7 @@ module Sinatra {
result.getReceiver() instanceof SelfVariableReadAccess
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "SyntheticGlobal[" + global + "].Element[:" + local + "]" and
output = "ReturnValue" and
preservesValue = true

View File

@@ -94,7 +94,7 @@ module Sqlite3 {
override MethodCall getACall() { result = any(SQLite3QuoteSanitization c).asExpr().getExpr() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@ private class Base64Decode extends SummarizedCallable {
.getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false

View File

@@ -31,7 +31,7 @@ module Hash {
final override MethodCall getACallSimple() { result = getAStaticHashCall("[]") }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
// we make use of the special `hash-splat` argument kind, which contains all keyword
// arguments wrapped in an implicit hash, as well as explicit hash splat arguments
input = "Argument[hash-splat]" and
@@ -62,7 +62,7 @@ module Hash {
result.getNumberOfArguments() = 1
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
// Hash[{symbol: x}]
input = "Argument[0].WithElement[any]" and
@@ -102,7 +102,7 @@ module Hash {
exists(result.getArgument(i))
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
// Hash[:symbol, x]
input = "Argument[" + i + "]" and
output = "ReturnValue.Element[" + key.serialize() + "]" and
@@ -115,7 +115,7 @@ module Hash {
override MethodCall getACallSimple() { result = getAStaticHashCall("try_convert") }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0].WithElement[any]" and
output = "ReturnValue" and
preservesValue = true
@@ -130,7 +130,7 @@ module Hash {
final override MethodCall getACallSimple() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[1]" and
output = "ReturnValue" and
preservesValue = true
@@ -145,8 +145,8 @@ module Hash {
this = "store(" + key.serialize() + ")"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
super.propagatesFlowExt(input, output, preservesValue)
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
super.propagatesFlow(input, output, preservesValue)
or
input = "Argument[1]" and
output = "Argument[self].Element[" + key.serialize() + "]" and
@@ -164,8 +164,8 @@ module Hash {
this = "store"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
super.propagatesFlowExt(input, output, preservesValue)
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
super.propagatesFlow(input, output, preservesValue)
or
input = "Argument[1]" and
output = "Argument[self].Element[?]" and
@@ -192,7 +192,7 @@ module Hash {
key = DataFlow::Content::getKnownElementIndex(mc.getArgument(0))
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[" + key.serialize() + "]" and
output = "ReturnValue.Element[1]" and
preservesValue = true
@@ -208,7 +208,7 @@ module Hash {
not exists(DataFlow::Content::getKnownElementIndex(result.getArgument(0)))
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any].WithoutElement[any]" and
output = "ReturnValue.Element[1]" and
preservesValue = true
@@ -218,7 +218,7 @@ module Hash {
private class EachPairSummary extends SimpleSummarizedCallable {
EachPairSummary() { this = "each_pair" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self].Element[any]" and
output = "Argument[block].Parameter[1]"
@@ -233,7 +233,7 @@ module Hash {
private class EachValueSummary extends SimpleSummarizedCallable {
EachValueSummary() { this = "each_value" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self].Element[any]" and
output = "Argument[block].Parameter[0]"
@@ -264,7 +264,7 @@ module Hash {
final override MethodCall getACallSimple() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input =
"Argument[self]" +
concat(int i, string s |
@@ -290,7 +290,7 @@ abstract private class FetchValuesSummary extends SummarizedCallable {
final override MethodCall getACallSimple() { result = mc }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self].WithElement[?]" and
output = "ReturnValue"
@@ -314,8 +314,8 @@ private class FetchValuesKnownSummary extends FetchValuesSummary {
this = "fetch_values(" + key.serialize() + ")"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
super.propagatesFlowExt(input, output, preservesValue)
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
super.propagatesFlow(input, output, preservesValue)
or
input = "Argument[self].Element[" + key.serialize() + "]" and
output = "ReturnValue.Element[?]" and
@@ -329,8 +329,8 @@ private class FetchValuesUnknownSummary extends FetchValuesSummary {
this = "fetch_values(?)"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
super.propagatesFlowExt(input, output, preservesValue)
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
super.propagatesFlow(input, output, preservesValue)
or
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[?]" and
@@ -345,7 +345,7 @@ private class MergeSummary extends SimpleSummarizedCallable {
this = ["merge", "deep_merge"]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self,any].WithElement[any]" and
output = "ReturnValue"
@@ -364,7 +364,7 @@ private class MergeBangSummary extends SimpleSummarizedCallable {
this = ["merge!", "deep_merge!", "update"]
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self,any].WithElement[any]" and
output = ["ReturnValue", "Argument[self]"]
@@ -379,7 +379,7 @@ private class MergeBangSummary extends SimpleSummarizedCallable {
private class RassocSummary extends SimpleSummarizedCallable {
RassocSummary() { this = "rassoc" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any].WithoutElement[any]" and
output = "ReturnValue.Element[1]" and
preservesValue = true
@@ -404,7 +404,7 @@ private class SliceKnownSummary extends SliceSummary {
not key.isInt(_) // covered in `Array.qll`
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].WithElement[" + key.serialize() + "]" and
output = "ReturnValue" and
preservesValue = true
@@ -417,7 +417,7 @@ private class SliceUnknownSummary extends SliceSummary {
this = "slice(?)"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].WithoutElement[0..!].WithElement[any]" and
output = "ReturnValue" and
preservesValue = true
@@ -427,7 +427,7 @@ private class SliceUnknownSummary extends SliceSummary {
private class ToASummary extends SimpleSummarizedCallable {
ToASummary() { this = "to_a" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].WithoutElement[0..!].Element[any]" and
output = "ReturnValue.Element[?].Element[1]" and
preservesValue = true
@@ -437,7 +437,7 @@ private class ToASummary extends SimpleSummarizedCallable {
private class ToHWithoutBlockSummary extends SimpleSummarizedCallable {
ToHWithoutBlockSummary() { this = ["to_h", "to_hash"] and not exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].WithElement[any]" and
output = "ReturnValue" and
preservesValue = true
@@ -447,7 +447,7 @@ private class ToHWithoutBlockSummary extends SimpleSummarizedCallable {
private class ToHWithBlockSummary extends SimpleSummarizedCallable {
ToHWithBlockSummary() { this = "to_h" and exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self].Element[any]" and
output = "Argument[block].Parameter[1]"
@@ -462,7 +462,7 @@ private class ToHWithBlockSummary extends SimpleSummarizedCallable {
private class TransformKeysSummary extends SimpleSummarizedCallable {
TransformKeysSummary() { this = "transform_keys" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[?]" and
preservesValue = true
@@ -472,7 +472,7 @@ private class TransformKeysSummary extends SimpleSummarizedCallable {
private class TransformKeysBangSummary extends SimpleSummarizedCallable {
TransformKeysBangSummary() { this = "transform_keys!" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self].Element[any]" and
output = "Argument[self].Element[?]"
@@ -484,7 +484,7 @@ private class TransformKeysBangSummary extends SimpleSummarizedCallable {
private class TransformValuesSummary extends SimpleSummarizedCallable {
TransformValuesSummary() { this = "transform_values" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self].Element[any]" and
output = "Argument[block].Parameter[0]"
@@ -499,7 +499,7 @@ private class TransformValuesSummary extends SimpleSummarizedCallable {
private class TransformValuesBangSummary extends SimpleSummarizedCallable {
TransformValuesBangSummary() { this = "transform_values!" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
input = "Argument[self].Element[any]" and
output = "Argument[block].Parameter[0]"
@@ -517,7 +517,7 @@ private class TransformValuesBangSummary extends SimpleSummarizedCallable {
private class ValuesSummary extends SimpleSummarizedCallable {
ValuesSummary() { this = "values" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self].Element[any]" and
output = "ReturnValue.Element[?]" and
preservesValue = true

View File

@@ -177,7 +177,7 @@ module Kernel {
private class TapSummary extends SimpleSummarizedCallable {
TapSummary() { this = "tap" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = ["ReturnValue", "Argument[block].Parameter[0]"] and
preservesValue = true
@@ -219,7 +219,7 @@ module Kernel {
)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
(
// already an array
input = "Argument[0].WithElement[0..]" and

View File

@@ -36,7 +36,7 @@ module Object {
private class DupSummary extends SimpleSummarizedCallable {
DupSummary() { this = "dup" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = true

View File

@@ -127,7 +127,7 @@ module String {
result = API::getTopLevelMember("String").getAnInstantiation().getExprNode().getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = true
@@ -142,7 +142,7 @@ module String {
API::getTopLevelMember("String").getAMethodCall("try_convert").getExprNode().getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false
@@ -155,7 +155,7 @@ module String {
private class FormatSummary extends SimpleSummarizedCallable {
FormatSummary() { this = "%" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = ["Argument[self]", "Argument[0]", "Argument[0].Element[any]"] and
output = "ReturnValue" and
preservesValue = false
@@ -169,7 +169,7 @@ module String {
private class BSummary extends SimpleSummarizedCallable {
BSummary() { this = "b" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -180,7 +180,7 @@ module String {
private class BytesliceSummary extends SimpleSummarizedCallable {
BytesliceSummary() { this = "byteslice" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -191,7 +191,7 @@ module String {
private class CapitalizeSummary extends SimpleSummarizedCallable {
CapitalizeSummary() { this = ["capitalize", "capitalize!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
preservesValue = false and
output = "ReturnValue"
@@ -204,7 +204,7 @@ module String {
private class CenterSummary extends SimpleSummarizedCallable {
CenterSummary() { this = ["center", "ljust", "rjust"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
or
input = "Argument[1]" and
@@ -219,7 +219,7 @@ module String {
private class ChompSummary extends SimpleSummarizedCallable {
ChompSummary() { this = ["chomp", "chomp!", "chop", "chop!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
or
this = ["chomp!", "chop!"] and
@@ -236,6 +236,10 @@ module String {
*/
private class ClearSummary extends SimpleSummarizedCallable {
ClearSummary() { none() }
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
none()
}
}
/**
@@ -249,7 +253,7 @@ module String {
none()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self,0..]" and
output = ["ReturnValue", "Argument[self]"] and
preservesValue = false
@@ -262,7 +266,7 @@ module String {
private class DeleteSummary extends SimpleSummarizedCallable {
DeleteSummary() { this = ["delete", "delete_prefix", "delete_suffix"] + ["", "!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -273,7 +277,7 @@ module String {
private class DowncaseSummary extends SimpleSummarizedCallable {
DowncaseSummary() { this = ["downcase", "upcase", "swapcase"] + ["", "!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -284,7 +288,7 @@ module String {
private class DumpSummary extends SimpleSummarizedCallable {
DumpSummary() { this = ["dump", "undump"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -308,7 +312,7 @@ module String {
private class EachLineBlockSummary extends EachLineSummary {
EachLineBlockSummary() { this = "each_line_with_block" and exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = false and
input = "Argument[self]" and
output = ["Argument[block].Parameter[0]", "ReturnValue"]
@@ -321,7 +325,7 @@ module String {
private class EachLineNoBlockSummary extends EachLineSummary {
EachLineNoBlockSummary() { this = "each_line_without_block" and not exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = false and
input = "Argument[self]" and
output = "ReturnValue.Element[?]"
@@ -334,7 +338,7 @@ module String {
private class EncodeSummary extends SimpleSummarizedCallable {
EncodeSummary() { this = ["encode", "unicode_normalize"] + ["", "!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -345,7 +349,7 @@ module String {
private class ForceEncodingSummary extends SimpleSummarizedCallable {
ForceEncodingSummary() { this = "force_encoding" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -356,7 +360,7 @@ module String {
private class FreezeSummary extends SimpleSummarizedCallable {
FreezeSummary() { this = "freeze" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -370,7 +374,7 @@ module String {
// str.gsub(pattern, replacement) -> new_str
// str.gsub(pattern) {|match| block } -> new_str
// str.gsub(pattern) -> enumerator of matches
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
// receiver -> return value
// replacement -> return value
// block return -> return value
@@ -390,7 +394,7 @@ module String {
none()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
or
input = "Argument[1]" and output = "ReturnValue" and preservesValue = false
@@ -403,7 +407,7 @@ module String {
private class InspectSummary extends SimpleSummarizedCallable {
InspectSummary() { this = "inspect" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -414,7 +418,7 @@ module String {
private class StripSummary extends SimpleSummarizedCallable {
StripSummary() { this = ["strip", "lstrip", "rstrip"] + ["", "!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -425,7 +429,7 @@ module String {
private class NextSummary extends SimpleSummarizedCallable {
NextSummary() { this = ["next", "succ"] + ["", "!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -436,7 +440,7 @@ module String {
private class PartitionSummary extends SimpleSummarizedCallable {
PartitionSummary() { this = ["partition", "rpartition"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = "ReturnValue.Element[0,1,2]" and
preservesValue = false
@@ -449,7 +453,7 @@ module String {
private class ReplaceSummary extends SimpleSummarizedCallable {
ReplaceSummary() { this = "replace" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = ["ReturnValue", "Argument[self]"] and
preservesValue = false
@@ -463,7 +467,7 @@ module String {
private class ReverseSummary extends SimpleSummarizedCallable {
ReverseSummary() { this = ["reverse", "reverse!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -483,7 +487,7 @@ module String {
private class ScanBlockSummary extends ScanSummary {
ScanBlockSummary() { this = "scan_with_block" and exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
preservesValue = false and
output =
@@ -500,7 +504,7 @@ module String {
private class ScanNoBlockSummary extends ScanSummary {
ScanNoBlockSummary() { this = "scan_no_block" and not exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
// scan(pattern) -> array
input = "Argument[self]" and
output = "ReturnValue.Element[?]" and
@@ -523,7 +527,7 @@ module String {
private class ScrubBlockSummary extends ScrubSummary {
ScrubBlockSummary() { this = "scrub_block" and exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
or
preservesValue = false and
@@ -542,7 +546,7 @@ module String {
private class ScrubNoBlockSummary extends ScrubSummary {
ScrubNoBlockSummary() { this = "scrub_no_block" and not exists(mc.getBlock()) }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
or
preservesValue = false and
@@ -557,7 +561,7 @@ module String {
private class ShellescapeSummary extends SimpleSummarizedCallable {
ShellescapeSummary() { this = "shellescape" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -568,7 +572,7 @@ module String {
private class ShellSplitSummary extends SimpleSummarizedCallable {
ShellSplitSummary() { this = "shellsplit" }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = "ReturnValue.Element[?]" and
preservesValue = false
@@ -581,7 +585,7 @@ module String {
private class SliceSummary extends SimpleSummarizedCallable {
SliceSummary() { this = ["slice", "slice!", "split", "[]"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -592,7 +596,7 @@ module String {
private class SqueezeSummary extends SimpleSummarizedCallable {
SqueezeSummary() { this = ["squeeze", "squeeze!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -603,7 +607,7 @@ module String {
private class ToStrSummary extends SimpleSummarizedCallable {
ToStrSummary() { this = ["to_str", "to_s"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
}
}
@@ -614,7 +618,7 @@ module String {
private class TrSummary extends SimpleSummarizedCallable {
TrSummary() { this = ["tr", "tr_s"] + ["", "!"] }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
or
input = "Argument[1]" and output = "ReturnValue" and preservesValue = false
@@ -646,7 +650,7 @@ module String {
}
// TODO: if second arg ('exclusive') is true, the first arg is excluded
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
taintIdentityFlow(input, output, preservesValue)
or
input = ["Argument[self]", "Argument[0]"] and
@@ -668,7 +672,7 @@ module String {
mc.getArgument(1).getConstantValue().isBoolean(true)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[self]" and
output = "Argument[block].Parameter[0]" and
preservesValue = false

View File

@@ -48,7 +48,7 @@ private class SummarizedCallableFromModel extends SummarizedCallable {
)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
exists(string kind | ModelOutput::relevantSummaryModel(type, path, input, output, kind) |
kind = "value" and
preservesValue = true

View File

@@ -70,8 +70,8 @@ private module API = Specific::API;
private module DataFlow = Specific::DataFlow;
private import Specific::AccessPathSyntax
private import ApiGraphModelsExtensions as Extensions
import codeql.dataflow.internal.AccessPathSyntax
/** Module containing hooks for providing input data to be interpreted as a model. */
module ModelInput {
@@ -327,29 +327,29 @@ predicate isRelevantFullPath(string type, string path) {
}
/** A string from a CSV row that should be parsed as an access path. */
private class AccessPathRange extends AccessPath::Range {
AccessPathRange() {
isRelevantFullPath(_, this)
or
exists(string type | isRelevantType(type) |
summaryModel(type, _, this, _, _) or
summaryModel(type, _, _, this, _)
)
or
typeVariableModel(_, this)
}
private predicate accessPathRange(string s) {
isRelevantFullPath(_, s)
or
exists(string type | isRelevantType(type) |
summaryModel(type, _, s, _, _) or
summaryModel(type, _, _, s, _)
)
or
typeVariableModel(_, s)
}
import AccessPath<accessPathRange/1>
/**
* Gets a successor of `node` in the API graph.
*/
bindingset[token]
API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) {
API::Node getSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
// API graphs use the same label for arguments and parameters. An edge originating from a
// use-node represents an argument, and an edge originating from a def-node represents a parameter.
// We just map both to the same thing.
token.getName() = ["Argument", "Parameter"] and
result = node.getParameter(AccessPath::parseIntUnbounded(token.getAnArgument()))
result = node.getParameter(parseIntUnbounded(token.getAnArgument()))
or
token.getName() = "ReturnValue" and
result = node.getReturn()
@@ -362,11 +362,9 @@ API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) {
* Gets an API-graph successor for the given invocation.
*/
bindingset[token]
API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathToken token) {
API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathTokenBase token) {
token.getName() = "Argument" and
result =
invoke
.getParameter(AccessPath::parseIntWithArity(token.getAnArgument(), invoke.getNumArgument()))
result = invoke.getParameter(parseIntWithArity(token.getAnArgument(), invoke.getNumArgument()))
or
token.getName() = "ReturnValue" and
result = invoke.getReturn()
@@ -378,10 +376,12 @@ API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathToken to
/**
* Holds if `invoke` invokes a call-site filter given by `token`.
*/
pragma[inline]
private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, AccessPathToken token) {
bindingset[token]
private predicate invocationMatchesCallSiteFilter(
Specific::InvokeNode invoke, AccessPathTokenBase token
) {
token.getName() = "WithArity" and
invoke.getNumArgument() = AccessPath::parseIntUnbounded(token.getAnArgument())
invoke.getNumArgument() = parseIntUnbounded(token.getAnArgument())
or
Specific::invocationMatchesExtraCallSiteFilter(invoke, token)
}

View File

@@ -4,14 +4,13 @@
* It must export the following members:
* ```ql
* class Unit // a unit type
* module AccessPathSyntax // a re-export of the AccessPathSyntax module
* class InvokeNode // a type representing an invocation connected to the API graph
* module API // the API graph module
* predicate isPackageUsed(string package)
* API::Node getExtraNodeFromPath(string package, string type, string path, int n)
* API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token)
* API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathToken token)
* predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathToken token)
* API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token)
* API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathTokenBase token)
* predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathTokenBase token)
* InvokeNode getAnInvocationOf(API::Node node)
* predicate isExtraValidTokenNameInIdentifyingAccessPath(string name)
* predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name)
@@ -21,13 +20,11 @@
private import codeql.ruby.AST
private import ApiGraphModels
private import codeql.ruby.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
// Re-export libraries needed by ApiGraphModels.qll
import codeql.ruby.ApiGraphs
import codeql.ruby.dataflow.internal.AccessPathSyntax as AccessPathSyntax
import codeql.ruby.DataFlow::DataFlow as DataFlow
private import AccessPathSyntax
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.dataflow.internal.FlowSummaryImpl::Public
private import FlowSummaryImpl::Public
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
pragma[nomagic]
@@ -140,7 +137,7 @@ private predicate methodMatchedByName(AccessPath path, string methodName) {
* Gets a Ruby-specific API graph successor of `node` reachable by resolving `token`.
*/
bindingset[token]
API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) {
API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
token.getName() = "Member" and
result = node.getMember(token.getAnArgument())
or
@@ -152,13 +149,13 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) {
or
token.getName() = "Parameter" and
exists(DataFlowDispatch::ArgumentPosition argPos, DataFlowDispatch::ParameterPosition paramPos |
argPos = FlowSummaryImplSpecific::parseParamBody(token.getAnArgument()) and
token.getAnArgument() = FlowSummaryImpl::Input::encodeArgumentPosition(argPos) and
DataFlowDispatch::parameterMatch(paramPos, argPos) and
result = node.getParameterAtPosition(paramPos)
)
or
exists(DataFlow::ContentSet contents |
SummaryComponent::content(contents) = FlowSummaryImplSpecific::interpretComponentSpecific(token) and
token.getName() = FlowSummaryImpl::Input::encodeContent(contents, token.getAnArgument()) and
result = node.getContents(contents)
)
}
@@ -167,10 +164,10 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) {
* Gets a Ruby-specific API graph successor of `node` reachable by resolving `token`.
*/
bindingset[token]
API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathToken token) {
API::Node getExtraSuccessorFromInvoke(InvokeNode node, AccessPathTokenBase token) {
token.getName() = "Argument" and
exists(DataFlowDispatch::ArgumentPosition argPos, DataFlowDispatch::ParameterPosition paramPos |
paramPos = FlowSummaryImplSpecific::parseArgBody(token.getAnArgument()) and
token.getAnArgument() = FlowSummaryImpl::Input::encodeParameterPosition(paramPos) and
DataFlowDispatch::parameterMatch(paramPos, argPos) and
result = node.getArgumentAtPosition(argPos)
)
@@ -199,7 +196,7 @@ API::Node getAFuzzySuccessor(API::Node node) {
* Holds if `invoke` matches the Ruby-specific call site filter in `token`.
*/
bindingset[token]
predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathToken token) {
predicate invocationMatchesExtraCallSiteFilter(InvokeNode invoke, AccessPathTokenBase token) {
token.getName() = "WithBlock" and
exists(invoke.getBlock())
or

View File

@@ -22,7 +22,7 @@ module Utils {
.getExpr()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and output = "ReturnValue" and preservesValue = false
}
}

View File

@@ -5,6 +5,7 @@
*/
private import TypeTrackerSpecific
private import codeql.util.Boolean
cached
private module Cached {

View File

@@ -1,16 +1,7 @@
private import codeql.ruby.AST as Ast
private import codeql.ruby.CFG as Cfg
private import Cfg::CfgNodes
private import codeql.ruby.dataflow.FlowSummary
private import codeql.ruby.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
private import codeql.ruby.dataflow.internal.DataFlowPublic as DataFlowPublic
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
private import codeql.ruby.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.dataflow.internal.AccessPathSyntax
private import internal.TypeTrackingImpl as TypeTrackingImpl
import codeql.util.Boolean
deprecated import codeql.util.Boolean
deprecated class Node = DataFlowPublic::Node;

View File

@@ -11,8 +11,6 @@ private import codeql.ruby.dataflow.internal.DataFlowPublic as DataFlowPublic
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
private import codeql.ruby.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.dataflow.internal.AccessPathSyntax
/** Holds if there is direct flow from `param` to a return. */
pragma[nomagic]
@@ -170,30 +168,30 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
}
// Summaries and their stacks
class SummaryComponent = FlowSummary::SummaryComponent;
class SummaryComponent = FlowSummaryImpl::Private::SummaryComponent;
class SummaryComponentStack = FlowSummary::SummaryComponentStack;
class SummaryComponentStack = FlowSummaryImpl::Private::SummaryComponentStack;
predicate singleton = FlowSummary::SummaryComponentStack::singleton/1;
predicate singleton = FlowSummaryImpl::Private::SummaryComponentStack::singleton/1;
predicate push = FlowSummary::SummaryComponentStack::push/2;
predicate push = FlowSummaryImpl::Private::SummaryComponentStack::push/2;
// Relating content to summaries
predicate content = FlowSummary::SummaryComponent::content/1;
predicate content = FlowSummaryImpl::Private::SummaryComponent::content/1;
predicate withoutContent = FlowSummary::SummaryComponent::withoutContent/1;
predicate withoutContent = FlowSummaryImpl::Private::SummaryComponent::withoutContent/1;
predicate withContent = FlowSummary::SummaryComponent::withContent/1;
predicate withContent = FlowSummaryImpl::Private::SummaryComponent::withContent/1;
predicate return = FlowSummary::SummaryComponent::return/0;
predicate return = FlowSummaryImpl::Private::SummaryComponent::return/0;
// Callables
class SummarizedCallable = FlowSummary::SummarizedCallable;
class SummarizedCallable = FlowSummaryImpl::Private::SummarizedCallableImpl;
// Relating nodes to summaries
Node argumentOf(Node call, SummaryComponent arg, boolean isPostUpdate) {
exists(DataFlowDispatch::ParameterPosition pos, DataFlowPrivate::ArgumentNode n |
arg = FlowSummary::SummaryComponent::argument(pos) and
arg = FlowSummaryImpl::Private::SummaryComponent::argument(pos) and
argumentPositionMatch(call.asExpr(), n, pos)
|
isPostUpdate = false and result = n
@@ -204,7 +202,7 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
Node parameterOf(Node callable, SummaryComponent param) {
exists(DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos |
param = FlowSummary::SummaryComponent::parameter(apos) and
param = FlowSummaryImpl::Private::SummaryComponent::parameter(apos) and
DataFlowDispatch::parameterMatch(ppos, apos) and
result
.(DataFlowPrivate::ParameterNodeImpl)
@@ -213,13 +211,15 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
}
Node returnOf(Node callable, SummaryComponent return) {
return = FlowSummary::SummaryComponent::return() and
return = FlowSummaryImpl::Private::SummaryComponent::return() and
result.(DataFlowPrivate::ReturnNode).(DataFlowPrivate::NodeImpl).getCfgScope() =
callable.asExpr().getExpr()
}
// Relating callables to nodes
Node callTo(SummarizedCallable callable) { result.asExpr().getExpr() = callable.getACallSimple() }
Node callTo(SummarizedCallable callable) {
result.asExpr().getExpr() = callable.(FlowSummary::SummarizedCallable).getACallSimple()
}
}
private module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow<SummaryTypeTrackerInput>;

View File

@@ -4,7 +4,6 @@ private import ruby
private import codeql.ruby.dataflow.FlowSummary
private import codeql.ruby.dataflow.internal.DataFlowPrivate
private import codeql.ruby.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific
private import codeql.ruby.frameworks.core.Gem
private import codeql.ruby.frameworks.data.ModelsAsData
private import codeql.ruby.frameworks.data.internal.ApiGraphModelsExtensions

View File

@@ -1,16 +1,15 @@
import ruby
import codeql.dataflow.internal.AccessPathSyntax
import codeql.ruby.ast.internal.TreeSitter
import codeql.ruby.dataflow.internal.AccessPathSyntax
import codeql.ruby.frameworks.data.internal.ApiGraphModels
import codeql.ruby.frameworks.data.internal.ApiGraphModels as ApiGraphModels
import codeql.ruby.ApiGraphs
import TestUtilities.InlineExpectationsTest
class AccessPathFromExpectation extends AccessPath::Range {
AccessPathFromExpectation() { hasExpectationWithValue(_, this) }
}
private predicate accessPathRange(string s) { hasExpectationWithValue(_, s) }
import AccessPath<accessPathRange/1>
API::Node evaluatePath(AccessPath path, int n) {
path instanceof AccessPathFromExpectation and
n = 1 and
exists(AccessPathToken token | token = path.getToken(0) |
token.getName() = "Member" and
@@ -23,9 +22,9 @@ API::Node evaluatePath(AccessPath path, int n) {
result = token.getAnArgument().(API::EntryPoint).getANode()
)
or
result = getSuccessorFromNode(evaluatePath(path, n - 1), path.getToken(n - 1))
result = ApiGraphModels::getSuccessorFromNode(evaluatePath(path, n - 1), path.getToken(n - 1))
or
result = getSuccessorFromInvoke(evaluatePath(path, n - 1), path.getToken(n - 1))
result = ApiGraphModels::getSuccessorFromInvoke(evaluatePath(path, n - 1), path.getToken(n - 1))
or
// TODO this is a workaround, support parsing of Method['[]'] instead
path.getToken(n - 1).getName() = "MethodBracket" and

View File

@@ -16,7 +16,7 @@ abstract private class Summary extends SimpleSummarizedCallable {
bindingset[this]
Summary() { any() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
this.propagates(input, output) and preservesValue = true
}

View File

@@ -7,13 +7,12 @@ import codeql.ruby.ApiGraphs
import codeql.ruby.dataflow.FlowSummary
import codeql.ruby.TaintTracking
import codeql.ruby.dataflow.internal.FlowSummaryImpl
import codeql.ruby.dataflow.internal.AccessPathSyntax
import codeql.ruby.frameworks.data.ModelsAsData
import TestUtilities.InlineFlowTest
import PathGraph
query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c) {
(sc.propagatesFlowExt(s, _, _) or sc.propagatesFlowExt(_, s, _)) and
(sc.propagatesFlow(s, _, _) or sc.propagatesFlow(_, s, _)) and
Private::External::invalidSpecComponent(s, c)
}
@@ -24,7 +23,7 @@ private class SummarizedCallableIdentity extends SummarizedCallable {
override MethodCall getACall() { result.getMethodName() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = true
@@ -36,7 +35,7 @@ private class SummarizedCallableApplyBlock extends SummarizedCallable {
override MethodCall getACall() { result.getMethodName() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "Argument[block].Parameter[0]" and
preservesValue = true
@@ -52,7 +51,7 @@ private class SummarizedCallableApplyLambda extends SummarizedCallable {
override MethodCall getACall() { result.getMethodName() = this }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = "Argument[1]" and
output = "Argument[0].Parameter[0]" and
preservesValue = true