@@ -13,38 +13,100 @@ private import codeql.ruby.dataflow.BarrierGuards
1313module CodeInjection {
1414 /** Flow states used to distinguish whether an attacker controls the entire string. */
1515 module FlowState {
16- /** Flow state used for normal tainted data, where an attacker might only control a substring. */
17- DataFlow:: FlowState substring ( ) { result = "substring" }
16+ /**
17+ * Flow state used for normal tainted data, where an attacker might only control a substring.
18+ * DEPRECATED: Use `Full()`
19+ */
20+ deprecated DataFlow:: FlowState substring ( ) { result = "substring" }
21+
22+ /**
23+ * Flow state used for data that is entirely controlled by the attacker.
24+ * DEPRECATED: Use `Full()`
25+ */
26+ deprecated DataFlow:: FlowState full ( ) { result = "full" }
1827
19- /** Flow state used for data that is entirely controlled by the attacker. */
20- DataFlow:: FlowState full ( ) { result = "full" }
28+ private newtype TState =
29+ TFull ( ) or
30+ TSubString ( )
31+
32+ /** A flow state used to distinguish whether an attacker controls the entire string. */
33+ class State extends TState {
34+ /**
35+ * Gets a string representation of this state.
36+ */
37+ string toString ( ) { result = this .getStringRepresentation ( ) }
38+
39+ /**
40+ * Gets a canonical string representation of this state.
41+ */
42+ string getStringRepresentation ( ) {
43+ this = TSubString ( ) and result = "substring"
44+ or
45+ this = TFull ( ) and result = "full"
46+ }
47+ }
48+
49+ /**
50+ * A flow state used for normal tainted data, where an attacker might only control a substring.
51+ */
52+ class SubString extends State , TSubString { }
53+
54+ /**
55+ * A flow state used for data that is entirely controlled by the attacker.
56+ */
57+ class Full extends State , TFull { }
2158 }
2259
2360 /**
2461 * A data flow source for "Code injection" vulnerabilities.
2562 */
2663 abstract class Source extends DataFlow:: Node {
64+ /**
65+ * Gets a flow state for which this is a source.
66+ * DEPRECATED: Use `getAState()`
67+ */
68+ deprecated DataFlow:: FlowState getAFlowState ( ) {
69+ result = [ FlowState:: substring ( ) , FlowState:: full ( ) ]
70+ }
71+
2772 /** Gets a flow state for which this is a source. */
28- DataFlow:: FlowState getAFlowState ( ) { result = [ FlowState:: substring ( ) , FlowState:: full ( ) ] }
73+ FlowState:: State getAState ( ) {
74+ result instanceof FlowState:: SubString or result instanceof FlowState:: Full
75+ }
2976 }
3077
3178 /**
3279 * A data flow sink for "Code injection" vulnerabilities.
3380 */
3481 abstract class Sink extends DataFlow:: Node {
82+ /**
83+ * Holds if this sink is safe for an attacker that only controls a substring.
84+ * DEPRECATED: Use `getAState()`
85+ */
86+ deprecated DataFlow:: FlowState getAFlowState ( ) {
87+ result = [ FlowState:: substring ( ) , FlowState:: full ( ) ]
88+ }
89+
3590 /** Holds if this sink is safe for an attacker that only controls a substring. */
36- DataFlow :: FlowState getAFlowState ( ) { result = [ FlowState :: substring ( ) , FlowState :: full ( ) ] }
91+ FlowState :: State getAState ( ) { any ( ) }
3792 }
3893
3994 /**
4095 * A sanitizer for "Code injection" vulnerabilities.
4196 */
4297 abstract class Sanitizer extends DataFlow:: Node {
98+ /**
99+ * Gets a flow state for which this is a sanitizer.
100+ * Sanitizes all states if the result is empty.
101+ * DEPRECATED: Use `getAState()`
102+ */
103+ deprecated DataFlow:: FlowState getAFlowState ( ) { none ( ) }
104+
43105 /**
44106 * Gets a flow state for which this is a sanitizer.
45107 * Sanitizes all states if the result is empty.
46108 */
47- DataFlow :: FlowState getAFlowState ( ) { none ( ) }
109+ FlowState :: State getAState ( ) { none ( ) }
48110 }
49111
50112 /**
@@ -67,12 +129,17 @@ module CodeInjection {
67129
68130 CodeExecutionAsSink ( ) { this = c .getCode ( ) }
69131
70- /** Gets a flow state for which this is a sink. */
71- override DataFlow:: FlowState getAFlowState ( ) {
132+ deprecated override DataFlow:: FlowState getAFlowState ( ) {
72133 if c .runsArbitraryCode ( )
73134 then result = [ FlowState:: substring ( ) , FlowState:: full ( ) ] // If it runs arbitrary code then it's always vulnerable.
74135 else result = FlowState:: full ( ) // If it "just" loads something, then it's only vulnerable if the attacker controls the entire string.
75136 }
137+
138+ override FlowState:: State getAState ( ) {
139+ if c .runsArbitraryCode ( )
140+ then any ( ) // If it runs arbitrary code then it's always vulnerable.
141+ else result instanceof FlowState:: Full // If it "just" loads something, then it's only vulnerable if the attacker controls the entire string.
142+ }
76143 }
77144
78145 private import codeql.ruby.AST as Ast
@@ -92,6 +159,8 @@ module CodeInjection {
92159 )
93160 }
94161
95- override DataFlow:: FlowState getAFlowState ( ) { result = FlowState:: full ( ) }
162+ deprecated override DataFlow:: FlowState getAFlowState ( ) { result = FlowState:: full ( ) }
163+
164+ override FlowState:: State getAState ( ) { result instanceof FlowState:: Full }
96165 }
97166}
0 commit comments