Skip to content

Commit 837b90d

Browse files
author
Nikita Kraiouchkine
committed
Update OutOfBounds.qll
1 parent 667fc33 commit 837b90d

File tree

1 file changed

+73
-43
lines changed

1 file changed

+73
-43
lines changed

c/common/src/codingstandards/c/OutOfBounds.qll

+73-43
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import codingstandards.cpp.PossiblyUnsafeStringOperation
1313
import codingstandards.cpp.SimpleRangeAnalysisCustomizations
1414
import semmle.code.cpp.dataflow.DataFlow
1515
import 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

Comments
 (0)