@@ -18,13 +18,13 @@ module OutOfBounds {
18
18
bindingset [ name, result ]
19
19
private string getNameOrInternalName ( string name ) {
20
20
result = name or
21
- name .regexpMatch ( "__.*_+(?: " + result + ") " )
21
+ result .regexpMatch ( "__.*_+" + name + "_.* " )
22
22
}
23
23
24
24
/**
25
25
* MISRA-C Rule 21.17 function table of names and parameter indices
26
26
* which covers functions from <string.h> that rely on null-terminated strings.
27
- *
27
+ *
28
28
* This table is a subset of `libraryFunctionNameParamTable`.
29
29
*
30
30
* Note: These functions do not share a common semantic pattern of source and destination
@@ -33,11 +33,11 @@ module OutOfBounds {
33
33
* The `SimpleStringLibraryFunction` base class provides an appropriate
34
34
* interface for analyzing the functions in the below table.
35
35
*/
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
41
41
dst_sz = - 1 and
42
42
(
43
43
name = "strcat" and
@@ -48,7 +48,7 @@ module OutOfBounds {
48
48
dst = - 1 and
49
49
src = 0
50
50
or
51
- name = [ "strcmp" , "strcoll" ] and
51
+ name = [ "strcmp" , "strcoll" ] and
52
52
dst = - 1 and
53
53
src = [ 0 , 1 ]
54
54
or
@@ -86,18 +86,6 @@ module OutOfBounds {
86
86
)
87
87
}
88
88
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
-
101
89
/**
102
90
* A relation of the indices of buffer and size parameters of standard library functions
103
91
* which are defined in rules CERT ARR38-C and MISRA-C rules 21.17 and 21.18.
@@ -107,7 +95,7 @@ module OutOfBounds {
107
95
) {
108
96
result = libraryFunctionNameParamTableSimpleString ( name , dst , src , src_sz , dst_sz )
109
97
or
110
- result .hasGlobalOrStdName ( name ) and
98
+ result .getName ( ) = getNameOrInternalName ( name ) and
111
99
(
112
100
name = [ "fgets" , "fgetws" ] and
113
101
dst = 0 and
@@ -217,55 +205,41 @@ module OutOfBounds {
217
205
)
218
206
}
219
207
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
-
232
208
/**
233
209
* A library function that accesses one or more buffers supplied via arguments.
234
210
*/
235
211
class BufferAccessLibraryFunction extends Function {
236
- BufferAccessLibraryFunction ( ) {
237
- this = libraryFunctionNameParamTableRegex ( this .getName ( ) , _, _, _, _)
238
- }
212
+ BufferAccessLibraryFunction ( ) { this = libraryFunctionNameParamTable ( _, _, _, _, _) }
239
213
240
214
/**
241
215
* Returns the indices of parameters that are a destination buffer.
242
216
*/
243
217
int getWriteParamIndex ( ) {
244
- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , result , _, _, _) and
218
+ this = libraryFunctionNameParamTable ( _ , result , _, _, _) and
245
219
result >= 0
246
220
}
247
221
248
222
/**
249
223
* Returns the indices of parameters that are a source buffer.
250
224
*/
251
225
int getReadParamIndex ( ) {
252
- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , _, result , _, _) and
226
+ this = libraryFunctionNameParamTable ( _ , _, result , _, _) and
253
227
result >= 0
254
228
}
255
229
256
230
/**
257
231
* Returns the index of the parameter that is the source buffer size.
258
232
*/
259
233
int getReadSizeParamIndex ( ) {
260
- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , _, _, result , _) and
234
+ this = libraryFunctionNameParamTable ( _ , _, _, result , _) and
261
235
result >= 0
262
236
}
263
237
264
238
/**
265
239
* Returns the index of the parameter that is the destination buffer size.
266
240
*/
267
241
int getWriteCountParamIndex ( ) {
268
- this = libraryFunctionNameParamTableRegex ( this . getName ( ) , _, _, _, result ) and
242
+ this = libraryFunctionNameParamTable ( _ , _, _, _, result ) and
269
243
result >= 0
270
244
}
271
245
@@ -338,15 +312,19 @@ module OutOfBounds {
338
312
*/
339
313
class SimpleStringLibraryFunction extends BufferAccessLibraryFunction {
340
314
SimpleStringLibraryFunction ( ) {
341
- this = libraryFunctionNameParamTableSimpleStringRegex ( this .getName ( ) , _, _, _, _)
315
+ this = libraryFunctionNameParamTable ( this .getName ( ) , _, _, _, _)
342
316
}
343
317
344
318
override predicate getANullTerminatedParameterIndex ( int i ) {
345
319
// by default, require null-terminated parameters for src but
346
320
// only if the type of src is a plain char pointer.
347
321
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
350
328
}
351
329
}
352
330
@@ -358,7 +336,8 @@ module OutOfBounds {
358
336
/**
359
337
* A `BufferAccessLibraryFunction` modelling `strcat`
360
338
*/
361
- class StrcatLibraryFunction extends StringConcatenationFunctionLibraryFunction , SimpleStringLibraryFunction
339
+ class StrcatLibraryFunction extends StringConcatenationFunctionLibraryFunction ,
340
+ SimpleStringLibraryFunction
362
341
{
363
342
StrcatLibraryFunction ( ) { this .getName ( ) = getNameOrInternalName ( "strcat" ) }
364
343
@@ -380,6 +359,18 @@ module OutOfBounds {
380
359
}
381
360
}
382
361
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
+
383
374
/**
384
375
* A `FunctionCall` to a `BufferAccessLibraryFunction` that provides predicates for
385
376
* reasoning about buffer overflow and other buffer access violations.
@@ -417,15 +408,16 @@ module OutOfBounds {
417
408
int getStatedAllocValue ( Expr e ) {
418
409
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
419
410
// 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 ( ) )
423
413
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
+ ) )
429
421
}
430
422
431
423
int getStatedValue ( Expr e ) {
@@ -475,8 +467,9 @@ module OutOfBounds {
475
467
abstract predicate isNotNullTerminated ( ) ;
476
468
}
477
469
478
- class DynamicAllocationSource extends PointerToObjectSource
479
- instanceof AllocationExpr , FunctionCall {
470
+ class DynamicAllocationSource extends PointerToObjectSource instanceof AllocationExpr ,
471
+ FunctionCall
472
+ {
480
473
DynamicAllocationSource ( ) {
481
474
// exclude OperatorNewAllocationFunction to only deal with raw malloc-style calls,
482
475
// which do not apply a multiple to the size of the allocation passed to them.
@@ -509,23 +502,32 @@ module OutOfBounds {
509
502
* 2. `size_t sz = strlen(src); malloc(sz + 1);`
510
503
*/
511
504
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
+ )
520
523
or
521
- // case 2: expr + const in the variable assignment
522
- v .getAnAssignedValue ( ) = ae and
524
+ // case 3: function call + const
523
525
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 ( ) )
527
530
)
528
- then any ( ) // all logic handled in the `if` clause
529
531
else (
530
532
offset = 0 and
531
533
// case 3: a variable is read in the size expression
@@ -608,9 +610,8 @@ module OutOfBounds {
608
610
}
609
611
610
612
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
614
615
(
615
616
sink .asExpr ( ) = arg
616
617
or
@@ -627,9 +628,8 @@ module OutOfBounds {
627
628
useOrChild = use
628
629
or
629
630
getArithmeticOffsetValue ( use ) > 0 and
630
- useOrChild = use .getAChild * ( )
631
- )
632
- and
631
+ useOrChild = use .getAChild * ( )
632
+ ) and
633
633
config .hasFlow ( DataFlow:: exprNode ( source ) , DataFlow:: exprNode ( useOrChild ) )
634
634
)
635
635
}
@@ -652,7 +652,8 @@ module OutOfBounds {
652
652
or
653
653
// computable source value that flows to the size expression
654
654
size = source .( DynamicAllocationSource ) .getFixedSize ( ) and
655
- hasFlowFromBufferOrSizeExprToUse ( source .( DynamicAllocationSource ) .getSizeExprSource ( _, _) , sizeExpr )
655
+ hasFlowFromBufferOrSizeExprToUse ( source .( DynamicAllocationSource ) .getSizeExprSource ( _, _) ,
656
+ sizeExpr )
656
657
}
657
658
658
659
int getArithmeticOffsetValue ( Expr expr ) {
@@ -694,42 +695,65 @@ module OutOfBounds {
694
695
hasFlowFromBufferOrSizeExprToUse ( allocSize , bufferSizeArg )
695
696
}
696
697
697
- predicate isBufferSizeExprGreaterThanSourceSizeExpr (
698
+ predicate isBufferSizeExprGreaterThanSourceSizeExpr (
698
699
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
700
701
) {
701
702
exists ( float sizeMult |
702
703
(
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
707
712
(
713
+ offset = 0 and
714
+ base = bufferSize and
708
715
bufferUseComputableBufferSize ( bufferUse , sourceBufferAllocation , bufSize ) and
709
716
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
713
721
size = 0
714
722
)
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
- )
725
723
)
726
724
)
727
725
}
728
726
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
+
729
752
predicate problems ( BufferAccessLibraryFunctionCall fc , string msg ) {
730
753
exists ( Expr bufferUse , PointerToObjectSource source |
731
754
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
733
757
msg = "Buffer size is smaller than size arg."
734
758
)
735
759
or
@@ -740,6 +764,9 @@ module OutOfBounds {
740
764
hasFlowFromBufferOrSizeExprToUse ( source , bufferUse .getAChild * ( ) ) and
741
765
msg = "Buffer " + bufferUse .toString ( ) + " is not null-terminated."
742
766
)
767
+ or
768
+ isBufferSizeOffsetOfGVN ( fc , _, bufferUse , source , _, _, _, _, _, _) and
769
+ msg = "Buffer size is offset of GVN."
743
770
)
744
771
}
745
- }
772
+ }
0 commit comments