Skip to content

Commit 808cc9c

Browse files
authored
Merge pull request #8396 from alexrford/ruby/charpred-only-field
Ruby: resolve `ql/field-only-used-in-charpred` alerts
2 parents fa37ece + 757aa29 commit 808cc9c

File tree

10 files changed

+92
-100
lines changed

10 files changed

+92
-100
lines changed

javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -119,18 +119,18 @@ class EmptyPositiveSubPatttern extends RegExpSubPattern {
119119
* whose root node is not a disjunction.
120120
*/
121121
class RegExpRoot extends RegExpTerm {
122-
RegExpParent parent;
123-
124122
RegExpRoot() {
125-
exists(RegExpAlt alt |
126-
alt.isRootTerm() and
127-
this = alt.getAChild() and
128-
parent = alt.getParent()
123+
exists(RegExpParent parent |
124+
exists(RegExpAlt alt |
125+
alt.isRootTerm() and
126+
this = alt.getAChild() and
127+
parent = alt.getParent()
128+
)
129+
or
130+
this.isRootTerm() and
131+
not this instanceof RegExpAlt and
132+
parent = this.getParent()
129133
)
130-
or
131-
this.isRootTerm() and
132-
not this instanceof RegExpAlt and
133-
parent = this.getParent()
134134
}
135135

136136
/**
@@ -466,13 +466,14 @@ private module CharacterClasses {
466466
* An implementation of `CharacterClass` for \d, \s, and \w.
467467
*/
468468
private class PositiveCharacterClassEscape extends CharacterClass {
469-
RegExpTerm cc;
470469
string charClass;
471470

472471
PositiveCharacterClassEscape() {
473-
isEscapeClass(cc, charClass) and
474-
this = getCanonicalCharClass(cc) and
475-
charClass = ["d", "s", "w"]
472+
exists(RegExpTerm cc |
473+
isEscapeClass(cc, charClass) and
474+
this = getCanonicalCharClass(cc) and
475+
charClass = ["d", "s", "w"]
476+
)
476477
}
477478

478479
override string getARelevantChar() {
@@ -504,13 +505,14 @@ private module CharacterClasses {
504505
* An implementation of `CharacterClass` for \D, \S, and \W.
505506
*/
506507
private class NegativeCharacterClassEscape extends CharacterClass {
507-
RegExpTerm cc;
508508
string charClass;
509509

510510
NegativeCharacterClassEscape() {
511-
isEscapeClass(cc, charClass) and
512-
this = getCanonicalCharClass(cc) and
513-
charClass = ["D", "S", "W"]
511+
exists(RegExpTerm cc |
512+
isEscapeClass(cc, charClass) and
513+
this = getCanonicalCharClass(cc) and
514+
charClass = ["D", "S", "W"]
515+
)
514516
}
515517

516518
override string getARelevantChar() {

python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -119,18 +119,18 @@ class EmptyPositiveSubPatttern extends RegExpSubPattern {
119119
* whose root node is not a disjunction.
120120
*/
121121
class RegExpRoot extends RegExpTerm {
122-
RegExpParent parent;
123-
124122
RegExpRoot() {
125-
exists(RegExpAlt alt |
126-
alt.isRootTerm() and
127-
this = alt.getAChild() and
128-
parent = alt.getParent()
123+
exists(RegExpParent parent |
124+
exists(RegExpAlt alt |
125+
alt.isRootTerm() and
126+
this = alt.getAChild() and
127+
parent = alt.getParent()
128+
)
129+
or
130+
this.isRootTerm() and
131+
not this instanceof RegExpAlt and
132+
parent = this.getParent()
129133
)
130-
or
131-
this.isRootTerm() and
132-
not this instanceof RegExpAlt and
133-
parent = this.getParent()
134134
}
135135

136136
/**
@@ -466,13 +466,14 @@ private module CharacterClasses {
466466
* An implementation of `CharacterClass` for \d, \s, and \w.
467467
*/
468468
private class PositiveCharacterClassEscape extends CharacterClass {
469-
RegExpTerm cc;
470469
string charClass;
471470

472471
PositiveCharacterClassEscape() {
473-
isEscapeClass(cc, charClass) and
474-
this = getCanonicalCharClass(cc) and
475-
charClass = ["d", "s", "w"]
472+
exists(RegExpTerm cc |
473+
isEscapeClass(cc, charClass) and
474+
this = getCanonicalCharClass(cc) and
475+
charClass = ["d", "s", "w"]
476+
)
476477
}
477478

478479
override string getARelevantChar() {
@@ -504,13 +505,14 @@ private module CharacterClasses {
504505
* An implementation of `CharacterClass` for \D, \S, and \W.
505506
*/
506507
private class NegativeCharacterClassEscape extends CharacterClass {
507-
RegExpTerm cc;
508508
string charClass;
509509

510510
NegativeCharacterClassEscape() {
511-
isEscapeClass(cc, charClass) and
512-
this = getCanonicalCharClass(cc) and
513-
charClass = ["D", "S", "W"]
511+
exists(RegExpTerm cc |
512+
isEscapeClass(cc, charClass) and
513+
this = getCanonicalCharClass(cc) and
514+
charClass = ["D", "S", "W"]
515+
)
514516
}
515517

516518
override string getARelevantChar() {

ruby/ql/lib/codeql/ruby/ast/internal/Scope.qll

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,7 @@ abstract class ScopeImpl extends AstNode, TScopeType {
184184
}
185185

186186
private class ScopeRealImpl extends ScopeImpl, TScopeReal {
187-
private Scope::Range range;
188-
189-
ScopeRealImpl() { range = toGenerated(this) }
187+
ScopeRealImpl() { toGenerated(this) instanceof Scope::Range }
190188

191189
override Variable getAVariableImpl() { result.getDeclaringScope() = this }
192190
}

ruby/ql/lib/codeql/ruby/ast/internal/Variable.qll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,10 +675,11 @@ private class ClassVariableAccessSynth extends ClassVariableAccessRealImpl,
675675
abstract class SelfVariableAccessImpl extends LocalVariableAccessImpl, TSelfVariableAccess { }
676676

677677
private class SelfVariableAccessReal extends SelfVariableAccessImpl, TSelfReal {
678-
private Ruby::Self self;
679678
private SelfVariable var;
680679

681-
SelfVariableAccessReal() { this = TSelfReal(self) and var = TSelfVariable(scopeOf(self)) }
680+
SelfVariableAccessReal() {
681+
exists(Ruby::Self self | this = TSelfReal(self) and var = TSelfVariable(scopeOf(self)))
682+
}
682683

683684
final override SelfVariable getVariableImpl() { result = var }
684685

ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,7 @@ abstract class ParamsCall extends MethodCall {
127127
* ActionController parameters available via the `params` method.
128128
*/
129129
class ParamsSource extends RemoteFlowSource::Range {
130-
ParamsCall call;
131-
132-
ParamsSource() { this.asExpr().getExpr() = call }
130+
ParamsSource() { this.asExpr().getExpr() instanceof ParamsCall }
133131

134132
override string getSourceType() { result = "ActionController::Metal#params" }
135133
}
@@ -146,9 +144,7 @@ abstract class CookiesCall extends MethodCall {
146144
* ActionController parameters available via the `cookies` method.
147145
*/
148146
class CookiesSource extends RemoteFlowSource::Range {
149-
CookiesCall call;
150-
151-
CookiesSource() { this.asExpr().getExpr() = call }
147+
CookiesSource() { this.asExpr().getExpr() instanceof CookiesCall }
152148

153149
override string getSourceType() { result = "ActionController::Metal#cookies" }
154150
}

ruby/ql/lib/codeql/ruby/frameworks/ActionDispatch.qll

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -573,15 +573,16 @@ module ActionDispatch {
573573
*/
574574
private class ResourcesRoute extends RouteImpl, TResourcesRoute {
575575
RouteBlock parent;
576-
string resource;
577576
string action;
578577
string httpMethod;
579578
string pathComponent;
580579

581580
ResourcesRoute() {
582-
this = TResourcesRoute(parent, method, action) and
583-
method.getArgument(0).getConstantValue().isStringOrSymbol(resource) and
584-
isDefaultResourceRoute(resource, httpMethod, pathComponent, action)
581+
exists(string resource |
582+
this = TResourcesRoute(parent, method, action) and
583+
method.getArgument(0).getConstantValue().isStringOrSymbol(resource) and
584+
isDefaultResourceRoute(resource, httpMethod, pathComponent, action)
585+
)
585586
}
586587

587588
override string getAPrimaryQlClass() { result = "ResourcesRoute" }
@@ -610,15 +611,16 @@ module ActionDispatch {
610611
*/
611612
private class SingularResourceRoute extends RouteImpl, TResourceRoute {
612613
RouteBlock parent;
613-
string resource;
614614
string action;
615615
string httpMethod;
616616
string pathComponent;
617617

618618
SingularResourceRoute() {
619-
this = TResourceRoute(parent, method, action) and
620-
method.getArgument(0).getConstantValue().isStringOrSymbol(resource) and
621-
isDefaultSingularResourceRoute(resource, httpMethod, pathComponent, action)
619+
exists(string resource |
620+
this = TResourceRoute(parent, method, action) and
621+
method.getArgument(0).getConstantValue().isStringOrSymbol(resource) and
622+
isDefaultSingularResourceRoute(resource, httpMethod, pathComponent, action)
623+
)
622624
}
623625

624626
override string getAPrimaryQlClass() { result = "SingularResourceRoute" }

ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,15 @@ private Expr getUltimateReceiver(MethodCall call) {
269269

270270
// A call to `find`, `where`, etc. that may return active record model object(s)
271271
private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation, DataFlow::CallNode {
272-
private MethodCall call;
273272
private ActiveRecordModelClass cls;
274-
private Expr recv;
275273

276274
ActiveRecordModelFinderCall() {
277-
call = this.asExpr().getExpr() and
278-
recv = getUltimateReceiver(call) and
279-
resolveConstant(recv) = cls.getAQualifiedName() and
280-
call.getMethodName() = finderMethodName()
275+
exists(MethodCall call, Expr recv |
276+
call = this.asExpr().getExpr() and
277+
recv = getUltimateReceiver(call) and
278+
resolveConstant(recv) = cls.getAQualifiedName() and
279+
call.getMethodName() = finderMethodName()
280+
)
281281
}
282282

283283
final override ActiveRecordModelClass getClass() { result = cls }
@@ -347,10 +347,8 @@ private module Persistence {
347347

348348
/** A call to e.g. `User.create(name: "foo")` */
349349
private class CreateLikeCall extends DataFlow::CallNode, PersistentWriteAccess::Range {
350-
private ActiveRecordModelClass modelCls;
351-
352350
CreateLikeCall() {
353-
modelCls = this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass() and
351+
exists(this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass()) and
354352
this.getMethodName() =
355353
[
356354
"create", "create!", "create_or_find_by", "create_or_find_by!", "find_or_create_by",
@@ -367,10 +365,8 @@ private module Persistence {
367365

368366
/** A call to e.g. `User.update(1, name: "foo")` */
369367
private class UpdateLikeClassMethodCall extends DataFlow::CallNode, PersistentWriteAccess::Range {
370-
private ActiveRecordModelClass modelCls;
371-
372368
UpdateLikeClassMethodCall() {
373-
modelCls = this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass() and
369+
exists(this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass()) and
374370
this.getMethodName() = ["update", "update!", "upsert"]
375371
}
376372

@@ -397,10 +393,9 @@ private module Persistence {
397393
/** A call to e.g. `User.insert_all([{name: "foo"}, {name: "bar"}])` */
398394
private class InsertAllLikeCall extends DataFlow::CallNode, PersistentWriteAccess::Range {
399395
private ExprNodes::ArrayLiteralCfgNode arr;
400-
private ActiveRecordModelClass modelCls;
401396

402397
InsertAllLikeCall() {
403-
modelCls = this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass() and
398+
exists(this.asExpr().getExpr().(ActiveRecordModelClassMethodCall).getReceiverClass()) and
404399
this.getMethodName() = ["insert_all", "insert_all!", "upsert_all"] and
405400
arr = this.getArgument(0).asExpr()
406401
}

ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,15 @@ module Kernel {
1818
* providing a specific receiver as in `Kernel.exit`.
1919
*/
2020
class KernelMethodCall extends DataFlow::CallNode {
21-
private MethodCall methodCall;
22-
2321
KernelMethodCall() {
24-
methodCall = this.asExpr().getExpr() and
22+
this = API::getTopLevelMember("Kernel").getAMethodCall(_)
23+
or
24+
this.asExpr().getExpr() instanceof UnknownMethodCall and
2525
(
26-
this = API::getTopLevelMember("Kernel").getAMethodCall(_)
26+
this.getReceiver().asExpr().getExpr() instanceof SelfVariableAccess and
27+
isPrivateKernelMethod(this.getMethodName())
2728
or
28-
methodCall instanceof UnknownMethodCall and
29-
(
30-
this.getReceiver().asExpr().getExpr() instanceof SelfVariableAccess and
31-
isPrivateKernelMethod(methodCall.getMethodName())
32-
or
33-
isPublicKernelMethod(methodCall.getMethodName())
34-
)
29+
isPublicKernelMethod(this.getMethodName())
3530
)
3631
}
3732
}

ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -119,18 +119,18 @@ class EmptyPositiveSubPatttern extends RegExpSubPattern {
119119
* whose root node is not a disjunction.
120120
*/
121121
class RegExpRoot extends RegExpTerm {
122-
RegExpParent parent;
123-
124122
RegExpRoot() {
125-
exists(RegExpAlt alt |
126-
alt.isRootTerm() and
127-
this = alt.getAChild() and
128-
parent = alt.getParent()
123+
exists(RegExpParent parent |
124+
exists(RegExpAlt alt |
125+
alt.isRootTerm() and
126+
this = alt.getAChild() and
127+
parent = alt.getParent()
128+
)
129+
or
130+
this.isRootTerm() and
131+
not this instanceof RegExpAlt and
132+
parent = this.getParent()
129133
)
130-
or
131-
this.isRootTerm() and
132-
not this instanceof RegExpAlt and
133-
parent = this.getParent()
134134
}
135135

136136
/**
@@ -466,13 +466,14 @@ private module CharacterClasses {
466466
* An implementation of `CharacterClass` for \d, \s, and \w.
467467
*/
468468
private class PositiveCharacterClassEscape extends CharacterClass {
469-
RegExpTerm cc;
470469
string charClass;
471470

472471
PositiveCharacterClassEscape() {
473-
isEscapeClass(cc, charClass) and
474-
this = getCanonicalCharClass(cc) and
475-
charClass = ["d", "s", "w"]
472+
exists(RegExpTerm cc |
473+
isEscapeClass(cc, charClass) and
474+
this = getCanonicalCharClass(cc) and
475+
charClass = ["d", "s", "w"]
476+
)
476477
}
477478

478479
override string getARelevantChar() {
@@ -504,13 +505,14 @@ private module CharacterClasses {
504505
* An implementation of `CharacterClass` for \D, \S, and \W.
505506
*/
506507
private class NegativeCharacterClassEscape extends CharacterClass {
507-
RegExpTerm cc;
508508
string charClass;
509509

510510
NegativeCharacterClassEscape() {
511-
isEscapeClass(cc, charClass) and
512-
this = getCanonicalCharClass(cc) and
513-
charClass = ["D", "S", "W"]
511+
exists(RegExpTerm cc |
512+
isEscapeClass(cc, charClass) and
513+
this = getCanonicalCharClass(cc) and
514+
charClass = ["D", "S", "W"]
515+
)
514516
}
515517

516518
override string getARelevantChar() {

ruby/ql/lib/codeql/ruby/security/performance/RegExpTreeView.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,11 @@ newtype TRegExpParent =
241241

242242
class RegExpQuantifier extends RegExpTerm, TRegExpQuantifier {
243243
int part_end;
244-
boolean maybe_empty;
245244
boolean may_repeat_forever;
246245

247246
RegExpQuantifier() {
248247
this = TRegExpQuantifier(re, start, end) and
249-
re.qualifiedPart(start, part_end, end, maybe_empty, may_repeat_forever)
248+
re.qualifiedPart(start, part_end, end, _, may_repeat_forever)
250249
}
251250

252251
override RegExpTerm getChild(int i) {

0 commit comments

Comments
 (0)