@@ -16,11 +16,6 @@ import cpp
1616import codingstandards.cpp.misra
1717import semmle.code.cpp.dataflow.new.TaintTracking
1818import semmle.code.cpp.security.BufferAccess
19- private import semmle.code.cpp.ir.IR // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
20- private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
21- private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
22- private import semmle.code.cpp.ir.dataflow.FlowSteps // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
23- private import semmle.code.cpp.ir.dataflow.internal.SsaInternals as Ssa
2419
2520class ArrayDeclaration extends VariableDeclarationEntry {
2621 int length ;
@@ -31,11 +26,6 @@ class ArrayDeclaration extends VariableDeclarationEntry {
3126 * Gets the declared length of this array.
3227 */
3328 int getLength ( ) { result = length }
34-
35- /**
36- * Gets the expression that the variable declared is initialized to, given there is such one.
37- */
38- Expr getInitExpr ( ) { result = this .getVariable ( ) .getInitializer ( ) .getExpr ( ) }
3929}
4030
4131class HeapAllocationFunctionCall extends FunctionCall {
@@ -49,21 +39,27 @@ class HeapAllocationFunctionCall extends FunctionCall {
4939
5040 predicate isReallocCall ( ) { heapAllocFunction .getName ( ) = "realloc" }
5141
52- abstract Expr getByteArgument ( ) ;
53-
54- int getByteLowerBound ( ) { result = lowerBound ( this .getByteArgument ( ) ) }
42+ abstract int getMinNumBytes ( ) ;
5543}
5644
5745class MallocFunctionCall extends HeapAllocationFunctionCall {
5846 MallocFunctionCall ( ) { this .isMallocCall ( ) }
5947
60- override Expr getByteArgument ( ) { result = this .getArgument ( 0 ) }
48+ override int getMinNumBytes ( ) { result = lowerBound ( this .getArgument ( 0 ) ) }
6149}
6250
63- class CallocReallocFunctionCall extends HeapAllocationFunctionCall {
64- CallocReallocFunctionCall ( ) { this .isCallocCall ( ) or this . isReallocCall ( ) }
51+ class CallocFunctionCall extends HeapAllocationFunctionCall {
52+ CallocFunctionCall ( ) { this .isCallocCall ( ) }
6553
66- override Expr getByteArgument ( ) { result = this .getArgument ( 1 ) }
54+ override int getMinNumBytes ( ) {
55+ result = lowerBound ( this .getArgument ( 0 ) ) * lowerBound ( this .getArgument ( 1 ) )
56+ }
57+ }
58+
59+ class ReallocFunctionCall extends HeapAllocationFunctionCall {
60+ ReallocFunctionCall ( ) { this .isReallocCall ( ) }
61+
62+ override int getMinNumBytes ( ) { result = lowerBound ( this .getArgument ( 1 ) ) }
6763}
6864
6965class NarrowedHeapAllocationFunctionCall extends Cast {
@@ -72,8 +68,7 @@ class NarrowedHeapAllocationFunctionCall extends Cast {
7268 NarrowedHeapAllocationFunctionCall ( ) { alloc = this .getExpr ( ) }
7369
7470 int getMinNumElements ( ) {
75- result =
76- alloc .getByteLowerBound ( ) / this .getUnderlyingType ( ) .( PointerType ) .getBaseType ( ) .getSize ( )
71+ result = alloc .getMinNumBytes ( ) / this .getUnderlyingType ( ) .( PointerType ) .getBaseType ( ) .getSize ( )
7772 }
7873
7974 HeapAllocationFunctionCall getAllocFunctionCall ( ) { result = alloc }
@@ -112,7 +107,7 @@ class ArrayAllocation extends TArrayAllocation {
112107 }
113108
114109 DataFlow:: Node getNode ( ) {
115- result .asExpr ( ) = this .asStackAllocation ( ) .getInitExpr ( ) or
110+ result .asUninitialized ( ) = this .asStackAllocation ( ) .getVariable ( ) or
116111 result .asConvertedExpr ( ) = this .asDynamicAllocation ( )
117112 }
118113}
@@ -140,8 +135,8 @@ class PointerFormation extends TPointerFormation {
140135 }
141136
142137 Expr asExpr ( ) {
143- result = this .asArrayExpr ( ) or // This needs to be array base, as we are only dealing with pointers here.
144- result = this .asPointerArithmetic ( )
138+ result = this .asArrayExpr ( ) or
139+ /*.getArrayBase()*/ result = this .asPointerArithmetic ( )
145140 }
146141
147142 DataFlow:: Node getNode ( ) { result .asExpr ( ) = this .asExpr ( ) }
@@ -155,47 +150,57 @@ class PointerFormation extends TPointerFormation {
155150/**
156151 * NOTE
157152 */
158- private predicate operandToInstructionTaintStep ( Operand opFrom , Instruction instrTo ) {
159- // Taint can flow through expressions that alter the value but preserve
160- // more than one bit of it _or_ expressions that follow data through
161- // pointer indirections.
162- instrTo .getAnOperand ( ) = opFrom and
163- (
164- instrTo instanceof ArithmeticInstruction
153+ module Copied {
154+ import semmle.code.cpp.ir.IR // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
155+ import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
156+ import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
157+ import semmle.code.cpp.ir.dataflow.FlowSteps // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below)
158+ import semmle.code.cpp.ir.dataflow.internal.SsaInternals as Ssa
159+
160+ predicate operandToInstructionTaintStep ( Operand opFrom , Instruction instrTo ) {
161+ // Taint can flow through expressions that alter the value but preserve
162+ // more than one bit of it _or_ expressions that follow data through
163+ // pointer indirections.
164+ instrTo .getAnOperand ( ) = opFrom and
165+ (
166+ instrTo instanceof ArithmeticInstruction
167+ or
168+ instrTo instanceof BitwiseInstruction
169+ or
170+ instrTo instanceof PointerArithmeticInstruction
171+ )
165172 or
166- instrTo instanceof BitwiseInstruction
173+ // Taint flow from an address to its dereference.
174+ Ssa:: isDereference ( instrTo , opFrom , _)
167175 or
168- instrTo instanceof PointerArithmeticInstruction
169- )
170- or
171- // Taint flow from an address to its dereference.
172- Ssa:: isDereference ( instrTo , opFrom , _)
173- or
174- // Unary instructions tend to preserve enough information in practice that we
175- // want taint to flow through.
176- // The exception is `FieldAddressInstruction`. Together with the rules below for
177- // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction`
178- // could cause flow into one field to come out an unrelated field.
179- // This would happen across function boundaries, where the IR would not be able to
180- // match loads to stores.
181- instrTo .( UnaryInstruction ) .getUnaryOperand ( ) = opFrom and
182- (
183- not instrTo instanceof FieldAddressInstruction
176+ // Unary instructions tend to preserve enough information in practice that we
177+ // want taint to flow through.
178+ // The exception is `FieldAddressInstruction`. Together with the rules below for
179+ // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction`
180+ // could cause flow into one field to come out an unrelated field.
181+ // This would happen across function boundaries, where the IR would not be able to
182+ // match loads to stores.
183+ instrTo .( UnaryInstruction ) .getUnaryOperand ( ) = opFrom and
184+ (
185+ not instrTo instanceof FieldAddressInstruction
186+ or
187+ instrTo .( FieldAddressInstruction ) .getField ( ) .getDeclaringType ( ) instanceof Union
188+ )
184189 or
185- instrTo .( FieldAddressInstruction ) .getField ( ) .getDeclaringType ( ) instanceof Union
186- )
187- or
188- // Taint from int to boolean casts. This ensures that we have flow to `!x` in:
189- // ```cpp
190- // x = integer_source();
191- // if(!x) { ... }
192- // ```
193- exists ( Operand zero |
194- zero .getDef ( ) .( ConstantValueInstruction ) .getValue ( ) = "0" and
195- instrTo .( CompareNEInstruction ) .hasOperands ( opFrom , zero )
196- )
190+ // Taint from int to boolean casts. This ensures that we have flow to `!x` in:
191+ // ```cpp
192+ // x = integer_source();
193+ // if(!x) { ... }
194+ // ```
195+ exists ( Operand zero |
196+ zero .getDef ( ) .( ConstantValueInstruction ) .getValue ( ) = "0" and
197+ instrTo .( CompareNEInstruction ) .hasOperands ( opFrom , zero )
198+ )
199+ }
197200}
198201
202+ import Copied
203+
199204module TrackArrayConfig implements DataFlow:: ConfigSig {
200205 predicate isSource ( DataFlow:: Node node ) {
201206 exists ( ArrayAllocation arrayAllocation | node = arrayAllocation .getNode ( ) )
@@ -206,44 +211,58 @@ module TrackArrayConfig implements DataFlow::ConfigSig {
206211 }
207212
208213 predicate isAdditionalFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
209- /*
210- * NOTE
211- */
212-
213214 operandToInstructionTaintStep ( nodeFrom .asOperand ( ) , nodeTo .asInstruction ( ) )
214- or
215- exists ( PointerArithmeticInstruction pai , int indirectionIndex |
216- nodeHasOperand ( nodeFrom , pai .getAnOperand ( ) , pragma [ only_bind_into ] ( indirectionIndex ) ) and
217- hasInstructionAndIndex ( nodeTo , pai , indirectionIndex + 1 )
218- )
219215 }
220216}
221217
222218module TrackArray = DataFlow:: Global< TrackArrayConfig > ;
223219
224- private predicate arrayIndexExceedsOutOfBounds (
220+ predicate arrayIndexIsNegative (
225221 DataFlow:: Node arrayDeclarationNode , DataFlow:: Node pointerFormationNode
226222) {
227223 /* 1. Ensure the array access is reachable from the array declaration. */
228224 TrackArray:: flow ( arrayDeclarationNode , pointerFormationNode ) and
229- /* 2. Cases where a pointer formation becomes illegal . */
225+ /* 2. An offset cannot be negative . */
230226 exists ( ArrayAllocation arrayAllocation , PointerFormation pointerFormation |
231227 arrayDeclarationNode = arrayAllocation .getNode ( ) and
232228 pointerFormationNode = pointerFormation .getNode ( )
233229 |
234- /* 2-1. An offset cannot be negative. */
235230 pointerFormation .getOffset ( ) < 0
236- or
237- /* 2-2. The offset should be at most (number of elements) + 1 = (the declared length). */
238- arrayAllocation .getLength ( ) < pointerFormation .getOffset ( )
231+ )
232+ }
233+
234+ predicate arrayIndexExceedsBounds (
235+ DataFlow:: Node arrayDeclarationNode , DataFlow:: Node pointerFormationNode , int pointerOffset ,
236+ int arrayLength
237+ ) {
238+ /* 1. Ensure the array access is reachable from the array declaration. */
239+ TrackArray:: flow ( arrayDeclarationNode , pointerFormationNode ) and
240+ /* 2. The offset must be at most (number of elements) + 1 = (the declared length). */
241+ exists ( ArrayAllocation arrayAllocation , PointerFormation pointerFormation |
242+ arrayDeclarationNode = arrayAllocation .getNode ( ) and
243+ pointerFormationNode = pointerFormation .getNode ( ) and
244+ pointerOffset = pointerFormation .getOffset ( ) and
245+ arrayLength = arrayAllocation .getLength ( )
246+ |
247+ arrayLength < pointerOffset
239248 )
240249}
241250
242251import TrackArray:: PathGraph
243252
244- from TrackArray:: PathNode source , TrackArray:: PathNode sink
253+ from TrackArray:: PathNode source , TrackArray:: PathNode sink , string message
245254where
246255 not isExcluded ( sink .getNode ( ) .asExpr ( ) ,
247256 Memory1Package:: pointerArithmeticFormsAnInvalidPointerQuery ( ) ) and
248- arrayIndexExceedsOutOfBounds ( source .getNode ( ) , sink .getNode ( ) )
249- select sink , source , sink , "TODO"
257+ (
258+ exists ( int pointerOffset , int arrayLength |
259+ arrayIndexExceedsBounds ( source .getNode ( ) , sink .getNode ( ) , pointerOffset , arrayLength ) and
260+ message =
261+ "This pointer has offset " + pointerOffset +
262+ " when the minimum possible length of the object is " + arrayLength + "."
263+ )
264+ or
265+ arrayIndexIsNegative ( source .getNode ( ) , sink .getNode ( ) ) and
266+ message = "This pointer has a negative offset."
267+ )
268+ select sink , source , sink , message
0 commit comments