Skip to content

Commit 226bd1f

Browse files
committed
add flow-state support to sanitizers in code-execution, and use that to refactor the string-concatenation-sanitizer
1 parent 3e51f6f commit 226bd1f

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

ruby/ql/lib/codeql/ruby/security/CodeInjectionCustomizations.qll

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ module CodeInjection {
3939
/**
4040
* A sanitizer for "Code injection" vulnerabilities.
4141
*/
42-
abstract class Sanitizer extends DataFlow::Node { }
42+
abstract class Sanitizer extends DataFlow::Node {
43+
/**
44+
* Gets a flow state for which this is a sanitizer.
45+
* Sanitizes all states if the result is empty.
46+
*/
47+
DataFlow::FlowState getAFlowState() { none() }
48+
}
4349

4450
/**
4551
* DEPRECATED: Use `Sanitizer` instead.
@@ -68,4 +74,24 @@ module CodeInjection {
6874
else result = FlowState::full() // If it "just" loads something, then it's only vulnerable if the attacker controls the entire string.
6975
}
7076
}
77+
78+
private import codeql.ruby.AST as Ast
79+
80+
/**
81+
* A string-concatenation that sanitizes the `full()` state.
82+
*/
83+
class StringConcatenationSanitizer extends Sanitizer {
84+
StringConcatenationSanitizer() {
85+
// string concatenations sanitize the `full` state, as an attacker no longer controls the entire string
86+
exists(Ast::AstNode str |
87+
str instanceof Ast::StringLiteral
88+
or
89+
str instanceof Ast::AddExpr
90+
|
91+
this.asExpr().getExpr() = str
92+
)
93+
}
94+
95+
override DataFlow::FlowState getAFlowState() { result = FlowState::full() }
96+
}
7197
}

ruby/ql/lib/codeql/ruby/security/CodeInjectionQuery.qll

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import codeql.ruby.DataFlow
99
import codeql.ruby.TaintTracking
1010
import CodeInjectionCustomizations::CodeInjection
1111
import codeql.ruby.dataflow.BarrierGuards
12-
private import codeql.ruby.AST as Ast
1312

1413
/**
1514
* A taint-tracking configuration for detecting "Code injection" vulnerabilities.
@@ -26,21 +25,15 @@ class Configuration extends TaintTracking::Configuration {
2625
}
2726

2827
override predicate isSanitizer(DataFlow::Node node) {
29-
node instanceof Sanitizer or
30-
node instanceof StringConstCompareBarrier or
28+
node instanceof Sanitizer and not exists(node.(Sanitizer).getAFlowState())
29+
or
30+
node instanceof StringConstCompareBarrier
31+
or
3132
node instanceof StringConstArrayInclusionCallBarrier
3233
}
3334

3435
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
35-
// string concatenations sanitize the `full` state, as an attacker no longer controls the entire string
36-
exists(Ast::AstNode str |
37-
str instanceof Ast::StringLiteral
38-
or
39-
str instanceof Ast::AddExpr
40-
|
41-
node.asExpr().getExpr() = str and
42-
state = FlowState::full()
43-
)
36+
node.(Sanitizer).getAFlowState() = state
4437
}
4538

4639
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {

0 commit comments

Comments
 (0)