Skip to content

Commit 0000a7d

Browse files
committed
Ruby: Summarize load-store steps in type-tracking
fixup to LoadStore
1 parent a4d4e40 commit 0000a7d

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ private module Cached {
1414
ReturnStep() or
1515
StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
1616
LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
17+
LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
18+
basicLoadStoreStep(_, _, load, store)
19+
} or
1720
JumpStep()
1821

1922
cached
@@ -75,6 +78,16 @@ private module Cached {
7578
tt = noContentTypeTracker(hasCall) and
7679
result = MkTypeTracker(hasCall, storeContents)
7780
)
81+
or
82+
exists(
83+
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
84+
boolean hasCall
85+
|
86+
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
87+
compatibleContents(pragma[only_bind_into](currentContent), load) and
88+
tt = MkTypeTracker(pragma[only_bind_into](hasCall), currentContent) and
89+
result = MkTypeTracker(pragma[only_bind_out](hasCall), store)
90+
)
7891
}
7992

8093
pragma[nomagic]
@@ -110,6 +123,16 @@ private module Cached {
110123
tbt = noContentTypeBackTracker(hasReturn) and
111124
result = MkTypeBackTracker(hasReturn, loadContents)
112125
)
126+
or
127+
exists(
128+
TypeTrackerContent currentContent, TypeTrackerContent store, TypeTrackerContent load,
129+
boolean hasCall
130+
|
131+
step = LoadStoreStep(pragma[only_bind_into](load), pragma[only_bind_into](store)) and
132+
compatibleContents(store, pragma[only_bind_into](currentContent)) and
133+
tbt = MkTypeBackTracker(pragma[only_bind_into](hasCall), currentContent) and
134+
result = MkTypeBackTracker(pragma[only_bind_out](hasCall), load)
135+
)
113136
}
114137

115138
/**
@@ -146,6 +169,11 @@ private module Cached {
146169
or
147170
basicLoadStep(nodeFrom, nodeTo, content) and summary = LoadStep(content)
148171
)
172+
or
173+
exists(TypeTrackerContent loadContent, TypeTrackerContent storeContent |
174+
basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent) and
175+
summary = LoadStoreStep(loadContent, storeContent)
176+
)
149177
}
150178

151179
cached
@@ -208,6 +236,11 @@ class StepSummary extends TStepSummary {
208236
or
209237
exists(TypeTrackerContent content | this = LoadStep(content) | result = "load " + content)
210238
or
239+
exists(TypeTrackerContent load, TypeTrackerContent store |
240+
this = LoadStoreStep(load, store) and
241+
result = "load-store " + load + " -> " + store
242+
)
243+
or
211244
this instanceof JumpStep and result = "jump"
212245
}
213246
}

ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,23 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet content
231231
)
232232
}
233233

234+
/**
235+
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
236+
*/
237+
predicate basicLoadStoreStep(
238+
Node nodeFrom, Node nodeTo, DataFlow::ContentSet loadContent, DataFlow::ContentSet storeContent
239+
) {
240+
exists(
241+
SummarizedCallable callable, DataFlowPublic::CallNode call, SummaryComponent input,
242+
SummaryComponent output
243+
|
244+
hasLoadStoreSummary(callable, loadContent, storeContent, input, output) and
245+
call.asExpr().getExpr() = callable.getACallSimple() and
246+
nodeFrom = evaluateSummaryComponentLocal(call, input) and
247+
nodeTo = evaluateSummaryComponentLocal(call, output)
248+
)
249+
}
250+
234251
/**
235252
* A utility class that is equivalent to `boolean` but does not require type joining.
236253
*/
@@ -264,6 +281,15 @@ private predicate hasLoadSummary(
264281
singleton(output), true)
265282
}
266283

284+
private predicate hasLoadStoreSummary(
285+
SummarizedCallable callable, DataFlow::ContentSet loadContents,
286+
DataFlow::ContentSet storeContents, SummaryComponent input, SummaryComponent output
287+
) {
288+
callable
289+
.propagatesFlow(push(SummaryComponent::content(loadContents), singleton(input)),
290+
push(SummaryComponent::content(storeContents), singleton(output)), true)
291+
}
292+
267293
/**
268294
* Gets a data flow node corresponding an argument or return value of `call`,
269295
* as specified by `component`.

0 commit comments

Comments
 (0)