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 "strconv" 21 22 "github.com/securego/gosec/v2" 23) 24 25type filePermissions struct { 26 gosec.MetaData 27 mode int64 28 pkg string 29 calls []string 30} 31 32func (r *filePermissions) ID() string { 33 return r.MetaData.ID 34} 35 36func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMode int64) int64 { 37 var mode = defaultMode 38 if value, ok := conf[configKey]; ok { 39 switch value := value.(type) { 40 case int64: 41 mode = value 42 case string: 43 if m, e := strconv.ParseInt(value, 0, 64); e != nil { 44 mode = defaultMode 45 } else { 46 mode = m 47 } 48 } 49 } 50 return mode 51} 52 53func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { 54 if callexpr, matched := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matched { 55 modeArg := callexpr.Args[len(callexpr.Args)-1] 56 if mode, err := gosec.GetInt(modeArg); err == nil && mode > r.mode { 57 return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil 58 } 59 } 60 return nil, nil 61} 62 63// NewWritePerms creates a rule to detect file Writes with bad permissions. 64func NewWritePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { 65 mode := getConfiguredMode(conf, "G306", 0600) 66 return &filePermissions{ 67 mode: mode, 68 pkg: "io/ioutil", 69 calls: []string{"WriteFile"}, 70 MetaData: gosec.MetaData{ 71 ID: id, 72 Severity: gosec.Medium, 73 Confidence: gosec.High, 74 What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode), 75 }, 76 }, []ast.Node{(*ast.CallExpr)(nil)} 77} 78 79// NewFilePerms creates a rule to detect file creation with a more permissive than configured 80// permission mask. 81func NewFilePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { 82 mode := getConfiguredMode(conf, "G302", 0600) 83 return &filePermissions{ 84 mode: mode, 85 pkg: "os", 86 calls: []string{"OpenFile", "Chmod"}, 87 MetaData: gosec.MetaData{ 88 ID: id, 89 Severity: gosec.Medium, 90 Confidence: gosec.High, 91 What: fmt.Sprintf("Expect file permissions to be %#o or less", mode), 92 }, 93 }, []ast.Node{(*ast.CallExpr)(nil)} 94} 95 96// NewMkdirPerms creates a rule to detect directory creation with more permissive than 97// configured permission mask. 98func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { 99 mode := getConfiguredMode(conf, "G301", 0750) 100 return &filePermissions{ 101 mode: mode, 102 pkg: "os", 103 calls: []string{"Mkdir", "MkdirAll"}, 104 MetaData: gosec.MetaData{ 105 ID: id, 106 Severity: gosec.Medium, 107 Confidence: gosec.High, 108 What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode), 109 }, 110 }, []ast.Node{(*ast.CallExpr)(nil)} 111} 112