@@ -16,137 +16,215 @@ import LeapYear
1616 * The set of expressions which are ignorable; either because they seem to not be part of a year mutation,
1717 * or because they seem to be a conversion pattern of mapping date scalars.
1818 */
19- abstract class IgnorableOperationSource extends Expr { }
19+ abstract class IgnorableOperation extends Expr { }
2020
21- class IgnorableExprAssignRem extends IgnorableOperationSource instanceof AssignRemExpr { }
22- class IgnorableExprRem extends IgnorableOperationSource instanceof RemExpr { }
23- class IgnorableExprUnaryMinus extends IgnorableOperationSource instanceof UnaryMinusExpr { }
24- /**
25- * Ignore any operation that is nested inside a larger operation, assume the larger operation is the real source
26- * */
27- class IgnorableExprNestedExpr extends IgnorableOperationSource instanceof BinaryArithmeticOperation {
28- IgnorableExprNestedExpr ( ) {
29- exists ( BinaryArithmeticOperation parentOp |
30- parentOp .getAChild + ( ) = this
31- )
32- }
21+ class IgnorableExprAssignRem extends IgnorableOperation instanceof AssignRemExpr { }
22+
23+ class IgnorableExprRem extends IgnorableOperation instanceof RemExpr { }
24+
25+ class IgnorableExprUnaryMinus extends IgnorableOperation instanceof UnaryMinusExpr { }
26+
27+ class IgnorableNonPlusMinusOperation extends IgnorableOperation instanceof Operation {
28+ IgnorableNonPlusMinusOperation ( ) { not isOperationSourceCandidate ( this ) }
29+ }
30+
31+ class IgnorableNonPlusMinusAssignment extends IgnorableOperation instanceof AssignArithmeticOperation
32+ {
33+ IgnorableNonPlusMinusAssignment ( ) { not isOperationSourceCandidate ( this ) }
3334}
3435
3536/**
3637 * Anything involving a sub expression with char literal 48, ignore as a likely string conversion
3738 */
38- class IgnorableExpr48Mapping extends IgnorableOperationSource {
39- IgnorableExpr48Mapping ( ) {
40- exists ( SubExpr child | this .( Operation ) .getAChild * ( ) = child |
41- child .getRightOperand ( ) .( Literal ) .getValue ( ) .toInt ( ) = 48
42- or
43- child .getRightOperand ( ) .( CharLiteral ) .getValue ( ) .toInt ( ) = 48
44- )
45- }
39+ class IgnorableExpr48Mapping extends IgnorableOperation {
40+ IgnorableExpr48Mapping ( ) {
41+ exists ( SubExpr child | this .( Operation ) .getAChild * ( ) = child |
42+ child .getRightOperand ( ) .( Literal ) .getValue ( ) .toInt ( ) = 48
43+ or
44+ child .getRightOperand ( ) .( CharLiteral ) .getValue ( ) .toInt ( ) = 48
45+ )
46+ }
4647}
4748
4849/**
4950 * if doing any kind of operation involving multiplying 10, 100, 1000, etc., likely some kind of conversion
5051 * and ignorable
5152 */
52- class IgnorableExpr10MulipleComponent extends IgnorableOperationSource {
53- IgnorableExpr10MulipleComponent ( ) {
54- this .( Operation ) .getAChild * ( ) .( MulExpr ) .getAnOperand ( ) .( Literal ) .getValue ( ) .toInt ( ) % 10 = 0
55- or
56- this .( AssignMulExpr ) .getRValue ( ) .( Literal ) .getValue ( ) .toInt ( ) % 10 = 0
57- }
53+ class IgnorableExpr10MulipleComponent extends IgnorableOperation {
54+ IgnorableExpr10MulipleComponent ( ) {
55+ this .( Operation ) .getAChild * ( ) .( MulExpr ) .getAnOperand ( ) .( Literal ) .getValue ( ) .toInt ( ) in [
56+ 10 , 100 , 100
57+ ]
58+ or
59+ exists ( AssignMulExpr a | this = a or a .getRValue ( ) = this |
60+ a .getRValue ( ) .getAChild * ( ) .( Literal ) .getValue ( ) .toInt ( ) in [ 10 , 100 , 100 ]
61+ )
62+ }
5863}
5964
6065/*
6166 * linux time conversions expect the year to start from 1900, so subtracting or
6267 * adding 1900 or anything involving 1900 as a generalization is probably
6368 * a conversion that is ignorable
64- * */
65- class IgnorableExprExpr1900Mapping extends IgnorableOperationSource instanceof Operation {
69+ */
70+
71+ class IgnorableExprExpr1900Mapping extends IgnorableOperation {
6672 IgnorableExprExpr1900Mapping ( ) {
6773 this .( Operation ) .getAnOperand ( ) .getAChild * ( ) .( Literal ) .getValue ( ) .toInt ( ) = 1900
74+ or
75+ exists ( AssignArithmeticOperation a | this = a or this = a .getRValue ( ) |
76+ a .getRValue ( ) .getAChild * ( ) .( Literal ) .getValue ( ) .toInt ( ) = 1900
77+ )
78+ // or
79+ // this.(Literal).getValue().toInt() = 1900
6880 }
6981}
7082
83+ predicate isOperationSourceCandidate ( Expr e ) {
84+ e instanceof SubExpr
85+ or
86+ e instanceof AddExpr
87+ or
88+ e instanceof CrementOperation
89+ or
90+ exists ( AssignSubExpr a | a .getRValue ( ) = e )
91+ or
92+ exists ( AssignAddExpr a | a .getRValue ( ) = e )
93+ }
94+
7195class OperationSource extends Expr {
7296 OperationSource ( ) {
73- (
74- this instanceof BinaryArithmeticOperation
75- or
76- this instanceof UnaryArithmeticOperation
77- or
78- exists ( AssignArithmeticOperation a | a .getRValue ( ) = this )
79- ) and
80- not this instanceof IgnorableOperationSource
97+ // operation source candidates that aren't nested inside other operation source candidates
98+ isOperationSourceCandidate ( this ) and
99+ not exists ( Expr parent | isOperationSourceCandidate ( parent ) | parent .getAChild + ( ) = this ) and
100+ not this instanceof IgnorableOperation and
101+ not this .getEnclosingFunction ( ) instanceof IgnorableFunction
81102 }
82103}
83104
84105/**
85106 * An assignment to a year field, which will be a sink
107+ * NOTE: could not make this abstract, it was binding to all expressions
86108 */
87- abstract class YearFieldAssignment extends Expr { }
109+ abstract class YearFieldAssignment extends Expr {
110+ abstract YearFieldAccess getYearFieldAccess ( ) ;
111+ }
88112
89113/**
90114 * An assignment to x ie `x = a`.
91115 */
92- class YearFieldAssignmentAccess extends YearFieldAssignment {
93- YearFieldAssignmentAccess ( ) {
94- // TODO: why can't I make this just the L value? Doesn't seem to work
95- exists ( Assignment a |
96- a .getLValue ( ) instanceof YearFieldAccess and
97- a .getRValue ( ) = this
98- )
99- }
116+ class YearFieldAssignmentAccess extends YearFieldAssignment {
117+ YearFieldAccess access ;
118+
119+ YearFieldAssignmentAccess ( ) {
120+ // TODO: why can't I make this just the L value? Doesn't seem to work
121+ exists ( Assignment a |
122+ a .getLValue ( ) = access and
123+ a .getRValue ( ) = this
124+ )
125+ }
126+
127+ override YearFieldAccess getYearFieldAccess ( ) { result = access }
100128}
101129
102130/**
103131 * A year field assignment, by a unary operator ie `x++`.
104132 */
105- class YearFieldAssignmentUnary extends YearFieldAssignment instanceof UnaryArithmeticOperation {
106- YearFieldAssignmentUnary ( ) {
107- this .getOperand ( ) instanceof YearFieldAccess
108- }
133+ class YearFieldAssignmentUnary extends YearFieldAssignment instanceof CrementOperation {
134+ YearFieldAccess access ;
135+
136+ YearFieldAssignmentUnary ( ) { this .getOperand ( ) = access }
137+
138+ override YearFieldAccess getYearFieldAccess ( ) { result = access }
109139}
110140
111- class MonthOrDayFieldAccess extends FieldAccess {
112- MonthOrDayFieldAccess ( ) {
113- this instanceof MonthFieldAccess
114- or
115- this instanceof DayFieldAccess
116- }
141+ /**
142+ * An access to either a Month or Day.
143+ */
144+ class MonthOrDayFieldAccess extends FieldAccess {
145+ MonthOrDayFieldAccess ( ) {
146+ this instanceof MonthFieldAccess
147+ or
148+ this instanceof DayFieldAccess
149+ }
117150}
118151
119152/**
120- * A static assignment to the day or month access
121- *
122- * ```
123- * a.day = 28;
124- * ```
153+ * Flow for non operation candidate sources to year assignments to detect
154+ * ignorable functions.
155+ * If the ignorable operation flows to a year assignment and the source and sink
156+ * are in the same function, we will consider that function ignorable.
125157 */
126- class GoodExpr extends YearFieldAssignment {
127- GoodExpr ( ) {
128- exists ( Variable var , VariableAccess va , YearFieldAccess yfa |
129- // yfa = this.getYearAccess() and
130- yfa .getQualifier ( ) = va and
131- var .getAnAccess ( ) = va and
132- exists ( MonthOrDayFieldAccess mfa , AssignExpr ae , int val |
133- mfa .getQualifier ( ) = var .getAnAccess ( ) and
134- mfa .isModified ( ) and
135- (
136- mfa .getBasicBlock ( ) = yfa .getBasicBlock ( ) .getASuccessor * ( ) or
137- yfa .getBasicBlock ( ) = mfa .getBasicBlock ( ) .getASuccessor + ( )
138- ) and
139- ae = mfa .getEnclosingElement ( ) and
140- ae .getAnOperand ( ) .getValue ( ) .toInt ( ) = val
141- )
142- )
143- }
158+ module IgnorableOperationToYearConfig implements DataFlow:: ConfigSig {
159+ predicate isSource ( DataFlow:: Node n ) {
160+ (
161+ n .asExpr ( ) instanceof Operation or
162+ n .asExpr ( ) instanceof AssignArithmeticOperation
163+ ) and
164+ not isOperationSourceCandidate ( n .asExpr ( ) )
165+ }
166+
167+ predicate isSink ( DataFlow:: Node n ) {
168+ n .asExpr ( ) instanceof YearFieldAssignment
169+ or
170+ n .asExpr ( ) instanceof YearFieldAccess
171+ }
172+
173+ // looking for sources and sinks in the same function
174+ DataFlow:: FlowFeature getAFeature ( ) {
175+ result instanceof DataFlow:: FeatureEqualSourceSinkCallContext
176+ }
177+
178+ predicate isBarrierOut ( DataFlow:: Node n ) { isSink ( n ) }
179+ }
180+
181+ module IgnorableOperationToYearFlow = TaintTracking:: Global< IgnorableOperationToYearConfig > ;
182+
183+ module YearToIgnorableOperationConfig implements DataFlow:: ConfigSig {
184+ predicate isSink ( DataFlow:: Node n ) {
185+ (
186+ n .asExpr ( ) instanceof Operation or
187+ n .asExpr ( ) instanceof AssignArithmeticOperation
188+ ) and
189+ not isOperationSourceCandidate ( n .asExpr ( ) )
190+ }
191+
192+ predicate isSource ( DataFlow:: Node n ) {
193+ n .asExpr ( ) instanceof YearFieldAssignment
194+ or
195+ n .asExpr ( ) instanceof YearFieldAccess
196+ }
197+
198+ // looking for sources and sinks in the same function
199+ DataFlow:: FlowFeature getAFeature ( ) {
200+ result instanceof DataFlow:: FeatureEqualSourceSinkCallContext
201+ }
202+
203+ predicate isBarrierOut ( DataFlow:: Node n ) { isSink ( n ) }
204+ }
205+
206+ module YearToIgnorableOperationFlow = TaintTracking:: Global< YearToIgnorableOperationConfig > ;
207+
208+ class IgnorableFunction extends Function {
209+ IgnorableFunction ( ) { isIgnorableFunction ( this ) }
210+ }
211+
212+ predicate isIgnorableFunction ( Function f ) {
213+ exists ( IgnorableOperationToYearFlow:: PathNode sink |
214+ sink .getNode ( ) .asExpr ( ) .getEnclosingFunction ( ) = f and
215+ sink .isSink ( )
216+ )
217+ or
218+ exists ( YearToIgnorableOperationFlow:: PathNode sink |
219+ sink .getNode ( ) .asExpr ( ) .getEnclosingFunction ( ) = f and
220+ sink .isSink ( )
221+ )
144222}
145223
146224/**
147- * A DataFlow configuration for identifying flows from some non trivial access or literal
148- * to the Year field of a date object.
149- */
225+ * A DataFlow configuration for identifying flows from some non trivial access or literal
226+ * to the Year field of a date object.
227+ */
150228module OperationToYearAssignmentConfig implements DataFlow:: ConfigSig {
151229 predicate isSource ( DataFlow:: Node n ) { n .asExpr ( ) instanceof OperationSource }
152230
@@ -157,15 +235,50 @@ module OperationToYearAssignmentConfig implements DataFlow::ConfigSig {
157235 or
158236 n .asExpr ( ) .getUnspecifiedType ( ) instanceof PointerType
159237 or
160- n .asExpr ( ) instanceof IgnorableOperationSource
238+ n .asExpr ( ) instanceof IgnorableOperation
161239 or
162240 exists ( ChecksForLeapYearFunctionCall fc | fc .getAnArgument ( ) = n .asExpr ( ) )
241+ or
242+ n .asExpr ( ) .getEnclosingFunction ( ) instanceof IgnorableFunction
163243 }
164244}
165245
166246module OperationToYearAssignmentFlow = TaintTracking:: Global< OperationToYearAssignmentConfig > ;
247+
248+ predicate isYearModifiedWithCheck ( YearFieldAccess fa ) {
249+ // If there is a local check for leap year after the modification
250+ exists ( LeapYearFieldAccess yfacheck , Variable var , YearFieldAccess yfa |
251+ // TODO: cleanup
252+ yfa = fa and
253+ var .getAnAccess ( ) = fa .getQualifier ( ) and
254+ yfacheck .getQualifier ( ) = var .getAnAccess ( ) and
255+ yfacheck .isUsedInCorrectLeapYearCheck ( ) and
256+ yfacheck .getBasicBlock ( ) = yfa .getBasicBlock ( ) .getASuccessor * ( )
257+ )
258+ or
259+ // If there is a data flow from the variable that was modified to a function that seems to check for leap year
260+ exists ( VariableAccess source , ChecksForLeapYearFunctionCall fc , Variable var |
261+ var .getAnAccess ( ) = fa .getQualifier ( ) and
262+ source = var .getAnAccess ( ) and
263+ LeapYearCheckFlow:: flow ( DataFlow:: exprNode ( source ) , DataFlow:: exprNode ( fc .getAnArgument ( ) ) )
264+ )
265+ or
266+ // If there is a data flow from the field that was modified to a function that seems to check for leap year
267+ exists (
268+ VariableAccess vacheck , YearFieldAccess yfacheck , ChecksForLeapYearFunctionCall fc , Variable var
269+ |
270+ // TODO: cleanup
271+ var .getAnAccess ( ) = fa .getQualifier ( ) and
272+ vacheck = var .getAnAccess ( ) and
273+ yfacheck .getQualifier ( ) = vacheck and
274+ LeapYearCheckFlow:: flow ( DataFlow:: exprNode ( yfacheck ) , DataFlow:: exprNode ( fc .getAnArgument ( ) ) )
275+ )
276+ }
277+
167278import OperationToYearAssignmentFlow:: PathGraph
168279
169280from OperationToYearAssignmentFlow:: PathNode src , OperationToYearAssignmentFlow:: PathNode sink
170- where OperationToYearAssignmentFlow:: flowPath ( src , sink )
171- select sink , src , sink , "TEST"
281+ where
282+ OperationToYearAssignmentFlow:: flowPath ( src , sink ) and
283+ not isYearModifiedWithCheck ( sink .getNode ( ) .asExpr ( ) .( YearFieldAssignment ) .getYearFieldAccess ( ) )
284+ select sink , src , sink , "TEST"
0 commit comments