Skip to content

Commit d180a55

Browse files
committed
Ruby: Fix value/taint flow in String summaries
1 parent f07ae35 commit d180a55

File tree

3 files changed

+283
-408
lines changed

3 files changed

+283
-408
lines changed

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

Lines changed: 68 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ private import codeql.ruby.DataFlow
66
private import codeql.ruby.dataflow.FlowSummary
77
private import codeql.ruby.dataflow.internal.DataFlowDispatch
88

9-
// TODO: the way we interpret `preservesValue` in this module may not be
10-
// correct: we assume that if the input string appears intact in the output,
11-
// then value is preserves. This means that we consider appending or prepending
12-
// characters to the string to be value-preserving.
13-
// We may want to be stricter here, and define value-preserving as when the
14-
// output string exactly matches the input string.
159
/**
1610
* Provides flow summaries for the `String` class.
1711
*
@@ -79,7 +73,7 @@ module String {
7973
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
8074
input = ["Receiver", "Argument[0]", "ArrayElement of Argument[0]"] and
8175
output = "ReturnValue" and
82-
preservesValue = true
76+
preservesValue = false
8377
}
8478
}
8579

@@ -110,7 +104,7 @@ module String {
110104
override MethodCall getACall() { result = mc }
111105

112106
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
113-
valueIdentityFlow(input, output, preservesValue)
107+
taintIdentityFlow(input, output, preservesValue)
114108
}
115109
}
116110

@@ -138,13 +132,10 @@ module String {
138132
CenterSummary() { this = ["center", "ljust", "rjust"] }
139133

140134
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
141-
(
142-
input = "Receiver" and
143-
output = "ReturnValue"
144-
or
145-
input = "Argument[1]" and
146-
output = "ReturnValue"
147-
) and
135+
taintIdentityFlow(input, output, preservesValue)
136+
or
137+
input = "Argument[1]" and
138+
output = "ReturnValue" and
148139
preservesValue = false
149140
}
150141
}
@@ -160,13 +151,12 @@ module String {
160151
override MethodCall getACall() { result = mc }
161152

162153
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
154+
taintIdentityFlow(input, output, preservesValue)
155+
or
156+
this = ["chomp!", "chop!"] and
163157
input = "Receiver" and
164158
preservesValue = false and
165-
(
166-
output = "ReturnValue"
167-
or
168-
this = ["chomp!", "chop!"] and output = "Receiver"
169-
)
159+
output = "Receiver"
170160
}
171161
}
172162

@@ -185,7 +175,7 @@ module String {
185175
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
186176
input = ["Receiver", "Argument[_]"] and
187177
output = ["ReturnValue", "Receiver"] and
188-
preservesValue = true
178+
preservesValue = false
189179
}
190180
}
191181

@@ -279,9 +269,7 @@ module String {
279269
ForceEncodingSummary() { this = "force_encoding" }
280270

281271
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
282-
input = "Receiver" and
283-
output = "ReturnValue" and
284-
preservesValue = false
272+
taintIdentityFlow(input, output, preservesValue)
285273
}
286274
}
287275

@@ -309,13 +297,9 @@ module String {
309297
// receiver -> return value
310298
// replacement -> return value
311299
// block return -> return value
312-
(
313-
input = ["Receiver", "Argument[1]"] and
314-
preservesValue = false
315-
or
316-
input = "ReturnValue of BlockArgument" and preservesValue = true
317-
) and
318-
output = "ReturnValue"
300+
preservesValue = false and
301+
output = "ReturnValue" and
302+
input = ["Receiver", "Argument[1]", "ReturnValue of BlockArgument"]
319303
}
320304
}
321305

@@ -330,12 +314,9 @@ module String {
330314
}
331315

332316
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
333-
(
334-
input = "Receiver" and preservesValue = false
335-
or
336-
input = "Argument[1]" and preservesValue = true
337-
) and
338-
output = "ReturnValue"
317+
taintIdentityFlow(input, output, preservesValue)
318+
or
319+
input = "Argument[1]" and output = "ReturnValue" and preservesValue = false
339320
}
340321
}
341322

@@ -357,7 +338,7 @@ module String {
357338
StripSummary() { this = ["strip", "lstrip", "rstrip"] + ["", "!"] }
358339

359340
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
360-
valueIdentityFlow(input, output, preservesValue)
341+
taintIdentityFlow(input, output, preservesValue)
361342
}
362343
}
363344

@@ -427,14 +408,14 @@ module String {
427408

428409
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
429410
input = "Receiver" and
430-
(
431-
// Parameter[_] doesn't seem to work
432-
output = "Parameter[" + [0 .. 10] + "] of BlockArgument" and preservesValue = false
433-
or
434-
// scan(pattern) -> array
435-
output = "ReturnValue" and
436-
preservesValue = true
437-
)
411+
preservesValue = false and
412+
output =
413+
[
414+
// scan(pattern) -> array
415+
"ReturnValue",
416+
// Parameter[_] doesn't seem to work
417+
"Parameter[" + [0 .. 10] + "] of BlockArgument"
418+
]
438419
}
439420
}
440421

@@ -443,14 +424,14 @@ module String {
443424

444425
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
445426
input = "Receiver" and
446-
(
447-
// scan(pattern) {|match, ...| block } -> str
448-
output = "ArrayElement[?] of ReturnValue" and
449-
preservesValue = false
450-
or
451-
// Parameter[_] doesn't seem to work
452-
output = "Parameter[" + [0 .. 10] + "] of BlockArgument" and preservesValue = false
453-
)
427+
preservesValue = false and
428+
output =
429+
[
430+
// scan(pattern) {|match, ...| block } -> str
431+
"ArrayElement[?] of ReturnValue",
432+
// Parameter[_] doesn't seem to work
433+
"Parameter[" + [0 .. 10] + "] of BlockArgument"
434+
]
454435
}
455436
}
456437

@@ -470,35 +451,48 @@ module String {
470451
ScrubBlockSummary() { this = "scrub_block" and exists(mc.getBlock()) }
471452

472453
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
473-
input = "Receiver" and
474-
output = "Parameter[0] of BlockArgument" and
475-
preservesValue = true
476-
or
477-
input = "Argument[0]" and output = "ReturnValue" and preservesValue = true
478-
or
479-
input = "ReturnValue of BlockArgument" and
480-
output = "ReturnValue" and
481-
preservesValue = true
482-
or
483454
taintIdentityFlow(input, output, preservesValue)
455+
or
456+
preservesValue = false and
457+
(
458+
input = "Receiver" and
459+
output = "Parameter[0] of BlockArgument"
460+
or
461+
input = "Argument[0]" and output = "ReturnValue"
462+
or
463+
input = "ReturnValue of BlockArgument" and
464+
output = "ReturnValue"
465+
)
484466
}
485467
}
486468

487469
private class ScrubNoBlockSummary extends ScrubSummary {
488470
ScrubNoBlockSummary() { this = "scrub_no_block" and not exists(mc.getBlock()) }
489471

490472
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
491-
input = "Receiver" and
492-
output = "Parameter[0] of BlockArgument" and
493-
preservesValue = true
494-
or
495-
input = "Argument[0]" and output = "ReturnValue" and preservesValue = true
473+
taintIdentityFlow(input, output, preservesValue)
496474
or
475+
preservesValue = false and
476+
(
477+
input = "Receiver" and
478+
output = "Parameter[0] of BlockArgument"
479+
or
480+
input = "Argument[0]" and output = "ReturnValue"
481+
)
482+
}
483+
}
484+
485+
/**
486+
* A flow summary for `String#shellescape`.
487+
*/
488+
private class ShellescapeSummary extends SimpleSummarizedCallable {
489+
ShellescapeSummary() { this = "shellescape" }
490+
491+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
497492
taintIdentityFlow(input, output, preservesValue)
498493
}
499494
}
500495

501-
// TODO: what do we do about `String#shellescape`?
502496
/**
503497
* A flow summary for `String#shellsplit`.
504498
*/
@@ -552,7 +546,9 @@ module String {
552546
TrSummary() { this = ["tr", "tr_s"] + ["", "!"] }
553547

554548
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
555-
input = ["Receiver", "Argument[1]"] and output = "ReturnValue" and preservesValue = false
549+
taintIdentityFlow(input, output, preservesValue)
550+
or
551+
input = "Argument[1]" and output = "ReturnValue" and preservesValue = false
556552
}
557553
}
558554

@@ -604,7 +600,7 @@ module String {
604600
}
605601

606602
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
607-
input = ["Receiver"] and
603+
input = "Receiver" and
608604
output = "Parameter[0] of BlockArgument" and
609605
preservesValue = true
610606
or

0 commit comments

Comments
 (0)