From 3a6aa58e48ad534ca4aad9eac428f5464b980e13 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 18 Jun 2020 09:27:45 +0100 Subject: [PATCH 01/16] Fix typo in QLDoc --- ql/src/semmle/go/controlflow/ControlFlowGraph.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/semmle/go/controlflow/ControlFlowGraph.qll b/ql/src/semmle/go/controlflow/ControlFlowGraph.qll index abf5eab4682..caca0adea41 100644 --- a/ql/src/semmle/go/controlflow/ControlFlowGraph.qll +++ b/ql/src/semmle/go/controlflow/ControlFlowGraph.qll @@ -168,7 +168,7 @@ module ControlFlow { } /** - * A control-flow node recording the fact that a certain expression is has a known + * A control-flow node recording the fact that a certain expression has a known * Boolean value at this point in the program. */ class ConditionGuardNode extends IR::Instruction, MkConditionGuardNode { From ac49aa25275873c60d73a3909519b7be8899e712 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 5 Aug 2020 12:08:38 +0100 Subject: [PATCH 02/16] Delete experimental query and tests for it --- .../CWE-681/IncorrectNumericConversion.go | 20 - .../CWE-681/IncorrectNumericConversion.qhelp | 65 ---- .../CWE-681/IncorrectNumericConversion.ql | 266 ------------- .../CWE-681/IncorrectNumericConversionGood.go | 51 --- .../IncorrectNumericConversion.expected | 83 ---- .../CWE-681/IncorrectNumericConversion.go | 355 ------------------ .../CWE-681/IncorrectNumericConversion.qlref | 1 - 7 files changed, 841 deletions(-) delete mode 100644 ql/src/experimental/CWE-681/IncorrectNumericConversion.go delete mode 100644 ql/src/experimental/CWE-681/IncorrectNumericConversion.qhelp delete mode 100644 ql/src/experimental/CWE-681/IncorrectNumericConversion.ql delete mode 100644 ql/src/experimental/CWE-681/IncorrectNumericConversionGood.go delete mode 100644 ql/test/experimental/CWE-681/IncorrectNumericConversion.expected delete mode 100644 ql/test/experimental/CWE-681/IncorrectNumericConversion.go delete mode 100644 ql/test/experimental/CWE-681/IncorrectNumericConversion.qlref diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversion.go b/ql/src/experimental/CWE-681/IncorrectNumericConversion.go deleted file mode 100644 index 518ca38cee0..00000000000 --- a/ql/src/experimental/CWE-681/IncorrectNumericConversion.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "strconv" -) - -func parseAllocateBad1(wanted string) int32 { - parsed, err := strconv.Atoi(wanted) - if err != nil { - panic(err) - } - return int32(parsed) -} -func parseAllocateBad2(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 64) - if err != nil { - panic(err) - } - return int32(parsed) -} diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversion.qhelp b/ql/src/experimental/CWE-681/IncorrectNumericConversion.qhelp deleted file mode 100644 index f978858ed89..00000000000 --- a/ql/src/experimental/CWE-681/IncorrectNumericConversion.qhelp +++ /dev/null @@ -1,65 +0,0 @@ - - - -

- If a numeric value string is parsed using strconv.Atoi into an int, and subsequently that int - is converted into another type of a smaller size, the result can produce unexpected values. -

-

- This also applies to the results of strconv.ParseFloat, strconv.ParseInt, - and strconv.ParseUint when the specified size is larger than the size of the - type that number is converted to. -

-
- -

- If you need to parse numeric values with specific bit sizes, avoid strconv.Atoi, and instead - use the functions specific to each type (strconv.ParseFloat, strconv.ParseInt, - strconv.ParseUint) that also allow to specify the wanted bit size. -

-

- When using those functions, be careful to not convert the result to another type with a smaller bit size than - the bit size you specified when parsing the number. -

-

- If this is not possible, then add upper (and lower) bound checks specific to each type and - bit size (you can find the minimum and maximum value for each type in the `math` package). -

-
- -

- In the first example, assume that an input string is passed to parseAllocateBad1 function, - parsed by strconv.Atoi, and then converted into an int32 type: -

- -

- The bounds are not checked, so this means that if the provided number is greater than the maximum value of type int32, - the resulting value from the conversion will be different from the actual provided value. -

-

- To avoid unexpected values, you should either use the other functions provided by the strconv - package to parse the specific types and bit sizes as shown in the - parseAllocateGood2 function; or check bounds as in the parseAllocateGood1 - function. -

- -
- -

- In the second example, assume that an input string is passed to parseAllocateBad2 function, - parsed by strconv.ParseInt with a bit size set to 64, and then converted into an int32 type: -

- -

- If the provided number is greater than the maximum value of type int32, the resulting value from the conversion will be - different from the actual provided value. -

-

- To avoid unexpected values, you should specify the correct bit size as in parseAllocateGood3; - or check bounds before making the conversion as in parseAllocateGood4. -

- -
-
diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversion.ql b/ql/src/experimental/CWE-681/IncorrectNumericConversion.ql deleted file mode 100644 index def77b696e9..00000000000 --- a/ql/src/experimental/CWE-681/IncorrectNumericConversion.ql +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @name Incorrect conversion between numeric types - * @description Converting the result of strconv.Atoi (and other parsers from strconv package) - * to numeric types of smaller bit size can produce unexpected values. - * @kind path-problem - * @problem.severity warning - * @id go/incorrect-numeric-conversion - * @tags security - * external/cwe/cwe-190 - * external/cwe/cwe-681 - */ - -import go -import DataFlow::PathGraph - -/** A function that parses integers. */ -class Atoi extends Function { - Atoi() { this.hasQualifiedName("strconv", "Atoi") } -} - -/** A function that parses floating-point numbers. */ -class ParseFloat extends Function { - ParseFloat() { this.hasQualifiedName("strconv", "ParseFloat") } -} - -/** A function that parses integers with a specifiable bitSize. */ -class ParseInt extends Function { - ParseInt() { this.hasQualifiedName("strconv", "ParseInt") } -} - -/** A function that parses unsigned integers with a specifiable bitSize. */ -class ParseUint extends Function { - ParseUint() { this.hasQualifiedName("strconv", "ParseUint") } -} - -/** Provides a class for modeling calls to number-parsing functions. */ -module ParserCall { - /** - * A data-flow call node that parses a number. - */ - abstract class Range extends DataFlow::CallNode { - /** Gets the bit size of the result number. */ - abstract int getTargetBitSize(); - - /** Gets the name of the parser function. */ - abstract string getParserName(); - } -} - -class ParserCall extends DataFlow::CallNode { - ParserCall::Range self; - - ParserCall() { this = self } - - int getTargetBitSize() { result = self.getTargetBitSize() } - - string getParserName() { result = self.getParserName() } -} - -class AtoiCall extends DataFlow::CallNode, ParserCall::Range { - AtoiCall() { exists(Atoi atoi | this = atoi.getACall()) } - - override int getTargetBitSize() { result = 0 } - - override string getParserName() { result = "strconv.Atoi" } -} - -class ParseIntCall extends DataFlow::CallNode, ParserCall::Range { - ParseIntCall() { exists(ParseInt parseInt | this = parseInt.getACall()) } - - override int getTargetBitSize() { result = this.getArgument(2).getIntValue() } - - override string getParserName() { result = "strconv.ParseInt" } -} - -class ParseUintCall extends DataFlow::CallNode, ParserCall::Range { - ParseUintCall() { exists(ParseUint parseUint | this = parseUint.getACall()) } - - override int getTargetBitSize() { result = this.getArgument(2).getIntValue() } - - override string getParserName() { result = "strconv.ParseUint" } -} - -class ParseFloatCall extends DataFlow::CallNode, ParserCall::Range { - ParseFloatCall() { exists(ParseFloat parseFloat | this = parseFloat.getACall()) } - - override int getTargetBitSize() { result = this.getArgument(1).getIntValue() } - - override string getParserName() { result = "strconv.ParseFloat" } -} - -class NumericConversionExpr extends ConversionExpr { - string fullTypeName; - int bitSize; - - NumericConversionExpr() { - exists(NumericType conv | - conv = getTypeExpr().getType().getUnderlyingType() and - fullTypeName = conv.getName() and - bitSize = conv.getSize() - ) - } - - string getFullTypeName() { result = fullTypeName } - - int getBitSize() { result = bitSize } -} - -/** - * An `if` statement with the condition being either a relational comparison, - * or one or more `&&`. - */ -class IfRelationalComparison extends IfStmt { - IfRelationalComparison() { - this.getCond() instanceof RelationalComparisonExpr or this.getCond() instanceof LandExpr - } - - RelationalComparisonExpr getComparison() { result = this.getCond().(RelationalComparisonExpr) } - - LandExpr getLandExpr() { result = this.getCond().(LandExpr) } -} - -/** - * Flow of result of parsing a 64 bit number, to conversion to lower bit numbers. - */ -class Lt64BitFlowConfig extends TaintTracking::Configuration, DataFlow::Configuration { - Lt64BitFlowConfig() { this = "Lt64BitFlowConfig" } - - override predicate isSource(DataFlow::Node source) { - exists(ParserCall call | call.getTargetBitSize() = [0, 64] | source = call) - } - - override predicate isSink(DataFlow::Node sink) { - exists(NumericConversionExpr conv | conv.getBitSize() = [32, 16, 8] | sink.asExpr() = conv) - } - - override predicate isSanitizerIn(DataFlow::Node node) { isSanitizedInsideAnIfBoundCheck(node) } -} - -/** - * Flow of result of parsing a 32 bit number, to conversion to lower bit numbers. - */ -class Lt32BitFlowConfig extends TaintTracking::Configuration, DataFlow::Configuration { - Lt32BitFlowConfig() { this = "Lt32BitFlowConfig" } - - override predicate isSource(DataFlow::Node source) { - // NOTE: target bit size 0 is already addressed in Lt64BitFlowConfig. - exists(ParserCall call | call.getTargetBitSize() = [/*0,*/ 32] | source = call) - } - - override predicate isSink(DataFlow::Node sink) { - exists(NumericConversionExpr conv | conv.getBitSize() = [16, 8] | sink.asExpr() = conv) - } - - override predicate isSanitizerIn(DataFlow::Node node) { isSanitizedInsideAnIfBoundCheck(node) } -} - -/** - * Flow of result of parsing a 16 bit number, to conversion to lower bit numbers. - */ -class Lt16BitFlowConfig extends TaintTracking::Configuration, DataFlow::Configuration { - Lt16BitFlowConfig() { this = "Lt16BitFlowConfig" } - - override predicate isSource(DataFlow::Node source) { - exists(ParserCall call | call.getTargetBitSize() = 16 | source = call) - } - - override predicate isSink(DataFlow::Node sink) { - exists(NumericConversionExpr conv | conv.getBitSize() = 8 | sink.asExpr() = conv) - } - - override predicate isSanitizerIn(DataFlow::Node node) { isSanitizedInsideAnIfBoundCheck(node) } -} - -/** - * Check if the node is a numeric conversion inside an `if` body, where - * the `if` condition contains an upper bound check on the conversion operand. - */ -predicate isSanitizedInsideAnIfBoundCheck(DataFlow::Node node) { - exists(IfRelationalComparison comp, NumericConversionExpr conv | - conv = node.asExpr().(NumericConversionExpr) and - conv.getBitSize() = [8, 16, 32] and - comp.getThen().getAChild*() = conv and - ( - // If the conversion is inside an `if` block that compares the source as - // `source > 0` or `source >= 0`, then that sanitizes conversion of int to int32; - conv.getFullTypeName() = "int32" and - comp.getComparison().getLesserOperand().getNumericValue() = 0 and - comp.getComparison().getGreaterOperand().getGlobalValueNumber() = - conv.getOperand().getGlobalValueNumber() - or - comparisonGreaterOperandValueIsEqual("int8", comp, conv, getMaxInt8()) - or - comparisonGreaterOperandValueIsEqual("int16", comp, conv, getMaxInt16()) - or - comparisonGreaterOperandValueIsEqual("int32", comp, conv, getMaxInt32()) - or - comparisonGreaterOperandValueIsEqual("uint8", comp, conv, getMaxUint8()) - or - comparisonGreaterOperandValueIsEqual("uint16", comp, conv, getMaxUint16()) - ) - ) -} - -int getMaxInt8() { result = 2.pow(7) - 1 } - -int getMaxInt16() { result = 2.pow(15) - 1 } - -int getMaxInt32() { result = 2.pow(31) - 1 } - -int getMaxUint8() { result = 2.pow(8) - 1 } - -int getMaxUint16() { result = 2.pow(16) - 1 } - -/** - * The `if` relational comparison (which can also be inside a `LandExpr`) stating that - * the greater operand is equal to `value`, and the lesses operand is the conversion operand. - */ -predicate comparisonGreaterOperandValueIsEqual( - string typeName, IfRelationalComparison ifExpr, NumericConversionExpr conv, int value -) { - conv.getFullTypeName() = typeName and - ( - // exclude cases like: if parsed < math.MaxInt8 {return int8(parsed)} - exists(RelationalComparisonExpr comp | comp = ifExpr.getComparison() | - // greater operand is equal to value: - comp.getGreaterOperand().getNumericValue() = value and - // and lesser is the conversion operand: - comp.getLesserOperand().getGlobalValueNumber() = conv.getOperand().getGlobalValueNumber() - ) - or - // exclude cases like: if err == nil && parsed < math.MaxInt8 {return int8(parsed)} - exists(RelationalComparisonExpr andExpr | - andExpr = ifExpr.getLandExpr().getAnOperand().(RelationalComparisonExpr) - | - // greater operand is equal to value: - andExpr.getGreaterOperand().getNumericValue() = value and - // and lesser is the conversion operand: - andExpr.getLesserOperand().getGlobalValueNumber() = conv.getOperand().getGlobalValueNumber() - ) - ) -} - -string formatBitSize(ParserCall call) { - call.getTargetBitSize() = 0 and result = "(arch-dependent)" - or - call.getTargetBitSize() > 0 and result = call.getTargetBitSize().toString() -} - -from DataFlow::PathNode source, DataFlow::PathNode sink -where - ( - exists(Lt64BitFlowConfig cfg | cfg.hasFlowPath(source, sink)) - or - exists(Lt32BitFlowConfig cfg | cfg.hasFlowPath(source, sink)) - or - exists(Lt16BitFlowConfig cfg | cfg.hasFlowPath(source, sink)) - ) and - // Exclude results in test files: - exists(File fl | fl = sink.getNode().asExpr().(NumericConversionExpr).getFile() | - not fl instanceof TestFile - ) -select source.getNode(), source, sink, - "Incorrect conversion of a " + formatBitSize(source.getNode().(ParserCall)) + "-bit number from " + - source.getNode().(ParserCall).getParserName() + " result to a lower bit size type " + - sink.getNode().asExpr().(NumericConversionExpr).getFullTypeName() diff --git a/ql/src/experimental/CWE-681/IncorrectNumericConversionGood.go b/ql/src/experimental/CWE-681/IncorrectNumericConversionGood.go deleted file mode 100644 index 29c111cf54e..00000000000 --- a/ql/src/experimental/CWE-681/IncorrectNumericConversionGood.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "math" - "strconv" -) - -func main() { - -} - -const DefaultAllocate int32 = 256 - -func parseAllocateGood1(desired string) int32 { - parsed, err := strconv.Atoi(desired) - if err != nil { - return DefaultAllocate - } - // GOOD: check for lower and uppper bounds - if parsed > 0 && parsed <= math.MaxInt32 { - return int32(parsed) - } - return DefaultAllocate -} -func parseAllocateGood2(desired string) int32 { - // GOOD: parse specifying the bit size - parsed, err := strconv.ParseInt(desired, 10, 32) - if err != nil { - return DefaultAllocate - } - return int32(parsed) -} - -func parseAllocateGood3(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 32) - if err != nil { - panic(err) - } - return int32(parsed) -} -func parseAllocateGood4(wanted string) int32 { - parsed, err := strconv.ParseInt(wanted, 10, 64) - if err != nil { - panic(err) - } - // GOOD: check for lower and uppper bounds - if parsed > 0 && parsed <= math.MaxInt32 { - return int32(parsed) - } - return DefaultAllocate -} diff --git a/ql/test/experimental/CWE-681/IncorrectNumericConversion.expected b/ql/test/experimental/CWE-681/IncorrectNumericConversion.expected deleted file mode 100644 index 64aa194012e..00000000000 --- a/ql/test/experimental/CWE-681/IncorrectNumericConversion.expected +++ /dev/null @@ -1,83 +0,0 @@ -edges -| IncorrectNumericConversion.go:26:14:26:28 | call to Atoi : tuple type | IncorrectNumericConversion.go:35:41:35:50 | type conversion | -| IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:57:7:57:19 | type conversion | -| IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:64:7:64:19 | type conversion | -| IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:73:7:73:18 | type conversion | -| IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:80:7:80:19 | type conversion | -| IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:87:7:87:19 | type conversion | -| IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt : tuple type | IncorrectNumericConversion.go:94:7:94:19 | type conversion | -| IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:103:7:103:18 | type conversion | -| IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:110:7:110:19 | type conversion | -| IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:117:7:117:19 | type conversion | -| IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint : tuple type | IncorrectNumericConversion.go:124:7:124:19 | type conversion | -| IncorrectNumericConversion.go:208:18:208:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:212:7:212:18 | type conversion | -| IncorrectNumericConversion.go:215:18:215:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:219:7:219:19 | type conversion | -| IncorrectNumericConversion.go:222:18:222:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:226:7:226:19 | type conversion | -| IncorrectNumericConversion.go:229:18:229:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:233:7:233:19 | type conversion | -| IncorrectNumericConversion.go:236:18:236:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:240:7:240:20 | type conversion | -| IncorrectNumericConversion.go:243:18:243:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:247:7:247:20 | type conversion | -| IncorrectNumericConversion.go:250:18:250:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:254:7:254:21 | type conversion | -| IncorrectNumericConversion.go:257:18:257:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:262:7:262:18 | type conversion | -| IncorrectNumericConversion.go:266:18:266:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:270:7:270:23 | type conversion | -nodes -| IncorrectNumericConversion.go:26:14:26:28 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat : tuple type | semmle.label | call to ParseFloat : tuple type | -| IncorrectNumericConversion.go:57:7:57:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat : tuple type | semmle.label | call to ParseFloat : tuple type | -| IncorrectNumericConversion.go:64:7:64:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:73:7:73:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:80:7:80:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:87:7:87:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt : tuple type | semmle.label | call to ParseInt : tuple type | -| IncorrectNumericConversion.go:94:7:94:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:103:7:103:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:110:7:110:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:117:7:117:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint : tuple type | semmle.label | call to ParseUint : tuple type | -| IncorrectNumericConversion.go:124:7:124:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:208:18:208:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:212:7:212:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:215:18:215:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:219:7:219:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:222:18:222:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:226:7:226:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:229:18:229:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:233:7:233:19 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:236:18:236:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:240:7:240:20 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:243:18:243:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:247:7:247:20 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:250:18:250:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:254:7:254:21 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:257:18:257:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:262:7:262:18 | type conversion | semmle.label | type conversion | -| IncorrectNumericConversion.go:266:18:266:36 | call to Atoi : tuple type | semmle.label | call to Atoi : tuple type | -| IncorrectNumericConversion.go:270:7:270:23 | type conversion | semmle.label | type conversion | -#select -| IncorrectNumericConversion.go:26:14:26:28 | call to Atoi | IncorrectNumericConversion.go:26:14:26:28 | call to Atoi : tuple type | IncorrectNumericConversion.go:35:41:35:50 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int32 | -| IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat | IncorrectNumericConversion.go:53:18:53:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:57:7:57:19 | type conversion | Incorrect conversion of a 32-bit number from strconv.ParseFloat result to a lower bit size type int16 | -| IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat | IncorrectNumericConversion.go:60:18:60:47 | call to ParseFloat : tuple type | IncorrectNumericConversion.go:64:7:64:19 | type conversion | Incorrect conversion of a 64-bit number from strconv.ParseFloat result to a lower bit size type int32 | -| IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt | IncorrectNumericConversion.go:69:18:69:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:73:7:73:18 | type conversion | Incorrect conversion of a 16-bit number from strconv.ParseInt result to a lower bit size type int8 | -| IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt | IncorrectNumericConversion.go:76:18:76:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:80:7:80:19 | type conversion | Incorrect conversion of a 32-bit number from strconv.ParseInt result to a lower bit size type int16 | -| IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt | IncorrectNumericConversion.go:83:18:83:49 | call to ParseInt : tuple type | IncorrectNumericConversion.go:87:7:87:19 | type conversion | Incorrect conversion of a 64-bit number from strconv.ParseInt result to a lower bit size type int32 | -| IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt | IncorrectNumericConversion.go:90:18:90:48 | call to ParseInt : tuple type | IncorrectNumericConversion.go:94:7:94:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.ParseInt result to a lower bit size type int32 | -| IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint | IncorrectNumericConversion.go:99:18:99:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:103:7:103:18 | type conversion | Incorrect conversion of a 16-bit number from strconv.ParseUint result to a lower bit size type int8 | -| IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint | IncorrectNumericConversion.go:106:18:106:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:110:7:110:19 | type conversion | Incorrect conversion of a 32-bit number from strconv.ParseUint result to a lower bit size type int16 | -| IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint | IncorrectNumericConversion.go:113:18:113:50 | call to ParseUint : tuple type | IncorrectNumericConversion.go:117:7:117:19 | type conversion | Incorrect conversion of a 64-bit number from strconv.ParseUint result to a lower bit size type int32 | -| IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint | IncorrectNumericConversion.go:120:18:120:49 | call to ParseUint : tuple type | IncorrectNumericConversion.go:124:7:124:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.ParseUint result to a lower bit size type int32 | -| IncorrectNumericConversion.go:208:18:208:36 | call to Atoi | IncorrectNumericConversion.go:208:18:208:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:212:7:212:18 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int8 | -| IncorrectNumericConversion.go:215:18:215:36 | call to Atoi | IncorrectNumericConversion.go:215:18:215:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:219:7:219:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int16 | -| IncorrectNumericConversion.go:222:18:222:36 | call to Atoi | IncorrectNumericConversion.go:222:18:222:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:226:7:226:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int32 | -| IncorrectNumericConversion.go:229:18:229:36 | call to Atoi | IncorrectNumericConversion.go:229:18:229:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:233:7:233:19 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint8 | -| IncorrectNumericConversion.go:236:18:236:36 | call to Atoi | IncorrectNumericConversion.go:236:18:236:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:240:7:240:20 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint16 | -| IncorrectNumericConversion.go:243:18:243:36 | call to Atoi | IncorrectNumericConversion.go:243:18:243:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:247:7:247:20 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint32 | -| IncorrectNumericConversion.go:250:18:250:36 | call to Atoi | IncorrectNumericConversion.go:250:18:250:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:254:7:254:21 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type float32 | -| IncorrectNumericConversion.go:257:18:257:36 | call to Atoi | IncorrectNumericConversion.go:257:18:257:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:262:7:262:18 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type uint8 | -| IncorrectNumericConversion.go:266:18:266:36 | call to Atoi | IncorrectNumericConversion.go:266:18:266:36 | call to Atoi : tuple type | IncorrectNumericConversion.go:270:7:270:23 | type conversion | Incorrect conversion of a (arch-dependent)-bit number from strconv.Atoi result to a lower bit size type int16 | diff --git a/ql/test/experimental/CWE-681/IncorrectNumericConversion.go b/ql/test/experimental/CWE-681/IncorrectNumericConversion.go deleted file mode 100644 index cdabda91a4a..00000000000 --- a/ql/test/experimental/CWE-681/IncorrectNumericConversion.go +++ /dev/null @@ -1,355 +0,0 @@ -package main - -import ( - "math" - "strconv" -) - -func main() { - -} - -type Something struct { -} -type Config struct { -} -type Registry struct { -} - -func LookupTarget(conf *Config, num int32) (int32, error) { - return 567, nil -} -func LookupNumberByName(reg *Registry, name string) (int32, error) { - return 567, nil -} -func lab(s string) (*Something, error) { - num, err := strconv.Atoi(s) - - if err != nil { - number, err := LookupNumberByName(&Registry{}, s) - if err != nil { - return nil, err - } - num = int(number) - } - target, err := LookupTarget(&Config{}, int32(num)) - if err != nil { - return nil, err - } - - // convert the resolved target number back to a string - - s = strconv.Itoa(int(target)) - - return nil, nil -} - -const CustomMaxInt16 = 1<<15 - 1 - -type CustomInt int16 - -func badParseFloat() { - { - parsed, err := strconv.ParseFloat("1.32", 32) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseFloat("1.32", 64) - if err != nil { - panic(err) - } - _ = int32(parsed) - } -} -func badParseInt() { - { - parsed, err := strconv.ParseInt("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int8(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int32(parsed) - } -} -func badParseUint() { - { - parsed, err := strconv.ParseUint("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int8(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int32(parsed) - } -} - -func goodParseFloat() { - { - parsed, err := strconv.ParseFloat("1.32", 32) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseFloat("1.32", 64) - if err != nil { - panic(err) - } - _ = int64(parsed) - } -} -func goodParseInt() { - { - parsed, err := strconv.ParseInt("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int64(parsed) - } - { - parsed, err := strconv.ParseInt("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int64(parsed) - } -} -func goodParseUint() { - { - parsed, err := strconv.ParseUint("3456", 10, 16) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 32) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 64) - if err != nil { - panic(err) - } - _ = int64(parsed) - } - { - parsed, err := strconv.ParseUint("3456", 10, 0) - if err != nil { - panic(err) - } - _ = int64(parsed) - } -} - -// these should be caught: -func upperBoundIsNOTChecked(input string) { - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = int8(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = int16(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = int32(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = uint8(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = uint16(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = uint32(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = float32(parsed) - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - // NOTE: byte is uint8 - _ = byte(parsed) - } - { - // using custom type: - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - _ = CustomInt(parsed) - } - -} - -// these should NOT be caught: -func upperBoundIsChecked(input string) { - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxInt8 { - _ = int8(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxInt16 { - _ = int16(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed > 0 { - _ = int32(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxInt32 { - _ = int32(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxUint8 { - _ = uint8(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxUint16 { - _ = uint16(parsed) - } - } - { - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < math.MaxUint8 { - _ = byte(parsed) - } - } - { // multiple `and` conditions - parsed, err := strconv.Atoi(input) - if err == nil && 1 == 1 && parsed < math.MaxInt8 { - _ = int8(parsed) - } - } - { // custom maxInt16 - parsed, err := strconv.Atoi(input) - if err != nil { - panic(err) - } - if parsed < CustomMaxInt16 { - _ = int16(parsed) - } - } -} diff --git a/ql/test/experimental/CWE-681/IncorrectNumericConversion.qlref b/ql/test/experimental/CWE-681/IncorrectNumericConversion.qlref deleted file mode 100644 index 884cf918f1c..00000000000 --- a/ql/test/experimental/CWE-681/IncorrectNumericConversion.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/CWE-681/IncorrectNumericConversion.ql From 34fa07267b7f85c8916fead4de22f7b86485288e Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 5 Aug 2020 12:10:05 +0100 Subject: [PATCH 03/16] Add modeling to Stdlib.qll Adds classes for some integer-parsing functions and a constant from strconv, plus a class for calls to integer-parsing functions. --- ql/src/semmle/go/frameworks/Stdlib.qll | 113 +++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/ql/src/semmle/go/frameworks/Stdlib.qll b/ql/src/semmle/go/frameworks/Stdlib.qll index c42844e2a38..f975cc13441 100644 --- a/ql/src/semmle/go/frameworks/Stdlib.qll +++ b/ql/src/semmle/go/frameworks/Stdlib.qll @@ -507,6 +507,119 @@ module Path { } } +/** + * Provides classes for some functions in the `strconv` package for + * converting strings to numbers. + */ +module StrConv { + /** A function that parses integers. */ + class Atoi extends Function { + Atoi() { this.hasQualifiedName("strconv", "Atoi") } + } + + /** A function that parses floating-point numbers. */ + class ParseFloat extends Function { + ParseFloat() { this.hasQualifiedName("strconv", "ParseFloat") } + } + + /** A function that parses integers with a specifiable bitSize. */ + class ParseInt extends Function { + ParseInt() { this.hasQualifiedName("strconv", "ParseInt") } + } + + /** A function that parses unsigned integers with a specifiable bitSize. */ + class ParseUint extends Function { + ParseUint() { this.hasQualifiedName("strconv", "ParseUint") } + } + + /** + * A constant that gives the size in bits of an int or uint + * value on the current architecture (32 or 64). + */ + class IntSize extends DeclaredConstant { + IntSize() { this.hasQualifiedName("strconv", "IntSize") } + } +} + +/** Provides a class for modeling calls to number-parsing functions. */ +module ParserCall { + /** A data-flow call node that parses a number. */ + abstract class Range extends DataFlow::CallNode { + /** Gets the bit size of the type of the result number. */ + abstract int getTargetBitSize(); + + /** Holds if the type of the result number is signed. */ + abstract boolean getTargetIsSigned(); + + /** Gets the name of the parser function. */ + abstract string getParserName(); + } +} + +/** A call to a number-parsing function */ +class ParserCall extends DataFlow::CallNode { + ParserCall::Range self; + + ParserCall() { this = self } + + /** Gets the bit size of the type of the result number. */ + int getTargetBitSize() { result = self.getTargetBitSize() } + + /** Holds if the type of the result number is signed. */ + boolean getTargetIsSigned() { result = self.getTargetIsSigned() } + + /** Gets the name of the parser function. */ + string getParserName() { result = self.getParserName() } + + /** Gets a string describing the size of the integer parsed. */ + string getBitSizeString() { + if getTargetBitSize() != 0 + then result = "a " + getTargetBitSize() + "-bit integer" + else result = "an integer with architecture-dependent bit-width" + } +} + +/** A call to `strconv.Atoi` */ +class AtoiCall extends DataFlow::CallNode, ParserCall::Range { + AtoiCall() { exists(StrConv::Atoi atoi | this = atoi.getACall()) } + + override int getTargetBitSize() { result = 0 } + + override boolean getTargetIsSigned() { result = true } + + override string getParserName() { result = "strconv.Atoi" } +} + +/** A call to `strconv.ParseInt` */ +class ParseIntCall extends DataFlow::CallNode, ParserCall::Range { + ParseIntCall() { exists(StrConv::ParseInt parseInt | this = parseInt.getACall()) } + + override int getTargetBitSize() { + if exists(StrConv::IntSize intSize | this.getArgument(2).(DataFlow::ReadNode).reads(intSize)) + then result = 0 + else result = this.getArgument(2).getIntValue() + } + + override boolean getTargetIsSigned() { result = true } + + override string getParserName() { result = "strconv.ParseInt" } +} + +/** A call to `strconv.ParseUint` */ +class ParseUintCall extends DataFlow::CallNode, ParserCall::Range { + ParseUintCall() { exists(StrConv::ParseUint parseUint | this = parseUint.getACall()) } + + override int getTargetBitSize() { + if exists(StrConv::IntSize intSize | this.getArgument(2).(DataFlow::ReadNode).reads(intSize)) + then result = 0 + else result = this.getArgument(2).getIntValue() + } + + override boolean getTargetIsSigned() { result = false } + + override string getParserName() { result = "strconv.ParseUint" } +} + /** Provides models of commonly used functions in the `strings` package. */ module Strings { /** The `Join` function. */ From 329888e62c587bf81c1b50a1442e85b3c4c25d13 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 5 Aug 2020 12:10:59 +0100 Subject: [PATCH 04/16] Add query for incorrect integer conversion --- .../CWE-681/IncorrectIntegerConversion.go | 20 +++ .../CWE-681/IncorrectIntegerConversion.qhelp | 67 +++++++++ .../CWE-681/IncorrectIntegerConversion.ql | 142 ++++++++++++++++++ .../CWE-681/IncorrectIntegerConversionGood.go | 51 +++++++ 4 files changed, 280 insertions(+) create mode 100644 ql/src/Security/CWE-681/IncorrectIntegerConversion.go create mode 100644 ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp create mode 100644 ql/src/Security/CWE-681/IncorrectIntegerConversion.ql create mode 100644 ql/src/Security/CWE-681/IncorrectIntegerConversionGood.go diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.go b/ql/src/Security/CWE-681/IncorrectIntegerConversion.go new file mode 100644 index 00000000000..518ca38cee0 --- /dev/null +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.go @@ -0,0 +1,20 @@ +package main + +import ( + "strconv" +) + +func parseAllocateBad1(wanted string) int32 { + parsed, err := strconv.Atoi(wanted) + if err != nil { + panic(err) + } + return int32(parsed) +} +func parseAllocateBad2(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 64) + if err != nil { + panic(err) + } + return int32(parsed) +} diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp new file mode 100644 index 00000000000..48682b46a7d --- /dev/null +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp @@ -0,0 +1,67 @@ + + + +

+If a string is parsed into an int using strconv.Atoi, and subsequently that int +is converted into another integer type of a smaller size, the result can produce unexpected values. +

+

+This also applies to the results of strconv.ParseInt and strconv.ParseUint when +the specified size is larger than the size of the type that number is converted to. +

+
+ + +

+If you need to parse integer values with specific bit sizes, avoid strconv.Atoi, and instead +use strconv.ParseInt or strconv.ParseUint, which also allow specifying the +bit size. +

+

+When using those functions, be careful to not convert the result to another type with a smaller bit size than +the bit size you specified when parsing the number. +

+

+If this is not possible, then add upper (and lower) bound checks specific to each type and +bit size (you can find the minimum and maximum value for each type in the `math` package). +

+
+ + +

+In the first example, assume that an input string is passed to parseAllocateBad1 function, +parsed by strconv.Atoi, and then converted into an int32 type: +

+ +

+The bounds are not checked, so this means that if the provided number is greater than the maximum value of type int32, +the resulting value from the conversion will be different from the actual provided value. +

+

+To avoid unexpected values, you should either use the other functions provided by the strconv +package to parse the specific types and bit sizes as shown in the +parseAllocateGood2 function; or check bounds as in the parseAllocateGood1 +function. +

+ +
+ + +

+In the second example, assume that an input string is passed to parseAllocateBad2 function, +parsed by strconv.ParseInt with a bit size set to 64, and then converted into an int32 type: +

+ +

+If the provided number is greater than the maximum value of type int32, the resulting value from the conversion will be +different from the actual provided value. +

+

+To avoid unexpected values, you should specify the correct bit size as in parseAllocateGood3; +or check bounds before making the conversion as in parseAllocateGood4. +

+ +
+
diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql new file mode 100644 index 00000000000..c3049773d24 --- /dev/null +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -0,0 +1,142 @@ +/** + * @name Incorrect conversion between integer types + * @description Converting the result of strconv.Atoi, strconv.ParseInt and strconv.ParseUint + * to integer types of smaller bit size can produce unexpected values. + * @kind path-problem + * @problem.severity warning + * @id go/incorrect-integer-conversion + * @tags security + * external/cwe/cwe-190 + * external/cwe/cwe-681 + * @precision very-high + */ + +import go +import DataFlow::PathGraph + +/** + * Gets the maximum value of an integer (signed if `isSigned` + * is true, unsigned otherwise) with `bitSize` bits. + */ +float getMaxIntValue(int bitSize, boolean isSigned) { + bitSize in [8, 16, 32, 64] and + ( + isSigned = true and result = 2.pow(bitSize - 1) - 1 + or + isSigned = false and result = 2.pow(bitSize) - 1 + ) +} + +/** + * Holds if converting from an integer types with size `sourceBitSize` to + * one with size `sinkBitSize` can produce unexpected values, where 0 means + * architecture-dependent. + */ +private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSize) { + sourceBitSize in [0, 16, 32, 64] and + sinkBitSize in [0, 8, 16, 32] and + not (sourceBitSize = 0 and sinkBitSize = 0) and + exists(int source, int sink | + (if sourceBitSize = 0 then source = 64 else source = sourceBitSize) and + if sinkBitSize = 0 then sink = 32 else sink = sinkBitSize + | + source > sink + ) +} + +/** + * A taint-tracking configuration for reasoning about when an integer + * obtained from parsing a string flows to a type conversion to a smaller + * integer types, which could cause unexpected values. + */ +class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { + boolean sourceIsSigned; + int sourceBitSize; + int sinkBitSize; + + ConversionWithoutBoundsCheckConfig() { + sourceIsSigned in [true, false] and + isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and + this = + sourceBitSize.toString() + sourceIsSigned.toString() + sinkBitSize.toString() + + "ConversionWithoutBoundsCheckConfig" + } + + override predicate isSource(DataFlow::Node source) { + exists(ParserCall pc, int bitSize | source = pc.getResult(0) | + sourceIsSigned = pc.getTargetIsSigned() and + (if pc.getTargetBitSize() = 0 then bitSize = 0 else bitSize = pc.getTargetBitSize()) and + // `bitSize` could be any value between 0 and 64, but we can round + // it up to the nearest size of an integer type without changing + // behaviour. + sourceBitSize = min(int b | b in [0, 8, 16, 32, 64] and b >= bitSize) + ) + } + + /** + * Holds if sink is a typecast to an integer type with size `bitSize` (where + * 0 represents architecture-dependent) and the expression being typecast is + * not also in a right-shift expression. + */ + predicate isSink(DataFlow::TypeCastNode sink, int bitSize) { + exists(IntegerType integerType | sink.getType().getUnderlyingType() = integerType | + bitSize = integerType.getSize() + or + ( + integerType instanceof IntType or + integerType instanceof UintType + ) and + bitSize = 0 + ) and + not exists(ShrExpr shrExpr | + shrExpr.getLeftOperand().getGlobalValueNumber() = + sink.getOperand().asExpr().getGlobalValueNumber() + ) + } + + override predicate isSink(DataFlow::Node sink) { isSink(sink, sinkBitSize) } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + exists(int bitSize | if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32 | + guard.(UpperBoundCheckGuard).getBound() <= getMaxIntValue(bitSize, sourceIsSigned) + ) + } + + override predicate isSanitizerOut(DataFlow::Node node) { + exists(int bitSize | isIncorrectIntegerConversion(sourceBitSize, bitSize) | + isSink(node, bitSize) + ) + } +} + +/** An upper bound check that compares a variable to a constant value. */ +class UpperBoundCheckGuard extends DataFlow::BarrierGuard, DataFlow::RelationalComparisonNode { + UpperBoundCheckGuard() { count(expr.getAnOperand().getIntValue()) = 1 } + + /** + * Gets the constant value which this upper bound check ensures the + * other value is less than or equal to. + */ + float getBound() { + exists(int strictnessOffset | + if expr.isStrict() then strictnessOffset = 1 else strictnessOffset = 0 + | + result = expr.getAnOperand().getIntValue() - strictnessOffset + ) + } + + override predicate checks(Expr e, boolean branch) { + this.leq(branch, DataFlow::exprNode(e), _, _) and + not exists(e.getIntValue()) + } +} + +from + DataFlow::PathNode source, DataFlow::PathNode sink, ConversionWithoutBoundsCheckConfig cfg, + ParserCall pc +where cfg.hasFlowPath(source, sink) and pc.getResult(0) = source.getNode() +select source.getNode(), source, sink, + "Incorrect conversion of " + pc.getBitSizeString() + " from " + pc.getParserName() + + " to a lower bit size type " + + sink.getNode().(DataFlow::TypeCastNode).getType().getUnderlyingType().getName() + + " without an upper bound check." diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversionGood.go b/ql/src/Security/CWE-681/IncorrectIntegerConversionGood.go new file mode 100644 index 00000000000..9227b2bf143 --- /dev/null +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversionGood.go @@ -0,0 +1,51 @@ +package main + +import ( + "math" + "strconv" +) + +func main() { + +} + +const DefaultAllocate int32 = 256 + +func parseAllocateGood1(desired string) int32 { + parsed, err := strconv.Atoi(desired) + if err != nil { + return DefaultAllocate + } + // GOOD: check for lower and upper bounds + if parsed > 0 && parsed <= math.MaxInt32 { + return int32(parsed) + } + return DefaultAllocate +} +func parseAllocateGood2(desired string) int32 { + // GOOD: parse specifying the bit size + parsed, err := strconv.ParseInt(desired, 10, 32) + if err != nil { + return DefaultAllocate + } + return int32(parsed) +} + +func parseAllocateGood3(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 32) + if err != nil { + panic(err) + } + return int32(parsed) +} +func parseAllocateGood4(wanted string) int32 { + parsed, err := strconv.ParseInt(wanted, 10, 64) + if err != nil { + panic(err) + } + // GOOD: check for lower and uppper bounds + if parsed > 0 && parsed <= math.MaxInt32 { + return int32(parsed) + } + return DefaultAllocate +} From 06d1eb9bdb944fa3637ffafe546c2f14ba6b39d5 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 5 Aug 2020 12:11:12 +0100 Subject: [PATCH 05/16] Add tests for incorrect integer conversion --- .../IncorrectIntegerConversion.expected | 196 +++++++++++ .../CWE-681/IncorrectIntegerConversion.go | 319 ++++++++++++++++++ .../CWE-681/IncorrectIntegerConversion.qlref | 1 + 3 files changed, 516 insertions(+) create mode 100644 ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected create mode 100644 ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go create mode 100644 ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.qlref diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected new file mode 100644 index 00000000000..8eaad5f4c9e --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -0,0 +1,196 @@ +edges +| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:70:7:70:19 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:85:7:85:18 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:86:7:86:19 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:87:7:87:19 | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:88:7:88:20 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:101:7:101:18 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:102:7:102:19 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:103:7:103:19 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:104:7:104:20 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:105:7:105:19 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:106:7:106:20 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:109:7:109:17 | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:110:7:110:18 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:152:7:152:18 | type conversion | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:153:7:153:19 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:168:7:168:18 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:169:7:169:19 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:170:7:170:19 | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:171:7:171:20 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:184:7:184:18 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:185:7:185:19 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:186:7:186:19 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:187:7:187:20 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:188:7:188:19 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:189:7:189:20 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:192:7:192:17 | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:193:7:193:18 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:240:7:240:18 | type conversion | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | +| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:287:7:287:19 | type conversion | +| IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | +| IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | +nodes +| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:69:7:69:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:70:7:70:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:85:7:85:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:86:7:86:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:87:7:87:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:88:7:88:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:101:7:101:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:102:7:102:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:103:7:103:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:104:7:104:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:105:7:105:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:106:7:106:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:109:7:109:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:110:7:110:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:117:7:117:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:118:7:118:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:119:7:119:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:120:7:120:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:121:7:121:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:122:7:122:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:152:7:152:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:153:7:153:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:168:7:168:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:169:7:169:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:170:7:170:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:171:7:171:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:184:7:184:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:185:7:185:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:186:7:186:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:187:7:187:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:188:7:188:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:189:7:189:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:192:7:192:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:193:7:193:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:200:7:200:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:201:7:201:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:202:7:202:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:203:7:203:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:204:7:204:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:205:7:205:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:218:6:218:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:219:6:219:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:220:6:220:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:221:6:221:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:222:6:222:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:223:6:223:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:240:7:240:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:241:7:241:23 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | +| IncorrectIntegerConversion.go:261:8:261:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | +| IncorrectIntegerConversion.go:282:8:282:21 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:287:7:287:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:307:7:307:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:317:7:317:19 | type conversion | semmle.label | type conversion | +#select +| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:70:7:70:19 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:85:7:85:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:86:7:86:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:87:7:87:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:88:7:88:20 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:101:7:101:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:102:7:102:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:103:7:103:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:104:7:104:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:105:7:105:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:106:7:106:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:109:7:109:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int without an upper bound check. | +| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:110:7:110:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:152:7:152:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:153:7:153:19 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:168:7:168:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:169:7:169:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:170:7:170:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:171:7:171:20 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:184:7:184:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:185:7:185:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:186:7:186:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:187:7:187:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:188:7:188:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:189:7:189:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:192:7:192:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int without an upper bound check. | +| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:193:7:193:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:240:7:240:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:287:7:287:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] | IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] | IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go new file mode 100644 index 00000000000..e4d7419759d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -0,0 +1,319 @@ +package main + +import ( + "math" + "strconv" +) + +func main() { + +} + +type something struct { +} +type config struct { +} +type registry struct { +} + +func lookupTarget(conf *config, num int32) (int32, error) { + return 567, nil +} +func lookupNumberByName(reg *registry, name string) (int32, error) { + return 567, nil +} +func lab(s string) (*something, error) { + num, err := strconv.Atoi(s) + + if err != nil { + number, err := lookupNumberByName(®istry{}, s) + if err != nil { + return nil, err + } + num = int(number) + } + target, err := lookupTarget(&config{}, int32(num)) // NOT OK + if err != nil { + return nil, err + } + + // convert the resolved target number back to a string + + s = strconv.Itoa(int(target)) + + return nil, nil +} + +func testParseInt() { + { + parsed, err := strconv.ParseInt("3456", 10, 8) + if err != nil { + panic(err) + } + _ = int8(parsed) // OK + _ = uint8(parsed) // OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 16) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 32) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // NOT OK + _ = uint(parsed) // NOT OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} + +func testParseUint() { + { + parsed, err := strconv.ParseUint("3456", 10, 8) + if err != nil { + panic(err) + } + _ = int8(parsed) // OK + _ = uint8(parsed) // OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 16) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // OK + _ = uint16(parsed) // OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 32) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // NOT OK + _ = uint(parsed) // NOT OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} + +func testAtoi() { + parsed, err := strconv.Atoi("3456") + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK +} + +type customInt int16 + +// these should be caught: +func typeAliases(input string) { + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + // NOTE: byte is uint8 + _ = byte(parsed) // NOT OK + _ = customInt(parsed) // NOT OK + } +} + +func testBoundsChecking(input string) { + { + parsed, err := strconv.Atoi(input) + if err != nil { + panic(err) + } + if parsed <= math.MaxInt8 && parsed >= math.MinInt8 { + _ = int8(parsed) // OK + } + if parsed < math.MaxInt8 { + _ = int8(parsed) // OK (because we only check for upper bounds) + if parsed >= 0 { + _ = int16(parsed) // OK + } + } + if parsed >= math.MinInt8 { + _ = int8(parsed) // NOT OK + if parsed <= 0 { + _ = int16(parsed) // OK + } + } + } + { + parsed, err := strconv.ParseUint(input, 10, 32) + if err != nil { + panic(err) + } + if parsed <= math.MaxInt8 { + _ = uint8(parsed) // OK + } + if parsed < 5 { + _ = uint16(parsed) // OK + } + if err == nil && 1 == 1 && parsed < math.MaxInt8 { + _ = int8(parsed) // OK + } + if parsed > 42 { + _ = uint16(parsed) // NOT OK + } + if parsed < 5 { + return + } + _ = uint8(parsed) // OK + } +} + +func testRightShifted(input string) { + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + _ = byte(parsed) // OK + _ = byte(parsed >> 8) + _ = byte(parsed >> 16) + _ = byte(parsed >> 24) + } + { + parsed, err := strconv.ParseInt(input, 10, 16) + if err != nil { + panic(err) + } + _ = byte(parsed) // NOT OK + _ = byte(parsed << 8) + } +} + +func testPathWithMoreThanOneSink(input string) { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + v := int16(parsed) // NOT OK + _ = int8(v) // OK +} diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.qlref b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.qlref new file mode 100644 index 00000000000..47d8c34c0ee --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.qlref @@ -0,0 +1 @@ +Security/CWE-681/IncorrectIntegerConversion.ql From 681ca9065a4efaa4ad07e04ec9c1e02ba1d01fb7 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 5 Aug 2020 14:32:59 +0100 Subject: [PATCH 06/16] Add change note --- change-notes/2020-08-05-incorrect-integer-conversion.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change-notes/2020-08-05-incorrect-integer-conversion.md diff --git a/change-notes/2020-08-05-incorrect-integer-conversion.md b/change-notes/2020-08-05-incorrect-integer-conversion.md new file mode 100644 index 00000000000..258d8427f27 --- /dev/null +++ b/change-notes/2020-08-05-incorrect-integer-conversion.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Query "Incorrect integer conversion" (`go/incorrect-integer-conversion`) is promoted from experimental status. This checks for parsing a string to an integer and then assigning it to an integer type of a smaller bit size. From 4bfb2b4138e70daed901b2bc3c1d71d60ea1e0cf Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 5 Aug 2020 16:24:24 +0100 Subject: [PATCH 07/16] Address review comments 1 --- .../CWE-681/IncorrectIntegerConversion.qhelp | 2 +- .../CWE-681/IncorrectIntegerConversion.ql | 4 ++-- ql/src/semmle/go/frameworks/Stdlib.qll | 24 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp index 48682b46a7d..e0a39f59d82 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp @@ -25,7 +25,7 @@ the bit size you specified when parsing the number.

If this is not possible, then add upper (and lower) bound checks specific to each type and -bit size (you can find the minimum and maximum value for each type in the `math` package). +bit size (you can find the minimum and maximum value for each type in the math package).

diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index c3049773d24..b27f290ed05 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -64,7 +64,7 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { exists(ParserCall pc, int bitSize | source = pc.getResult(0) | - sourceIsSigned = pc.getTargetIsSigned() and + (if pc.targetIsSigned() then sourceIsSigned = true else sourceIsSigned = false) and (if pc.getTargetBitSize() = 0 then bitSize = 0 else bitSize = pc.getTargetBitSize()) and // `bitSize` could be any value between 0 and 64, but we can round // it up to the nearest size of an integer type without changing @@ -74,7 +74,7 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { } /** - * Holds if sink is a typecast to an integer type with size `bitSize` (where + * Holds if `sink` is a typecast to an integer type with size `bitSize` (where * 0 represents architecture-dependent) and the expression being typecast is * not also in a right-shift expression. */ diff --git a/ql/src/semmle/go/frameworks/Stdlib.qll b/ql/src/semmle/go/frameworks/Stdlib.qll index f975cc13441..17ded52c27a 100644 --- a/ql/src/semmle/go/frameworks/Stdlib.qll +++ b/ql/src/semmle/go/frameworks/Stdlib.qll @@ -522,18 +522,18 @@ module StrConv { ParseFloat() { this.hasQualifiedName("strconv", "ParseFloat") } } - /** A function that parses integers with a specifiable bitSize. */ + /** A function that parses integers with a specifiable bit size. */ class ParseInt extends Function { ParseInt() { this.hasQualifiedName("strconv", "ParseInt") } } - /** A function that parses unsigned integers with a specifiable bitSize. */ + /** A function that parses unsigned integers with a specifiable bit size. */ class ParseUint extends Function { ParseUint() { this.hasQualifiedName("strconv", "ParseUint") } } /** - * A constant that gives the size in bits of an int or uint + * A constant that gives the size in bits of an `int` or `uint` * value on the current architecture (32 or 64). */ class IntSize extends DeclaredConstant { @@ -549,14 +549,14 @@ module ParserCall { abstract int getTargetBitSize(); /** Holds if the type of the result number is signed. */ - abstract boolean getTargetIsSigned(); + abstract predicate targetIsSigned(); /** Gets the name of the parser function. */ abstract string getParserName(); } } -/** A call to a number-parsing function */ +/** A call to a number-parsing function. */ class ParserCall extends DataFlow::CallNode { ParserCall::Range self; @@ -566,7 +566,7 @@ class ParserCall extends DataFlow::CallNode { int getTargetBitSize() { result = self.getTargetBitSize() } /** Holds if the type of the result number is signed. */ - boolean getTargetIsSigned() { result = self.getTargetIsSigned() } + predicate targetIsSigned() { self.targetIsSigned() } /** Gets the name of the parser function. */ string getParserName() { result = self.getParserName() } @@ -579,18 +579,18 @@ class ParserCall extends DataFlow::CallNode { } } -/** A call to `strconv.Atoi` */ +/** A call to `strconv.Atoi`. */ class AtoiCall extends DataFlow::CallNode, ParserCall::Range { AtoiCall() { exists(StrConv::Atoi atoi | this = atoi.getACall()) } override int getTargetBitSize() { result = 0 } - override boolean getTargetIsSigned() { result = true } + override predicate targetIsSigned() { any() } override string getParserName() { result = "strconv.Atoi" } } -/** A call to `strconv.ParseInt` */ +/** A call to `strconv.ParseInt`. */ class ParseIntCall extends DataFlow::CallNode, ParserCall::Range { ParseIntCall() { exists(StrConv::ParseInt parseInt | this = parseInt.getACall()) } @@ -600,12 +600,12 @@ class ParseIntCall extends DataFlow::CallNode, ParserCall::Range { else result = this.getArgument(2).getIntValue() } - override boolean getTargetIsSigned() { result = true } + override predicate targetIsSigned() { any() } override string getParserName() { result = "strconv.ParseInt" } } -/** A call to `strconv.ParseUint` */ +/** A call to `strconv.ParseUint`. */ class ParseUintCall extends DataFlow::CallNode, ParserCall::Range { ParseUintCall() { exists(StrConv::ParseUint parseUint | this = parseUint.getACall()) } @@ -615,7 +615,7 @@ class ParseUintCall extends DataFlow::CallNode, ParserCall::Range { else result = this.getArgument(2).getIntValue() } - override boolean getTargetIsSigned() { result = false } + override predicate targetIsSigned() { none() } override string getParserName() { result = "strconv.ParseUint" } } From 89eae10d963525e11ffdb60312a3aaf256c97060 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 7 Aug 2020 14:57:55 +0100 Subject: [PATCH 08/16] Address review comments 2 --- .../CWE-681/IncorrectIntegerConversion.ql | 72 ++++++---- ql/src/semmle/go/frameworks/Stdlib.qll | 130 +++++------------- .../IncorrectIntegerConversion.expected | 40 +++--- 3 files changed, 101 insertions(+), 141 deletions(-) diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index b27f290ed05..58204f9869a 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -1,7 +1,8 @@ /** * @name Incorrect conversion between integer types - * @description Converting the result of strconv.Atoi, strconv.ParseInt and strconv.ParseUint - * to integer types of smaller bit size can produce unexpected values. + * @description Converting the result of `strconv.Atoi`, `strconv.ParseInt`, + * and `strconv.ParseUint` to integer types of smaller bit size + * can produce unexpected values. * @kind path-problem * @problem.severity warning * @id go/incorrect-integer-conversion @@ -19,7 +20,7 @@ import DataFlow::PathGraph * is true, unsigned otherwise) with `bitSize` bits. */ float getMaxIntValue(int bitSize, boolean isSigned) { - bitSize in [8, 16, 32, 64] and + bitSize in [8, 16, 32] and ( isSigned = true and result = 2.pow(bitSize - 1) - 1 or @@ -33,15 +34,15 @@ float getMaxIntValue(int bitSize, boolean isSigned) { * architecture-dependent. */ private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSize) { - sourceBitSize in [0, 16, 32, 64] and - sinkBitSize in [0, 8, 16, 32] and - not (sourceBitSize = 0 and sinkBitSize = 0) and - exists(int source, int sink | - (if sourceBitSize = 0 then source = 64 else source = sourceBitSize) and - if sinkBitSize = 0 then sink = 32 else sink = sinkBitSize - | - source > sink - ) + sourceBitSize in [16, 32, 64] and + sinkBitSize in [8, 16, 32] and + sourceBitSize > sinkBitSize + or + sourceBitSize = 0 and + sinkBitSize in [8, 16, 32] + or + sourceBitSize = 64 and + sinkBitSize = 0 } /** @@ -57,15 +58,24 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { ConversionWithoutBoundsCheckConfig() { sourceIsSigned in [true, false] and isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and - this = - sourceBitSize.toString() + sourceIsSigned.toString() + sinkBitSize.toString() + - "ConversionWithoutBoundsCheckConfig" + this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sourceIsSigned + sinkBitSize } + int getSourceBitSize() { result = sourceBitSize } + override predicate isSource(DataFlow::Node source) { - exists(ParserCall pc, int bitSize | source = pc.getResult(0) | - (if pc.targetIsSigned() then sourceIsSigned = true else sourceIsSigned = false) and - (if pc.getTargetBitSize() = 0 then bitSize = 0 else bitSize = pc.getTargetBitSize()) and + exists(DataFlow::CallNode c, IntegerParser::Range ip, int bitSize | + c.getTarget() = ip and source = c.getResult(0) + | + ( + if ip.getResultType(0) instanceof SignedIntegerType + then sourceIsSigned = true + else sourceIsSigned = false + ) and + ( + bitSize = ip.getTargetBitSize() or + bitSize = ip.getTargetBitSizeInput().getNode(c).getIntValue() + ) and // `bitSize` could be any value between 0 and 64, but we can round // it up to the nearest size of an integer type without changing // behaviour. @@ -76,16 +86,14 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { /** * Holds if `sink` is a typecast to an integer type with size `bitSize` (where * 0 represents architecture-dependent) and the expression being typecast is - * not also in a right-shift expression. + * not also in a right-shift expression. We allow this case because it is + * a common pattern to serialise `byte(v)`, `byte(v >> 8)`, and so on. */ predicate isSink(DataFlow::TypeCastNode sink, int bitSize) { exists(IntegerType integerType | sink.getType().getUnderlyingType() = integerType | bitSize = integerType.getSize() or - ( - integerType instanceof IntType or - integerType instanceof UintType - ) and + not exists(integerType.getSize()) and bitSize = 0 ) and not exists(ShrExpr shrExpr | @@ -131,12 +139,18 @@ class UpperBoundCheckGuard extends DataFlow::BarrierGuard, DataFlow::RelationalC } } +/** Gets a string describing the size of the integer parsed. */ +string describeBitSize(int bitSize) { + if bitSize != 0 + then bitSize in [8, 16, 32, 64] and result = "a " + bitSize + "-bit integer" + else result = "an integer with architecture-dependent bit size" +} + from DataFlow::PathNode source, DataFlow::PathNode sink, ConversionWithoutBoundsCheckConfig cfg, - ParserCall pc -where cfg.hasFlowPath(source, sink) and pc.getResult(0) = source.getNode() + DataFlow::CallNode call +where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode() select source.getNode(), source, sink, - "Incorrect conversion of " + pc.getBitSizeString() + " from " + pc.getParserName() + - " to a lower bit size type " + - sink.getNode().(DataFlow::TypeCastNode).getType().getUnderlyingType().getName() + - " without an upper bound check." + "Incorrect conversion of " + describeBitSize(cfg.getSourceBitSize()) + " from " + + call.getTarget().getQualifiedName() + " to a lower bit size type " + + sink.getNode().getType().getUnderlyingType().getName() + " without an upper bound check." diff --git a/ql/src/semmle/go/frameworks/Stdlib.qll b/ql/src/semmle/go/frameworks/Stdlib.qll index 17ded52c27a..93eac91ba01 100644 --- a/ql/src/semmle/go/frameworks/Stdlib.qll +++ b/ql/src/semmle/go/frameworks/Stdlib.qll @@ -507,119 +507,65 @@ module Path { } } +/** Provides a class for modeling functions which convert strings into integers. */ +module IntegerParser { + /** + * A function that converts strings into integers. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `IntegerParser` instead. + */ + abstract class Range extends Function { + /** + * Gets the maximum bit size of the return value, if this makes + * sense, where 0 represents the bit size of `int` and `uint`. + */ + int getTargetBitSize() { none() } + + /** + * Gets the `FunctionInput` containing the maximum bit size of the + * return value, if this makes sense, where 0 represents the bit + * size of `int` and `uint`. + */ + FunctionInput getTargetBitSizeInput() { none() } + } +} + /** * Provides classes for some functions in the `strconv` package for * converting strings to numbers. */ module StrConv { - /** A function that parses integers. */ - class Atoi extends Function { + /** The `Atoi` function. */ + class Atoi extends IntegerParser::Range { Atoi() { this.hasQualifiedName("strconv", "Atoi") } + + override int getTargetBitSize() { result = 0 } } - /** A function that parses floating-point numbers. */ - class ParseFloat extends Function { - ParseFloat() { this.hasQualifiedName("strconv", "ParseFloat") } - } - - /** A function that parses integers with a specifiable bit size. */ - class ParseInt extends Function { + /** The `ParseInt` function. */ + class ParseInt extends IntegerParser::Range { ParseInt() { this.hasQualifiedName("strconv", "ParseInt") } + + override FunctionInput getTargetBitSizeInput() { result.isParameter(2) } } - /** A function that parses unsigned integers with a specifiable bit size. */ - class ParseUint extends Function { + /** The `ParseUint` function. */ + class ParseUint extends IntegerParser::Range { ParseUint() { this.hasQualifiedName("strconv", "ParseUint") } + + override FunctionInput getTargetBitSizeInput() { result.isParameter(2) } } /** - * A constant that gives the size in bits of an `int` or `uint` - * value on the current architecture (32 or 64). + * The `IntSize` constant, that gives the size in bits of an `int` or + * `uint` value on the current architecture (32 or 64). */ class IntSize extends DeclaredConstant { IntSize() { this.hasQualifiedName("strconv", "IntSize") } } } -/** Provides a class for modeling calls to number-parsing functions. */ -module ParserCall { - /** A data-flow call node that parses a number. */ - abstract class Range extends DataFlow::CallNode { - /** Gets the bit size of the type of the result number. */ - abstract int getTargetBitSize(); - - /** Holds if the type of the result number is signed. */ - abstract predicate targetIsSigned(); - - /** Gets the name of the parser function. */ - abstract string getParserName(); - } -} - -/** A call to a number-parsing function. */ -class ParserCall extends DataFlow::CallNode { - ParserCall::Range self; - - ParserCall() { this = self } - - /** Gets the bit size of the type of the result number. */ - int getTargetBitSize() { result = self.getTargetBitSize() } - - /** Holds if the type of the result number is signed. */ - predicate targetIsSigned() { self.targetIsSigned() } - - /** Gets the name of the parser function. */ - string getParserName() { result = self.getParserName() } - - /** Gets a string describing the size of the integer parsed. */ - string getBitSizeString() { - if getTargetBitSize() != 0 - then result = "a " + getTargetBitSize() + "-bit integer" - else result = "an integer with architecture-dependent bit-width" - } -} - -/** A call to `strconv.Atoi`. */ -class AtoiCall extends DataFlow::CallNode, ParserCall::Range { - AtoiCall() { exists(StrConv::Atoi atoi | this = atoi.getACall()) } - - override int getTargetBitSize() { result = 0 } - - override predicate targetIsSigned() { any() } - - override string getParserName() { result = "strconv.Atoi" } -} - -/** A call to `strconv.ParseInt`. */ -class ParseIntCall extends DataFlow::CallNode, ParserCall::Range { - ParseIntCall() { exists(StrConv::ParseInt parseInt | this = parseInt.getACall()) } - - override int getTargetBitSize() { - if exists(StrConv::IntSize intSize | this.getArgument(2).(DataFlow::ReadNode).reads(intSize)) - then result = 0 - else result = this.getArgument(2).getIntValue() - } - - override predicate targetIsSigned() { any() } - - override string getParserName() { result = "strconv.ParseInt" } -} - -/** A call to `strconv.ParseUint`. */ -class ParseUintCall extends DataFlow::CallNode, ParserCall::Range { - ParseUintCall() { exists(StrConv::ParseUint parseUint | this = parseUint.getACall()) } - - override int getTargetBitSize() { - if exists(StrConv::IntSize intSize | this.getArgument(2).(DataFlow::ReadNode).reads(intSize)) - then result = 0 - else result = this.getArgument(2).getIntValue() - } - - override predicate targetIsSigned() { none() } - - override string getParserName() { result = "strconv.ParseUint" } -} - /** Provides models of commonly used functions in the `strings` package. */ module Strings { /** The `Join` function. */ diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected index 8eaad5f4c9e..b73a4f419b1 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -140,7 +140,7 @@ nodes | IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | semmle.label | type conversion | #select -| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:70:7:70:19 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:85:7:85:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | @@ -155,12 +155,12 @@ nodes | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:106:7:106:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:109:7:109:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int without an upper bound check. | | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:110:7:110:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:152:7:152:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:153:7:153:19 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:168:7:168:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | @@ -175,21 +175,21 @@ nodes | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:189:7:189:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint32 without an upper bound check. | | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:192:7:192:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int without an upper bound check. | | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:193:7:193:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.ParseUint to a lower bit size type uint32 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type uint32 without an upper bound check. | | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:240:7:240:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit-width from strconv.Atoi to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int8 without an upper bound check. | | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:287:7:287:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | | IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] | IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | From 30f176246ab8b6731c8073f373912b22d75b704f Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 10 Aug 2020 12:39:32 +0100 Subject: [PATCH 09/16] Address review comments 3 --- .../CWE-681/IncorrectIntegerConversion.qhelp | 7 +++++++ .../CWE-681/IncorrectIntegerConversion.ql | 13 +++++++++--- ql/src/semmle/go/frameworks/Stdlib.qll | 4 ++-- .../IncorrectIntegerConversion.expected | 21 +++++++++++++++++++ .../CWE-681/IncorrectIntegerConversion.go | 17 +++++++++++++++ 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp index e0a39f59d82..c1e7801dd80 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.qhelp @@ -64,4 +64,11 @@ or check bounds before making the conversion as in parseAllocateGood4 + +
  • Wikipedia Integer overflow.
  • +
  • Go language specification Integer overflow.
  • +
  • Documentation for strconv.Atoi.
  • +
  • Documentation for strconv.ParseInt.
  • +
  • Documentation for strconv.ParseUint.
  • +
    diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index 58204f9869a..e93af44aa07 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -61,6 +61,7 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sourceIsSigned + sinkBitSize } + /** Gets the bit size of the source. */ int getSourceBitSize() { result = sourceBitSize } override predicate isSource(DataFlow::Node source) { @@ -73,8 +74,14 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { else sourceIsSigned = false ) and ( - bitSize = ip.getTargetBitSize() or - bitSize = ip.getTargetBitSizeInput().getNode(c).getIntValue() + bitSize = ip.getTargetBitSize() + or + if + exists(StrConv::IntSize intSize | + ip.getTargetBitSizeInput().getNode(c).(DataFlow::ReadNode).reads(intSize) + ) + then bitSize = 0 + else bitSize = ip.getTargetBitSizeInput().getNode(c).getIntValue() ) and // `bitSize` could be any value between 0 and 64, but we can round // it up to the nearest size of an integer type without changing @@ -129,7 +136,7 @@ class UpperBoundCheckGuard extends DataFlow::BarrierGuard, DataFlow::RelationalC exists(int strictnessOffset | if expr.isStrict() then strictnessOffset = 1 else strictnessOffset = 0 | - result = expr.getAnOperand().getIntValue() - strictnessOffset + result = expr.getAnOperand().getExactValue().toFloat() - strictnessOffset ) } diff --git a/ql/src/semmle/go/frameworks/Stdlib.qll b/ql/src/semmle/go/frameworks/Stdlib.qll index 93eac91ba01..680b78e6bf7 100644 --- a/ql/src/semmle/go/frameworks/Stdlib.qll +++ b/ql/src/semmle/go/frameworks/Stdlib.qll @@ -524,8 +524,8 @@ module IntegerParser { /** * Gets the `FunctionInput` containing the maximum bit size of the - * return value, if this makes sense, where 0 represents the bit - * size of `int` and `uint`. + * return value, if this makes sense. Note that if the value of the + * input is 0 then it means the bit size of `int` and `uint`. */ FunctionInput getTargetBitSizeInput() { none() } } diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected index b73a4f419b1..ebd2d1a01df 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -53,6 +53,12 @@ edges | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:287:7:287:19 | type conversion | | IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | | IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:326:6:326:17 | type conversion | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:327:6:327:18 | type conversion | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:328:6:328:18 | type conversion | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:329:6:329:19 | type conversion | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:330:6:330:18 | type conversion | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:331:6:331:19 | type conversion | nodes | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | @@ -139,6 +145,15 @@ nodes | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | semmle.label | type conversion | | IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:326:6:326:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:327:6:327:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:328:6:328:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:329:6:329:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:330:6:330:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:331:6:331:19 | type conversion | semmle.label | type conversion | #select | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | @@ -194,3 +209,9 @@ nodes | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:287:7:287:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | | IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] | IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | | IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] | IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:326:6:326:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:327:6:327:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:328:6:328:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:329:6:329:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:330:6:330:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:331:6:331:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go index e4d7419759d..3dd4c0f482b 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -317,3 +317,20 @@ func testPathWithMoreThanOneSink(input string) { v := int16(parsed) // NOT OK _ = int8(v) // OK } + +func testUsingStrConvIntSize(input string) { + parsed, err := strconv.ParseInt(input, 10, strconv.IntSize) + if err != nil { + panic(err) + } + _ = int8(parsed) // NOT OK + _ = uint8(parsed) // NOT OK + _ = int16(parsed) // NOT OK + _ = uint16(parsed) // NOT OK + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + _ = int64(parsed) // OK + _ = uint64(parsed) // OK + _ = int(parsed) // OK + _ = uint(parsed) // OK +} From ed469a355efd165b7789e7c28314626c3e6ce638 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 10 Aug 2020 17:28:55 +0100 Subject: [PATCH 10/16] Fix mistake in test --- .../query-tests/Security/CWE-681/IncorrectIntegerConversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go index 3dd4c0f482b..0d37bfcfb5f 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -281,7 +281,7 @@ func testBoundsChecking(input string) { if parsed > 42 { _ = uint16(parsed) // NOT OK } - if parsed < 5 { + if parsed > 5 { return } _ = uint8(parsed) // OK From 4907f6529edb7d62db81f9b90113b0f664a83a0b Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 10 Aug 2020 17:33:02 +0100 Subject: [PATCH 11/16] Address review comments 4 --- .../CWE-681/IncorrectIntegerConversion.ql | 15 +++++ .../IncorrectIntegerConversion.expected | 62 +++++++++---------- .../CWE-681/IncorrectIntegerConversion.go | 16 +++++ 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index e93af44aa07..b4e85e1822f 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -32,15 +32,24 @@ float getMaxIntValue(int bitSize, boolean isSigned) { * Holds if converting from an integer types with size `sourceBitSize` to * one with size `sinkBitSize` can produce unexpected values, where 0 means * architecture-dependent. + * + * Architecture-dependent bit sizes can be 32 or 64. To catch flows that + * only manifest on 64-bit architectures we consider an + * architecture-dependent source bit size to be 64. To catch flows that + * only happen on 32-bit architectures we consider an + * architecture-dependent sink bit size to be 32. We exclude the case where + * both source and sink have architecture-dependent bit sizes. */ private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSize) { sourceBitSize in [16, 32, 64] and sinkBitSize in [8, 16, 32] and sourceBitSize > sinkBitSize or + // Treat `sourceBitSize = 0` like `sourceBitSize = 64`, and exclude `sinkBitSize = 0` sourceBitSize = 0 and sinkBitSize in [8, 16, 32] or + // Treat `sinkBitSize = 0` like `sinkBitSize = 32`, and exclude `sourceBitSize = 0` sourceBitSize = 64 and sinkBitSize = 0 } @@ -76,6 +85,8 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { ( bitSize = ip.getTargetBitSize() or + // If we are reading a variable, check if it is + // `strconv.IntSize`, and use 0 if it is. if exists(StrConv::IntSize intSize | ip.getTargetBitSizeInput().getNode(c).(DataFlow::ReadNode).reads(intSize) @@ -105,6 +116,8 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { ) and not exists(ShrExpr shrExpr | shrExpr.getLeftOperand().getGlobalValueNumber() = + sink.getOperand().asExpr().getGlobalValueNumber() or + shrExpr.getLeftOperand().(AndExpr).getAnOperand().getGlobalValueNumber() = sink.getOperand().asExpr().getGlobalValueNumber() ) } @@ -112,6 +125,8 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { isSink(sink, sinkBitSize) } override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + // To catch flows that only happen on 32-bit architectures we + // consider an architecture-dependent sink bit size to be 32. exists(int bitSize | if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32 | guard.(UpperBoundCheckGuard).getBound() <= getMaxIntValue(bitSize, sourceIsSigned) ) diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected index ebd2d1a01df..d9f26dfb1d1 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -50,15 +50,14 @@ edges | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | -| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:287:7:287:19 | type conversion | -| IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | -| IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:326:6:326:17 | type conversion | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:327:6:327:18 | type conversion | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:328:6:328:18 | type conversion | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:329:6:329:19 | type conversion | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:330:6:330:18 | type conversion | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:331:6:331:19 | type conversion | +| IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | +| IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:333:7:333:19 | type conversion | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:6:342:17 | type conversion | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:343:6:343:18 | type conversion | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:344:6:344:18 | type conversion | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:345:6:345:19 | type conversion | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:346:6:346:18 | type conversion | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:347:6:347:19 | type conversion | nodes | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | @@ -138,22 +137,20 @@ nodes | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | semmle.label | type conversion | | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | -| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | semmle.label | ... := ...[0] : uint64 | | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:287:7:287:19 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:307:7:307:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:317:7:317:19 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:326:6:326:17 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:327:6:327:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:328:6:328:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:329:6:329:19 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:330:6:330:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:331:6:331:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:323:7:323:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:333:7:333:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:342:6:342:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:343:6:343:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:344:6:344:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:345:6:345:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:346:6:346:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:347:6:347:19 | type conversion | semmle.label | type conversion | #select | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | @@ -206,12 +203,11 @@ nodes | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int8 without an upper bound check. | | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:287:7:287:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] | IncorrectIntegerConversion.go:303:3:303:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:307:7:307:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] | IncorrectIntegerConversion.go:313:2:313:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:317:7:317:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:326:6:326:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:327:6:327:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:328:6:328:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:329:6:329:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:330:6:330:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] | IncorrectIntegerConversion.go:322:2:322:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:331:6:331:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] | IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:333:7:333:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:6:342:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:343:6:343:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:344:6:344:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:345:6:345:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:346:6:346:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:347:6:347:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go index 0d37bfcfb5f..77399c5d038 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -299,6 +299,22 @@ func testRightShifted(input string) { _ = byte(parsed >> 16) _ = byte(parsed >> 24) } + { + parsed, err := strconv.ParseInt(input, 10, 16) + if err != nil { + panic(err) + } + _ = byte(parsed) // OK + _ = byte(parsed & 0xff00 >> 8) + } + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + _ = byte(parsed) // OK + _ = byte(parsed >> 8 & 0xff) + } { parsed, err := strconv.ParseInt(input, 10, 16) if err != nil { From c7a8730c4065086ae4252a3116f0dc3734b30f49 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 11 Aug 2020 06:40:06 +0100 Subject: [PATCH 12/16] Improve tests of paths with more than one sink --- .../IncorrectIntegerConversion.expected | 70 ++++++++++++------- .../CWE-681/IncorrectIntegerConversion.go | 39 +++++++++-- 2 files changed, 79 insertions(+), 30 deletions(-) diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected index d9f26dfb1d1..3800d89e3cc 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -51,13 +51,20 @@ edges | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | -| IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:333:7:333:19 | type conversion | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:6:342:17 | type conversion | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:343:6:343:18 | type conversion | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:344:6:344:18 | type conversion | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:345:6:345:19 | type conversion | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:346:6:346:18 | type conversion | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:347:6:347:19 | type conversion | +| IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:334:9:334:21 | type conversion | +| IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:8:342:20 | type conversion | +| IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:350:9:350:21 | type conversion : int64 | +| IncorrectIntegerConversion.go:350:9:350:21 | type conversion : int64 | IncorrectIntegerConversion.go:351:9:351:17 | type conversion | +| IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:359:9:359:21 | type conversion : int64 | +| IncorrectIntegerConversion.go:359:9:359:21 | type conversion : int64 | IncorrectIntegerConversion.go:360:9:360:17 | type conversion : int64 | +| IncorrectIntegerConversion.go:360:9:360:17 | type conversion : int64 | IncorrectIntegerConversion.go:361:9:361:17 | type conversion : int64 | +| IncorrectIntegerConversion.go:361:9:361:17 | type conversion : int64 | IncorrectIntegerConversion.go:362:7:362:14 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:371:6:371:17 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:372:6:372:18 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:373:6:373:18 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | nodes | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | @@ -140,17 +147,27 @@ nodes | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | semmle.label | type conversion | | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:333:7:333:19 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | -| IncorrectIntegerConversion.go:342:6:342:17 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:343:6:343:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:344:6:344:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:345:6:345:19 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:346:6:346:18 | type conversion | semmle.label | type conversion | -| IncorrectIntegerConversion.go:347:6:347:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:334:9:334:21 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:342:8:342:20 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:350:9:350:21 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:351:9:351:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:359:9:359:21 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:360:9:360:17 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:361:9:361:17 | type conversion : int64 | semmle.label | type conversion : int64 | +| IncorrectIntegerConversion.go:362:7:362:14 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| IncorrectIntegerConversion.go:371:6:371:17 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:372:6:372:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:373:6:373:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:374:6:374:19 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:375:6:375:18 | type conversion | semmle.label | type conversion | +| IncorrectIntegerConversion.go:376:6:376:19 | type conversion | semmle.label | type conversion | #select | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | @@ -204,10 +221,13 @@ nodes | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int8 without an upper bound check. | | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] | IncorrectIntegerConversion.go:329:2:329:47 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:333:7:333:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:6:342:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:343:6:343:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:344:6:344:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:345:6:345:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:346:6:346:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] | IncorrectIntegerConversion.go:338:2:338:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:347:6:347:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | +| IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] | IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:334:9:334:21 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] | IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:8:342:20 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] | IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:351:9:351:17 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] | IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:362:7:362:14 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:371:6:371:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:372:6:372:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:373:6:373:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | +| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go index 77399c5d038..b99f1f42691 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -326,12 +326,41 @@ func testRightShifted(input string) { } func testPathWithMoreThanOneSink(input string) { - parsed, err := strconv.ParseInt(input, 10, 32) - if err != nil { - panic(err) + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + v1 := int16(parsed) // NOT OK + _ = int16(v1) // OK + } + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + v := int16(parsed) // NOT OK + _ = int8(v) // OK + } + { + parsed, err := strconv.ParseInt(input, 10, 32) + if err != nil { + panic(err) + } + v1 := int32(parsed) // OK + v2 := int16(v1) // NOT OK + _ = int8(v2) // OK + } + { + parsed, err := strconv.ParseInt(input, 10, 16) + if err != nil { + panic(err) + } + v1 := int64(parsed) // OK + v2 := int32(v1) // OK + v3 := int16(v2) // OK + _ = int8(v3) // NOT OK } - v := int16(parsed) // NOT OK - _ = int8(v) // OK } func testUsingStrConvIntSize(input string) { From 1e0b9cc6a32ef5619137d238b8e6668145265366 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 11 Aug 2020 10:57:02 +0100 Subject: [PATCH 13/16] Address review comments 5 --- ql/src/Security/CWE-681/IncorrectIntegerConversion.ql | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index b4e85e1822f..53ed1033e9b 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -87,12 +87,11 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { or // If we are reading a variable, check if it is // `strconv.IntSize`, and use 0 if it is. - if - exists(StrConv::IntSize intSize | - ip.getTargetBitSizeInput().getNode(c).(DataFlow::ReadNode).reads(intSize) - ) - then bitSize = 0 - else bitSize = ip.getTargetBitSizeInput().getNode(c).getIntValue() + exists(DataFlow::Node rawBitSize | rawBitSize = ip.getTargetBitSizeInput().getNode(c) | + if rawBitSize = any(StrConv::IntSize intSize).getARead() + then bitSize = 0 + else bitSize = rawBitSize.getIntValue() + ) ) and // `bitSize` could be any value between 0 and 64, but we can round // it up to the nearest size of an integer type without changing From 69212b9ad9bb75ee2b11ee56777987ad48588143 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Mon, 10 Aug 2020 11:58:48 +0100 Subject: [PATCH 14/16] Deal with build constraints Note that build constraints can be explicit (comments at the top of the file) or implicit (part of the file name) --- Makefile | 1 + .../CWE-681/IncorrectIntegerConversion.ql | 54 ++++++++++++++----- ql/src/semmle/go/Files.qll | 51 ++++++++++++++++++ .../IncorrectIntegerConversion.expected | 14 +++++ ...chitectureBuildConstraintInFileName_386.go | 34 ++++++++++++ .../Test32BitArchitectureBuildConstraints.go | 36 +++++++++++++ ...itectureBuildConstraintInFileName_amd64.go | 26 +++++++++ .../Test64BitArchitectureBuildConstraints.go | 28 ++++++++++ .../TestNoArchitectureBuildConstraints.go | 27 ++++++++++ 9 files changed, 258 insertions(+), 13 deletions(-) create mode 100644 ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraintInFileName_386.go create mode 100644 ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go create mode 100644 ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraintInFileName_amd64.go create mode 100644 ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go create mode 100644 ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go diff --git a/Makefile b/Makefile index 6290cf67b47..da5040aa151 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ ql/src/go.dbscheme.stats: ql/src/go.dbscheme build/stats/src.stamp extractor test: all build/testdb/check-upgrade-path codeql test run ql/test --search-path . + env GOARCH=386 codeql$(EXE) test run ql/test/query-tests/Security/CWE-681 --search-path . cd extractor; go test -mod=vendor ./... | grep -vF "[no test files]" .PHONY: build/testdb/check-upgrade-path diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index 53ed1033e9b..9ed810c4c8a 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -28,6 +28,19 @@ float getMaxIntValue(int bitSize, boolean isSigned) { ) } +/** + * Get the size of `int` or `uint` in `file`, or 0 if it is + * architecture-specific. + */ +int getIntTypeBitSize(File file) { + if file.hasConstrainedIntBitSize(32) + then result = 32 + else + if file.hasConstrainedIntBitSize(64) + then result = 64 + else result = 0 +} + /** * Holds if converting from an integer types with size `sourceBitSize` to * one with size `sinkBitSize` can produce unexpected values, where 0 means @@ -74,7 +87,9 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { int getSourceBitSize() { result = sourceBitSize } override predicate isSource(DataFlow::Node source) { - exists(DataFlow::CallNode c, IntegerParser::Range ip, int bitSize | + exists( + DataFlow::CallNode c, IntegerParser::Range ip, int apparentBitSize, int effectiveBitSize + | c.getTarget() = ip and source = c.getResult(0) | ( @@ -83,20 +98,25 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { else sourceIsSigned = false ) and ( - bitSize = ip.getTargetBitSize() + apparentBitSize = ip.getTargetBitSize() or // If we are reading a variable, check if it is // `strconv.IntSize`, and use 0 if it is. exists(DataFlow::Node rawBitSize | rawBitSize = ip.getTargetBitSizeInput().getNode(c) | if rawBitSize = any(StrConv::IntSize intSize).getARead() - then bitSize = 0 - else bitSize = rawBitSize.getIntValue() + then apparentBitSize = 0 + else apparentBitSize = rawBitSize.getIntValue() ) ) and - // `bitSize` could be any value between 0 and 64, but we can round - // it up to the nearest size of an integer type without changing - // behaviour. - sourceBitSize = min(int b | b in [0, 8, 16, 32, 64] and b >= bitSize) + ( + if apparentBitSize = 0 + then effectiveBitSize = getIntTypeBitSize(source.getFile()) + else effectiveBitSize = apparentBitSize + ) and + // `effectiveBitSize` could be any value between 0 and 64, but we + // can round it up to the nearest size of an integer type without + // changing behaviour. + sourceBitSize = min(int b | b in [0, 8, 16, 32, 64] and b >= effectiveBitSize) ) } @@ -111,7 +131,7 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { bitSize = integerType.getSize() or not exists(integerType.getSize()) and - bitSize = 0 + bitSize = getIntTypeBitSize(sink.getFile()) ) and not exists(ShrExpr shrExpr | shrExpr.getLeftOperand().getGlobalValueNumber() = @@ -161,10 +181,17 @@ class UpperBoundCheckGuard extends DataFlow::BarrierGuard, DataFlow::RelationalC } /** Gets a string describing the size of the integer parsed. */ -string describeBitSize(int bitSize) { +string describeBitSize(int bitSize, int intTypeBitSize) { + intTypeBitSize in [0, 32, 64] and if bitSize != 0 then bitSize in [8, 16, 32, 64] and result = "a " + bitSize + "-bit integer" - else result = "an integer with architecture-dependent bit size" + else + if intTypeBitSize = 0 + then result = "an integer with architecture-dependent bit size" + else + result = + "a number with architecture-dependent bit-width, which is constrained to be " + + intTypeBitSize + "-bit by build constraints," } from @@ -172,6 +199,7 @@ from DataFlow::CallNode call where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode() select source.getNode(), source, sink, - "Incorrect conversion of " + describeBitSize(cfg.getSourceBitSize()) + " from " + - call.getTarget().getQualifiedName() + " to a lower bit size type " + + "Incorrect conversion of " + + describeBitSize(cfg.getSourceBitSize(), getIntTypeBitSize(source.getNode().getFile())) + + " from " + call.getTarget().getQualifiedName() + " to a lower bit size type " + sink.getNode().getType().getUnderlyingType().getName() + " without an upper bound check." diff --git a/ql/src/semmle/go/Files.qll b/ql/src/semmle/go/Files.qll index e157b80c9b6..5e3e1151b74 100644 --- a/ql/src/semmle/go/Files.qll +++ b/ql/src/semmle/go/Files.qll @@ -203,6 +203,57 @@ class File extends Container, @file, Documentable, ExprParent, GoModExprParent, pragma[noinline] predicate hasBuildConstraints() { exists(BuildConstraintComment bc | this = bc.getFile()) } + /** + * Gets an architecture that is valid in a build constraint with bit + * size `bitSize`. + * + * Information obtained from + * https://github.com/golang/go/blob/98cbf45cfc6a5a50cc6ac2367f9572cb198b57c7/src/go/types/gccgosizes.go + * where the first field of the struct is 4 for 32-bit architectures + * and 8 for 64-bit architectures. + */ + private string getAnArchitecture(int bitSize) { + bitSize = 32 and + result in ["386", "amd64p32", "arm", "armbe", "mips", "mipsle", "mips64p32", "mips64p32le", + "ppc", "s390", "sparc"] + or + bitSize = 64 and + result in ["amd64", "arm64", "arm64be", "ppc64", "ppc64le", "mips64", "mips64le", "s390x", + "sparc64"] + } + + /** + * Holds if this file contains build constraints that ensure that it + * is only built on architectures of bit size `bitSize`. + */ + predicate hasConstrainedIntBitSize(int bitSize) { + hasExplicitBuildConstraintsForArchitectures(bitSize) or + hasImplicitBuildConstraintForAnArchitecture(bitSize) + } + + /** + * Holds if this file contains explicit build constraints that ensure + * that it is only built on an architecture of bit size `bitSize`. + */ + predicate hasExplicitBuildConstraintsForArchitectures(int bitSize) { + exists(BuildConstraintComment bcc, string bc | + this = bcc.getFile() and bc = bcc.getText().splitAt("+build ", 1) + | + forex(string disjunct | disjunct = bc.splitAt(" ") | + disjunct.splitAt(",").matches(getAnArchitecture(bitSize)) + ) + ) + } + + /** + * Holds if this file has a name which acts as an implicit build + * constraint that ensures that it is only built on an + * architecture of bit size `bitSize`. + */ + predicate hasImplicitBuildConstraintForAnArchitecture(int bitSize) { + this.getStem().regexpMatch(".*_" + getAnArchitecture(bitSize) + "(_test)?") + } + override string toString() { result = Container.super.toString() } /** Gets the URL of this file. */ diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected index 3800d89e3cc..f582ad14120 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -65,6 +65,10 @@ edges | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | nodes | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | semmle.label | ... := ...[0] : int | | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | semmle.label | type conversion | @@ -168,6 +172,12 @@ nodes | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | semmle.label | type conversion | | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | semmle.label | type conversion | | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | semmle.label | ... := ...[0] : int64 | +| TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | semmle.label | type conversion | +| TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | semmle.label | type conversion | #select | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | @@ -231,3 +241,7 @@ nodes | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | +| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int without an upper bound check. | +| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint without an upper bound check. | diff --git a/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraintInFileName_386.go b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraintInFileName_386.go new file mode 100644 index 00000000000..ac1200dc4d5 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraintInFileName_386.go @@ -0,0 +1,34 @@ +// Note that the filename acts as an implicit build constraint + +package main + +import ( + "strconv" +) + +func testIntSource386() { + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.Atoi("3456") + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go new file mode 100644 index 00000000000..11e317d46cd --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go @@ -0,0 +1,36 @@ +// +build 386 amd64p32 arm armbe mips mipsle mips64p32 mips64p32le ppc s390 sparc +// +build gc +// +build go1.4 + +package main + +import ( + "strconv" +) + +func testIntSource32() { + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } + { + parsed, err := strconv.Atoi("3456") + if err != nil { + panic(err) + } + _ = int32(parsed) // OK + _ = uint32(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraintInFileName_amd64.go b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraintInFileName_amd64.go new file mode 100644 index 00000000000..95c2cf92860 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraintInFileName_amd64.go @@ -0,0 +1,26 @@ +// Note that the filename acts as an implicit build constraint + +package main + +import ( + "strconv" +) + +func testIntSinkAmd64() { + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go new file mode 100644 index 00000000000..82bd2965cee --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go @@ -0,0 +1,28 @@ +// +build amd64 arm64 arm64be ppc64 ppc64le mips64 mips64le s390x sparc64 +// +build gc +// +build go1.4 + +package main + +import ( + "strconv" +) + +func testIntSink64() { + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} diff --git a/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go new file mode 100644 index 00000000000..98cb6abdd61 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go @@ -0,0 +1,27 @@ +// +build gc +// +build go1.4 + +package main + +import ( + "strconv" +) + +func testIntSizeIsArchicturallyDependent1() { + { + parsed, err := strconv.ParseInt("3456", 10, 0) + if err != nil { + panic(err) + } + _ = int32(parsed) // NOT OK + _ = uint32(parsed) // NOT OK + } + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // NOT OK + _ = uint(parsed) // NOT OK + } +} From 2e60d40ccd0c84a69b1c1b6c5e1bd456c1e0f944 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 12 Aug 2020 12:35:50 +0100 Subject: [PATCH 15/16] Address review comments 6 --- .../CWE-681/IncorrectIntegerConversion.ql | 10 ++--- ql/src/go.qll | 1 + ql/src/semmle/go/Architectures.qll | 27 +++++++++++ ql/src/semmle/go/Comments.qll | 6 +++ ql/src/semmle/go/Files.qll | 45 +++++++------------ 5 files changed, 53 insertions(+), 36 deletions(-) create mode 100644 ql/src/semmle/go/Architectures.qll diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index 9ed810c4c8a..c38b0092041 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -33,12 +33,10 @@ float getMaxIntValue(int bitSize, boolean isSigned) { * architecture-specific. */ int getIntTypeBitSize(File file) { - if file.hasConstrainedIntBitSize(32) - then result = 32 - else - if file.hasConstrainedIntBitSize(64) - then result = 64 - else result = 0 + file.constrainsIntBitSize(result) + or + not file.constrainsIntBitSize(_) and + result = 0 } /** diff --git a/ql/src/go.qll b/ql/src/go.qll index 0f497ac8c31..4a5f9186902 100644 --- a/ql/src/go.qll +++ b/ql/src/go.qll @@ -3,6 +3,7 @@ */ import Customizations +import semmle.go.Architectures import semmle.go.AST import semmle.go.Comments import semmle.go.Concepts diff --git a/ql/src/semmle/go/Architectures.qll b/ql/src/semmle/go/Architectures.qll new file mode 100644 index 00000000000..c2ea35acc4c --- /dev/null +++ b/ql/src/semmle/go/Architectures.qll @@ -0,0 +1,27 @@ +/** Provides classes for working with architectures. */ + +import go + +/** + * An architecture that is valid in a build constraint. + * + * Information obtained from + * https://github.com/golang/go/blob/98cbf45cfc6a5a50cc6ac2367f9572cb198b57c7/src/go/types/gccgosizes.go + * where the first field of the struct is 4 for 32-bit architectures + * and 8 for 64-bit architectures. + */ +class Architecture extends string { + int bitSize; + + Architecture() { + this in ["386", "amd64p32", "arm", "armbe", "mips", "mipsle", "mips64p32", "mips64p32le", "ppc", + "s390", "sparc"] and + bitSize = 32 + or + this in ["amd64", "arm64", "arm64be", "ppc64", "ppc64le", "mips64", "mips64le", "s390x", + "sparc64"] and + bitSize = 64 + } + + int getBitSize() { result = bitSize } +} diff --git a/ql/src/semmle/go/Comments.qll b/ql/src/semmle/go/Comments.qll index 3dce789efba..2a765c5e972 100644 --- a/ql/src/semmle/go/Comments.qll +++ b/ql/src/semmle/go/Comments.qll @@ -211,4 +211,10 @@ class BuildConstraintComment extends LineComment { } override string getAPrimaryQlClass() { result = "BuildConstraintComment" } + + /** Gets the body of this build constraint. */ + string getConstraintBody() { result = getText().splitAt("+build ", 1) } + + /** Gets a disjunct of this build constraint. */ + string getADisjunct() { result = getConstraintBody().splitAt(" ") } } diff --git a/ql/src/semmle/go/Files.qll b/ql/src/semmle/go/Files.qll index 5e3e1151b74..717632486b0 100644 --- a/ql/src/semmle/go/Files.qll +++ b/ql/src/semmle/go/Files.qll @@ -203,44 +203,27 @@ class File extends Container, @file, Documentable, ExprParent, GoModExprParent, pragma[noinline] predicate hasBuildConstraints() { exists(BuildConstraintComment bc | this = bc.getFile()) } - /** - * Gets an architecture that is valid in a build constraint with bit - * size `bitSize`. - * - * Information obtained from - * https://github.com/golang/go/blob/98cbf45cfc6a5a50cc6ac2367f9572cb198b57c7/src/go/types/gccgosizes.go - * where the first field of the struct is 4 for 32-bit architectures - * and 8 for 64-bit architectures. - */ - private string getAnArchitecture(int bitSize) { - bitSize = 32 and - result in ["386", "amd64p32", "arm", "armbe", "mips", "mipsle", "mips64p32", "mips64p32le", - "ppc", "s390", "sparc"] - or - bitSize = 64 and - result in ["amd64", "arm64", "arm64be", "ppc64", "ppc64le", "mips64", "mips64le", "s390x", - "sparc64"] - } - /** * Holds if this file contains build constraints that ensure that it - * is only built on architectures of bit size `bitSize`. + * is only built on architectures of bit size `bitSize`, which can be + * 32 or 64. */ - predicate hasConstrainedIntBitSize(int bitSize) { - hasExplicitBuildConstraintsForArchitectures(bitSize) or - hasImplicitBuildConstraintForAnArchitecture(bitSize) + predicate constrainsIntBitSize(int bitSize) { + explicitlyConstrainsIntBitSize(bitSize) or + implicitlyConstrainsIntBitSize(bitSize) } /** * Holds if this file contains explicit build constraints that ensure - * that it is only built on an architecture of bit size `bitSize`. + * that it is only built on an architecture of bit size `bitSize`, + * which can be 32 or 64. */ - predicate hasExplicitBuildConstraintsForArchitectures(int bitSize) { + predicate explicitlyConstrainsIntBitSize(int bitSize) { exists(BuildConstraintComment bcc, string bc | this = bcc.getFile() and bc = bcc.getText().splitAt("+build ", 1) | - forex(string disjunct | disjunct = bc.splitAt(" ") | - disjunct.splitAt(",").matches(getAnArchitecture(bitSize)) + forex(string disjunct | disjunct = bcc.getADisjunct() | + disjunct.splitAt(",").(Architecture).getBitSize() = bitSize ) ) } @@ -248,10 +231,12 @@ class File extends Container, @file, Documentable, ExprParent, GoModExprParent, /** * Holds if this file has a name which acts as an implicit build * constraint that ensures that it is only built on an - * architecture of bit size `bitSize`. + * architecture of bit size `bitSize`, which can be 32 or 64. */ - predicate hasImplicitBuildConstraintForAnArchitecture(int bitSize) { - this.getStem().regexpMatch(".*_" + getAnArchitecture(bitSize) + "(_test)?") + predicate implicitlyConstrainsIntBitSize(int bitSize) { + this + .getStem() + .regexpMatch(".*_" + any(Architecture arch | arch.getBitSize() = bitSize) + "(_test)?") } override string toString() { result = Container.super.toString() } From 951d59752afebd1adca3dbf762fa74d3361c99fa Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 13 Aug 2020 16:17:36 +0100 Subject: [PATCH 16/16] Address review comments 7 --- .../CWE-681/IncorrectIntegerConversion.ql | 6 +- ql/src/semmle/go/Files.qll | 10 +- .../IncorrectIntegerConversion.expected | 132 +++++++++--------- 3 files changed, 73 insertions(+), 75 deletions(-) diff --git a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql index c38b0092041..6a68c41501b 100644 --- a/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql +++ b/ql/src/Security/CWE-681/IncorrectIntegerConversion.ql @@ -196,8 +196,8 @@ from DataFlow::PathNode source, DataFlow::PathNode sink, ConversionWithoutBoundsCheckConfig cfg, DataFlow::CallNode call where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode() -select source.getNode(), source, sink, +select sink.getNode(), source, sink, "Incorrect conversion of " + describeBitSize(cfg.getSourceBitSize(), getIntTypeBitSize(source.getNode().getFile())) + - " from " + call.getTarget().getQualifiedName() + " to a lower bit size type " + - sink.getNode().getType().getUnderlyingType().getName() + " without an upper bound check." + " from $@ to a lower bit size type " + sink.getNode().getType().getUnderlyingType().getName() + + " without an upper bound check.", source, call.getTarget().getQualifiedName() diff --git a/ql/src/semmle/go/Files.qll b/ql/src/semmle/go/Files.qll index 717632486b0..7bf684cb9c7 100644 --- a/ql/src/semmle/go/Files.qll +++ b/ql/src/semmle/go/Files.qll @@ -219,9 +219,7 @@ class File extends Container, @file, Documentable, ExprParent, GoModExprParent, * which can be 32 or 64. */ predicate explicitlyConstrainsIntBitSize(int bitSize) { - exists(BuildConstraintComment bcc, string bc | - this = bcc.getFile() and bc = bcc.getText().splitAt("+build ", 1) - | + exists(BuildConstraintComment bcc | this = bcc.getFile() | forex(string disjunct | disjunct = bcc.getADisjunct() | disjunct.splitAt(",").(Architecture).getBitSize() = bitSize ) @@ -234,9 +232,9 @@ class File extends Container, @file, Documentable, ExprParent, GoModExprParent, * architecture of bit size `bitSize`, which can be 32 or 64. */ predicate implicitlyConstrainsIntBitSize(int bitSize) { - this - .getStem() - .regexpMatch(".*_" + any(Architecture arch | arch.getBitSize() = bitSize) + "(_test)?") + exists(Architecture arch | arch.getBitSize() = bitSize | + this.getStem().regexpMatch("(?i).*_\\Q" + arch + "\\E(_test)?") + ) } override string toString() { result = Container.super.toString() } diff --git a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected index f582ad14120..a1bf571c4d7 100644 --- a/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected +++ b/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -179,69 +179,69 @@ nodes | TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | semmle.label | type conversion | | TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | semmle.label | type conversion | #select -| IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:70:7:70:19 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:85:7:85:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:86:7:86:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:87:7:87:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:88:7:88:20 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:101:7:101:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:102:7:102:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:103:7:103:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:104:7:104:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:105:7:105:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:106:7:106:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:109:7:109:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int without an upper bound check. | -| IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:110:7:110:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | -| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:152:7:152:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:153:7:153:19 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:168:7:168:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:169:7:169:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:170:7:170:19 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:171:7:171:20 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:184:7:184:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:185:7:185:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:186:7:186:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:187:7:187:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:188:7:188:19 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:189:7:189:20 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint32 without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:192:7:192:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type int without an upper bound check. | -| IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:193:7:193:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseUint to a lower bit size type uint without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseUint to a lower bit size type uint32 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type uint32 without an upper bound check. | -| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:240:7:240:18 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.Atoi to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseUint to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] | IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:334:9:334:21 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] | IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:8:342:20 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] | IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:351:9:351:17 | type conversion | Incorrect conversion of a 32-bit integer from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] | IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:362:7:362:14 | type conversion | Incorrect conversion of a 16-bit integer from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:371:6:371:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int8 without an upper bound check. | -| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:372:6:372:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint8 without an upper bound check. | -| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:373:6:373:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int16 without an upper bound check. | -| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint16 without an upper bound check. | -| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | -| IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | -| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type int32 without an upper bound check. | -| TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from strconv.ParseInt to a lower bit size type uint32 without an upper bound check. | -| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type int without an upper bound check. | -| TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | Incorrect conversion of a 64-bit integer from strconv.ParseInt to a lower bit size type uint without an upper bound check. | +| IncorrectIntegerConversion.go:35:41:35:50 | type conversion | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | IncorrectIntegerConversion.go:35:41:35:50 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:26:2:26:28 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:69:7:69:18 | type conversion | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:69:7:69:18 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:70:7:70:19 | type conversion | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:70:7:70:19 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:65:3:65:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:85:7:85:18 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:85:7:85:18 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:86:7:86:19 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:86:7:86:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:87:7:87:19 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:87:7:87:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:88:7:88:20 | type conversion | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:88:7:88:20 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:81:3:81:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:101:7:101:18 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:101:7:101:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:102:7:102:19 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:102:7:102:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:103:7:103:19 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:103:7:103:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:104:7:104:20 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:104:7:104:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:105:7:105:19 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:105:7:105:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:106:7:106:20 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:106:7:106:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:109:7:109:17 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:109:7:109:17 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:110:7:110:18 | type conversion | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:110:7:110:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint without an upper bound check. | IncorrectIntegerConversion.go:97:3:97:49 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:117:7:117:18 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:117:7:117:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:118:7:118:19 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:118:7:118:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:119:7:119:19 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:119:7:119:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:120:7:120:20 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:120:7:120:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:121:7:121:19 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:121:7:121:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:122:7:122:20 | type conversion | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:122:7:122:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:113:3:113:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:152:7:152:18 | type conversion | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:152:7:152:18 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:153:7:153:19 | type conversion | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:153:7:153:19 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:148:3:148:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:168:7:168:18 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:168:7:168:18 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:169:7:169:19 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:169:7:169:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:170:7:170:19 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:170:7:170:19 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:171:7:171:20 | type conversion | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:171:7:171:20 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:164:3:164:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:184:7:184:18 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:184:7:184:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:185:7:185:19 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:185:7:185:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:186:7:186:19 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:186:7:186:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:187:7:187:20 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:187:7:187:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:188:7:188:19 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:188:7:188:19 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:189:7:189:20 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:189:7:189:20 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:192:7:192:17 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:192:7:192:17 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:193:7:193:18 | type conversion | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:193:7:193:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint without an upper bound check. | IncorrectIntegerConversion.go:180:3:180:50 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:200:7:200:18 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:200:7:200:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:201:7:201:19 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:201:7:201:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:202:7:202:19 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:202:7:202:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:203:7:203:20 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:203:7:203:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:204:7:204:19 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:204:7:204:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:205:7:205:20 | type conversion | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:205:7:205:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:196:3:196:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:218:6:218:17 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:218:6:218:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:219:6:219:18 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:219:6:219:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:220:6:220:18 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:220:6:220:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:221:6:221:19 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:221:6:221:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:222:6:222:18 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:222:6:222:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:223:6:223:19 | type conversion | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:223:6:223:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:214:2:214:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:240:7:240:18 | type conversion | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:240:7:240:18 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:241:7:241:23 | type conversion | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:241:7:241:23 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:235:3:235:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:261:8:261:19 | type conversion | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | IncorrectIntegerConversion.go:261:8:261:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:247:3:247:36 | ... := ...[0] : int | strconv.Atoi | +| IncorrectIntegerConversion.go:282:8:282:21 | type conversion | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | IncorrectIntegerConversion.go:282:8:282:21 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:268:3:268:49 | ... := ...[0] : uint64 | strconv.ParseUint | +| IncorrectIntegerConversion.go:323:7:323:18 | type conversion | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:323:7:323:18 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:319:3:319:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:334:9:334:21 | type conversion | IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:334:9:334:21 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:330:3:330:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:342:8:342:20 | type conversion | IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:342:8:342:20 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:338:3:338:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:351:9:351:17 | type conversion | IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:351:9:351:17 | type conversion | Incorrect conversion of a 32-bit integer from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:346:3:346:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:362:7:362:14 | type conversion | IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:362:7:362:14 | type conversion | Incorrect conversion of a 16-bit integer from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:355:3:355:48 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:371:6:371:17 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:371:6:371:17 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int8 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:372:6:372:18 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:372:6:372:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint8 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:373:6:373:18 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:373:6:373:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int16 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:374:6:374:19 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:374:6:374:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint16 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:375:6:375:18 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:375:6:375:18 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| IncorrectIntegerConversion.go:376:6:376:19 | type conversion | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | IncorrectIntegerConversion.go:376:6:376:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | IncorrectIntegerConversion.go:367:2:367:60 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:16:7:16:19 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type int32 without an upper bound check. | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:17:7:17:20 | type conversion | Incorrect conversion of an integer with architecture-dependent bit size from $@ to a lower bit size type uint32 without an upper bound check. | TestNoArchitectureBuildConstraints.go:12:3:12:48 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:24:7:24:17 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type int without an upper bound check. | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | strconv.ParseInt | +| TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | TestNoArchitectureBuildConstraints.go:25:7:25:18 | type conversion | Incorrect conversion of a 64-bit integer from $@ to a lower bit size type uint without an upper bound check. | TestNoArchitectureBuildConstraints.go:20:3:20:49 | ... := ...[0] : int64 | strconv.ParseInt |