19
19
private import javascript
20
20
private import internal.ApiGraphModels as Shared
21
21
private import internal.ApiGraphModelsSpecific as Specific
22
+ private import semmle.javascript.dataflow.internal.FlowSummaryPrivate
22
23
private import semmle.javascript.endpoints.EndpointNaming as EndpointNaming
23
24
import Shared:: ModelInput as ModelInput
24
25
import Shared:: ModelOutput as ModelOutput
@@ -45,12 +46,94 @@ private class ThreatModelSourceFromDataExtension extends ThreatModelSource::Rang
45
46
}
46
47
}
47
48
49
+ private class SummarizedCallableFromModel extends DataFlow:: SummarizedCallable {
50
+ string type ;
51
+ string path ;
52
+
53
+ SummarizedCallableFromModel ( ) {
54
+ ModelOutput:: relevantSummaryModel ( type , path , _, _, _, _) and
55
+ this = type + ";" + path
56
+ }
57
+
58
+ override DataFlow:: InvokeNode getACall ( ) { ModelOutput:: resolvedSummaryBase ( type , path , result ) }
59
+
60
+ override predicate propagatesFlow (
61
+ string input , string output , boolean preservesValue , string model
62
+ ) {
63
+ exists ( string kind | ModelOutput:: relevantSummaryModel ( type , path , input , output , kind , model ) |
64
+ kind = "value" and
65
+ preservesValue = true
66
+ or
67
+ kind = "taint" and
68
+ preservesValue = false
69
+ )
70
+ }
71
+
72
+ predicate hasTypeAndPath ( string type_ , string path_ ) { type = type_ and path = path_ }
73
+
74
+ predicate isUnsupportedByFlowSummaries ( ) { unsupportedCallable ( this ) }
75
+ }
76
+
77
+ private predicate shouldInduceStepsFromSummary ( string type , string path ) {
78
+ exists ( SummarizedCallableFromModel callable |
79
+ callable .isUnsupportedByFlowSummaries ( ) and
80
+ callable .hasTypeAndPath ( type , path )
81
+ )
82
+ }
83
+
84
+ /**
85
+ * Holds if `path` is an input or output spec for a summary with the given `base` node.
86
+ */
87
+ pragma [ nomagic]
88
+ private predicate relevantInputOutputPath ( API:: InvokeNode base , AccessPath inputOrOutput ) {
89
+ exists ( string type , string input , string output , string path |
90
+ // If the summary for 'callable' could not be handled as a flow summary, we need to evaluate
91
+ // its inputs and outputs to a set of nodes, so we can generate steps instead.
92
+ shouldInduceStepsFromSummary ( type , path ) and
93
+ ModelOutput:: resolvedSummaryBase ( type , path , base ) and
94
+ ModelOutput:: relevantSummaryModel ( type , path , input , output , _, _) and
95
+ inputOrOutput = [ input , output ]
96
+ )
97
+ }
98
+
99
+ /**
100
+ * Gets the API node for the first `n` tokens of the given input/output path, evaluated relative to `baseNode`.
101
+ */
102
+ private API:: Node getNodeFromInputOutputPath ( API:: InvokeNode baseNode , AccessPath path , int n ) {
103
+ relevantInputOutputPath ( baseNode , path ) and
104
+ (
105
+ n = 1 and
106
+ result = Shared:: getSuccessorFromInvoke ( baseNode , path .getToken ( 0 ) )
107
+ or
108
+ result =
109
+ Shared:: getSuccessorFromNode ( getNodeFromInputOutputPath ( baseNode , path , n - 1 ) ,
110
+ path .getToken ( n - 1 ) )
111
+ )
112
+ }
113
+
114
+ /**
115
+ * Gets the API node for the given input/output path, evaluated relative to `baseNode`.
116
+ */
117
+ private API:: Node getNodeFromInputOutputPath ( API:: InvokeNode baseNode , AccessPath path ) {
118
+ result = getNodeFromInputOutputPath ( baseNode , path , path .getNumToken ( ) )
119
+ }
120
+
121
+ private predicate summaryStep ( API:: Node pred , API:: Node succ , string kind ) {
122
+ exists ( string type , string path , API:: InvokeNode base , AccessPath input , AccessPath output |
123
+ shouldInduceStepsFromSummary ( type , path ) and
124
+ ModelOutput:: relevantSummaryModel ( type , path , input , output , kind , _) and
125
+ ModelOutput:: resolvedSummaryBase ( type , path , base ) and
126
+ pred = getNodeFromInputOutputPath ( base , input ) and
127
+ succ = getNodeFromInputOutputPath ( base , output )
128
+ )
129
+ }
130
+
48
131
/**
49
132
* Like `ModelOutput::summaryStep` but with API nodes mapped to data-flow nodes.
50
133
*/
51
134
private predicate summaryStepNodes ( DataFlow:: Node pred , DataFlow:: Node succ , string kind ) {
52
135
exists ( API:: Node predNode , API:: Node succNode |
53
- Specific :: summaryStep ( predNode , succNode , kind ) and
136
+ summaryStep ( predNode , succNode , kind ) and
54
137
pred = predNode .asSink ( ) and
55
138
succ = succNode .asSource ( )
56
139
)
0 commit comments