@@ -13,8 +13,9 @@ import codingstandards.cpp.PossiblyUnsafeStringOperation
1313import codingstandards.cpp.SimpleRangeAnalysisCustomizations
1414import semmle.code.cpp.dataflow.DataFlow
1515import semmle.code.cpp.valuenumbering.GlobalValueNumbering
16+ import semmle.code.cpp.security.BufferWrite
1617
17- module OutOfBounds {
18+ module OOB {
1819 bindingset [ name, result ]
1920 private string getNameOrInternalName ( string name ) {
2021 result = name or
@@ -312,7 +313,7 @@ module OutOfBounds {
312313 */
313314 class SimpleStringLibraryFunction extends BufferAccessLibraryFunction {
314315 SimpleStringLibraryFunction ( ) {
315- this = libraryFunctionNameParamTable ( this .getName ( ) , _, _, _ , _ )
316+ this = libraryFunctionNameParamTableSimpleString ( this .getName ( ) , _, _, - 1 , - 1 )
316317 }
317318
318319 override predicate getANullTerminatedParameterIndex ( int i ) {
@@ -405,9 +406,11 @@ module OutOfBounds {
405406 }
406407 }
407408
409+ class SimpleStringLibraryFunctionCall extends BufferAccessLibraryFunctionCall {
410+ SimpleStringLibraryFunctionCall ( ) { this .getTarget ( ) instanceof SimpleStringLibraryFunction }
411+ }
412+
408413 int getStatedAllocValue ( Expr e ) {
409- // `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
410- // result in this case we pick the minimum value obtainable from dataflow and range analysis.
411414 if upperBound ( e ) = exprMaxVal ( e )
412415 then result = max ( Expr source | DataFlow:: localExprFlow ( source , e ) | source .getValue ( ) .toInt ( ) )
413416 else
@@ -620,6 +623,26 @@ module OutOfBounds {
620623 )
621624 )
622625 }
626+
627+ override predicate isBarrierOut ( DataFlow:: Node node ) {
628+ // the default interprocedural data-flow model flows through any array assignment expressions
629+ // to the qualifier (array base or pointer dereferenced) instead of the individual element
630+ // that the assignment modifies. this default behaviour causes false positives for any future
631+ // access of the array base, so remove the assignment edge at the expense of false-negatives.
632+ exists ( AssignExpr a |
633+ node .asExpr ( ) = a .getRValue ( ) .getAChild * ( ) and
634+ (
635+ a .getLValue ( ) instanceof ArrayExpr or
636+ a .getLValue ( ) instanceof PointerDereferenceExpr
637+ )
638+ )
639+ or
640+ // remove flow from `src` to `dst` in memcpy
641+ exists ( FunctionCall fc |
642+ fc .getTarget ( ) .getName ( ) = getNameOrInternalName ( "memcpy" ) and
643+ node .asExpr ( ) = fc .getArgument ( 1 ) .getAChild * ( )
644+ )
645+ }
623646 }
624647
625648 predicate hasFlowFromBufferOrSizeExprToUse ( Expr source , Expr use ) {
@@ -695,31 +718,25 @@ module OutOfBounds {
695718 hasFlowFromBufferOrSizeExprToUse ( allocSize , bufferSizeArg )
696719 }
697720
698- predicate isBufferSizeExprGreaterThanSourceSizeExpr (
699- Expr bufferUse , Expr bufferSize , Expr sizeSource , PointerToObjectSource sourceBufferAllocation ,
700- int bufSize , int size , BufferAccessLibraryFunctionCall fc , int offset , Expr base
721+ predicate isSizeArgGreaterThanBufferSize (
722+ Expr bufferArg , Expr sizeArg , PointerToObjectSource bufferSource , int bufferArgSize ,
723+ int sizeArgValue , BufferAccessLibraryFunctionCall fc
701724 ) {
702725 exists ( float sizeMult |
703726 (
704- bufferUse = fc .getWriteArg ( ) and
705- bufferSize = fc .getWriteSizeArg ( ) and
727+ bufferArg = fc .getWriteArg ( ) and
728+ sizeArg = fc .getWriteSizeArg ( ) and
706729 sizeMult = fc .getWriteSizeArgMult ( )
707730 or
708- bufferUse = fc .getReadArg ( ) and
709- bufferSize = fc .getReadSizeArg ( ) and
731+ bufferArg = fc .getReadArg ( ) and
732+ sizeArg = fc .getReadSizeArg ( ) and
710733 sizeMult = fc .getReadSizeArgMult ( )
711734 ) and
712735 (
713- offset = 0 and
714- base = bufferSize and
715- bufferUseComputableBufferSize ( bufferUse , sourceBufferAllocation , bufSize ) and
716- sizeExprComputableSize ( bufferSize , sizeSource , size ) and
717- (
718- bufSize - getArithmeticOffsetValue ( bufferUse ) <
719- ( sizeMult * ( size + getArithmeticOffsetValue ( bufferSize ) ) .( float ) )
720- or
721- size = 0
722- )
736+ bufferUseComputableBufferSize ( bufferArg , bufferSource , bufferArgSize ) and
737+ sizeExprComputableSize ( sizeArg , _, sizeArgValue ) and
738+ bufferArgSize - getArithmeticOffsetValue ( bufferArg ) <
739+ sizeMult .( float ) * ( sizeArgValue + getArithmeticOffsetValue ( sizeArg ) ) .( float )
723740 )
724741 )
725742 }
@@ -741,32 +758,45 @@ module OutOfBounds {
741758 sourceSizeExpr = source .getSizeExprSource ( sourceSizeExprBase , sourceSizeExprOffset ) and
742759 bufferUseNonComputableSize ( bufferUse , source ) and
743760 not globalValueNumber ( sourceSizeExpr ) = globalValueNumber ( bufferSize ) and
744- exists ( Expr offsetExpr |
745- offsetExpr = bufferSize .getAChild * ( ) and
746- sizeArgOffset = getArithmeticOffsetValue ( offsetExpr )
747- ) and
761+ sizeArgOffset = getArithmeticOffsetValue ( bufferSize .getAChild * ( ) ) and
748762 bufferArgOffset = getArithmeticOffsetValue ( bufferUse ) and
749763 sourceSizeExprOffset + bufferArgOffset < sizeArgOffset
750764 }
751765
752- predicate problems ( BufferAccessLibraryFunctionCall fc , string msg ) {
753- exists ( Expr bufferUse , PointerToObjectSource source |
754- exists ( int bufSize , int size , Expr bufferSize , Expr sizeSource |
755- isBufferSizeExprGreaterThanSourceSizeExpr ( bufferUse , bufferSize , sizeSource , source ,
756- bufSize , size , fc , _, _) and
757- msg = "Buffer size is smaller than size arg."
758- )
759- or
760- exists ( int i |
761- fc .getTarget ( ) .( BufferAccessLibraryFunction ) .getANullTerminatedParameterIndex ( i ) and
762- fc .getArgument ( i ) = bufferUse and
763- source .isNotNullTerminated ( ) and
764- hasFlowFromBufferOrSizeExprToUse ( source , bufferUse .getAChild * ( ) ) and
765- msg = "Buffer " + bufferUse .toString ( ) + " is not null-terminated."
766- )
767- or
768- isBufferSizeOffsetOfGVN ( fc , _, bufferUse , source , _, _, _, _, _, _) and
769- msg = "Buffer size is offset of GVN."
766+ predicate isMandatoryBufferArgNull ( Expr bufferArg , BufferAccessLibraryFunctionCall fc ) {
767+ exists ( int i |
768+ i =
769+ [
770+ fc .getTarget ( ) .( BufferAccessLibraryFunction ) .getReadParamIndex ( ) ,
771+ fc .getTarget ( ) .( BufferAccessLibraryFunction ) .getWriteParamIndex ( )
772+ ] and
773+ not fc .getTarget ( ) .( BufferAccessLibraryFunction ) .getAPermissiblyNullParameterIndex ( i ) and
774+ bufferArg = fc .getArgument ( i ) and
775+ getStatedValue ( bufferArg ) = 0
776+ )
777+ }
778+
779+ predicate isNullTerminatorMissingFromBufferArg (
780+ Expr bufferArg , PointerToObjectSource source , BufferAccessLibraryFunctionCall fc
781+ ) {
782+ exists ( int i |
783+ fc .getTarget ( ) .( BufferAccessLibraryFunction ) .getANullTerminatedParameterIndex ( i ) and
784+ fc .getArgument ( i ) = bufferArg and
785+ source .isNotNullTerminated ( ) and
786+ hasFlowFromBufferOrSizeExprToUse ( source , bufferArg .getAChild * ( ) )
787+ )
788+ }
789+
790+ predicate isReadBufferSizeSmallerThanWriteBufferSize (
791+ Expr readBuffer , Expr writeBuffer , SimpleStringLibraryFunctionCall fc
792+ ) {
793+ readBuffer = fc .getReadArg ( ) and
794+ writeBuffer = fc .getWriteArg ( ) and
795+ exists ( int readBufferSize , int writeBufferSize |
796+ bufferUseComputableBufferSize ( readBuffer , _, readBufferSize ) and
797+ bufferUseComputableBufferSize ( writeBuffer , _, writeBufferSize ) and
798+ readBufferSize - getArithmeticOffsetValue ( readBuffer ) <
799+ writeBufferSize - getArithmeticOffsetValue ( writeBuffer )
770800 )
771801 }
772802}
0 commit comments