From 4b36a62834692e37b3af3be4dce2434a566fb292 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 3 Jan 2021 00:51:34 +0300 Subject: [PATCH 01/12] divide by zero rule --- .../experimental/CWE-369/DivideByZero.qhelp | 23 ++++++++ ql/src/experimental/CWE-369/DivideByZero.ql | 57 +++++++++++++++++++ .../experimental/CWE-369/DivideByZeroBad.go | 19 +++++++ 3 files changed, 99 insertions(+) create mode 100644 ql/src/experimental/CWE-369/DivideByZero.qhelp create mode 100644 ql/src/experimental/CWE-369/DivideByZero.ql create mode 100644 ql/src/experimental/CWE-369/DivideByZeroBad.go diff --git a/ql/src/experimental/CWE-369/DivideByZero.qhelp b/ql/src/experimental/CWE-369/DivideByZero.qhelp new file mode 100644 index 00000000000..c2b4d546866 --- /dev/null +++ b/ql/src/experimental/CWE-369/DivideByZero.qhelp @@ -0,0 +1,23 @@ + + + +

+ 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. +

+
+ +

+ 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(). +

+
+ +

+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. +

+ +
+
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql new file mode 100644 index 00000000000..7670f3a5dae --- /dev/null +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -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() \ No newline at end of file diff --git a/ql/src/experimental/CWE-369/DivideByZeroBad.go b/ql/src/experimental/CWE-369/DivideByZeroBad.go new file mode 100644 index 00000000000..be70aca3f8f --- /dev/null +++ b/ql/src/experimental/CWE-369/DivideByZeroBad.go @@ -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 +} \ No newline at end of file From d81ec159900a2192574754f800205022f7124cbf Mon Sep 17 00:00:00 2001 From: monkey-junkie Date: Sun, 3 Jan 2021 00:54:42 +0300 Subject: [PATCH 02/12] Update DivideByZeroBad.go --- ql/src/experimental/CWE-369/DivideByZeroBad.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/experimental/CWE-369/DivideByZeroBad.go b/ql/src/experimental/CWE-369/DivideByZeroBad.go index be70aca3f8f..cb943aa82b8 100644 --- a/ql/src/experimental/CWE-369/DivideByZeroBad.go +++ b/ql/src/experimental/CWE-369/DivideByZeroBad.go @@ -16,4 +16,4 @@ func main() { out := val1 / value fmt.Println(out) return -} \ No newline at end of file +} From de566da91c9b677bea76ca543972263fed878af5 Mon Sep 17 00:00:00 2001 From: monkey-junkie Date: Sun, 3 Jan 2021 00:55:10 +0300 Subject: [PATCH 03/12] Update DivideByZero.ql --- ql/src/experimental/CWE-369/DivideByZero.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 7670f3a5dae..741f0155195 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -54,4 +54,4 @@ from 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() \ No newline at end of file + sink, sink.getNode().toString() From 3251fb5c07047218ff0be7d306cb4560dd27f7d2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 18 Jan 2021 02:37:53 +0300 Subject: [PATCH 04/12] updated --- ql/src/experimental/CWE-369/DivideByZero.ql | 50 ++++++++++++--------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 741f0155195..a7a16b2f9c5 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -12,13 +12,23 @@ import go import DataFlow::PathGraph +import semmle.go.dataflow.internal.TaintTrackingUtil -class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode { +class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard { override predicate checks(Expr e, boolean branch) { - exists(DataFlow::Node zero, DataFlow::Node sink | + exists( + DataFlow::Node zero, DataFlow::Node sink, DataFlow::EqualityTestNode eqNode, + DataFlow::RelationalComparisonNode compNode + | zero.getNumericValue() = 0 and - sink.getType().getUnderlyingType() instanceof SignedIntegerType and - this.eq(branch.booleanNot(), sink, zero) and + ( + sink.getType().getUnderlyingType() instanceof SignedIntegerType or + sink.getType().getUnderlyingType() instanceof UnsignedIntegerType + ) and + ( + eqNode.eq(branch.booleanNot(), sink, zero) or + compNode.leq(branch.booleanNot(), sink, zero, 0) + ) and globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(sink) ) } @@ -27,31 +37,31 @@ class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard, DataFlow::Equali 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 isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } - 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 isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(Function f | + ( + f.getName() = "Atoi" or + f.getName() = "ParseInt" or + f.getName() = "ParseUint" + ) and + node1 = f.getACall().getArgument(0) and + node2 = f.getACall().getResult(0) ) } override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { guard instanceof DivideByZeroSanitizeGuard } + + override predicate isSink(DataFlow::Node sink) { + exists(QuoExpr e | sink.asExpr().getParent().(QuoExpr).getRightOperand() = e.getAnOperand()) + } } -from - DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg, - DataFlow::CallNode call -where cfg.hasFlowPath(source, sink) and call.getResult(0) = source.getNode() +from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg +where cfg.hasFlowPath(source, sink) 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() From c8da633d7be0a902ada454a8524733e1cce3f892 Mon Sep 17 00:00:00 2001 From: monkey-junkie Date: Thu, 21 Jan 2021 00:54:00 +0300 Subject: [PATCH 05/12] Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton --- ql/src/experimental/CWE-369/DivideByZero.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index a7a16b2f9c5..cb147b8f48a 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -22,8 +22,7 @@ class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard { | zero.getNumericValue() = 0 and ( - sink.getType().getUnderlyingType() instanceof SignedIntegerType or - sink.getType().getUnderlyingType() instanceof UnsignedIntegerType + sink.getType().getUnderlyingType() instanceof IntegerType ) and ( eqNode.eq(branch.booleanNot(), sink, zero) or From ad22445d1630a20d158b4ff1b8b9c20222568ff2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 Jan 2021 01:52:00 +0300 Subject: [PATCH 06/12] refactor --- ql/src/experimental/CWE-369/DivideByZero.ql | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index cb147b8f48a..23cbd206578 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -17,18 +17,17 @@ import semmle.go.dataflow.internal.TaintTrackingUtil class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard { override predicate checks(Expr e, boolean branch) { exists( - DataFlow::Node zero, DataFlow::Node sink, DataFlow::EqualityTestNode eqNode, + DataFlow::Node zero, DataFlow::Node checked, DataFlow::EqualityTestNode eqNode, DataFlow::RelationalComparisonNode compNode | zero.getNumericValue() = 0 and ( - sink.getType().getUnderlyingType() instanceof IntegerType + checked.getType().getUnderlyingType() instanceof IntegerType ) and ( - eqNode.eq(branch.booleanNot(), sink, zero) or - compNode.leq(branch.booleanNot(), sink, zero, 0) - ) and - globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(sink) + this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or + this.(RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0) + ) ) } } @@ -41,9 +40,9 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { exists(Function f | ( - f.getName() = "Atoi" or - f.getName() = "ParseInt" or - f.getName() = "ParseUint" + f.hasQualifiedName() = "Atoi" or + f.hasQualifiedName() = "ParseInt" or + f.hasQualifiedName() = "ParseUint" ) and node1 = f.getACall().getArgument(0) and node2 = f.getACall().getResult(0) From a77f36fba850eee1ed43ce28e1dcfee63df4b95d Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 Jan 2021 01:57:19 +0300 Subject: [PATCH 07/12] formatting fix Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton --- ql/src/experimental/CWE-369/DivideByZero.ql | 31 +++++++++++---------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 23cbd206578..314f2f8a9a1 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -15,20 +15,23 @@ import DataFlow::PathGraph import semmle.go.dataflow.internal.TaintTrackingUtil class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard { + + DivideByZeroSanitizeGuard() { + this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or + this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0 + } + override predicate checks(Expr e, boolean branch) { - exists( - DataFlow::Node zero, DataFlow::Node checked, DataFlow::EqualityTestNode eqNode, - DataFlow::RelationalComparisonNode compNode - | - zero.getNumericValue() = 0 and - ( - checked.getType().getUnderlyingType() instanceof IntegerType - ) and - ( - this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or - this.(RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0) + exists(DataFlow::Node zero, DataFlow::Node checked + | + zero.getNumericValue() = 0 and + e = checked.asExpr() and + checked.getType().getUnderlyingType() instanceof IntegerType and + ( + this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or + this.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0) + ) ) - ) } } @@ -40,9 +43,7 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { exists(Function f | ( - f.hasQualifiedName() = "Atoi" or - f.hasQualifiedName() = "ParseInt" or - f.hasQualifiedName() = "ParseUint" + f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) ) and node1 = f.getACall().getArgument(0) and node2 = f.getACall().getResult(0) From 41e808dab43f27945e549475f9a2e1a6ae6ed8fc Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 25 Jan 2021 03:40:26 +0300 Subject: [PATCH 08/12] conversion detect + tests --- ql/src/experimental/CWE-369/DivideByZero.ql | 27 ++++++++++--------- .../CWE-369/DivideByZero.expected | 13 +++++++++ ql/test/experimental/CWE-369/DivideByZero.go | 21 +++++++++++++++ .../experimental/CWE-369/DivideByZero.qlref | 1 + 4 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 ql/test/experimental/CWE-369/DivideByZero.expected create mode 100644 ql/test/experimental/CWE-369/DivideByZero.go create mode 100644 ql/test/experimental/CWE-369/DivideByZero.qlref diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 314f2f8a9a1..389f49f262a 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -15,23 +15,21 @@ import DataFlow::PathGraph import semmle.go.dataflow.internal.TaintTrackingUtil class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard { - DivideByZeroSanitizeGuard() { this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0 } override predicate checks(Expr e, boolean branch) { - exists(DataFlow::Node zero, DataFlow::Node checked - | - zero.getNumericValue() = 0 and - e = checked.asExpr() and - checked.getType().getUnderlyingType() instanceof IntegerType and - ( - this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or - this.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0) - ) + exists(DataFlow::Node zero, DataFlow::Node checked | + zero.getNumericValue() = 0 and + e = checked.asExpr() and + checked.getType().getUnderlyingType() instanceof IntegerType and + ( + this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or + this.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0) ) + ) } } @@ -42,12 +40,15 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { exists(Function f | - ( - f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) - ) and + f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and node1 = f.getACall().getArgument(0) and node2 = f.getACall().getResult(0) ) + or + exists(ConversionExpr ce | ce.getType().getUnderlyingType() instanceof IntegerType | + node1.asExpr() = ce.getOperand() and + node2.asExpr() = ce.getAChildExpr() + ) } override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected new file mode 100644 index 00000000000..85d634ae3c0 --- /dev/null +++ b/ql/test/experimental/CWE-369/DivideByZero.expected @@ -0,0 +1,13 @@ +edges +| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value | +| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:752:11:752:24 | type conversion : uint8 | +| DivideByZero.go:752:11:752:24 | type conversion : uint8 | DivideByZero.go:753:16:753:20 | value | +nodes +| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:745:16:745:20 | value | semmle.label | value | +| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:752:11:752:24 | type conversion : uint8 | semmle.label | type conversion : uint8 | +| DivideByZero.go:753:16:753:20 | value | semmle.label | value | +#select +| DivideByZero.go:745:16:745:20 | value | DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:745:16:745:20 | value | value | +| DivideByZero.go:753:16:753:20 | value | DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:753:16:753:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:753:16:753:20 | value | value | \ No newline at end of file diff --git a/ql/test/experimental/CWE-369/DivideByZero.go b/ql/test/experimental/CWE-369/DivideByZero.go new file mode 100644 index 00000000000..575d23504f3 --- /dev/null +++ b/ql/test/experimental/CWE-369/DivideByZero.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "net/http" + "strconv" +) + +func myHandler1(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value, _ := strconv.Atoi(param1) + out := 1337 / value + fmt.Println(out) +} + +func myHandler2(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value := int(param1[0]) + out := 1337 / value + fmt.Println(out) +} diff --git a/ql/test/experimental/CWE-369/DivideByZero.qlref b/ql/test/experimental/CWE-369/DivideByZero.qlref new file mode 100644 index 00000000000..6aae6de95d7 --- /dev/null +++ b/ql/test/experimental/CWE-369/DivideByZero.qlref @@ -0,0 +1 @@ +experimental/CWE-369/DivideByZero.ql From 8c5e0a42b396e310b50a0612e7e8a189e220a5b5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 26 Jan 2021 03:07:36 +0300 Subject: [PATCH 09/12] test fixed Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton --- ql/src/experimental/CWE-369/DivideByZero.ql | 6 +++--- .../CWE-369/DivideByZero.expected | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 389f49f262a..4fde3b6164b 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -14,7 +14,7 @@ import go import DataFlow::PathGraph import semmle.go.dataflow.internal.TaintTrackingUtil -class DivideByZeroSanitizeGuard extends DataFlow::BarrierGuard { +class DivideByZeroSanitizerGuard extends DataFlow::BarrierGuard { DivideByZeroSanitizeGuard() { this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0 @@ -38,7 +38,7 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } - override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { exists(Function f | f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and node1 = f.getACall().getArgument(0) and @@ -63,5 +63,5 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg where cfg.hasFlowPath(source, sink) select sink, source, sink, - "Variable $@, which is used at division statement might be zero and leads to division by zero exception.", + "Variable $@, which is used at division statement might be zero leading to a division-by-zero panic.", sink, sink.getNode().toString() diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected index 85d634ae3c0..0d22d93159d 100644 --- a/ql/test/experimental/CWE-369/DivideByZero.expected +++ b/ql/test/experimental/CWE-369/DivideByZero.expected @@ -1,13 +1,13 @@ edges -| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value | -| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:752:11:752:24 | type conversion : uint8 | -| DivideByZero.go:752:11:752:24 | type conversion : uint8 | DivideByZero.go:753:16:753:20 | value | +| DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | +| DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:18:11:18:24 | type conversion : uint8 | +| DivideByZero.go:18:11:18:24 | type conversion : uint8 | DivideByZero.go:19:16:19:20 | value | nodes -| DivideByZero.go:743:12:743:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | -| DivideByZero.go:745:16:745:20 | value | semmle.label | value | -| DivideByZero.go:751:12:751:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | -| DivideByZero.go:752:11:752:24 | type conversion : uint8 | semmle.label | type conversion : uint8 | -| DivideByZero.go:753:16:753:20 | value | semmle.label | value | +| DivideByZero.go:10:12:10:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:12:16:12:20 | value | semmle.label | value | +| DivideByZero.go:17:12:17:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 | +| DivideByZero.go:19:16:19:20 | value | semmle.label | value | #select -| DivideByZero.go:745:16:745:20 | value | DivideByZero.go:743:12:743:16 | selection of URL : pointer type | DivideByZero.go:745:16:745:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:745:16:745:20 | value | value | -| DivideByZero.go:753:16:753:20 | value | DivideByZero.go:751:12:751:16 | selection of URL : pointer type | DivideByZero.go:753:16:753:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:753:16:753:20 | value | value | \ No newline at end of file +| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:12:16:12:20 | value | value | +| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:19:16:19:20 | value | value | From bd09868686dffa21b97365c078620d5b3e58106f Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 27 Jan 2021 03:46:50 +0300 Subject: [PATCH 10/12] test fixed, comments added Update ql/src/experimental/CWE-369/DivideByZero.qhelp Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.qhelp Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.qhelp Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton --- .../experimental/CWE-369/DivideByZero.qhelp | 11 ++++----- ql/src/experimental/CWE-369/DivideByZero.ql | 23 ++++++++++--------- .../CWE-369/DivideByZero.expected | 4 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.qhelp b/ql/src/experimental/CWE-369/DivideByZero.qhelp index c2b4d546866..2fadf452e48 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.qhelp +++ b/ql/src/experimental/CWE-369/DivideByZero.qhelp @@ -3,20 +3,19 @@

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. + In Go, integer divide by zero leads to a panic, which might interrupt execution of the program and lead to program termination.

- 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(). + Check that all user inputs used as a divisor are non-zero. It is also possible to handle a panic, + generated by division by zero, using the built-in function recover.

-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. +The following example shows data received from user input being used as a divisor and +possibly causing a divide-by-zero panic.

diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 4fde3b6164b..70f0b0f38c6 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -14,8 +14,11 @@ import go import DataFlow::PathGraph import semmle.go.dataflow.internal.TaintTrackingUtil +/** + * A barrier-guard, which represents comparison and equality with zero. + */ class DivideByZeroSanitizerGuard extends DataFlow::BarrierGuard { - DivideByZeroSanitizeGuard() { + DivideByZeroSanitizerGuard() { this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0 } @@ -33,6 +36,9 @@ class DivideByZeroSanitizerGuard extends DataFlow::BarrierGuard { } } +/** + * A taint-tracking configuration for reasoning about division by zero, where divisor is user-controlled and unchecked. + */ class DivideByZeroCheckConfig extends TaintTracking::Configuration { DivideByZeroCheckConfig() { this = "DivideByZeroCheckConfig" } @@ -41,27 +47,22 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { exists(Function f | f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and - node1 = f.getACall().getArgument(0) and - node2 = f.getACall().getResult(0) - ) - or - exists(ConversionExpr ce | ce.getType().getUnderlyingType() instanceof IntegerType | - node1.asExpr() = ce.getOperand() and - node2.asExpr() = ce.getAChildExpr() + pred = f.getACall().getArgument(0) and + succ = f.getACall().getResult(0) ) } override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { - guard instanceof DivideByZeroSanitizeGuard + guard instanceof DivideByZeroSanitizerGuard } override predicate isSink(DataFlow::Node sink) { - exists(QuoExpr e | sink.asExpr().getParent().(QuoExpr).getRightOperand() = e.getAnOperand()) + sink = DataFlow::exprNode(any(QuoExpr e).getRightOperand()) } } from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg where cfg.hasFlowPath(source, sink) select sink, source, sink, - "Variable $@, which is used at division statement might be zero leading to a division-by-zero panic.", + "Variable $@ might be zero leading to a division-by-zero panic.", sink, sink.getNode().toString() diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected index 0d22d93159d..f62d9ed3ef4 100644 --- a/ql/test/experimental/CWE-369/DivideByZero.expected +++ b/ql/test/experimental/CWE-369/DivideByZero.expected @@ -9,5 +9,5 @@ nodes | DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 | | DivideByZero.go:19:16:19:20 | value | semmle.label | value | #select -| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:12:16:12:20 | value | value | -| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero and leads to division by zero exception. | DivideByZero.go:19:16:19:20 | value | value | +| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value | +| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value | From 4b24e5641ea78c4e16f93bd76932a030b7bf926d Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 27 Jan 2021 22:33:33 +0300 Subject: [PATCH 11/12] formatting + example fix test fix Update ql/src/experimental/CWE-369/DivideByZero.ql Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.qhelp Co-authored-by: Chris Smowton Update ql/src/experimental/CWE-369/DivideByZero.qhelp Co-authored-by: Chris Smowton --- .../experimental/CWE-369/DivideByZero.qhelp | 7 ++++-- ql/src/experimental/CWE-369/DivideByZero.ql | 9 +++----- .../experimental/CWE-369/DivideByZeroGood.go | 23 +++++++++++++++++++ .../CWE-369/DivideByZero.expected | 4 ++-- 4 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 ql/src/experimental/CWE-369/DivideByZeroGood.go diff --git a/ql/src/experimental/CWE-369/DivideByZero.qhelp b/ql/src/experimental/CWE-369/DivideByZero.qhelp index 2fadf452e48..ae39d1df890 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.qhelp +++ b/ql/src/experimental/CWE-369/DivideByZero.qhelp @@ -2,8 +2,7 @@

- Divide by zero is division where the divisor (denominator) is zero. - In Go, integer divide by zero leads to a panic, which might interrupt execution of the program and lead to program termination. + In Go, dividing an integer by zero leads to a panic, which might interrupt execution of the program and lead to program termination.

@@ -18,5 +17,9 @@ The following example shows data received from user input being used as a diviso possibly causing a divide-by-zero panic.

+

+This can be fixed by testing the divisor against against zero: +

+
diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 70f0b0f38c6..8f7b0bf205d 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -1,8 +1,6 @@ /** * @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. + * @description Dividing an integer by a user-controlled value may lead to division by zero and an unexpected panic. * @kind path-problem * @problem.severity error * @id go/divide-by-zero @@ -63,6 +61,5 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg where cfg.hasFlowPath(source, sink) -select sink, source, sink, - "Variable $@ might be zero leading to a division-by-zero panic.", - sink, sink.getNode().toString() +select sink, source, sink, "Variable $@ might be zero leading to a division-by-zero panic.", sink, + sink.getNode().toString() diff --git a/ql/src/experimental/CWE-369/DivideByZeroGood.go b/ql/src/experimental/CWE-369/DivideByZeroGood.go new file mode 100644 index 00000000000..3b80421322b --- /dev/null +++ b/ql/src/experimental/CWE-369/DivideByZeroGood.go @@ -0,0 +1,23 @@ +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]) + if value == 0 { + fmt.Println("Division by zero attempted!") + return + } + out := val1 / value + fmt.Println(out) + return +} diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected index f62d9ed3ef4..215db52ab8c 100644 --- a/ql/test/experimental/CWE-369/DivideByZero.expected +++ b/ql/test/experimental/CWE-369/DivideByZero.expected @@ -9,5 +9,5 @@ nodes | DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 | | DivideByZero.go:19:16:19:20 | value | semmle.label | value | #select -| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value | -| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@, which is used at division statement might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value | +| DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value | +| DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value | From c29ab8958f85381fabc4750c2999741bdb0fb444 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Feb 2021 00:04:52 +0300 Subject: [PATCH 12/12] tests and docs updated --- ql/src/experimental/CWE-369/DivideByZero.ql | 6 +- .../CWE-369/DivideByZero.expected | 18 ++++++ ql/test/experimental/CWE-369/DivideByZero.go | 59 +++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/ql/src/experimental/CWE-369/DivideByZero.ql b/ql/src/experimental/CWE-369/DivideByZero.ql index 8f7b0bf205d..5b4518b1c6e 100644 --- a/ql/src/experimental/CWE-369/DivideByZero.ql +++ b/ql/src/experimental/CWE-369/DivideByZero.ql @@ -43,10 +43,10 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(Function f | + exists(Function f, DataFlow::CallNode cn | cn = f.getACall() | f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and - pred = f.getACall().getArgument(0) and - succ = f.getACall().getResult(0) + pred = cn.getArgument(0) and + succ = cn.getResult(0) ) } diff --git a/ql/test/experimental/CWE-369/DivideByZero.expected b/ql/test/experimental/CWE-369/DivideByZero.expected index 215db52ab8c..370d5d099c4 100644 --- a/ql/test/experimental/CWE-369/DivideByZero.expected +++ b/ql/test/experimental/CWE-369/DivideByZero.expected @@ -2,12 +2,30 @@ edges | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:18:11:18:24 | type conversion : uint8 | | DivideByZero.go:18:11:18:24 | type conversion : uint8 | DivideByZero.go:19:16:19:20 | value | +| DivideByZero.go:24:12:24:16 | selection of URL : pointer type | DivideByZero.go:26:16:26:20 | value | +| DivideByZero.go:31:12:31:16 | selection of URL : pointer type | DivideByZero.go:33:16:33:20 | value | +| DivideByZero.go:38:12:38:16 | selection of URL : pointer type | DivideByZero.go:40:16:40:20 | value | +| DivideByZero.go:54:12:54:16 | selection of URL : pointer type | DivideByZero.go:55:11:55:24 | type conversion : uint8 | +| DivideByZero.go:55:11:55:24 | type conversion : uint8 | DivideByZero.go:57:17:57:21 | value | nodes | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | | DivideByZero.go:12:16:12:20 | value | semmle.label | value | | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | | DivideByZero.go:18:11:18:24 | type conversion : uint8 | semmle.label | type conversion : uint8 | | DivideByZero.go:19:16:19:20 | value | semmle.label | value | +| DivideByZero.go:24:12:24:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:26:16:26:20 | value | semmle.label | value | +| DivideByZero.go:31:12:31:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:33:16:33:20 | value | semmle.label | value | +| DivideByZero.go:38:12:38:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:40:16:40:20 | value | semmle.label | value | +| DivideByZero.go:54:12:54:16 | selection of URL : pointer type | semmle.label | selection of URL : pointer type | +| DivideByZero.go:55:11:55:24 | type conversion : uint8 | semmle.label | type conversion : uint8 | +| DivideByZero.go:57:17:57:21 | value | semmle.label | value | #select | DivideByZero.go:12:16:12:20 | value | DivideByZero.go:10:12:10:16 | selection of URL : pointer type | DivideByZero.go:12:16:12:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:12:16:12:20 | value | value | | DivideByZero.go:19:16:19:20 | value | DivideByZero.go:17:12:17:16 | selection of URL : pointer type | DivideByZero.go:19:16:19:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:19:16:19:20 | value | value | +| DivideByZero.go:26:16:26:20 | value | DivideByZero.go:24:12:24:16 | selection of URL : pointer type | DivideByZero.go:26:16:26:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:26:16:26:20 | value | value | +| DivideByZero.go:33:16:33:20 | value | DivideByZero.go:31:12:31:16 | selection of URL : pointer type | DivideByZero.go:33:16:33:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:33:16:33:20 | value | value | +| DivideByZero.go:40:16:40:20 | value | DivideByZero.go:38:12:38:16 | selection of URL : pointer type | DivideByZero.go:40:16:40:20 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:40:16:40:20 | value | value | +| DivideByZero.go:57:17:57:21 | value | DivideByZero.go:54:12:54:16 | selection of URL : pointer type | DivideByZero.go:57:17:57:21 | value | Variable $@ might be zero leading to a division-by-zero panic. | DivideByZero.go:57:17:57:21 | value | value | diff --git a/ql/test/experimental/CWE-369/DivideByZero.go b/ql/test/experimental/CWE-369/DivideByZero.go index 575d23504f3..613479981b1 100644 --- a/ql/test/experimental/CWE-369/DivideByZero.go +++ b/ql/test/experimental/CWE-369/DivideByZero.go @@ -19,3 +19,62 @@ func myHandler2(w http.ResponseWriter, r *http.Request) { out := 1337 / value fmt.Println(out) } + +func myHandler3(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value, _ := strconv.ParseInt(param1, 10, 64) + out := 1337 / value + fmt.Println(out) +} + +func myHandler4(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value, _ := strconv.ParseFloat(param1, 32) + out := 1337 / value + fmt.Println(out) +} + +func myHandler5(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value, _ := strconv.ParseUint(param1, 10, 64) + out := 1337 / value + fmt.Println(out) +} + +func myHandler6(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value := int(param1[0]) + if value != 0 { + out := 1337 / value + fmt.Println(out) + } +} + +func myHandler7(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value := int(param1[0]) + if value >= 0 { + out := 1337 / value + fmt.Println(out) + } +} + +func myHandler8(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value, _ := strconv.ParseInt(param1, 10, 64) + if value > 0 { + out := 1337 / value + fmt.Println(out) + } +} + +func myHandler9(w http.ResponseWriter, r *http.Request) { + param1 := r.URL.Query()["param1"][0] + value, _ := strconv.ParseInt(param1, 10, 64) + if value == 0 { + fmt.Println(param1) + return + } + out := 1337 / value + fmt.Println(out) +}