@@ -18,13 +18,13 @@ module OutOfBounds {
1818 bindingset [ name, result ]
1919 private string getNameOrInternalName ( string name ) {
2020 result = name or
21- name .regexpMatch ( "__.*_+(?: " + result + ") " )
21+ result .regexpMatch ( "__.*_+" + name + "_.* " )
2222 }
2323
2424 /**
2525 * MISRA-C Rule 21.17 function table of names and parameter indices
2626 * which covers functions from <string.h> that rely on null-terminated strings.
27- *
27+ *
2828 * This table is a subset of `libraryFunctionNameParamTable`.
2929 *
3030 * Note: These functions do not share a common semantic pattern of source and destination
@@ -33,11 +33,11 @@ module OutOfBounds {
3333 * The `SimpleStringLibraryFunction` base class provides an appropriate
3434 * interface for analyzing the functions in the below table.
3535 */
36- private Function libraryFunctionNameParamTableSimpleString ( string name ,
37- int dst , int src , int src_sz , int dst_sz )
38- {
39- result .hasGlobalOrStdName ( name ) and
40- src_sz = - 1 and
36+ private Function libraryFunctionNameParamTableSimpleString (
37+ string name , int dst , int src , int src_sz , int dst_sz
38+ ) {
39+ result .getName ( ) = getNameOrInternalName ( name ) and
40+ src_sz = - 1 and
4141 dst_sz = - 1 and
4242 (
4343 name = "strcat" and
@@ -48,7 +48,7 @@ module OutOfBounds {
4848 dst = - 1 and
4949 src = 0
5050 or
51- name = [ "strcmp" , "strcoll" ] and
51+ name = [ "strcmp" , "strcoll" ] and
5252 dst = - 1 and
5353 src = [ 0 , 1 ]
5454 or
@@ -86,18 +86,6 @@ module OutOfBounds {
8686 )
8787 }
8888
89- /**
90- * An expansion of `libraryFunctionNameParamTableSimpleString` to include internal functions with
91- * prefixes/suffixes such as "__builtin_%"" or "%_chk" (e.g. `__builtin___strcpy_chk`)
92- */
93- bindingset [ name]
94- Function libraryFunctionNameParamTableSimpleStringRegex ( string name , int dst , int src , int src_sz , int dst_sz ) {
95- exists ( string stdName |
96- result = libraryFunctionNameParamTableSimpleString ( stdName , dst , src , src_sz , dst_sz ) and
97- getNameOrInternalName ( name ) = stdName
98- )
99- }
100-
10189 /**
10290 * A relation of the indices of buffer and size parameters of standard library functions
10391 * which are defined in rules CERT ARR38-C and MISRA-C rules 21.17 and 21.18.
@@ -107,7 +95,7 @@ module OutOfBounds {
10795 ) {
10896 result = libraryFunctionNameParamTableSimpleString ( name , dst , src , src_sz , dst_sz )
10997 or
110- result .hasGlobalOrStdName ( name ) and
98+ result .getName ( ) = getNameOrInternalName ( name ) and
11199 (
112100 name = [ "fgets" , "fgetws" ] and
113101 dst = 0 and
@@ -217,55 +205,41 @@ module OutOfBounds {
217205 )
218206 }
219207
220- /**
221- * An expansion of `libraryFunctionNameParamTable` to include internal functions with
222- * prefixes/suffixes such as "__builtin_%"" or "%_chk" (e.g. `__builtin___strncpy_chk`)
223- */
224- bindingset [ name]
225- Function libraryFunctionNameParamTableRegex ( string name , int dst , int src , int src_sz , int dst_sz ) {
226- exists ( string stdName |
227- result = libraryFunctionNameParamTable ( stdName , dst , src , src_sz , dst_sz ) and
228- getNameOrInternalName ( name ) = stdName
229- )
230- }
231-
232208 /**
233209 * A library function that accesses one or more buffers supplied via arguments.
234210 */
235211 class BufferAccessLibraryFunction extends Function {
236- BufferAccessLibraryFunction ( ) {
237- this = libraryFunctionNameParamTableRegex ( this .getName ( ) , _, _, _, _)
238- }
212+ BufferAccessLibraryFunction ( ) { this = libraryFunctionNameParamTable ( _, _, _, _, _) }
239213
240214 /**
241215 * Returns the indices of parameters that are a destination buffer.
242216 */
243217 int getWriteParamIndex ( ) {
244- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , result , _, _, _) and
218+ this = libraryFunctionNameParamTable ( _ , result , _, _, _) and
245219 result >= 0
246220 }
247221
248222 /**
249223 * Returns the indices of parameters that are a source buffer.
250224 */
251225 int getReadParamIndex ( ) {
252- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , _, result , _, _) and
226+ this = libraryFunctionNameParamTable ( _ , _, result , _, _) and
253227 result >= 0
254228 }
255229
256230 /**
257231 * Returns the index of the parameter that is the source buffer size.
258232 */
259233 int getReadSizeParamIndex ( ) {
260- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , _, _, result , _) and
234+ this = libraryFunctionNameParamTable ( _ , _, _, result , _) and
261235 result >= 0
262236 }
263237
264238 /**
265239 * Returns the index of the parameter that is the destination buffer size.
266240 */
267241 int getWriteCountParamIndex ( ) {
268- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , _, _, _, result ) and
242+ this = libraryFunctionNameParamTable ( _ , _, _, _, result ) and
269243 result >= 0
270244 }
271245
@@ -338,15 +312,19 @@ module OutOfBounds {
338312 */
339313 class SimpleStringLibraryFunction extends BufferAccessLibraryFunction {
340314 SimpleStringLibraryFunction ( ) {
341- this = libraryFunctionNameParamTableSimpleStringRegex ( this .getName ( ) , _, _, _, _)
315+ this = libraryFunctionNameParamTable ( this .getName ( ) , _, _, _, _)
342316 }
343317
344318 override predicate getANullTerminatedParameterIndex ( int i ) {
345319 // by default, require null-terminated parameters for src but
346320 // only if the type of src is a plain char pointer.
347321 this .getReadParamIndex ( ) = i and
348- this .getReadParam ( ) .getType ( ) .getUnspecifiedType ( ) .
349- ( PointerType ) .getBaseType ( ) .getUnspecifiedType ( ) instanceof PlainCharType
322+ this .getReadParam ( )
323+ .getType ( )
324+ .getUnspecifiedType ( )
325+ .( PointerType )
326+ .getBaseType ( )
327+ .getUnspecifiedType ( ) instanceof PlainCharType
350328 }
351329 }
352330
@@ -358,7 +336,8 @@ module OutOfBounds {
358336 /**
359337 * A `BufferAccessLibraryFunction` modelling `strcat`
360338 */
361- class StrcatLibraryFunction extends StringConcatenationFunctionLibraryFunction , SimpleStringLibraryFunction
339+ class StrcatLibraryFunction extends StringConcatenationFunctionLibraryFunction ,
340+ SimpleStringLibraryFunction
362341 {
363342 StrcatLibraryFunction ( ) { this .getName ( ) = getNameOrInternalName ( "strcat" ) }
364343
@@ -380,6 +359,18 @@ module OutOfBounds {
380359 }
381360 }
382361
362+ /**
363+ * A `BufferAccessLibraryFunction` modelling `strncpy`
364+ */
365+ class StrncpyLibraryFunction extends BufferAccessLibraryFunction {
366+ StrncpyLibraryFunction ( ) { this .getName ( ) = getNameOrInternalName ( "strncpy" ) }
367+
368+ override predicate getANullTerminatedParameterIndex ( int i ) {
369+ // `strncpy` does not require null-terminated parameters
370+ none ( )
371+ }
372+ }
373+
383374 /**
384375 * A `FunctionCall` to a `BufferAccessLibraryFunction` that provides predicates for
385376 * reasoning about buffer overflow and other buffer access violations.
@@ -417,15 +408,16 @@ module OutOfBounds {
417408 int getStatedAllocValue ( Expr e ) {
418409 // `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
419410 // result in this case we pick the minimum value obtainable from dataflow and range analysis.
420- if upperBound ( e ) = exprMaxVal ( e )
421- then
422- result = max ( Expr source | DataFlow:: localExprFlow ( source , e ) | source .getValue ( ) .toInt ( ) )
411+ if upperBound ( e ) = exprMaxVal ( e )
412+ then result = max ( Expr source | DataFlow:: localExprFlow ( source , e ) | source .getValue ( ) .toInt ( ) )
423413 else
424- result =
425- upperBound ( e )
426- .minimum ( min ( Expr source | DataFlow:: localExprFlow ( source , e ) | source .getValue ( ) .toInt ( ) ) )
427-
428-
414+ result =
415+ upperBound ( e )
416+ .minimum ( min ( Expr source |
417+ DataFlow:: localExprFlow ( source , e )
418+ |
419+ source .getValue ( ) .toInt ( )
420+ ) )
429421 }
430422
431423 int getStatedValue ( Expr e ) {
@@ -475,8 +467,9 @@ module OutOfBounds {
475467 abstract predicate isNotNullTerminated ( ) ;
476468 }
477469
478- class DynamicAllocationSource extends PointerToObjectSource
479- instanceof AllocationExpr , FunctionCall {
470+ class DynamicAllocationSource extends PointerToObjectSource instanceof AllocationExpr ,
471+ FunctionCall
472+ {
480473 DynamicAllocationSource ( ) {
481474 // exclude OperatorNewAllocationFunction to only deal with raw malloc-style calls,
482475 // which do not apply a multiple to the size of the allocation passed to them.
@@ -509,23 +502,32 @@ module OutOfBounds {
509502 * 2. `size_t sz = strlen(src); malloc(sz + 1);`
510503 */
511504 Expr getSizeExprSource ( Expr base , int offset ) {
512- if
513- exists ( Variable v , AddExpr ae |
514- // case 1: variable_access + const in the size expression
515- this .getSizeExpr ( ) = ae and
516- result = v .getAnAssignedValue ( ) and
517- base = ae .getLeftOperand ( ) and
518- offset = constOrZero ( ae .getRightOperand ( ) ) and
519- DataFlow:: localExprFlow ( result , base )
505+ if this .getSizeExpr ( ) instanceof AddExpr
506+ then
507+ exists ( AddExpr ae |
508+ exists ( Variable v |
509+ // case 1: variable access + const in the size expression
510+ this .getSizeExpr ( ) = ae and
511+ result = v .getAnAssignedValue ( ) and
512+ base = ae .getLeftOperand ( ) and
513+ offset = constOrZero ( ae .getRightOperand ( ) ) and
514+ DataFlow:: localExprFlow ( result , base )
515+ or
516+ // case 2: expr + const in the variable assignment
517+ v .getAnAssignedValue ( ) = ae and
518+ result = ae and
519+ base = ae .getLeftOperand ( ) and
520+ offset = constOrZero ( ae .getRightOperand ( ) ) and
521+ DataFlow:: localExprFlow ( result , this .getSizeExpr ( ) )
522+ )
520523 or
521- // case 2: expr + const in the variable assignment
522- v .getAnAssignedValue ( ) = ae and
524+ // case 3: function call + const
523525 result = ae and
524- base = ae .getLeftOperand ( ) and
525- offset = constOrZero ( ae .getRightOperand ( ) ) and
526- DataFlow:: localExprFlow ( result , this .getSizeExpr ( ) )
526+ this .getSizeExpr ( ) = ae and
527+ ae .getLeftOperand ( ) = base and
528+ ae .getLeftOperand ( ) instanceof FunctionCall and
529+ offset = constOrZero ( ae .getRightOperand ( ) )
527530 )
528- then any ( ) // all logic handled in the `if` clause
529531 else (
530532 offset = 0 and
531533 // case 3: a variable is read in the size expression
@@ -608,9 +610,8 @@ module OutOfBounds {
608610 }
609611
610612 override predicate isSink ( DataFlow:: Node sink ) {
611- exists ( BufferAccessLibraryFunctionCall call , Expr arg |
612- arg = call .getAnArgument ( )
613- and
613+ exists ( BufferAccessLibraryFunctionCall call , Expr arg |
614+ arg = call .getAnArgument ( ) and
614615 (
615616 sink .asExpr ( ) = arg
616617 or
@@ -627,9 +628,8 @@ module OutOfBounds {
627628 useOrChild = use
628629 or
629630 getArithmeticOffsetValue ( use ) > 0 and
630- useOrChild = use .getAChild * ( )
631- )
632- and
631+ useOrChild = use .getAChild * ( )
632+ ) and
633633 config .hasFlow ( DataFlow:: exprNode ( source ) , DataFlow:: exprNode ( useOrChild ) )
634634 )
635635 }
@@ -652,7 +652,8 @@ module OutOfBounds {
652652 or
653653 // computable source value that flows to the size expression
654654 size = source .( DynamicAllocationSource ) .getFixedSize ( ) and
655- hasFlowFromBufferOrSizeExprToUse ( source .( DynamicAllocationSource ) .getSizeExprSource ( _, _) , sizeExpr )
655+ hasFlowFromBufferOrSizeExprToUse ( source .( DynamicAllocationSource ) .getSizeExprSource ( _, _) ,
656+ sizeExpr )
656657 }
657658
658659 int getArithmeticOffsetValue ( Expr expr ) {
@@ -694,42 +695,65 @@ module OutOfBounds {
694695 hasFlowFromBufferOrSizeExprToUse ( allocSize , bufferSizeArg )
695696 }
696697
697- predicate isBufferSizeExprGreaterThanSourceSizeExpr (
698+ predicate isBufferSizeExprGreaterThanSourceSizeExpr (
698699 Expr bufferUse , Expr bufferSize , Expr sizeSource , PointerToObjectSource sourceBufferAllocation ,
699- int bufSize , int size , BufferAccessLibraryFunctionCall fc
700+ int bufSize , int size , BufferAccessLibraryFunctionCall fc , int offset , Expr base
700701 ) {
701702 exists ( float sizeMult |
702703 (
703- bufferUse = fc .getWriteArg ( ) and bufferSize = fc .getWriteSizeArg ( ) and sizeMult = fc .getWriteSizeArgMult ( ) or
704- bufferUse = fc .getReadArg ( ) and bufferSize = fc .getReadSizeArg ( ) and sizeMult = fc .getReadSizeArgMult ( )
705- )
706- and
704+ bufferUse = fc .getWriteArg ( ) and
705+ bufferSize = fc .getWriteSizeArg ( ) and
706+ sizeMult = fc .getWriteSizeArgMult ( )
707+ or
708+ bufferUse = fc .getReadArg ( ) and
709+ bufferSize = fc .getReadSizeArg ( ) and
710+ sizeMult = fc .getReadSizeArgMult ( )
711+ ) and
707712 (
713+ offset = 0 and
714+ base = bufferSize and
708715 bufferUseComputableBufferSize ( bufferUse , sourceBufferAllocation , bufSize ) and
709716 sizeExprComputableSize ( bufferSize , sizeSource , size ) and
710- (
711- bufSize - getArithmeticOffsetValue ( bufferUse ) < ( sizeMult * ( float ) ( size + getArithmeticOffsetValue ( bufferSize ) ) )
712- or
717+ (
718+ bufSize - getArithmeticOffsetValue ( bufferUse ) <
719+ ( sizeMult * ( size + getArithmeticOffsetValue ( bufferSize ) ) .( float ) )
720+ or
713721 size = 0
714722 )
715- or
716- exists ( int offset , Expr base |
717- sizeSource = sourceBufferAllocation .( DynamicAllocationSource ) .getSizeExprSource ( base , offset ) and
718- bufferUseNonComputableSize ( bufferUse , sourceBufferAllocation ) and
719- not globalValueNumber ( sizeSource ) = globalValueNumber ( bufferSize ) and
720- globalValueNumber ( base ) = globalValueNumber ( bufferSize .getAChild * ( ) ) and
721- bufSize = getArithmeticOffsetValue ( bufferUse ) and
722- size = getArithmeticOffsetValue ( bufferSize ) and
723- bufSize >= size - offset
724- )
725723 )
726724 )
727725 }
728726
727+ predicate isBufferSizeOffsetOfGVN (
728+ BufferAccessLibraryFunctionCall fc , Expr bufferSize , Expr bufferUse ,
729+ DynamicAllocationSource source , Expr sourceSizeExpr , Expr sourceSizeExprBase ,
730+ int sourceSizeExprOffset , int sizeMult , int sizeArgOffset , int bufferArgOffset
731+ ) {
732+ (
733+ bufferUse = fc .getWriteArg ( ) and
734+ bufferSize = fc .getWriteSizeArg ( ) and
735+ sizeMult = fc .getWriteSizeArgMult ( )
736+ or
737+ bufferUse = fc .getReadArg ( ) and
738+ bufferSize = fc .getReadSizeArg ( ) and
739+ sizeMult = fc .getReadSizeArgMult ( )
740+ ) and
741+ sourceSizeExpr = source .getSizeExprSource ( sourceSizeExprBase , sourceSizeExprOffset ) and
742+ bufferUseNonComputableSize ( bufferUse , source ) and
743+ not globalValueNumber ( sourceSizeExpr ) = globalValueNumber ( bufferSize ) and
744+ exists ( Expr offsetExpr |
745+ offsetExpr = bufferSize .getAChild * ( ) and
746+ sizeArgOffset = getArithmeticOffsetValue ( offsetExpr )
747+ ) and
748+ bufferArgOffset = getArithmeticOffsetValue ( bufferUse ) and
749+ sourceSizeExprOffset + bufferArgOffset < sizeArgOffset
750+ }
751+
729752 predicate problems ( BufferAccessLibraryFunctionCall fc , string msg ) {
730753 exists ( Expr bufferUse , PointerToObjectSource source |
731754 exists ( int bufSize , int size , Expr bufferSize , Expr sizeSource |
732- isBufferSizeExprGreaterThanSourceSizeExpr ( bufferUse , bufferSize , sizeSource , source , bufSize , size , fc ) and
755+ isBufferSizeExprGreaterThanSourceSizeExpr ( bufferUse , bufferSize , sizeSource , source ,
756+ bufSize , size , fc , _, _) and
733757 msg = "Buffer size is smaller than size arg."
734758 )
735759 or
@@ -740,6 +764,9 @@ module OutOfBounds {
740764 hasFlowFromBufferOrSizeExprToUse ( source , bufferUse .getAChild * ( ) ) and
741765 msg = "Buffer " + bufferUse .toString ( ) + " is not null-terminated."
742766 )
767+ or
768+ isBufferSizeOffsetOfGVN ( fc , _, bufferUse , source , _, _, _, _, _, _) and
769+ msg = "Buffer size is offset of GVN."
743770 )
744771 }
745- }
772+ }
0 commit comments