Skip to content

Commit 80ac05d

Browse files
committed
Bump codeql submodule to 'main'
1 parent 6a18aa4 commit 80ac05d

File tree

6 files changed

+210
-58
lines changed

6 files changed

+210
-58
lines changed

codeql

Submodule codeql updated 966 files

ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
21392139
) and
21402140
accessPathApproxCostLimits(apLimit, tupleLimit) and
21412141
apLimit < tails and
2142-
tupleLimit < (tails - 1) * nodes
2142+
tupleLimit < (tails - 1) * nodes and
2143+
not tc.forceHighPrecision()
21432144
)
21442145
}
21452146

@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
29732974
* expected to be expensive. Holds with `unfold = true` otherwise.
29742975
*/
29752976
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
2976-
exists(int aps, int nodes, int apLimit, int tupleLimit |
2977-
aps = countPotentialAps(apa, config) and
2978-
nodes = countNodesUsingAccessPath(apa, config) and
2979-
accessPathCostLimits(apLimit, tupleLimit) and
2980-
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
2981-
)
2977+
if apa.getHead().forceHighPrecision()
2978+
then unfold = true
2979+
else
2980+
exists(int aps, int nodes, int apLimit, int tupleLimit |
2981+
aps = countPotentialAps(apa, config) and
2982+
nodes = countNodesUsingAccessPath(apa, config) and
2983+
accessPathCostLimits(apLimit, tupleLimit) and
2984+
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
2985+
)
29822986
}
29832987

29842988
/**
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
32483252
* The location spans column `startcolumn` of line `startline` to
32493253
* column `endcolumn` of line `endline` in file `filepath`.
32503254
* For more information, see
3251-
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
3255+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
32523256
*/
32533257
predicate hasLocationInfo(
32543258
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -4033,7 +4037,7 @@ private module FlowExploration {
40334037
* The location spans column `startcolumn` of line `startline` to
40344038
* column `endcolumn` of line `endline` in file `filepath`.
40354039
* For more information, see
4036-
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
4040+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
40374041
*/
40384042
predicate hasLocationInfo(
40394043
string filepath, int startline, int startcolumn, int endline, int endcolumn

ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
21392139
) and
21402140
accessPathApproxCostLimits(apLimit, tupleLimit) and
21412141
apLimit < tails and
2142-
tupleLimit < (tails - 1) * nodes
2142+
tupleLimit < (tails - 1) * nodes and
2143+
not tc.forceHighPrecision()
21432144
)
21442145
}
21452146

@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
29732974
* expected to be expensive. Holds with `unfold = true` otherwise.
29742975
*/
29752976
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
2976-
exists(int aps, int nodes, int apLimit, int tupleLimit |
2977-
aps = countPotentialAps(apa, config) and
2978-
nodes = countNodesUsingAccessPath(apa, config) and
2979-
accessPathCostLimits(apLimit, tupleLimit) and
2980-
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
2981-
)
2977+
if apa.getHead().forceHighPrecision()
2978+
then unfold = true
2979+
else
2980+
exists(int aps, int nodes, int apLimit, int tupleLimit |
2981+
aps = countPotentialAps(apa, config) and
2982+
nodes = countNodesUsingAccessPath(apa, config) and
2983+
accessPathCostLimits(apLimit, tupleLimit) and
2984+
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
2985+
)
29822986
}
29832987

29842988
/**
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
32483252
* The location spans column `startcolumn` of line `startline` to
32493253
* column `endcolumn` of line `endline` in file `filepath`.
32503254
* For more information, see
3251-
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
3255+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
32523256
*/
32533257
predicate hasLocationInfo(
32543258
string filepath, int startline, int startcolumn, int endline, int endcolumn
@@ -4033,7 +4037,7 @@ private module FlowExploration {
40334037
* The location spans column `startcolumn` of line `startline` to
40344038
* column `endcolumn` of line `endline` in file `filepath`.
40354039
* For more information, see
4036-
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
4040+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
40374041
*/
40384042
predicate hasLocationInfo(
40394043
string filepath, int startline, int startcolumn, int endline, int endcolumn

ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,13 @@ class TypedContent extends MkTypedContent {
12361236

12371237
/** Gets a textual representation of this content. */
12381238
string toString() { result = c.toString() }
1239+
1240+
/**
1241+
* Holds if access paths with this `TypedContent` at their head always should
1242+
* be tracked at high precision. This disables adaptive access path precision
1243+
* for such access paths.
1244+
*/
1245+
predicate forceHighPrecision() { forceHighPrecision(c) }
12391246
}
12401247

12411248
/**

ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 169 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,17 @@ module Private {
186186
TArgumentSummaryComponent(int i) { parameterPosition(i) } or
187187
TReturnSummaryComponent(ReturnKind rk)
188188

189+
private TSummaryComponent thisParam() {
190+
result = TParameterSummaryComponent(instanceParameterPosition())
191+
}
192+
189193
newtype TSummaryComponentStack =
190194
TSingletonSummaryComponentStack(SummaryComponent c) or
191195
TConsSummaryComponentStack(SummaryComponent head, SummaryComponentStack tail) {
192196
tail.(RequiredSummaryComponentStack).required(head)
197+
or
198+
tail.(RequiredSummaryComponentStack).required(TParameterSummaryComponent(_)) and
199+
head = thisParam()
193200
}
194201

195202
pragma[nomagic]
@@ -198,21 +205,63 @@ module Private {
198205
boolean preservesValue
199206
) {
200207
c.propagatesFlow(input, output, preservesValue)
208+
or
209+
// observe side effects of callbacks on input arguments
210+
c.propagatesFlow(output, input, preservesValue) and
211+
preservesValue = true and
212+
isCallbackParameter(input) and
213+
isContentOfArgument(output)
214+
or
215+
// flow from the receiver of a callback into the instance-parameter
216+
exists(SummaryComponentStack s, SummaryComponentStack callbackRef |
217+
c.propagatesFlow(s, _, _) or c.propagatesFlow(_, s, _)
218+
|
219+
callbackRef = s.drop(_) and
220+
(isCallbackParameter(callbackRef) or callbackRef.head() = TReturnSummaryComponent(_)) and
221+
input = callbackRef.tail() and
222+
output = TConsSummaryComponentStack(thisParam(), input) and
223+
preservesValue = true
224+
)
225+
}
226+
227+
private predicate isCallbackParameter(SummaryComponentStack s) {
228+
s.head() = TParameterSummaryComponent(_) and exists(s.tail())
229+
}
230+
231+
private predicate isContentOfArgument(SummaryComponentStack s) {
232+
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail())
233+
or
234+
s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(_))
235+
}
236+
237+
private predicate outputState(SummarizedCallable c, SummaryComponentStack s) {
238+
summary(c, _, s, _)
239+
or
240+
exists(SummaryComponentStack out |
241+
outputState(c, out) and
242+
out.head() = TContentSummaryComponent(_) and
243+
s = out.tail()
244+
)
245+
or
246+
// Add the argument node corresponding to the requested post-update node
247+
inputState(c, s) and isCallbackParameter(s)
248+
}
249+
250+
private predicate inputState(SummarizedCallable c, SummaryComponentStack s) {
251+
summary(c, s, _, _)
252+
or
253+
exists(SummaryComponentStack inp | inputState(c, inp) and s = inp.tail())
254+
or
255+
exists(SummaryComponentStack out |
256+
outputState(c, out) and
257+
out.head() = TParameterSummaryComponent(_) and
258+
s = out.tail()
259+
)
201260
}
202261

203262
private newtype TSummaryNodeState =
204-
TSummaryNodeInputState(SummaryComponentStack s) {
205-
exists(SummaryComponentStack input |
206-
summary(_, input, _, _) and
207-
s = input.drop(_)
208-
)
209-
} or
210-
TSummaryNodeOutputState(SummaryComponentStack s) {
211-
exists(SummaryComponentStack output |
212-
summary(_, _, output, _) and
213-
s = output.drop(_)
214-
)
215-
}
263+
TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or
264+
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) }
216265

217266
/**
218267
* A state used to break up (complex) flow summaries into atomic flow steps.
@@ -238,20 +287,14 @@ module Private {
238287
pragma[nomagic]
239288
predicate isInputState(SummarizedCallable c, SummaryComponentStack s) {
240289
this = TSummaryNodeInputState(s) and
241-
exists(SummaryComponentStack input |
242-
summary(c, input, _, _) and
243-
s = input.drop(_)
244-
)
290+
inputState(c, s)
245291
}
246292

247293
/** Holds if this state is a valid output state for `c`. */
248294
pragma[nomagic]
249295
predicate isOutputState(SummarizedCallable c, SummaryComponentStack s) {
250296
this = TSummaryNodeOutputState(s) and
251-
exists(SummaryComponentStack output |
252-
summary(c, _, output, _) and
253-
s = output.drop(_)
254-
)
297+
outputState(c, s)
255298
}
256299

257300
/** Gets a textual representation of this state. */
@@ -331,19 +374,12 @@ module Private {
331374
receiver = summaryNodeInputState(c, s.drop(1))
332375
}
333376

334-
private Node pre(Node post) {
335-
summaryPostUpdateNode(post, result)
336-
or
337-
not summaryPostUpdateNode(post, _) and
338-
result = post
339-
}
340-
341377
private predicate callbackInput(
342378
SummarizedCallable c, SummaryComponentStack s, Node receiver, int i
343379
) {
344380
any(SummaryNodeState state).isOutputState(c, s) and
345381
s.head() = TParameterSummaryComponent(i) and
346-
receiver = pre(summaryNodeOutputState(c, s.drop(1)))
382+
receiver = summaryNodeInputState(c, s.drop(1))
347383
}
348384

349385
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
@@ -395,7 +431,7 @@ module Private {
395431
or
396432
exists(int i | head = TParameterSummaryComponent(i) |
397433
result =
398-
getCallbackParameterType(getNodeType(summaryNodeOutputState(pragma[only_bind_out](c),
434+
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
399435
s.drop(1))), i)
400436
)
401437
)
@@ -421,10 +457,16 @@ module Private {
421457
}
422458

423459
/** Holds if summary node `post` is a post-update node with pre-update node `pre`. */
424-
predicate summaryPostUpdateNode(Node post, ParamNode pre) {
460+
predicate summaryPostUpdateNode(Node post, Node pre) {
425461
exists(SummarizedCallable c, int i |
426462
isParameterPostUpdate(post, c, i) and
427-
pre.isParameterOf(c, i)
463+
pre.(ParamNode).isParameterOf(c, i)
464+
)
465+
or
466+
exists(SummarizedCallable callable, SummaryComponentStack s |
467+
callbackInput(callable, s, _, _) and
468+
pre = summaryNodeOutputState(callable, s) and
469+
post = summaryNodeInputState(callable, s)
428470
)
429471
}
430472

@@ -462,7 +504,11 @@ module Private {
462504
// for `StringBuilder.append(x)` with a specified value flow from qualifier to
463505
// return value and taint flow from argument 0 to the qualifier, then this
464506
// allows us to infer taint flow from argument 0 to the return value.
465-
summaryPostUpdateNode(pred, succ) and preservesValue = true
507+
succ instanceof ParamNode and summaryPostUpdateNode(pred, succ) and preservesValue = true
508+
or
509+
// Similarly we would like to chain together summaries where values get passed
510+
// into callbacks along the way.
511+
pred instanceof ArgNode and summaryPostUpdateNode(succ, pred) and preservesValue = true
466512
}
467513

468514
/**
@@ -824,4 +870,95 @@ module Private {
824870
)
825871
}
826872
}
873+
874+
/**
875+
* Provides query predicates for rendering the generated data flow graph for
876+
* a summarized callable.
877+
*
878+
* Import this module into a `.ql` file of `@kind graph` to render the graph.
879+
* The graph is restricted to callables from `RelevantSummarizedCallable`.
880+
*/
881+
module RenderSummarizedCallable {
882+
/** A summarized callable to include in the graph. */
883+
abstract class RelevantSummarizedCallable extends SummarizedCallable { }
884+
885+
private newtype TNodeOrCall =
886+
MkNode(Node n) {
887+
exists(RelevantSummarizedCallable c |
888+
n = summaryNode(c, _)
889+
or
890+
n.(ParamNode).isParameterOf(c, _)
891+
)
892+
} or
893+
MkCall(DataFlowCall call) {
894+
call = summaryDataFlowCall(_) and
895+
call.getEnclosingCallable() instanceof RelevantSummarizedCallable
896+
}
897+
898+
private class NodeOrCall extends TNodeOrCall {
899+
Node asNode() { this = MkNode(result) }
900+
901+
DataFlowCall asCall() { this = MkCall(result) }
902+
903+
string toString() {
904+
result = this.asNode().toString()
905+
or
906+
result = this.asCall().toString()
907+
}
908+
909+
/**
910+
* Holds if this element is at the specified location.
911+
* The location spans column `startcolumn` of line `startline` to
912+
* column `endcolumn` of line `endline` in file `filepath`.
913+
* For more information, see
914+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
915+
*/
916+
predicate hasLocationInfo(
917+
string filepath, int startline, int startcolumn, int endline, int endcolumn
918+
) {
919+
this.asNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
920+
or
921+
this.asCall().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
922+
}
923+
}
924+
925+
query predicate nodes(NodeOrCall n, string key, string val) {
926+
key = "semmle.label" and val = n.toString()
927+
}
928+
929+
private predicate edgesComponent(NodeOrCall a, NodeOrCall b, string value) {
930+
exists(boolean preservesValue |
931+
Private::Steps::summaryLocalStep(a.asNode(), b.asNode(), preservesValue) and
932+
if preservesValue = true then value = "value" else value = "taint"
933+
)
934+
or
935+
exists(Content c |
936+
Private::Steps::summaryReadStep(a.asNode(), c, b.asNode()) and
937+
value = "read (" + c + ")"
938+
or
939+
Private::Steps::summaryStoreStep(a.asNode(), c, b.asNode()) and
940+
value = "store (" + c + ")"
941+
or
942+
Private::Steps::summaryClearsContent(a.asNode(), c) and
943+
b = a and
944+
value = "clear (" + c + ")"
945+
)
946+
or
947+
summaryPostUpdateNode(b.asNode(), a.asNode()) and
948+
value = "post-update"
949+
or
950+
b.asCall() = summaryDataFlowCall(a.asNode()) and
951+
value = "receiver"
952+
or
953+
exists(int i |
954+
summaryArgumentNode(b.asCall(), a.asNode(), i) and
955+
value = "argument (" + i + ")"
956+
)
957+
}
958+
959+
query predicate edges(NodeOrCall a, NodeOrCall b, string key, string value) {
960+
key = "semmle.label" and
961+
value = strictconcat(string s | edgesComponent(a, b, s) | s, " / ")
962+
}
963+
}
827964
}

0 commit comments

Comments
 (0)