Ignore struct pointers in G601 (#1003)

Updates https://github.com/securego/gosec/issues/966

Signed-off-by: Alexander Yastrebov <yastrebov.alex@gmail.com>
This commit is contained in:
Alexander Yastrebov 2023-08-18 17:05:17 +02:00 committed by GitHub
parent 85005c43d9
commit 21d13c9a9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 100 additions and 21 deletions

View file

@ -11,7 +11,6 @@ endif
BUILDFLAGS := "-w -s -X 'main.Version=$(GIT_TAG)' -X 'main.GitTag=$(GIT_TAG)' -X 'main.BuildDate=$(BUILD_DATE)'" BUILDFLAGS := "-w -s -X 'main.Version=$(GIT_TAG)' -X 'main.GitTag=$(GIT_TAG)' -X 'main.BuildDate=$(BUILD_DATE)'"
CGO_ENABLED = 0 CGO_ENABLED = 0
GO := GO111MODULE=on go GO := GO111MODULE=on go
GO_NOMOD :=GO111MODULE=off go
GOPATH ?= $(shell $(GO) env GOPATH) GOPATH ?= $(shell $(GO) env GOPATH)
GOBIN ?= $(GOPATH)/bin GOBIN ?= $(GOPATH)/bin
GOSEC ?= $(GOBIN)/gosec GOSEC ?= $(GOBIN)/gosec
@ -25,8 +24,8 @@ default:
install-test-deps: install-test-deps:
go install github.com/onsi/ginkgo/v2/ginkgo@latest go install github.com/onsi/ginkgo/v2/ginkgo@latest
$(GO_NOMOD) get -u golang.org/x/crypto/ssh go install golang.org/x/crypto/...@latest
$(GO_NOMOD) get -u github.com/lib/pq go install github.com/lib/pq/...@latest
install-govulncheck: install-govulncheck:
@if [ $(GO_MINOR_VERSION) -gt $(GOVULN_MIN_VERSION) ]; then \ @if [ $(GO_MINOR_VERSION) -gt $(GOVULN_MIN_VERSION) ]; then \
@ -89,5 +88,5 @@ image-push: image
tlsconfig: tlsconfig:
go generate ./... go generate ./...
.PHONY: test build clean release image image-push tlsconfig .PHONY: test build clean release image image-push tlsconfig

View file

@ -3,6 +3,7 @@ package rules
import ( import (
"go/ast" "go/ast"
"go/token" "go/token"
"go/types"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue" "github.com/securego/gosec/v2/issue"
@ -28,23 +29,20 @@ func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
return false return false
} }
func getIdentExpr(expr ast.Expr) *ast.Ident { func getIdentExpr(expr ast.Expr) (*ast.Ident, bool) {
return doGetIdentExpr(expr, false)
}
func doGetIdentExpr(expr ast.Expr, hasSelector bool) (*ast.Ident, bool) {
switch node := expr.(type) { switch node := expr.(type) {
case *ast.Ident: case *ast.Ident:
return node return node, hasSelector
case *ast.SelectorExpr: case *ast.SelectorExpr:
return getIdentExpr(node.X) return doGetIdentExpr(node.X, true)
case *ast.UnaryExpr: case *ast.UnaryExpr:
switch e := node.X.(type) { return doGetIdentExpr(node.X, hasSelector)
case *ast.Ident:
return e
case *ast.SelectorExpr:
return getIdentExpr(e.X)
default:
return nil
}
default: default:
return nil return nil, false
} }
} }
@ -92,9 +90,13 @@ func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*issue.Issue, er
} }
// If we find a unary op of & (reference) of an object within r.aliases, complain. // If we find a unary op of & (reference) of an object within r.aliases, complain.
if identExpr := getIdentExpr(node); identExpr != nil && node.Op.String() == "&" { if identExpr, hasSelector := getIdentExpr(node); identExpr != nil && node.Op.String() == "&" {
if _, contains := r.aliases[identExpr.Obj]; contains { if _, contains := r.aliases[identExpr.Obj]; contains {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil _, isPointer := c.Info.TypeOf(identExpr).(*types.Pointer)
if !hasSelector || !isPointer {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
} }
} }
case *ast.ReturnStmt: case *ast.ReturnStmt:

View file

@ -1178,7 +1178,7 @@ func HelloServer(w http.ResponseWriter, r *http.Request) {
"fmt" "fmt"
"net/http" "net/http"
) )
func main() { func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:]) fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
@ -1199,7 +1199,7 @@ func HelloServer(w http.ResponseWriter, r *http.Request) {
"time" "time"
"net/http" "net/http"
) )
func main() { func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:]) fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
@ -1222,7 +1222,7 @@ func HelloServer(w http.ResponseWriter, r *http.Request) {
"time" "time"
"net/http" "net/http"
) )
func main() { func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:]) fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
@ -3623,6 +3623,46 @@ type sampleStruct struct {
name string name string
} }
func main() {
samples := []*sampleStruct{
{name: "a"},
{name: "b"},
}
for _, sample := range samples {
fmt.Println(&sample)
}
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type sampleStruct struct {
name string
}
func main() {
samples := []*sampleStruct{
{name: "a"},
{name: "b"},
}
for _, sample := range samples {
fmt.Println(&sample.name)
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type sampleStruct struct {
name string
}
func main() { func main() {
samples := []sampleStruct{ samples := []sampleStruct{
{name: "a"}, {name: "a"},
@ -3655,6 +3695,44 @@ func main() {
for _, sample := range samples { for _, sample := range samples {
fmt.Println(&sample.sub.name) fmt.Println(&sample.sub.name)
} }
}`}, 1, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
type subStruct struct {
name string
}
type sampleStruct struct {
sub subStruct
}
func main() {
samples := []*sampleStruct{
{sub: subStruct{name: "a"}},
{sub: subStruct{name: "b"}},
}
for _, sample := range samples {
fmt.Println(&sample.sub.name)
}
}`}, 0, gosec.NewConfig()},
{[]string{`
package main
import (
"fmt"
)
func main() {
one, two := 1, 2
samples := []*int{&one, &two}
for _, sample := range samples {
fmt.Println(&sample)
}
}`}, 1, gosec.NewConfig()}, }`}, 1, gosec.NewConfig()},
} }