Skip to content

Commit be378e6

Browse files
hyorimitsuccojocar
authored andcommittedMar 7, 2024
Add support for math/rand/v2 added in Go 1.22
1 parent 36878a9 commit be378e6

File tree

3 files changed

+109
-10
lines changed

3 files changed

+109
-10
lines changed
 

‎import_tracker.go

+10
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,14 @@ package gosec
1515
import (
1616
"go/ast"
1717
"go/types"
18+
"regexp"
1819
"strings"
1920
)
2021

22+
var (
23+
versioningPackagePattern = regexp.MustCompile(`v[0-9]+$`)
24+
)
25+
2126
// ImportTracker is used to normalize the packages that have been imported
2227
// by a source file. It is able to differentiate between plain imports, aliased
2328
// imports and init only imports.
@@ -66,5 +71,10 @@ func importName(importPath string) string {
6671
if len(parts) > 0 {
6772
name = parts[len(parts)-1]
6873
}
74+
// If the last segment of the path is version information, consider the second to last segment as the package name.
75+
// (e.g., `math/rand/v2` would be `rand`)
76+
if len(parts) > 1 && versioningPackagePattern.MatchString(name) {
77+
name = parts[len(parts)-2]
78+
}
6979
return name
7080
}

‎rules/rand.go

+14-10
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,16 @@ import (
2323

2424
type weakRand struct {
2525
issue.MetaData
26-
funcNames []string
27-
packagePath string
26+
blocklist map[string][]string
2827
}
2928

3029
func (w *weakRand) ID() string {
3130
return w.MetaData.ID
3231
}
3332

3433
func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
35-
for _, funcName := range w.funcNames {
36-
if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
34+
for pkg, funcs := range w.blocklist {
35+
if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched {
3736
return c.NewIssue(n, w.ID(), w.What, w.Severity, w.Confidence), nil
3837
}
3938
}
@@ -43,17 +42,22 @@ func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
4342

4443
// NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure
4544
func NewWeakRandCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
45+
calls := make(map[string][]string)
46+
calls["math/rand"] = []string{
47+
"New", "Read", "Float32", "Float64", "Int", "Int31", "Int31n",
48+
"Int63", "Int63n", "Intn", "NormFloat64", "Uint32", "Uint64",
49+
}
50+
calls["math/rand/v2"] = []string{
51+
"New", "Float32", "Float64", "Int", "Int32", "Int32N",
52+
"Int64", "Int64N", "IntN", "N", "NormFloat64", "Uint32", "Uint32N", "Uint64", "Uint64N", "UintN",
53+
}
4654
return &weakRand{
47-
funcNames: []string{
48-
"New", "Read", "Float32", "Float64", "Int", "Int31",
49-
"Int31n", "Int63", "Int63n", "Intn", "NormalFloat64", "Uint32", "Uint64",
50-
},
51-
packagePath: "math/rand",
55+
blocklist: calls,
5256
MetaData: issue.MetaData{
5357
ID: id,
5458
Severity: issue.High,
5559
Confidence: issue.Medium,
56-
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
60+
What: "Use of weak random number generator (math/rand or math/rand/v2 instead of crypto/rand)",
5761
},
5862
}, []ast.Node{(*ast.CallExpr)(nil)}
5963
}

‎testutils/g404_samples.go

+85
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ func main() {
2727
{[]string{`
2828
package main
2929
30+
import "math/rand/v2"
31+
32+
func main() {
33+
bad := rand.Int()
34+
println(bad)
35+
}
36+
`}, 1, gosec.NewConfig()},
37+
{[]string{`
38+
package main
39+
3040
import (
3141
"crypto/rand"
3242
mrand "math/rand"
@@ -42,6 +52,21 @@ func main() {
4252
{[]string{`
4353
package main
4454
55+
import (
56+
"crypto/rand"
57+
mrand "math/rand/v2"
58+
)
59+
60+
func main() {
61+
good, _ := rand.Read(nil)
62+
println(good)
63+
bad := mrand.Int32()
64+
println(bad)
65+
}
66+
`}, 1, gosec.NewConfig()},
67+
{[]string{`
68+
package main
69+
4570
import (
4671
"math/rand"
4772
)
@@ -55,6 +80,19 @@ func main() {
5580
{[]string{`
5681
package main
5782
83+
import (
84+
"math/rand/v2"
85+
)
86+
87+
func main() {
88+
gen := rand.New(rand.NewPCG(1, 2))
89+
bad := gen.Int()
90+
println(bad)
91+
}
92+
`}, 1, gosec.NewConfig()},
93+
{[]string{`
94+
package main
95+
5896
import (
5997
"math/rand"
6098
)
@@ -67,6 +105,18 @@ func main() {
67105
{[]string{`
68106
package main
69107
108+
import (
109+
"math/rand/v2"
110+
)
111+
112+
func main() {
113+
bad := rand.IntN(10)
114+
println(bad)
115+
}
116+
`}, 1, gosec.NewConfig()},
117+
{[]string{`
118+
package main
119+
70120
import (
71121
"crypto/rand"
72122
"math/big"
@@ -83,6 +133,22 @@ func main() {
83133
{[]string{`
84134
package main
85135
136+
import (
137+
"crypto/rand"
138+
"math/big"
139+
rnd "math/rand/v2"
140+
)
141+
142+
func main() {
143+
good, _ := rand.Int(rand.Reader, big.NewInt(int64(2)))
144+
println(good)
145+
bad := rnd.IntN(2)
146+
println(bad)
147+
}
148+
`}, 1, gosec.NewConfig()},
149+
{[]string{`
150+
package main
151+
86152
import (
87153
crand "crypto/rand"
88154
"math/big"
@@ -98,5 +164,24 @@ func main() {
98164
_ = rand2.Intn(2) // bad
99165
_ = rand3.Intn(2) // bad
100166
}
167+
`}, 3, gosec.NewConfig()},
168+
{[]string{`
169+
package main
170+
171+
import (
172+
crand "crypto/rand"
173+
"math/big"
174+
"math/rand/v2"
175+
rand2 "math/rand/v2"
176+
rand3 "math/rand/v2"
177+
)
178+
179+
func main() {
180+
_, _ = crand.Int(crand.Reader, big.NewInt(int64(2))) // good
181+
182+
_ = rand.IntN(2) // bad
183+
_ = rand2.IntN(2) // bad
184+
_ = rand3.IntN(2) // bad
185+
}
101186
`}, 3, gosec.NewConfig()},
102187
}

0 commit comments

Comments
 (0)
Please sign in to comment.