Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1b4fef9

Browse files
committed
Make HTMLTemplateEscapingPassthrough use new API
Removed edges and nodes are mostly duplicates. They were only there originally due to multiple configurations being in scope. `DataFlow::PathNode` has union semantics for configurations. Nodes are only generated if they are reachable from a source, but this includes sources from other configurations. No alerts are lost.
1 parent ea1f396 commit 1b4fef9

2 files changed

Lines changed: 41 additions & 139 deletions

File tree

go/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql

Lines changed: 41 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
*/
1212

1313
import go
14-
import DataFlow::PathGraph
1514

1615
/**
1716
* Holds if the provided `untrusted` node flows into a conversion to a PassthroughType.
@@ -21,10 +20,10 @@ import DataFlow::PathGraph
2120
predicate flowsFromUntrustedToConversion(
2221
DataFlow::Node untrusted, PassthroughTypeName targetType, DataFlow::Node conversionSink
2322
) {
24-
exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::Node source |
25-
cfg.hasFlow(source, conversionSink) and
23+
exists(DataFlow::Node source |
24+
UntrustedToPassthroughTypeConversionFlow::flow(source, conversionSink) and
2625
source = untrusted and
27-
targetType = cfg.getDstTypeName()
26+
UntrustedToPassthroughTypeConversionConfig::isSinkToPassthroughType(conversionSink, targetType)
2827
)
2928
}
3029

@@ -42,72 +41,45 @@ class PassthroughTypeName extends string {
4241
* this allows the injection of arbitrary content (html, css, js) into the generated
4342
* output of the templates.
4443
*/
45-
class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Configuration {
46-
PassthroughTypeName dstTypeName;
44+
module UntrustedToPassthroughTypeConversionConfig implements DataFlow::ConfigSig {
45+
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
4746

48-
FlowConfFromUntrustedToPassthroughTypeConversion() {
49-
this = "UntrustedToConversion" + dstTypeName
50-
}
51-
52-
/**
53-
* Gets the name of conversion's destination type.
54-
*/
55-
PassthroughTypeName getDstTypeName() { result = dstTypeName }
56-
57-
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
58-
59-
private predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, PassthroughTypeName name) {
47+
additional predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, PassthroughTypeName name) {
6048
exists(Type typ |
6149
typ = sink.getResultType() and
6250
typ.getUnderlyingType*().hasQualifiedName("html/template", name)
6351
)
6452
}
6553

66-
override predicate isSink(DataFlow::Node sink) { this.isSinkToPassthroughType(sink, dstTypeName) }
54+
predicate isSink(DataFlow::Node sink) { isSinkToPassthroughType(sink, _) }
6755

68-
override predicate isSanitizer(DataFlow::Node sanitizer) {
69-
sanitizer instanceof SharedXss::Sanitizer or sanitizer.getType() instanceof NumericType
56+
predicate isBarrier(DataFlow::Node node) {
57+
node instanceof SharedXss::Sanitizer or node.getType() instanceof NumericType
7058
}
7159
}
7260

61+
module UntrustedToPassthroughTypeConversionFlow =
62+
TaintTracking::Global<UntrustedToPassthroughTypeConversionConfig>;
63+
7364
/**
7465
* Holds if the provided `conversion` node flows into the provided `execSink`.
7566
*/
7667
predicate flowsFromConversionToExec(
7768
DataFlow::Node conversion, PassthroughTypeName targetType, DataFlow::Node execSink
7869
) {
79-
exists(
80-
FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::Node source,
81-
DataFlow::Node execSinkLocal
82-
|
83-
cfg.hasFlow(source, execSinkLocal) and
84-
source = conversion and
85-
execSink = execSinkLocal and
86-
targetType = cfg.getDstTypeName()
87-
)
70+
PassthroughTypeConversionToTemplateExecutionCallFlow::flow(conversion, execSink) and
71+
PassthroughTypeConversionToTemplateExecutionCallConfig::isSourceConversionToPassthroughType(conversion,
72+
targetType)
8873
}
8974

9075
/**
9176
* A taint-tracking configuration for reasoning about when the result of a conversion
9277
* to a PassthroughType flows to a template execution call.
9378
*/
94-
class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking::Configuration {
95-
PassthroughTypeName dstTypeName;
96-
97-
FlowConfPassthroughTypeConversionToTemplateExecutionCall() {
98-
this = "ConversionToExec" + dstTypeName
99-
}
79+
module PassthroughTypeConversionToTemplateExecutionCallConfig implements DataFlow::ConfigSig {
80+
predicate isSource(DataFlow::Node source) { isSourceConversionToPassthroughType(source, _) }
10081

101-
/**
102-
* Gets the name of conversion's destination type.
103-
*/
104-
PassthroughTypeName getDstTypeName() { result = dstTypeName }
105-
106-
override predicate isSource(DataFlow::Node source) {
107-
this.isSourceConversionToPassthroughType(source, dstTypeName)
108-
}
109-
110-
private predicate isSourceConversionToPassthroughType(
82+
additional predicate isSourceConversionToPassthroughType(
11183
DataFlow::TypeCastNode source, PassthroughTypeName name
11284
) {
11385
exists(Type typ |
@@ -116,9 +88,12 @@ class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTrac
11688
)
11789
}
11890

119-
override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
91+
predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
12092
}
12193

94+
module PassthroughTypeConversionToTemplateExecutionCallFlow =
95+
TaintTracking::Global<PassthroughTypeConversionToTemplateExecutionCallConfig>;
96+
12297
/**
12398
* Holds if the sink is a data value argument of a template execution call.
12499
*/
@@ -137,37 +112,42 @@ predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) {
137112
* A taint-tracking configuration for reasoning about when an UntrustedFlowSource
138113
* flows into a template executor call.
139114
*/
140-
class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking::Configuration {
141-
FlowConfFromUntrustedToTemplateExecutionCall() {
142-
this = "FlowConfFromUntrustedToTemplateExecutionCall"
143-
}
115+
module FromUntrustedToTemplateExecutionCallConfig implements DataFlow::ConfigSig {
116+
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
144117

145-
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
146-
147-
override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
118+
predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
148119
}
149120

121+
module FromUntrustedToTemplateExecutionCallFlow =
122+
TaintTracking::Global<FromUntrustedToTemplateExecutionCallConfig>;
123+
124+
import FromUntrustedToTemplateExecutionCallFlow::PathGraph
125+
150126
/**
151127
* Holds if the provided `untrusted` node flows into the provided `execSink`.
152128
*/
153-
predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathNode execSink) {
154-
exists(FlowConfFromUntrustedToTemplateExecutionCall cfg | cfg.hasFlowPath(untrusted, execSink))
129+
predicate flowsFromUntrustedToExec(
130+
FromUntrustedToTemplateExecutionCallFlow::PathNode untrusted,
131+
FromUntrustedToTemplateExecutionCallFlow::PathNode execSink
132+
) {
133+
FromUntrustedToTemplateExecutionCallFlow::flowPath(untrusted, execSink)
155134
}
156135

157136
from
158-
DataFlow::PathNode untrustedSource, DataFlow::PathNode templateExecCall,
159-
PassthroughTypeName targetTypeName, DataFlow::PathNode conversion
137+
FromUntrustedToTemplateExecutionCallFlow::PathNode untrustedSource,
138+
FromUntrustedToTemplateExecutionCallFlow::PathNode templateExecCall,
139+
PassthroughTypeName targetTypeName, DataFlow::Node conversion
160140
where
161141
// A = untrusted remote flow source
162142
// B = conversion to PassthroughType
163143
// C = template execution call
164144
// Flows:
165145
// A -> B
166-
flowsFromUntrustedToConversion(untrustedSource.getNode(), targetTypeName, conversion.getNode()) and
146+
flowsFromUntrustedToConversion(untrustedSource.getNode(), targetTypeName, conversion) and
167147
// B -> C
168-
flowsFromConversionToExec(conversion.getNode(), targetTypeName, templateExecCall.getNode()) and
148+
flowsFromConversionToExec(conversion, targetTypeName, templateExecCall.getNode()) and
169149
// A -> C
170150
flowsFromUntrustedToExec(untrustedSource, templateExecCall)
171151
select templateExecCall.getNode(), untrustedSource, templateExecCall,
172152
"Data from an $@ will not be auto-escaped because it was $@ to template." + targetTypeName,
173-
untrustedSource.getNode(), "untrusted source", conversion.getNode(), "converted"
153+
untrustedSource.getNode(), "untrusted source", conversion, "converted"

0 commit comments

Comments
 (0)