Add a new rule which detects when a file is created with os.Create but the configured permissions are less than 0666

It seems that the os.Create will create by default a file with 0666 permissions.

This should be detected when the configured permissions are less than 0666. By default will not detect this case
unless the more restrictive mode is configured.

Signed-off-by: Cosmin Cojocar <gcojocar@adobe.com>
This commit is contained in:
Cosmin Cojocar 2023-09-25 13:11:00 +02:00 committed by Cosmin Cojocar
parent 293d887525
commit 0d332a1027
4 changed files with 89 additions and 0 deletions

View file

@ -157,6 +157,7 @@ directory you can supply `./...` as the input argument.
- G304: File path provided as taint input - G304: File path provided as taint input
- G305: File traversal when extracting zip/tar archive - G305: File traversal when extracting zip/tar archive
- G306: Poor file permissions used when writing to a new file - G306: Poor file permissions used when writing to a new file
- G307: Poor file permissions used when crating a file with os.Create
- G401: Detect the usage of DES, RC4, MD5 or SHA1 - G401: Detect the usage of DES, RC4, MD5 or SHA1
- G402: Look for bad TLS connection settings - G402: Look for bad TLS connection settings
- G403: Ensure minimum RSA key length of 2048 bits - G403: Ensure minimum RSA key length of 2048 bits

View file

@ -30,6 +30,7 @@ type filePermissions struct {
calls []string calls []string
} }
// ID returns the ID of the rule.
func (r *filePermissions) ID() string { func (r *filePermissions) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
@ -55,6 +56,7 @@ func modeIsSubset(subset int64, superset int64) bool {
return (subset | superset) == superset return (subset | superset) == superset
} }
// Match checks if the rule is matched.
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) { func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for _, pkg := range r.pkgs { for _, pkg := range r.pkgs {
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched { if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
@ -116,3 +118,48 @@ func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
} }
type osCreatePermissions struct {
issue.MetaData
defaultMode int64
mode int64
pkgs []string
calls []string
}
const defaultOsCreateMode = 0o666
// ID returns the ID of the rule.
func (r *osCreatePermissions) ID() string {
return r.MetaData.ID
}
// Match checks if the rule is matched.
func (r *osCreatePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for _, pkg := range r.pkgs {
if _, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
if !modeIsSubset(defaultOsCreateMode, r.mode) {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
return nil, nil
}
// NewOsCreatePerms reates a rule to detect file creation with a more permissive than configured
// permission mask.
func NewOsCreatePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
mode := getConfiguredMode(conf, id, 0o666)
return &osCreatePermissions{
mode: mode,
pkgs: []string{"os"},
calls: []string{"Create"},
MetaData: issue.MetaData{
ID: id,
Severity: issue.Medium,
Confidence: issue.High,
What: fmt.Sprintf("Expect file permissions to be %#o or less but os.Create used with default permissions %#o",
mode, defaultOsCreateMode),
},
}, []ast.Node{(*ast.CallExpr)(nil)}
}

View file

@ -91,6 +91,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
{"G304", "File path provided as taint input", NewReadFile}, {"G304", "File path provided as taint input", NewReadFile},
{"G305", "File path traversal when extracting zip archive", NewArchive}, {"G305", "File path traversal when extracting zip archive", NewArchive},
{"G306", "Poor file permissions used when writing to a file", NewWritePerms}, {"G306", "Poor file permissions used when writing to a file", NewWritePerms},
{"G307", "Poor file permissions used when creating a file with os.Create", NewOsCreatePerms},
// crypto // crypto
{"G401", "Detect the usage of DES, RC4, MD5 or SHA1", NewUsesWeakCryptography}, {"G401", "Detect the usage of DES, RC4, MD5 or SHA1", NewUsesWeakCryptography},

View file

@ -2913,6 +2913,46 @@ func main() {
}`}, 1, gosec.NewConfig()}, }`}, 1, gosec.NewConfig()},
} }
// SampleCodeG307 - Poor permissions for os.Create
SampleCodeG307 = []CodeSample{
{[]string{`package main
import (
"fmt"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
f, err := os.Create("/tmp/dat2")
check(err)
defer f.Close()
}`}, 0, gosec.NewConfig()},
{[]string{`package main
import (
"fmt"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
f, err := os.Create("/tmp/dat2")
check(err)
defer f.Close()
}`}, 1, gosec.Config{"G307": "0o600"}},
}
// SampleCodeG401 - Use of weak crypto MD5 // SampleCodeG401 - Use of weak crypto MD5
SampleCodeG401 = []CodeSample{ SampleCodeG401 = []CodeSample{
{[]string{` {[]string{`