Skip to content

Commit 0d332a1

Browse files
committed
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 <[email protected]>
1 parent 293d887 commit 0d332a1

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ directory you can supply `./...` as the input argument.
157157
- G304: File path provided as taint input
158158
- G305: File traversal when extracting zip/tar archive
159159
- G306: Poor file permissions used when writing to a new file
160+
- G307: Poor file permissions used when crating a file with os.Create
160161
- G401: Detect the usage of DES, RC4, MD5 or SHA1
161162
- G402: Look for bad TLS connection settings
162163
- G403: Ensure minimum RSA key length of 2048 bits

rules/fileperms.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type filePermissions struct {
3030
calls []string
3131
}
3232

33+
// ID returns the ID of the rule.
3334
func (r *filePermissions) ID() string {
3435
return r.MetaData.ID
3536
}
@@ -55,6 +56,7 @@ func modeIsSubset(subset int64, superset int64) bool {
5556
return (subset | superset) == superset
5657
}
5758

59+
// Match checks if the rule is matched.
5860
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
5961
for _, pkg := range r.pkgs {
6062
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) {
116118
},
117119
}, []ast.Node{(*ast.CallExpr)(nil)}
118120
}
121+
122+
type osCreatePermissions struct {
123+
issue.MetaData
124+
defaultMode int64
125+
mode int64
126+
pkgs []string
127+
calls []string
128+
}
129+
130+
const defaultOsCreateMode = 0o666
131+
132+
// ID returns the ID of the rule.
133+
func (r *osCreatePermissions) ID() string {
134+
return r.MetaData.ID
135+
}
136+
137+
// Match checks if the rule is matched.
138+
func (r *osCreatePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
139+
for _, pkg := range r.pkgs {
140+
if _, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
141+
if !modeIsSubset(defaultOsCreateMode, r.mode) {
142+
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
143+
}
144+
}
145+
}
146+
return nil, nil
147+
}
148+
149+
// NewOsCreatePerms reates a rule to detect file creation with a more permissive than configured
150+
// permission mask.
151+
func NewOsCreatePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
152+
mode := getConfiguredMode(conf, id, 0o666)
153+
return &osCreatePermissions{
154+
mode: mode,
155+
pkgs: []string{"os"},
156+
calls: []string{"Create"},
157+
MetaData: issue.MetaData{
158+
ID: id,
159+
Severity: issue.Medium,
160+
Confidence: issue.High,
161+
What: fmt.Sprintf("Expect file permissions to be %#o or less but os.Create used with default permissions %#o",
162+
mode, defaultOsCreateMode),
163+
},
164+
}, []ast.Node{(*ast.CallExpr)(nil)}
165+
}

rules/rulelist.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
9191
{"G304", "File path provided as taint input", NewReadFile},
9292
{"G305", "File path traversal when extracting zip archive", NewArchive},
9393
{"G306", "Poor file permissions used when writing to a file", NewWritePerms},
94+
{"G307", "Poor file permissions used when creating a file with os.Create", NewOsCreatePerms},
9495

9596
// crypto
9697
{"G401", "Detect the usage of DES, RC4, MD5 or SHA1", NewUsesWeakCryptography},

testutils/source.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2913,6 +2913,46 @@ func main() {
29132913
}`}, 1, gosec.NewConfig()},
29142914
}
29152915

2916+
// SampleCodeG307 - Poor permissions for os.Create
2917+
SampleCodeG307 = []CodeSample{
2918+
{[]string{`package main
2919+
2920+
import (
2921+
"fmt"
2922+
"os"
2923+
)
2924+
2925+
func check(e error) {
2926+
if e != nil {
2927+
panic(e)
2928+
}
2929+
}
2930+
2931+
func main() {
2932+
f, err := os.Create("/tmp/dat2")
2933+
check(err)
2934+
defer f.Close()
2935+
}`}, 0, gosec.NewConfig()},
2936+
{[]string{`package main
2937+
2938+
import (
2939+
"fmt"
2940+
"os"
2941+
)
2942+
2943+
func check(e error) {
2944+
if e != nil {
2945+
panic(e)
2946+
}
2947+
}
2948+
2949+
func main() {
2950+
f, err := os.Create("/tmp/dat2")
2951+
check(err)
2952+
defer f.Close()
2953+
}`}, 1, gosec.Config{"G307": "0o600"}},
2954+
}
2955+
29162956
// SampleCodeG401 - Use of weak crypto MD5
29172957
SampleCodeG401 = []CodeSample{
29182958
{[]string{`

0 commit comments

Comments
 (0)