1+ import java
2+ import semmle.code.java.dataflow.DataFlow
3+
4+ /**
5+ * A signature for the `getInstance()` method calls used in JCA, or direct
6+ * constructor calls used in BouncyCastle.
7+ */
8+ signature class NewCallSig instanceof Call ;
9+
10+ signature class InitCallSig instanceof MethodCall ;
11+
12+ signature class UseCallSig instanceof MethodCall {
13+ /**
14+ * Holds if the use is not a final use, such as an `update()` call before `doFinal()`
15+ */
16+ predicate isIntermediate ( ) ;
17+ }
18+
19+ /**
20+ * An generic analysis module for analyzing the `getInstance()` to `initialize()`
21+ * to `doOperation()` pattern in the JCA, and similar patterns in other libraries.
22+ *
23+ * For example:
24+ * ```
25+ * kpg = KeyPairGenerator.getInstance();
26+ * kpg.initialize(...);
27+ * kpg.generate(...);
28+ * ```
29+ */
30+ module NewToInitToUseFlowAnalysis< NewCallSig GetInstance, InitCallSig Init, UseCallSig Use>
31+ {
32+ newtype TFlowState =
33+ TUninitialized ( ) or
34+ TInitialized ( Init call ) or
35+ TIntermediateUse ( Use call )
36+
37+ abstract class InitFlowState extends TFlowState {
38+ string toString ( ) {
39+ this = TUninitialized ( ) and result = "Uninitialized"
40+ or
41+ this = TInitialized ( _) and result = "Initialized"
42+ // TODO: add intermediate use
43+ }
44+ }
45+
46+ class UninitializedFlowState extends InitFlowState , TUninitialized { }
47+
48+ class InitializedFlowState extends InitFlowState , TInitialized {
49+ Init call ;
50+ DataFlow:: Node node1 ;
51+ DataFlow:: Node node2 ;
52+
53+ InitializedFlowState ( ) {
54+ this = TInitialized ( call ) and
55+ node2 .asExpr ( ) = call .( MethodCall ) .getQualifier ( ) and
56+ DataFlow:: localFlowStep ( node1 , node2 ) and
57+ node1 != node2
58+ }
59+
60+ Init getInitCall ( ) { result = call }
61+
62+ DataFlow:: Node getFstNode ( ) { result = node1 }
63+
64+ DataFlow:: Node getSndNode ( ) { result = node2 }
65+ }
66+
67+ class IntermediateUseState extends InitFlowState , TIntermediateUse {
68+ Use call ;
69+ DataFlow:: Node node1 ;
70+ DataFlow:: Node node2 ;
71+
72+ IntermediateUseState ( ) {
73+ this = TIntermediateUse ( call ) and
74+ call .isIntermediate ( ) and
75+ node1 .asExpr ( ) = call .( MethodCall ) .getQualifier ( ) and
76+ node2 = node1
77+ }
78+
79+ Use getUseCall ( ) { result = call }
80+
81+ DataFlow:: Node getFstNode ( ) { result = node1 }
82+
83+ DataFlow:: Node getSndNode ( ) { result = node2 }
84+ }
85+
86+ module GetInstanceToInitToUseConfig implements DataFlow:: StateConfigSig {
87+ class FlowState = InitFlowState ;
88+
89+ predicate isSource ( DataFlow:: Node src , FlowState state ) {
90+ state instanceof UninitializedFlowState and
91+ src .asExpr ( ) instanceof GetInstance
92+ or
93+ src = state .( InitializedFlowState ) .getSndNode ( )
94+ or
95+ src = state .( IntermediateUseState ) .getSndNode ( )
96+ }
97+
98+ // TODO: document this, but this is intentional (avoid cross products?)
99+ predicate isSink ( DataFlow:: Node sink , FlowState state ) { none ( ) }
100+
101+ predicate isSink ( DataFlow:: Node sink ) {
102+ exists ( Init c | c .( MethodCall ) .getQualifier ( ) = sink .asExpr ( ) )
103+ or
104+ exists ( Use c | not c .isIntermediate ( ) and c .( MethodCall ) .getQualifier ( ) = sink .asExpr ( ) )
105+ }
106+
107+ predicate isAdditionalFlowStep (
108+ DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
109+ ) {
110+ state1 = state1 and
111+ (
112+ node1 = state2 .( InitializedFlowState ) .getFstNode ( ) and
113+ node2 = state2 .( InitializedFlowState ) .getSndNode ( )
114+ or
115+ node1 = state2 .( IntermediateUseState ) .getFstNode ( ) and
116+ node2 = state2 .( IntermediateUseState ) .getSndNode ( )
117+ )
118+ }
119+
120+ predicate isBarrier ( DataFlow:: Node node , FlowState state ) {
121+ exists ( Init call | node .asExpr ( ) = call .( MethodCall ) .getQualifier ( ) |
122+ state instanceof UninitializedFlowState
123+ or
124+ state .( InitializedFlowState ) .getInitCall ( ) != call
125+ )
126+ }
127+ }
128+
129+ module GetInstanceToInitToUseFlow = DataFlow:: GlobalWithState< GetInstanceToInitToUseConfig > ;
130+
131+ GetInstance getInstantiationFromUse (
132+ Use use , GetInstanceToInitToUseFlow:: PathNode src , GetInstanceToInitToUseFlow:: PathNode sink
133+ ) {
134+ src .getNode ( ) .asExpr ( ) = result and
135+ sink .getNode ( ) .asExpr ( ) = use .( MethodCall ) .getQualifier ( ) and
136+ GetInstanceToInitToUseFlow:: flowPath ( src , sink )
137+ }
138+
139+ GetInstance getInstantiationFromInit (
140+ Init init , GetInstanceToInitToUseFlow:: PathNode src , GetInstanceToInitToUseFlow:: PathNode sink
141+ ) {
142+ src .getNode ( ) .asExpr ( ) = result and
143+ sink .getNode ( ) .asExpr ( ) = init .( MethodCall ) .getQualifier ( ) and
144+ GetInstanceToInitToUseFlow:: flowPath ( src , sink )
145+ }
146+
147+ Init getInitFromUse (
148+ Use use , GetInstanceToInitToUseFlow:: PathNode src , GetInstanceToInitToUseFlow:: PathNode sink
149+ ) {
150+ src .getNode ( ) .asExpr ( ) = result .( MethodCall ) .getQualifier ( ) and
151+ sink .getNode ( ) .asExpr ( ) = use .( MethodCall ) .getQualifier ( ) and
152+ GetInstanceToInitToUseFlow:: flowPath ( src , sink )
153+ }
154+
155+ predicate hasInit ( Use use ) { exists ( getInitFromUse ( use , _, _) ) }
156+
157+ Use getAnIntermediateUseFromFinalUse (
158+ Use final , GetInstanceToInitToUseFlow:: PathNode src , GetInstanceToInitToUseFlow:: PathNode sink
159+ ) {
160+ not final .isIntermediate ( ) and
161+ result .isIntermediate ( ) and
162+ src .getNode ( ) .asExpr ( ) = result .( MethodCall ) .getQualifier ( ) and
163+ sink .getNode ( ) .asExpr ( ) = final .( MethodCall ) .getQualifier ( ) and
164+ GetInstanceToInitToUseFlow:: flowPath ( src , sink )
165+ }
166+ }
0 commit comments