mirror of
https://github.com/github/codeql.git
synced 2026-01-30 14:52:57 +01:00
divide by zero rule
This commit is contained in:
23
ql/src/experimental/CWE-369/DivideByZero.qhelp
Normal file
23
ql/src/experimental/CWE-369/DivideByZero.qhelp
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Divide by zero is division where the divisor (denominator) is zero.
|
||||
In Golang language, integer divide by zero leads to panic(), which might interrupt execution of the program and lead to program termination.
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Every user input should be checked for correctness, if needed.
|
||||
In case of divide by zero, comparison with zero should be added. It is also possible to handle panic(),
|
||||
generated by division by zero, by built-in function recover().
|
||||
</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>
|
||||
The following example shows simplified case, when data received from user input, which is used as a divisor and
|
||||
causes divide by zero with panic signal.
|
||||
</p>
|
||||
<sample src="DivideByZeroBad.go" />
|
||||
</example>
|
||||
</qhelp>
|
||||
57
ql/src/experimental/CWE-369/DivideByZero.ql
Normal file
57
ql/src/experimental/CWE-369/DivideByZero.ql
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @name Divide by zero
|
||||
* @description Converting the result of `strconv.Atoi`, `strconv.ParseInt`,
|
||||
* and `strconv.ParseUint` to integer types or use of integer types for division without checks
|
||||
* might lead to division by zero and panic, which cause denial of service.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id go/divide-by-zero
|
||||
* @tags security
|
||||
* external/cwe/cwe-369
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
|
||||
override predicate checks(Expr e, boolean branch) {
|
||||
exists(DataFlow::Node zero, DataFlow::Node sink |
|
||||
zero.getNumericValue() = 0 and
|
||||
sink.getType().getUnderlyingType() instanceof SignedIntegerType and
|
||||
this.eq(branch.booleanNot(), sink, zero) and
|
||||
globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(sink)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class DivideByZeroCheckConfig extends TaintTracking::Configuration {
|
||||
DivideByZeroCheckConfig() { this = "DivideByZeroCheckConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(DataFlow::CallNode c, IntegerParser::Range ip |
|
||||
c.getTarget() = ip and source = c.getResult(0)
|
||||
)
|
||||
or
|
||||
exists(IntegerType integerType | source.getType().getUnderlyingType() = integerType)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(IntegerType integerType, QuoExpr e |
|
||||
sink.asExpr().getParent().(QuoExpr).getRightOperand() = e.getAnOperand() and
|
||||
not sink.asExpr().getParent().(QuoExpr).getRightOperand().isConst() and
|
||||
sink.getType().getUnderlyingType() = integerType
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof DivideByZeroSanitizeGuard
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg,
|
||||
DataFlow::CallNode call
|
||||
where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode()
|
||||
select sink, source, sink,
|
||||
"Variable $@, which is used at division statement might be zero and leads to division by zero exception.",
|
||||
sink, sink.getNode().toString()
|
||||
19
ql/src/experimental/CWE-369/DivideByZeroBad.go
Normal file
19
ql/src/experimental/CWE-369/DivideByZeroBad.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Printf("Usage: ./program value\n")
|
||||
return
|
||||
}
|
||||
val1 := 1337
|
||||
value, _ := strconv.Atoi(os.Args[1])
|
||||
out := val1 / value
|
||||
fmt.Println(out)
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user