Merge pull request #12247 from smowton/smowton/fix/integer-conversion-sign

Go integer conversion: check against sink, not source signedness
This commit is contained in:
Chris Smowton
2023-02-18 08:55:52 +00:00
committed by GitHub
3 changed files with 18 additions and 13 deletions

View File

@@ -56,14 +56,14 @@ private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSiz
* integer types, which could cause unexpected values. * integer types, which could cause unexpected values.
*/ */
class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
boolean sourceIsSigned; boolean sinkIsSigned;
int sourceBitSize; int sourceBitSize;
int sinkBitSize; int sinkBitSize;
ConversionWithoutBoundsCheckConfig() { ConversionWithoutBoundsCheckConfig() {
sourceIsSigned in [true, false] and sinkIsSigned in [true, false] and
isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and
this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sourceIsSigned + sinkBitSize this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sinkIsSigned + sinkBitSize
} }
/** Gets the bit size of the source. */ /** Gets the bit size of the source. */
@@ -75,11 +75,6 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
| |
c.getTarget() = ip and source = c.getResult(0) c.getTarget() = ip and source = c.getResult(0)
| |
(
if ip.getResultType(0) instanceof SignedIntegerType
then sourceIsSigned = true
else sourceIsSigned = false
) and
( (
apparentBitSize = ip.getTargetBitSize() apparentBitSize = ip.getTargetBitSize()
or or
@@ -112,10 +107,13 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
predicate isSinkWithBitSize(DataFlow::TypeCastNode sink, int bitSize) { predicate isSinkWithBitSize(DataFlow::TypeCastNode sink, int bitSize) {
sink.asExpr() instanceof ConversionExpr and sink.asExpr() instanceof ConversionExpr and
exists(IntegerType integerType | sink.getResultType().getUnderlyingType() = integerType | exists(IntegerType integerType | sink.getResultType().getUnderlyingType() = integerType |
bitSize = integerType.getSize() (
or bitSize = integerType.getSize()
not exists(integerType.getSize()) and or
bitSize = getIntTypeBitSize(sink.getFile()) not exists(integerType.getSize()) and
bitSize = getIntTypeBitSize(sink.getFile())
) and
if integerType instanceof SignedIntegerType then sinkIsSigned = true else sinkIsSigned = false
) and ) and
not exists(ShrExpr shrExpr | not exists(ShrExpr shrExpr |
shrExpr.getLeftOperand().getGlobalValueNumber() = shrExpr.getLeftOperand().getGlobalValueNumber() =
@@ -134,7 +132,7 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32 if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32
| |
node = DataFlow::BarrierGuard<upperBoundCheckGuard/3>::getABarrierNodeForGuard(g) and node = DataFlow::BarrierGuard<upperBoundCheckGuard/3>::getABarrierNodeForGuard(g) and
g.isBoundFor(bitSize, sourceIsSigned) g.isBoundFor(bitSize, sinkIsSigned)
) )
} }

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The query `go/incorrect-integer-conversion` now correctly recognises guards of the form `if val <= x` to protect a conversion `uintX(val)` when `x` is in the range `(math.MaxIntX, math.MaxUintX]`.

View File

@@ -264,6 +264,9 @@ func testBoundsChecking(input string) {
_ = int16(parsed) _ = int16(parsed)
} }
} }
if parsed <= math.MaxUint16 {
_ = uint16(parsed)
}
} }
{ {
parsed, err := strconv.ParseUint(input, 10, 32) parsed, err := strconv.ParseUint(input, 10, 32)