mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge pull request #7985 from github/nickrolfe/constant_regexp
Ruby: separate constant propagation of regexps from strings
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Whereas `ConstantValue::getString()` previously returned both string and regular-expression values, it now returns only string values. The same applies to `ConstantValue::isString(value)`.
|
||||
* Regular-expression values can now be accessed with the new predicates `ConstantValue::getRegExp()`, `ConstantValue::isRegExp(value)`, and `ConstantValue::isRegExpWithFlags(value, flags)`.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* `ConstantValue::getStringOrSymbol` and `ConstantValue::isStringOrSymbol`, which return/hold for all string-like values (strings, symbols, and regular expressions), have been renamed to `ConstantValue::getStringlikeValue` and `ConstantValue::isStringlikeValue`, respectively. The old names have been marked as `deprecated`.
|
||||
@@ -268,7 +268,7 @@ module HTTP {
|
||||
string getUrlPattern() {
|
||||
exists(CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
|
||||
this.getUrlPatternArg().getALocalSource() = DataFlow::exprNode(strNode) and
|
||||
result = strNode.getExpr().getConstantValue().getStringOrSymbol()
|
||||
result = strNode.getExpr().getConstantValue().getStringlikeValue()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ module HTTP {
|
||||
string getMimetype() {
|
||||
exists(CfgNodes::ExprNodes::StringlikeLiteralCfgNode strNode |
|
||||
this.getMimetypeOrContentTypeArg().getALocalSource() = DataFlow::exprNode(strNode) and
|
||||
result = strNode.getExpr().getConstantValue().getStringOrSymbol().splitAt(";", 0)
|
||||
result = strNode.getExpr().getConstantValue().getStringlikeValue().splitAt(";", 0)
|
||||
)
|
||||
or
|
||||
not exists(this.getMimetypeOrContentTypeArg()) and
|
||||
|
||||
@@ -8,28 +8,37 @@ private import internal.TreeSitter
|
||||
/** A constant value. */
|
||||
class ConstantValue extends TConstantValue {
|
||||
/** Gets a textual representation of this constant value. */
|
||||
final string toString() {
|
||||
result = this.getInt().toString()
|
||||
final string toString() { this.hasValueWithType(result, _) }
|
||||
|
||||
/** Gets a string describing the type of this constant value. */
|
||||
string getValueType() { this.hasValueWithType(_, result) }
|
||||
|
||||
private predicate hasValueWithType(string value, string type) {
|
||||
value = this.getInt().toString() and type = "int"
|
||||
or
|
||||
result = this.getFloat().toString()
|
||||
value = this.getFloat().toString() and type = "float"
|
||||
or
|
||||
exists(int numerator, int denominator |
|
||||
this.isRational(numerator, denominator) and
|
||||
result = numerator + "/" + denominator
|
||||
value = numerator + "/" + denominator and
|
||||
type = "rational"
|
||||
)
|
||||
or
|
||||
exists(float real, float imaginary |
|
||||
this.isComplex(real, imaginary) and
|
||||
result = real + "+" + imaginary + "i"
|
||||
value = real + "+" + imaginary + "i" and
|
||||
type = "complex"
|
||||
)
|
||||
or
|
||||
result = this.getString()
|
||||
value = this.getString() and type = "string"
|
||||
or
|
||||
result = ":" + this.getSymbol()
|
||||
value = ":" + this.getSymbol() and type = "symbol"
|
||||
or
|
||||
result = this.getBoolean().toString()
|
||||
value = this.getRegExp() and type = "regexp"
|
||||
or
|
||||
this.isNil() and result = "nil"
|
||||
value = this.getBoolean().toString() and type = "boolean"
|
||||
or
|
||||
this.isNil() and value = "nil" and type = "nil"
|
||||
}
|
||||
|
||||
/** Gets the integer value, if this is an integer. */
|
||||
@@ -62,11 +71,31 @@ class ConstantValue extends TConstantValue {
|
||||
/** Holds if this is the symbol value `:s`. */
|
||||
predicate isSymbol(string s) { s = this.getSymbol() }
|
||||
|
||||
/** Gets the string or symbol value, if any. */
|
||||
string getStringOrSymbol() { result = [this.getString(), this.getSymbol()] }
|
||||
/** Gets the regexp value, if this is a regexp. */
|
||||
string getRegExp() { this.isRegExpWithFlags(result, _) }
|
||||
|
||||
/** Holds if this is the string value `s` or the symbol value `:s`. */
|
||||
predicate isStringOrSymbol(string s) { s = this.getStringOrSymbol() }
|
||||
/** Holds if this is the regexp value `/s/`, ignoring any flags. */
|
||||
predicate isRegExp(string s) { this.isRegExpWithFlags(s, _) }
|
||||
|
||||
/** Holds if this is the regexp value `/s/flags` . */
|
||||
predicate isRegExpWithFlags(string s, string flags) { this = TRegExp(s, flags) }
|
||||
|
||||
/** DEPRECATED: Use `getStringlikeValue` instead. */
|
||||
deprecated string getStringOrSymbol() { result = this.getStringlikeValue() }
|
||||
|
||||
/** DEPRECATED: Use `isStringlikeValue` instead. */
|
||||
deprecated predicate isStringOrSymbol(string s) { s = this.getStringlikeValue() }
|
||||
|
||||
/** Gets the string/symbol/regexp value, if any. */
|
||||
string getStringlikeValue() { result = [this.getString(), this.getSymbol(), this.getRegExp()] }
|
||||
|
||||
/**
|
||||
* Holds if this is:
|
||||
* - the string value `s`,
|
||||
* - the symbol value `:s`, or
|
||||
* - the regexp value `/s/`.
|
||||
*/
|
||||
predicate isStringlikeValue(string s) { s = this.getStringlikeValue() }
|
||||
|
||||
/** Gets the Boolean value, if this is a Boolean. */
|
||||
boolean getBoolean() { this = TBoolean(result) }
|
||||
@@ -92,11 +121,17 @@ module ConstantValue {
|
||||
/** A constant complex value. */
|
||||
class ConstantComplexValue extends ConstantValue, TComplex { }
|
||||
|
||||
/** A constant string-like value. */
|
||||
class ConstantStringlikeValue extends ConstantValue, TStringlike { }
|
||||
|
||||
/** A constant string value. */
|
||||
class ConstantStringValue extends ConstantValue, TString { }
|
||||
class ConstantStringValue extends ConstantStringlikeValue, TString { }
|
||||
|
||||
/** A constant symbol value. */
|
||||
class ConstantSymbolValue extends ConstantValue, TSymbol { }
|
||||
class ConstantSymbolValue extends ConstantStringlikeValue, TSymbol { }
|
||||
|
||||
/** A constant regexp value. */
|
||||
class ConstantRegExpValue extends ConstantStringlikeValue, TRegExp { }
|
||||
|
||||
/** A constant Boolean value. */
|
||||
class ConstantBooleanValue extends ConstantValue, TBoolean { }
|
||||
|
||||
@@ -454,11 +454,11 @@ class StringConcatenation extends Expr, TStringConcatenation {
|
||||
*/
|
||||
final string getConcatenatedValueText() {
|
||||
forall(StringLiteral c | c = this.getString(_) |
|
||||
exists(c.getConstantValue().getStringOrSymbol())
|
||||
exists(c.getConstantValue().getStringlikeValue())
|
||||
) and
|
||||
result =
|
||||
concat(string valueText, int i |
|
||||
valueText = this.getString(i).getConstantValue().getStringOrSymbol()
|
||||
valueText = this.getString(i).getConstantValue().getStringlikeValue()
|
||||
|
|
||||
valueText order by i
|
||||
)
|
||||
|
||||
@@ -53,7 +53,7 @@ private class MethodModifier extends MethodCall {
|
||||
predicate modifiesMethod(Namespace n, string name) {
|
||||
this = n.getAStmt() and
|
||||
[
|
||||
this.getMethodArgument().getConstantValue().getStringOrSymbol(),
|
||||
this.getMethodArgument().getConstantValue().getStringlikeValue(),
|
||||
this.getMethodArgument().(MethodBase).getName()
|
||||
] = name
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ class HashPattern extends CasePattern, THashPattern {
|
||||
/** Gets the value for a given key name. */
|
||||
CasePattern getValueByKey(string key) {
|
||||
exists(int i |
|
||||
this.getKey(i).getConstantValue().isStringOrSymbol(key) and result = this.getValue(i)
|
||||
this.getKey(i).getConstantValue().isStringlikeValue(key) and result = this.getValue(i)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -229,9 +229,16 @@ private module Propagation {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
string getNonSymbolValue() {
|
||||
string getStringValue() {
|
||||
result = this.getValue() and
|
||||
not this.getExpr() instanceof SymbolLiteral
|
||||
not this.getExpr() instanceof SymbolLiteral and
|
||||
not this.getExpr() instanceof RegExpLiteral
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
string getRegExpValue(string flags) {
|
||||
result = this.getValue() and
|
||||
flags = this.getExpr().(RegExpLiteral).getFlagString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +258,7 @@ private module Propagation {
|
||||
s = left + right
|
||||
)
|
||||
or
|
||||
s = e.(StringlikeLiteralWithInterpolationCfgNode).getNonSymbolValue()
|
||||
s = e.(StringlikeLiteralWithInterpolationCfgNode).getStringValue()
|
||||
or
|
||||
// If last statement in the interpolation is a constant or local variable read,
|
||||
// we attempt to look up its string value.
|
||||
@@ -267,13 +274,15 @@ private module Propagation {
|
||||
exists(ExprCfgNode last | last = e.(RegExpInterpolationComponentCfgNode).getLastStmt() |
|
||||
isInt(last, any(int i | s = i.toString())) or
|
||||
isFloat(last, any(float f | s = f.toString())) or
|
||||
isString(last, s)
|
||||
isString(last, s) or
|
||||
isRegExp(last, s, _) // Note: we lose the flags for interpolated regexps here.
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isStringExprNoCfg(Expr e, string s) {
|
||||
s = e.(StringlikeLiteralImpl).getStringValue() and
|
||||
not e instanceof SymbolLiteral
|
||||
not e instanceof SymbolLiteral and
|
||||
not e instanceof RegExpLiteral
|
||||
or
|
||||
s = e.(EncodingLiteralImpl).getValue()
|
||||
or
|
||||
@@ -319,6 +328,31 @@ private module Propagation {
|
||||
forex(ExprCfgNode n | n = e.getAControlFlowNode() | isSymbol(n, s))
|
||||
}
|
||||
|
||||
predicate isRegExp(ExprCfgNode e, string s, string flags) {
|
||||
isRegExpExprNoCfg(e.getExpr(), s, flags)
|
||||
or
|
||||
isRegExpExpr(e.getExpr().(ConstantReadAccess).getValue(), s, flags)
|
||||
or
|
||||
isRegExp(getSource(e), s, flags)
|
||||
or
|
||||
s = e.(StringlikeLiteralWithInterpolationCfgNode).getRegExpValue(flags)
|
||||
}
|
||||
|
||||
private predicate isRegExpExprNoCfg(Expr e, string s, string flags) {
|
||||
s = e.(StringlikeLiteralImpl).getStringValue() and
|
||||
e.(RegExpLiteral).getFlagString() = flags
|
||||
or
|
||||
isRegExpExprNoCfg(e.(ConstantReadAccess).getValue(), s, flags)
|
||||
}
|
||||
|
||||
predicate isRegExpExpr(Expr e, string s, string flags) {
|
||||
isRegExpExprNoCfg(e, s, flags)
|
||||
or
|
||||
isRegExpExpr(e.(ConstantReadAccess).getValue(), s, flags)
|
||||
or
|
||||
forex(ExprCfgNode n | n = e.getAControlFlowNode() | isRegExp(n, s, flags))
|
||||
}
|
||||
|
||||
predicate isBoolean(ExprCfgNode e, boolean b) {
|
||||
isBooleanExprNoCfg(e.getExpr(), b)
|
||||
or
|
||||
@@ -388,9 +422,18 @@ private module Cached {
|
||||
s = any(StringComponentImpl c).getValue()
|
||||
} or
|
||||
TSymbol(string s) { isString(_, s) or isSymbolExpr(_, s) } or
|
||||
TRegExp(string s, string flags) {
|
||||
isRegExp(_, s, flags)
|
||||
or
|
||||
isRegExpExpr(_, s, flags)
|
||||
or
|
||||
s = any(StringComponentImpl c).getValue() and flags = ""
|
||||
} or
|
||||
TBoolean(boolean b) { b in [false, true] } or
|
||||
TNil()
|
||||
|
||||
class TStringlike = TString or TSymbol or TRegExp;
|
||||
|
||||
cached
|
||||
ConstantValue getConstantValue(ExprCfgNode n) {
|
||||
result.isInt(any(int i | isInt(n, i)))
|
||||
@@ -411,6 +454,8 @@ private module Cached {
|
||||
or
|
||||
result.isSymbol(any(string s | isSymbol(n, s)))
|
||||
or
|
||||
exists(string s, string flags | isRegExp(n, s, flags) and result = TRegExp(s, flags))
|
||||
or
|
||||
result.isBoolean(any(boolean b | isBoolean(n, b)))
|
||||
or
|
||||
result.isNil() and
|
||||
@@ -437,6 +482,8 @@ private module Cached {
|
||||
or
|
||||
result.isSymbol(any(string s | isSymbolExpr(e, s)))
|
||||
or
|
||||
exists(string s, string flags | isRegExpExpr(e, s, flags) and result = TRegExp(s, flags))
|
||||
or
|
||||
result.isBoolean(any(boolean b | isBooleanExpr(e, b)))
|
||||
or
|
||||
result.isNil() and
|
||||
|
||||
@@ -189,7 +189,7 @@ class RedirectToCall extends ActionControllerContextCall {
|
||||
/** Gets the `ActionControllerActionMethod` to redirect to, if any */
|
||||
ActionControllerActionMethod getRedirectActionMethod() {
|
||||
exists(string methodName |
|
||||
this.getKeywordArgument("action").getConstantValue().isStringOrSymbol(methodName) and
|
||||
this.getKeywordArgument("action").getConstantValue().isStringlikeValue(methodName) and
|
||||
methodName = result.getName() and
|
||||
result.getEnclosingModule() = this.getControllerClass()
|
||||
)
|
||||
@@ -225,7 +225,7 @@ pragma[nomagic]
|
||||
private predicate actionControllerHasHelperMethodCall(ActionControllerControllerClass c, string name) {
|
||||
exists(MethodCall mc |
|
||||
mc.getMethodName() = "helper_method" and
|
||||
mc.getAnArgument().getConstantValue().isStringOrSymbol(name) and
|
||||
mc.getAnArgument().getConstantValue().isStringlikeValue(name) and
|
||||
mc.getEnclosingModule() = c
|
||||
)
|
||||
}
|
||||
@@ -317,7 +317,7 @@ class ActionControllerSkipForgeryProtectionCall extends CSRFProtectionSetting::R
|
||||
call.getMethodName() = "skip_forgery_protection"
|
||||
or
|
||||
call.getMethodName() = "skip_before_action" and
|
||||
call.getAnArgument().getConstantValue().isStringOrSymbol("verify_authenticity_token")
|
||||
call.getAnArgument().getConstantValue().isStringlikeValue("verify_authenticity_token")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -165,14 +165,14 @@ module ActionDispatch {
|
||||
override Location getLocation() { result = call.getLocation() }
|
||||
|
||||
override string getPathComponent() {
|
||||
call.getKeywordArgument("path").getConstantValue().isStringOrSymbol(result)
|
||||
call.getKeywordArgument("path").getConstantValue().isStringlikeValue(result)
|
||||
or
|
||||
not exists(call.getKeywordArgument("path")) and
|
||||
call.getArgument(0).getConstantValue().isStringOrSymbol(result)
|
||||
call.getArgument(0).getConstantValue().isStringlikeValue(result)
|
||||
}
|
||||
|
||||
override string getControllerComponent() {
|
||||
call.getKeywordArgument(["controller", "module"]).getConstantValue().isStringOrSymbol(result)
|
||||
call.getKeywordArgument(["controller", "module"]).getConstantValue().isStringlikeValue(result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ module ActionDispatch {
|
||||
MethodCall getDefiningMethodCall() { result = call }
|
||||
|
||||
override string getPathComponent() {
|
||||
exists(string resource | call.getArgument(0).getConstantValue().isStringOrSymbol(resource) |
|
||||
exists(string resource | call.getArgument(0).getConstantValue().isStringlikeValue(resource) |
|
||||
result = resource + "/:" + singularize(resource) + "_id"
|
||||
)
|
||||
}
|
||||
@@ -264,7 +264,7 @@ module ActionDispatch {
|
||||
override string getControllerComponent() { result = this.getNamespace() }
|
||||
|
||||
private string getNamespace() {
|
||||
call.getArgument(0).getConstantValue().isStringOrSymbol(result)
|
||||
call.getArgument(0).getConstantValue().isStringlikeValue(result)
|
||||
}
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
@@ -482,11 +482,11 @@ module ActionDispatch {
|
||||
override RouteBlock getParentBlock() { result = parentBlock }
|
||||
|
||||
override string getLastPathComponent() {
|
||||
method.getArgument(0).getConstantValue().isStringOrSymbol(result)
|
||||
method.getArgument(0).getConstantValue().isStringlikeValue(result)
|
||||
}
|
||||
|
||||
override string getLastControllerComponent() {
|
||||
method.getKeywordArgument("controller").getConstantValue().isStringOrSymbol(result)
|
||||
method.getKeywordArgument("controller").getConstantValue().isStringlikeValue(result)
|
||||
or
|
||||
not exists(method.getKeywordArgument("controller")) and
|
||||
(
|
||||
@@ -510,7 +510,7 @@ module ActionDispatch {
|
||||
}
|
||||
|
||||
private string getActionString() {
|
||||
method.getKeywordArgument("to").getConstantValue().isStringOrSymbol(result)
|
||||
method.getKeywordArgument("to").getConstantValue().isStringlikeValue(result)
|
||||
or
|
||||
method.getKeywordArgument("to").(MethodCall).getMethodName() = "redirect" and
|
||||
result = "<redirect>#<redirect>"
|
||||
@@ -518,7 +518,7 @@ module ActionDispatch {
|
||||
|
||||
override string getAction() {
|
||||
// get "/photos", action: "index"
|
||||
method.getKeywordArgument("action").getConstantValue().isStringOrSymbol(result)
|
||||
method.getKeywordArgument("action").getConstantValue().isStringlikeValue(result)
|
||||
or
|
||||
not exists(method.getKeywordArgument("action")) and
|
||||
(
|
||||
@@ -533,7 +533,7 @@ module ActionDispatch {
|
||||
or
|
||||
// get :some_action
|
||||
not exists(this.getActionString()) and
|
||||
method.getArgument(0).getConstantValue().isStringOrSymbol(result)
|
||||
method.getArgument(0).getConstantValue().isStringlikeValue(result)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -580,7 +580,7 @@ module ActionDispatch {
|
||||
ResourcesRoute() {
|
||||
exists(string resource |
|
||||
this = TResourcesRoute(parent, method, action) and
|
||||
method.getArgument(0).getConstantValue().isStringOrSymbol(resource) and
|
||||
method.getArgument(0).getConstantValue().isStringlikeValue(resource) and
|
||||
isDefaultResourceRoute(resource, httpMethod, pathComponent, action)
|
||||
)
|
||||
}
|
||||
@@ -592,7 +592,7 @@ module ActionDispatch {
|
||||
override string getLastPathComponent() { result = pathComponent }
|
||||
|
||||
override string getLastControllerComponent() {
|
||||
method.getArgument(0).getConstantValue().isStringOrSymbol(result)
|
||||
method.getArgument(0).getConstantValue().isStringlikeValue(result)
|
||||
}
|
||||
|
||||
override string getAction() { result = action }
|
||||
@@ -618,7 +618,7 @@ module ActionDispatch {
|
||||
SingularResourceRoute() {
|
||||
exists(string resource |
|
||||
this = TResourceRoute(parent, method, action) and
|
||||
method.getArgument(0).getConstantValue().isStringOrSymbol(resource) and
|
||||
method.getArgument(0).getConstantValue().isStringlikeValue(resource) and
|
||||
isDefaultSingularResourceRoute(resource, httpMethod, pathComponent, action)
|
||||
)
|
||||
}
|
||||
@@ -630,7 +630,7 @@ module ActionDispatch {
|
||||
override string getLastPathComponent() { result = pathComponent }
|
||||
|
||||
override string getLastControllerComponent() {
|
||||
method.getArgument(0).getConstantValue().isStringOrSymbol(result)
|
||||
method.getArgument(0).getConstantValue().isStringlikeValue(result)
|
||||
}
|
||||
|
||||
override string getAction() { result = action }
|
||||
@@ -663,25 +663,25 @@ module ActionDispatch {
|
||||
override string getLastPathComponent() {
|
||||
[method.getArgument(0), method.getArgument(0).(Pair).getKey()]
|
||||
.getConstantValue()
|
||||
.isStringOrSymbol(result)
|
||||
.isStringlikeValue(result)
|
||||
}
|
||||
|
||||
override string getLastControllerComponent() {
|
||||
result =
|
||||
extractController(method.getKeywordArgument("to").getConstantValue().getStringOrSymbol()) or
|
||||
method.getKeywordArgument("controller").getConstantValue().isStringOrSymbol(result) or
|
||||
extractController(method.getKeywordArgument("to").getConstantValue().getStringlikeValue()) or
|
||||
method.getKeywordArgument("controller").getConstantValue().isStringlikeValue(result) or
|
||||
result =
|
||||
extractController(method
|
||||
.getArgument(0)
|
||||
.(Pair)
|
||||
.getValue()
|
||||
.getConstantValue()
|
||||
.getStringOrSymbol())
|
||||
.getStringlikeValue())
|
||||
}
|
||||
|
||||
override string getHttpMethod() {
|
||||
exists(string via |
|
||||
method.getKeywordArgument("via").getConstantValue().isStringOrSymbol(via)
|
||||
method.getKeywordArgument("via").getConstantValue().isStringlikeValue(via)
|
||||
|
|
||||
via = "all" and result = anyHttpMethod()
|
||||
or
|
||||
@@ -694,14 +694,20 @@ module ActionDispatch {
|
||||
.(ArrayLiteral)
|
||||
.getElement(_)
|
||||
.getConstantValue()
|
||||
.getStringOrSymbol()
|
||||
.getStringlikeValue()
|
||||
}
|
||||
|
||||
override string getAction() {
|
||||
result = extractAction(method.getKeywordArgument("to").getConstantValue().getStringOrSymbol()) or
|
||||
method.getKeywordArgument("action").getConstantValue().isStringOrSymbol(result) or
|
||||
result =
|
||||
extractAction(method.getArgument(0).(Pair).getValue().getConstantValue().getStringOrSymbol())
|
||||
extractAction(method.getKeywordArgument("to").getConstantValue().getStringlikeValue()) or
|
||||
method.getKeywordArgument("action").getConstantValue().isStringlikeValue(result) or
|
||||
result =
|
||||
extractAction(method
|
||||
.getArgument(0)
|
||||
.(Pair)
|
||||
.getValue()
|
||||
.getConstantValue()
|
||||
.getStringlikeValue())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,7 +808,7 @@ module ActionDispatch {
|
||||
not exists(m.getKeywordArgument("only"))
|
||||
or
|
||||
exists(Expr only | only = m.getKeywordArgument("only") |
|
||||
[only.(ArrayLiteral).getElement(_), only].getConstantValue().isStringOrSymbol(action)
|
||||
[only.(ArrayLiteral).getElement(_), only].getConstantValue().isStringlikeValue(action)
|
||||
)
|
||||
) and
|
||||
// Respect the `except` keyword argument, which removes actions from the default set.
|
||||
@@ -810,7 +816,7 @@ module ActionDispatch {
|
||||
not exists(m.getKeywordArgument("except"))
|
||||
or
|
||||
exists(Expr except | except = m.getKeywordArgument("except") |
|
||||
[except.(ArrayLiteral).getElement(_), except].getConstantValue().getStringOrSymbol() !=
|
||||
[except.(ArrayLiteral).getElement(_), except].getConstantValue().getStringlikeValue() !=
|
||||
action
|
||||
)
|
||||
)
|
||||
|
||||
@@ -95,7 +95,7 @@ abstract class RenderCall extends MethodCall {
|
||||
}
|
||||
|
||||
private string getTemplatePathValue() {
|
||||
result = this.getTemplatePathArgument().getConstantValue().getStringOrSymbol()
|
||||
result = this.getTemplatePathArgument().getConstantValue().getStringlikeValue()
|
||||
}
|
||||
|
||||
// everything up to and including the final slash, but ignoring any leading slash
|
||||
|
||||
@@ -28,7 +28,7 @@ private DataFlow::Node ioInstance() {
|
||||
// will execute a shell command and read its output rather than reading from the
|
||||
// filesystem.
|
||||
private predicate pathArgSpawnsSubprocess(Expr arg) {
|
||||
arg.getConstantValue().getStringOrSymbol().charAt(0) = "|"
|
||||
arg.getConstantValue().getStringlikeValue().charAt(0) = "|"
|
||||
}
|
||||
|
||||
private DataFlow::Node fileInstanceInstantiation() {
|
||||
|
||||
@@ -248,7 +248,7 @@ class GraphqlFieldDefinitionMethodCall extends GraphqlSchemaObjectClassMethodCal
|
||||
GraphqlFieldDefinitionMethodCall() { this.getMethodName() = "field" }
|
||||
|
||||
/** Gets the name of this GraphQL field. */
|
||||
string getFieldName() { result = this.getArgument(0).getConstantValue().getStringOrSymbol() }
|
||||
string getFieldName() { result = this.getArgument(0).getConstantValue().getStringlikeValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,7 +284,7 @@ private class GraphqlFieldArgumentDefinitionMethodCall extends GraphqlSchemaObje
|
||||
string getFieldName() { result = this.getFieldDefinition().getFieldName() }
|
||||
|
||||
/** Gets the name of the argument (i.e. the first argument to this `argument` method call) */
|
||||
string getArgumentName() { result = this.getArgument(0).getConstantValue().getStringOrSymbol() }
|
||||
string getArgumentName() { result = this.getArgument(0).getConstantValue().getStringlikeValue() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,7 +333,9 @@ class GraphqlFieldResolutionMethod extends Method, HTTP::Server::RequestHandler:
|
||||
exists(GraphqlFieldDefinitionMethodCall defn |
|
||||
// field :foo, resolver_method: :custom_method
|
||||
// def custom_method(...)
|
||||
defn.getKeywordArgument("resolver_method").getConstantValue().isStringOrSymbol(this.getName())
|
||||
defn.getKeywordArgument("resolver_method")
|
||||
.getConstantValue()
|
||||
.isStringlikeValue(this.getName())
|
||||
or
|
||||
// field :foo
|
||||
// def foo(...)
|
||||
@@ -344,7 +346,10 @@ class GraphqlFieldResolutionMethod extends Method, HTTP::Server::RequestHandler:
|
||||
|
||||
/** Gets the method call which is the definition of the field corresponding to this resolver method. */
|
||||
GraphqlFieldDefinitionMethodCall getDefinition() {
|
||||
result.getKeywordArgument("resolver_method").getConstantValue().isStringOrSymbol(this.getName())
|
||||
result
|
||||
.getKeywordArgument("resolver_method")
|
||||
.getConstantValue()
|
||||
.isStringlikeValue(this.getName())
|
||||
or
|
||||
not exists(result.getKeywordArgument("resolver_method").(SymbolLiteral)) and
|
||||
result.getFieldName() = this.getName()
|
||||
|
||||
@@ -164,7 +164,7 @@ private module Settings {
|
||||
* A node that sets a Stringlike value.
|
||||
*/
|
||||
class StringlikeSetting extends LiteralSetting {
|
||||
override ConstantValue::ConstantStringValue value;
|
||||
override ConstantValue::ConstantStringlikeValue value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,12 +172,11 @@ private module Settings {
|
||||
*/
|
||||
class NillableStringlikeSetting extends LiteralSetting {
|
||||
NillableStringlikeSetting() {
|
||||
value instanceof ConstantValue::ConstantStringValue or
|
||||
value instanceof ConstantValue::ConstantSymbolValue or
|
||||
value instanceof ConstantValue::ConstantStringlikeValue or
|
||||
value instanceof ConstantValue::ConstantNilValue
|
||||
}
|
||||
|
||||
string getStringValue() { result = value.getStringOrSymbol() }
|
||||
string getStringValue() { result = value.getStringlikeValue() }
|
||||
|
||||
predicate isNilValue() { value.isNil() }
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ private class LibXmlRubyXmlParserCall extends XmlParserCall::Range, DataFlow::Ca
|
||||
exists(CfgNodes::ExprNodes::PairCfgNode pair |
|
||||
pair =
|
||||
this.getArgument(1).asExpr().(CfgNodes::ExprNodes::HashLiteralCfgNode).getAKeyValuePair() and
|
||||
pair.getKey().getConstantValue().isStringOrSymbol("options") and
|
||||
pair.getKey().getConstantValue().isStringlikeValue("options") and
|
||||
pair.getValue() =
|
||||
[
|
||||
trackEnableFeature(TNOENT()), trackEnableFeature(TDTDLOAD()),
|
||||
|
||||
@@ -125,7 +125,7 @@ private predicate setsDefaultVerification(DataFlow::CallNode callNode, boolean v
|
||||
|
||||
private predicate isSslVerifyPeerLiteral(DataFlow::Node node) {
|
||||
exists(DataFlow::LocalSourceNode literal |
|
||||
literal.asExpr().getExpr().getConstantValue().isStringOrSymbol("ssl_verify_peer") and
|
||||
literal.asExpr().getExpr().getConstantValue().isStringlikeValue("ssl_verify_peer") and
|
||||
literal.flowsTo(node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ private predicate isSslOptionsPairDisablingValidation(CfgNodes::ExprNodes::PairC
|
||||
/** Holds if `node` represents the symbol literal with the given `valueText`. */
|
||||
private predicate isSymbolLiteral(DataFlow::Node node, string valueText) {
|
||||
exists(DataFlow::LocalSourceNode literal |
|
||||
literal.asExpr().getExpr().getConstantValue().isStringOrSymbol(valueText) and
|
||||
literal.asExpr().getExpr().getConstantValue().isStringlikeValue(valueText) and
|
||||
literal.flowsTo(node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class HttpartyRequest extends HTTP::Client::Request::Range {
|
||||
/** Holds if `node` represents the symbol literal `verify` or `verify_peer`. */
|
||||
private predicate isVerifyLiteral(DataFlow::Node node) {
|
||||
exists(DataFlow::LocalSourceNode literal |
|
||||
literal.asExpr().getExpr().getConstantValue().isStringOrSymbol(["verify", "verify_peer"]) and
|
||||
literal.asExpr().getExpr().getConstantValue().isStringlikeValue(["verify", "verify_peer"]) and
|
||||
literal.flowsTo(node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ private predicate isSslVerifyModeNonePair(CfgNodes::ExprNodes::PairCfgNode p) {
|
||||
/** Holds if `node` can represent the symbol literal `:ssl_verify_mode`. */
|
||||
private predicate isSslVerifyModeLiteral(DataFlow::Node node) {
|
||||
exists(DataFlow::LocalSourceNode literal |
|
||||
literal.asExpr().getExpr().getConstantValue().isStringOrSymbol("ssl_verify_mode") and
|
||||
literal.asExpr().getExpr().getConstantValue().isStringlikeValue("ssl_verify_mode") and
|
||||
literal.flowsTo(node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ private predicate isVerifySslNonePair(CfgNodes::ExprNodes::PairCfgNode p) {
|
||||
/** Holds if `node` can represent the symbol literal `:verify_ssl`. */
|
||||
private predicate isSslVerifyModeLiteral(DataFlow::Node node) {
|
||||
exists(DataFlow::LocalSourceNode literal |
|
||||
literal.asExpr().getExpr().getConstantValue().isStringOrSymbol("verify_ssl") and
|
||||
literal.asExpr().getExpr().getConstantValue().isStringlikeValue("verify_ssl") and
|
||||
literal.flowsTo(node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ private predicate isSslVerifyPeerFalsePair(CfgNodes::ExprNodes::PairCfgNode p) {
|
||||
/** Holds if `node` represents the symbol literal `verify` or `verify_peer`. */
|
||||
private predicate isSslVerifyPeerLiteral(DataFlow::Node node) {
|
||||
exists(DataFlow::LocalSourceNode literal |
|
||||
literal.asExpr().getExpr().getConstantValue().isStringOrSymbol("ssl_verifypeer") and
|
||||
literal.asExpr().getExpr().getConstantValue().isStringlikeValue("ssl_verifypeer") and
|
||||
literal.flowsTo(node)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* the `x` (free-spacing) flag.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.ast.Literal as AST
|
||||
private import codeql.ruby.AST as AST
|
||||
private import codeql.Locations
|
||||
|
||||
/**
|
||||
@@ -254,7 +254,11 @@ abstract class RegExp extends AST::StringlikeLiteral {
|
||||
}
|
||||
|
||||
/** Gets the text of this regex */
|
||||
string getText() { result = this.getConstantValue().getString() }
|
||||
string getText() {
|
||||
exists(AST::ConstantValue c | c = this.getConstantValue() |
|
||||
result = [this.getConstantValue().getString(), this.getConstantValue().getRegExp()]
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `i`th character of this regex */
|
||||
string getChar(int i) { result = this.getText().charAt(i) }
|
||||
|
||||
@@ -74,7 +74,7 @@ module UnsafeDeserialization {
|
||||
}
|
||||
|
||||
private predicate isOjModePair(CfgNodes::ExprNodes::PairCfgNode p, string modeValue) {
|
||||
p.getKey().getConstantValue().isStringOrSymbol("mode") and
|
||||
p.getKey().getConstantValue().isStringlikeValue("mode") and
|
||||
exists(DataFlow::LocalSourceNode symbolLiteral, DataFlow::Node value |
|
||||
symbolLiteral.asExpr().getExpr().getConstantValue().isSymbol(modeValue) and
|
||||
symbolLiteral.flowsTo(value) and
|
||||
|
||||
@@ -141,7 +141,7 @@ private module Shared {
|
||||
exists(RenderCall call, Pair kvPair |
|
||||
call.getLocals().getAKeyValuePair() = kvPair and
|
||||
kvPair.getValue() = value and
|
||||
kvPair.getKey().getConstantValue().isStringOrSymbol(hashKey) and
|
||||
kvPair.getKey().getConstantValue().isStringlikeValue(hashKey) and
|
||||
call.getTemplateFile() = erb
|
||||
)
|
||||
}
|
||||
@@ -154,7 +154,7 @@ private module Shared {
|
||||
argNode.asExpr() = refNode.getArgument(0) and
|
||||
refNode.getReceiver().getExpr().(MethodCall).getMethodName() = "local_assigns" and
|
||||
argNode.getALocalSource() = DataFlow::exprNode(strNode) and
|
||||
strNode.getExpr().getConstantValue().isStringOrSymbol(hashKey) and
|
||||
strNode.getExpr().getConstantValue().isStringlikeValue(hashKey) and
|
||||
erb = refNode.getFile()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ module CleartextSources {
|
||||
* sensitive data with a call to `sub`.
|
||||
*/
|
||||
private predicate effectiveSubRegExp(CfgNodes::ExprNodes::RegExpLiteralCfgNode re) {
|
||||
re.getConstantValue().getStringOrSymbol().matches([".*", ".+"])
|
||||
re.getConstantValue().getStringlikeValue().matches([".*", ".+"])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +44,7 @@ module CleartextSources {
|
||||
* sensitive data with a call to `gsub`.
|
||||
*/
|
||||
private predicate effectiveGsubRegExp(CfgNodes::ExprNodes::RegExpLiteralCfgNode re) {
|
||||
re.getConstantValue().getStringOrSymbol().matches(".")
|
||||
re.getConstantValue().getStringlikeValue().matches(".")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +112,7 @@ module CleartextSources {
|
||||
.(CfgNodes::ExprNodes::ElementReferenceCfgNode)
|
||||
.getArgument(0)
|
||||
.getConstantValue()
|
||||
.getStringOrSymbol() = name
|
||||
.getStringlikeValue() = name
|
||||
or
|
||||
// calling a non-sensitive method
|
||||
this.(DataFlow::CallNode).getMethodName() = name
|
||||
@@ -123,7 +123,7 @@ module CleartextSources {
|
||||
.(CfgNodes::ExprNodes::ElementReferenceCfgNode)
|
||||
.getReceiver()
|
||||
.getConstantValue()
|
||||
.getStringOrSymbol()
|
||||
.getStringlikeValue()
|
||||
.regexpMatch("(?is).*(messages|strings).*")
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ module CleartextSources {
|
||||
private predicate hashKeyWrite(DataFlow::CallNode writeNode, string name, DataFlow::Node val) {
|
||||
writeNode.asExpr().getExpr() instanceof SetterMethodCall and
|
||||
// hash[name]
|
||||
writeNode.getArgument(0).asExpr().getConstantValue().getStringOrSymbol() = name and
|
||||
writeNode.getArgument(0).asExpr().getConstantValue().getStringlikeValue() = name and
|
||||
// val
|
||||
writeNode.getArgument(1).asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs() =
|
||||
val.asExpr()
|
||||
@@ -203,7 +203,7 @@ module CleartextSources {
|
||||
exists(CfgNodes::ExprNodes::PairCfgNode p |
|
||||
this.asExpr() = lit and p = lit.getAKeyValuePair()
|
||||
|
|
||||
p.getKey().getConstantValue().getStringOrSymbol() = name and
|
||||
p.getKey().getConstantValue().getStringlikeValue() = name and
|
||||
p.getValue() = val.asExpr()
|
||||
)
|
||||
)
|
||||
@@ -266,7 +266,7 @@ module CleartextSources {
|
||||
// from `hsh[password] = "changeme"` to a `hsh[password]` read
|
||||
nodeFrom.(HashKeyWritePasswordSource).getName() = name and
|
||||
nodeTo.asExpr().getExpr() = ref and
|
||||
ref.getArgument(0).getConstantValue().getStringOrSymbol() = name and
|
||||
ref.getArgument(0).getConstantValue().getStringlikeValue() = name and
|
||||
nodeFrom.(HashKeyWritePasswordSource).getVariable() = hashVar and
|
||||
ref.getReceiver().(VariableReadAccess).getVariable() = hashVar and
|
||||
nodeFrom.asExpr().getASuccessor*() = nodeTo.asExpr()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,10 @@
|
||||
import ruby
|
||||
import codeql.ruby.controlflow.CfgNodes
|
||||
|
||||
query predicate exprValue(Expr e, ConstantValue v) { v = e.getConstantValue() }
|
||||
query predicate exprValue(Expr e, ConstantValue v, string t) {
|
||||
v = e.getConstantValue() and t = v.getValueType()
|
||||
}
|
||||
|
||||
query predicate exprCfgNodeValue(ExprCfgNode n, ConstantValue v) { v = n.getConstantValue() }
|
||||
query predicate exprCfgNodeValue(ExprCfgNode n, ConstantValue v, string t) {
|
||||
v = n.getConstantValue() and t = v.getValueType()
|
||||
}
|
||||
|
||||
@@ -89,12 +89,12 @@ stringlikeLiterals
|
||||
| escapes.rb:38:1:38:6 | "\\C-?" | C-? | string |
|
||||
| escapes.rb:43:5:43:9 | "\\\\." | \\. | string |
|
||||
| escapes.rb:44:1:44:6 | "#{...}" | \\. | string |
|
||||
| escapes.rb:48:1:48:4 | /\\n/ | \\n | string |
|
||||
| escapes.rb:49:1:49:4 | /\\p/ | \\p | string |
|
||||
| escapes.rb:50:1:50:8 | /\\u0061/ | \\u0061 | string |
|
||||
| escapes.rb:48:1:48:4 | /\\n/ | \\n | regexp |
|
||||
| escapes.rb:49:1:49:4 | /\\p/ | \\p | regexp |
|
||||
| escapes.rb:50:1:50:8 | /\\u0061/ | \\u0061 | regexp |
|
||||
| escapes.rb:53:5:53:9 | "\\\\." | \\. | string |
|
||||
| escapes.rb:54:5:54:8 | /\\./ | \\. | string |
|
||||
| escapes.rb:55:1:55:10 | /#{...}#{...}/ | \\.\\. | string |
|
||||
| escapes.rb:54:5:54:8 | /\\./ | \\. | regexp |
|
||||
| escapes.rb:55:1:55:10 | /#{...}#{...}/ | \\.\\. | regexp |
|
||||
| escapes.rb:58:4:58:9 | "foo \\n" | foo\\n | string |
|
||||
| escapes.rb:58:11:58:13 | "bar" | bar | string |
|
||||
| escapes.rb:61:1:61:5 | :"\\'" | ' | symbol |
|
||||
|
||||
@@ -18,7 +18,7 @@ query predicate regexpEscapeSequenceComponents(RegExpEscapeSequenceComponent c,
|
||||
}
|
||||
|
||||
query predicate stringlikeLiterals(StringlikeLiteral l, string value, string kind) {
|
||||
value = l.getConstantValue().getString() and kind = "string"
|
||||
or
|
||||
value = l.getConstantValue().getSymbol() and kind = "symbol"
|
||||
exists(ConstantValue v |
|
||||
v = l.getConstantValue() and value = v.getStringlikeValue() and kind = v.getValueType()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import ruby
|
||||
|
||||
private string getValueText(MethodName m) {
|
||||
result = m.getConstantValue().getStringOrSymbol()
|
||||
result = m.getConstantValue().getStringlikeValue()
|
||||
or
|
||||
not exists(m.getConstantValue()) and result = "(none)"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user