@@ -13,8 +13,6 @@ import codingstandards.cpp.PossiblyUnsafeStringOperation
13
13
import codingstandards.cpp.SimpleRangeAnalysisCustomizations
14
14
import semmle.code.cpp.dataflow.DataFlow
15
15
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
16
- import semmle.code.cpp.security.BufferAccess
17
- import semmle.code.cpp.security.BufferWrite
18
16
19
17
module OOB {
20
18
bindingset [ name, result ]
@@ -588,47 +586,66 @@ module OOB {
588
586
SimpleStringLibraryFunctionCall ( ) { this .getTarget ( ) instanceof SimpleStringLibraryFunction }
589
587
}
590
588
591
- int getStatedAllocValue ( Expr e ) {
592
- if upperBound ( e ) = exprMaxVal ( e )
593
- then result = max ( Expr source | DataFlow:: localExprFlow ( source , e ) | source .getValue ( ) .toInt ( ) )
594
- else
595
- result =
596
- upperBound ( e )
597
- .minimum ( min ( Expr source |
598
- DataFlow:: localExprFlow ( source , e )
599
- |
600
- source .getValue ( ) .toInt ( )
601
- ) )
589
+ private Expr getSourceConstantExpr ( Expr dest ) {
590
+ exists ( result .getValue ( ) .toInt ( ) ) and
591
+ DataFlow:: localExprFlow ( result , dest )
602
592
}
603
593
604
- int getStatedValue ( Expr e ) {
605
- result =
606
- upperBound ( e )
607
- .minimum ( min ( Expr source | DataFlow:: localExprFlow ( source , e ) | source .getValue ( ) .toInt ( ) ) )
594
+ /**
595
+ * Gets the smallest of the upper bound of `e` or the largest source value (i.e. "stated value") that flows to `e`.
596
+ * Because range-analysis can over-widen bounds, take the minimum of range analysis and data-flow sources.
597
+ *
598
+ * If there is no source value that flows to `e`, this predicate does not hold.
599
+ */
600
+ private int getMaxStatedValue ( Expr e ) {
601
+ result = upperBound ( e ) .minimum ( max ( getSourceConstantExpr ( e ) .getValue ( ) .toInt ( ) ) )
602
+ }
603
+
604
+ /**
605
+ * Gets the smallest of the upper bound of `e` or the smallest source value (i.e. "stated value") that flows to `e`.
606
+ * Because range-analysis can over-widen bounds, take the minimum of range analysis and data-flow sources.
607
+ *
608
+ * If there is no source value that flows to `e`, this predicate does not hold.
609
+ */
610
+ private int getMinStatedValue ( Expr e ) {
611
+ result = upperBound ( e ) .minimum ( min ( getSourceConstantExpr ( e ) .getValue ( ) .toInt ( ) ) )
608
612
}
609
613
610
614
/**
611
615
* A class for reasoning about the offset of a variable from the original value flowing to it
612
616
* as a result of arithmetic or pointer arithmetic expressions.
613
617
*/
614
- int getArithmeticOperandStatedValue ( Expr expr ) {
615
- result = getStatedValue ( expr .( PointerArithmeticExpr ) .getOperand ( ) )
618
+ private int getArithmeticOffsetValue ( Expr expr , Expr base ) {
619
+ result = getMinStatedValue ( expr .( PointerArithmeticExpr ) .getOperand ( ) ) and
620
+ base = expr .( PointerArithmeticExpr ) .getPointer ( )
616
621
or
617
622
// &(array[index]) expressions
618
- result = getStatedValue ( expr .( AddressOfExpr ) .getOperand ( ) .( PointerArithmeticExpr ) .getOperand ( ) )
623
+ result =
624
+ getMinStatedValue ( expr .( AddressOfExpr ) .getOperand ( ) .( PointerArithmeticExpr ) .getOperand ( ) ) and
625
+ base = expr .( AddressOfExpr ) .getOperand ( ) .( PointerArithmeticExpr ) .getPointer ( )
626
+ or
627
+ result = getMinStatedValue ( expr .( AddExpr ) .getRightOperand ( ) ) and
628
+ base = expr .( AddExpr ) .getLeftOperand ( )
619
629
or
620
- result = getStatedValue ( expr .( BinaryArithmeticOperation ) .getRightOperand ( ) )
630
+ result = - getMinStatedValue ( expr .( SubExpr ) .getRightOperand ( ) ) and
631
+ base = expr .( SubExpr ) .getLeftOperand ( )
621
632
or
622
- expr instanceof IncrementOperation and result = 1
633
+ expr instanceof IncrementOperation and
634
+ result = 1 and
635
+ base = expr .( IncrementOperation ) .getOperand ( )
623
636
or
624
- expr instanceof DecrementOperation and result = - 1
637
+ expr instanceof DecrementOperation and
638
+ result = - 1 and
639
+ base = expr .( DecrementOperation ) .getOperand ( )
625
640
or
626
641
// fall-back if `expr` is not an arithmetic or pointer arithmetic expression
627
642
not expr instanceof PointerArithmeticExpr and
628
643
not expr .( AddressOfExpr ) .getOperand ( ) instanceof PointerArithmeticExpr and
629
- not expr instanceof BinaryArithmeticOperation and
644
+ not expr instanceof AddExpr and
645
+ not expr instanceof SubExpr and
630
646
not expr instanceof IncrementOperation and
631
647
not expr instanceof DecrementOperation and
648
+ base = expr and
632
649
result = 0
633
650
}
634
651
@@ -660,8 +677,9 @@ module OOB {
660
677
abstract predicate isNotNullTerminated ( ) ;
661
678
}
662
679
663
- class DynamicAllocationSource extends PointerToObjectSource instanceof AllocationExpr ,
664
- FunctionCall {
680
+ private class DynamicAllocationSource extends PointerToObjectSource instanceof AllocationExpr ,
681
+ FunctionCall
682
+ {
665
683
DynamicAllocationSource ( ) {
666
684
// exclude OperatorNewAllocationFunction to only deal with raw malloc-style calls,
667
685
// which do not apply a multiple to the size of the allocation passed to them.
@@ -742,7 +760,7 @@ module OOB {
742
760
)
743
761
}
744
762
745
- override int getFixedSize ( ) { result = getStatedAllocValue ( getSizeExpr ( ) ) }
763
+ override int getFixedSize ( ) { result = getMaxStatedValue ( getSizeExpr ( ) ) }
746
764
747
765
override predicate isNotNullTerminated ( ) { none ( ) }
748
766
}
@@ -751,7 +769,7 @@ module OOB {
751
769
* A `PointerToObjectSource` which is an `AddressOfExpr` to a variable
752
770
* that is not a field or pointer type.
753
771
*/
754
- class AddressOfExprSource extends PointerToObjectSource instanceof AddressOfExpr {
772
+ private class AddressOfExprSource extends PointerToObjectSource instanceof AddressOfExpr {
755
773
AddressOfExprSource ( ) {
756
774
exists ( Variable v |
757
775
v = this .getOperand ( ) .( VariableAccess ) .getTarget ( ) and
@@ -774,7 +792,7 @@ module OOB {
774
792
/**
775
793
* A `PointerToObjectSource` which is a `VariableAccess` to a static buffer
776
794
*/
777
- class StaticBufferAccessSource extends PointerToObjectSource instanceof VariableAccess {
795
+ private class StaticBufferAccessSource extends PointerToObjectSource instanceof VariableAccess {
778
796
StaticBufferAccessSource ( ) {
779
797
not this .getTarget ( ) instanceof Field and
780
798
not this .getTarget ( ) .getUnspecifiedType ( ) instanceof PointerType and
@@ -809,16 +827,6 @@ module OOB {
809
827
) and
810
828
not this .( VariableAccess ) .getTarget ( ) instanceof GlobalVariable and
811
829
not exists ( this .( VariableAccess ) .getTarget ( ) .getInitializer ( ) ) and
812
- not exists ( FunctionCall memset , Expr destBuffer |
813
- (
814
- destBuffer = memset .( MemsetBA ) .getBuffer ( _, _)
815
- or
816
- memset .getTarget ( ) .getName ( ) = getNameOrInternalName ( "memset" ) and
817
- destBuffer = memset .getArgument ( 0 )
818
- ) and
819
- memset .getArgument ( 1 ) .getValue ( ) .toInt ( ) = 0 and
820
- this .( VariableAccess ) .getTarget ( ) .getAnAccess ( ) = destBuffer
821
- ) and
822
830
// exclude any BufferAccessLibraryFunction that writes to the buffer and does not require
823
831
// a null-terminated buffer argument for its write argument
824
832
not exists (
@@ -845,7 +853,7 @@ module OOB {
845
853
* A `PointerToObjectSource` which is a string literal that is not
846
854
* part of an variable initializer (to deduplicate `StaticBufferAccessSource`)
847
855
*/
848
- class StringLiteralSource extends PointerToObjectSource instanceof StringLiteral {
856
+ private class StringLiteralSource extends PointerToObjectSource instanceof StringLiteral {
849
857
StringLiteralSource ( ) { not this instanceof CharArrayInitializedWithStringLiteral }
850
858
851
859
override Expr getPointer ( ) { result = this }
@@ -862,7 +870,7 @@ module OOB {
862
870
override predicate isNotNullTerminated ( ) { none ( ) }
863
871
}
864
872
865
- class PointerToObjectSourceOrSizeToBufferAccessFunctionConfig extends DataFlow:: Configuration {
873
+ private class PointerToObjectSourceOrSizeToBufferAccessFunctionConfig extends DataFlow:: Configuration {
866
874
PointerToObjectSourceOrSizeToBufferAccessFunctionConfig ( ) {
867
875
this = "PointerToObjectSourceOrSizeToBufferAccessFunctionConfig"
868
876
}
@@ -883,10 +891,8 @@ module OOB {
883
891
arg = ba .getARelevantExpr ( )
884
892
) and
885
893
(
886
- sink .asExpr ( ) = arg
887
- or
888
- getArithmeticOffsetValue ( arg ) > 0 and
889
- sink .asExpr ( ) = arg .getAChild * ( )
894
+ sink .asExpr ( ) = arg or
895
+ exists ( getArithmeticOffsetValue ( arg , sink .asExpr ( ) ) )
890
896
)
891
897
)
892
898
}
@@ -910,58 +916,35 @@ module OOB {
910
916
}
911
917
}
912
918
913
- predicate hasFlowFromBufferOrSizeExprToUse ( Expr source , Expr use ) {
919
+ private predicate hasFlowFromBufferOrSizeExprToUse ( Expr source , Expr use ) {
914
920
exists ( PointerToObjectSourceOrSizeToBufferAccessFunctionConfig config , Expr useOrChild |
915
- (
916
- useOrChild = use
917
- or
918
- getArithmeticOffsetValue ( use ) > 0 and
919
- useOrChild = use .getAChild * ( )
920
- ) and
921
+ exists ( getArithmeticOffsetValue ( use , useOrChild ) ) and
921
922
config .hasFlow ( DataFlow:: exprNode ( source ) , DataFlow:: exprNode ( useOrChild ) )
922
923
)
923
924
}
924
925
925
- predicate bufferUseComputableBufferSize ( Expr bufferUse , Expr source , int size ) {
926
+ private predicate bufferUseComputableBufferSize ( Expr bufferUse , Expr source , int size ) {
926
927
// flow from a PointerToObjectSource for which we can compute the exact size
927
928
size = source .( PointerToObjectSource ) .getFixedSize ( ) and
928
929
hasFlowFromBufferOrSizeExprToUse ( source , bufferUse )
929
930
}
930
931
931
- predicate bufferUseNonComputableSize ( Expr bufferUse , Expr source ) {
932
+ private predicate bufferUseNonComputableSize ( Expr bufferUse , Expr source ) {
932
933
not bufferUseComputableBufferSize ( bufferUse , source , _) and
933
934
hasFlowFromBufferOrSizeExprToUse ( source .( DynamicAllocationSource ) , bufferUse )
934
935
}
935
936
936
- predicate sizeExprComputableSize ( Expr sizeExpr , Expr source , int size ) {
937
+ private predicate sizeExprComputableSize ( Expr sizeExpr , Expr source , int size ) {
937
938
// computable direct value
938
- size = getStatedValue ( sizeExpr ) and
939
+ size = getMinStatedValue ( sizeExpr ) and
939
940
source = sizeExpr
940
941
or
941
942
// computable source value that flows to the size expression
942
- size = source .( DynamicAllocationSource ) .getFixedSize ( ) + getArithmeticOffsetValue ( sizeExpr ) and
943
+ size = source .( DynamicAllocationSource ) .getFixedSize ( ) + getArithmeticOffsetValue ( sizeExpr , _ ) and
943
944
hasFlowFromBufferOrSizeExprToUse ( source .( DynamicAllocationSource ) .getSizeExprSource ( _, _) ,
944
945
sizeExpr )
945
946
}
946
947
947
- int getArithmeticOffsetValue ( Expr expr ) {
948
- result = getStatedValue ( expr .( PointerArithmeticExpr ) .getOperand ( ) )
949
- or
950
- // edge-case: &(array[index]) expressions
951
- result = getStatedValue ( expr .( AddressOfExpr ) .getOperand ( ) .( PointerArithmeticExpr ) .getOperand ( ) )
952
- or
953
- // AddExpr
954
- result = getStatedValue ( expr .( AddExpr ) .getAnOperand ( ) )
955
- or
956
- // SubExpr
957
- result = - getStatedValue ( expr .( SubExpr ) .getAnOperand ( ) )
958
- or
959
- // fall-back
960
- not expr instanceof PointerArithmeticExpr and
961
- not expr .( AddressOfExpr ) .getOperand ( ) instanceof PointerArithmeticExpr and
962
- result = 0
963
- }
964
-
965
948
/**
966
949
* If the size is not computable locally, then it is either:
967
950
*
@@ -1012,12 +995,16 @@ module OOB {
1012
995
readBuffer = fc .getReadArg ( ) and
1013
996
writeBuffer = fc .getWriteArg ( ) and
1014
997
exists ( int readSizeMult , int writeSizeMult , int readBufferSizeBase , int writeBufferSizeBase |
998
+ // the read and write buffer sizes must be derived from computable constants
1015
999
bufferUseComputableBufferSize ( readBuffer , _, readBufferSizeBase ) and
1016
1000
bufferUseComputableBufferSize ( writeBuffer , _, writeBufferSizeBase ) and
1001
+ // calculate the buffer byte sizes (size base is the number of elements)
1017
1002
readSizeMult = fc .getReadSizeArgMult ( ) and
1018
1003
writeSizeMult = fc .getWriteSizeArgMult ( ) and
1019
- readBufferSize = readBufferSizeBase - readSizeMult * getArithmeticOffsetValue ( readBuffer ) and
1020
- writeBufferSize = writeBufferSizeBase - writeSizeMult * getArithmeticOffsetValue ( writeBuffer ) and
1004
+ readBufferSize = readBufferSizeBase - readSizeMult * getArithmeticOffsetValue ( readBuffer , _) and
1005
+ writeBufferSize =
1006
+ writeBufferSizeBase - writeSizeMult * getArithmeticOffsetValue ( writeBuffer , _) and
1007
+ // the read buffer size is larger than the write buffer size
1021
1008
readBufferSize > writeBufferSize and
1022
1009
(
1023
1010
// if a size arg exists and it is computable, then it must be <= to the write buffer size
@@ -1051,7 +1038,7 @@ module OOB {
1051
1038
// If the bufferArg is an access of a static buffer, do not look for "long distance" sources
1052
1039
( bufferArg instanceof StaticBufferAccessSource implies bufferSource = bufferArg ) and
1053
1040
sizeExprComputableSize ( sizeArg , _, sizeArgValue ) and
1054
- computedBufferSize = bufferArgSize - sizeMult .( float ) * getArithmeticOffsetValue ( bufferArg ) and
1041
+ computedBufferSize = bufferArgSize - sizeMult .( float ) * getArithmeticOffsetValue ( bufferArg , _ ) and
1055
1042
computedSizeAccessed =
1056
1043
sizeMult .( float ) * ( sizeArgValue + argNumCharactersOffset ( bufferAccess , sizeArg ) ) .( float ) and
1057
1044
computedBufferSize < computedSizeAccessed
@@ -1074,7 +1061,7 @@ module OOB {
1074
1061
bufferElementSize = fc .getWriteSizeArgMult ( )
1075
1062
) and
1076
1063
bufferUseComputableBufferSize ( bufferArg , _, bufferSize ) and
1077
- bufferArgOffset = getArithmeticOffsetValue ( bufferArg ) * bufferElementSize and
1064
+ bufferArgOffset = getArithmeticOffsetValue ( bufferArg , _ ) * bufferElementSize and
1078
1065
bufferArgOffset >= bufferSize
1079
1066
)
1080
1067
}
@@ -1100,8 +1087,8 @@ module OOB {
1100
1087
sourceSizeExpr = source .getSizeExprSource ( sourceSizeExprBase , sourceSizeExprOffset ) and
1101
1088
bufferUseNonComputableSize ( bufferArg , source ) and
1102
1089
not globalValueNumber ( sourceSizeExpr ) = globalValueNumber ( bufferSizeArg ) and
1103
- sizeArgOffset = getArithmeticOffsetValue ( bufferSizeArg .getAChild * ( ) ) and
1104
- bufferArgOffset = getArithmeticOffsetValue ( bufferArg ) and
1090
+ sizeArgOffset = getArithmeticOffsetValue ( bufferSizeArg .getAChild * ( ) , _ ) and
1091
+ bufferArgOffset = getArithmeticOffsetValue ( bufferArg , _ ) and
1105
1092
sourceSizeExprOffset + bufferArgOffset < sizeArgOffset
1106
1093
)
1107
1094
}
@@ -1119,7 +1106,7 @@ module OOB {
1119
1106
] and
1120
1107
not fc .getTarget ( ) .( BufferAccessLibraryFunction ) .getAPermissiblyNullParameterIndex ( i ) and
1121
1108
bufferArg = fc .getArgument ( i ) and
1122
- getStatedValue ( bufferArg ) = 0
1109
+ getMinStatedValue ( bufferArg ) = 0
1123
1110
)
1124
1111
}
1125
1112
@@ -1181,7 +1168,7 @@ module OOB {
1181
1168
// Not a size expression for which we can compute a specific size
1182
1169
not sizeExprComputableSize ( sizeArg , _, _) and
1183
1170
// If the lower bound is less than zero, taking into account any offsets
1184
- lowerBound ( sizeArg ) + getArithmeticOffsetValue ( bufferArg ) < 0
1171
+ lowerBound ( sizeArg ) + getArithmeticOffsetValue ( bufferArg , _ ) < 0
1185
1172
)
1186
1173
}
1187
1174
0 commit comments