1// (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package rules 16 17import ( 18 "fmt" 19 "go/ast" 20 21 "github.com/securego/gosec/v2" 22) 23 24type integerOverflowCheck struct { 25 gosec.MetaData 26 calls gosec.CallList 27} 28 29func (i *integerOverflowCheck) ID() string { 30 return i.MetaData.ID 31} 32 33func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { 34 var atoiVarObj map[*ast.Object]ast.Node 35 36 // To check multiple lines, ctx.PassedValues is used to store temporary data. 37 if _, ok := ctx.PassedValues[i.ID()]; !ok { 38 atoiVarObj = make(map[*ast.Object]ast.Node) 39 ctx.PassedValues[i.ID()] = atoiVarObj 40 } else if pv, ok := ctx.PassedValues[i.ID()].(map[*ast.Object]ast.Node); ok { 41 atoiVarObj = pv 42 } else { 43 return nil, fmt.Errorf("PassedValues[%s] of Context is not map[*ast.Object]ast.Node, but %T", i.ID(), ctx.PassedValues[i.ID()]) 44 } 45 46 // strconv.Atoi is a common function. 47 // To reduce false positives, This rule detects code which is converted to int32/int16 only. 48 switch n := node.(type) { 49 case *ast.AssignStmt: 50 for _, expr := range n.Rhs { 51 if callExpr, ok := expr.(*ast.CallExpr); ok && i.calls.ContainsPkgCallExpr(callExpr, ctx, false) != nil { 52 if idt, ok := n.Lhs[0].(*ast.Ident); ok && idt.Name != "_" { 53 // Example: 54 // v, _ := strconv.Atoi("1111") 55 // Add v's Obj to atoiVarObj map 56 atoiVarObj[idt.Obj] = n 57 } 58 } 59 } 60 case *ast.CallExpr: 61 if fun, ok := n.Fun.(*ast.Ident); ok { 62 if fun.Name == "int32" || fun.Name == "int16" { 63 if idt, ok := n.Args[0].(*ast.Ident); ok { 64 if n, ok := atoiVarObj[idt.Obj]; ok { 65 // Detect int32(v) and int16(v) 66 return gosec.NewIssue(ctx, n, i.ID(), i.What, i.Severity, i.Confidence), nil 67 } 68 } 69 } 70 } 71 } 72 73 return nil, nil 74} 75 76// NewIntegerOverflowCheck detects if there is potential Integer OverFlow 77func NewIntegerOverflowCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { 78 calls := gosec.NewCallList() 79 calls.Add("strconv", "Atoi") 80 return &integerOverflowCheck{ 81 MetaData: gosec.MetaData{ 82 ID: id, 83 Severity: gosec.High, 84 Confidence: gosec.Medium, 85 What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32", 86 }, 87 calls: calls, 88 }, []ast.Node{(*ast.FuncDecl)(nil), (*ast.AssignStmt)(nil), (*ast.CallExpr)(nil)} 89} 90