fix bug with concurrent math/rand.Rand.Read

firstly by using crypto/rand in those cases. and secondly by putting a lock
around the Read (though it isn't used at the moment).

found while working while implementing sending tls reports.
This commit is contained in:
Mechiel Lukkien 2023-11-09 17:15:46 +01:00
parent d02ac0cb86
commit 2535f351ed
No known key found for this signature in database
7 changed files with 38 additions and 15 deletions

View file

@ -272,7 +272,7 @@ func RemoveEvaluationsDomain(ctx context.Context, domain dns.Domain) error {
return err
}
var jitterRand = mox.NewRand()
var jitterRand = mox.NewPseudoRand()
// time to sleep until next whole hour t, replaced by tests.
// Jitter so we don't cause load at exactly whole hours, other processes may

View file

@ -1,14 +1,13 @@
package mox
import (
cryptorand "crypto/rand"
"encoding/base64"
)
var messageIDRand = NewRand()
// MessageIDGen returns a generated unique random Message-Id value, excluding <>.
func MessageIDGen(smtputf8 bool) string {
buf := make([]byte, 16)
messageIDRand.Read(buf)
cryptorand.Read(buf)
return base64.RawURLEncoding.EncodeToString(buf) + "@" + Conf.Static.HostnameDomain.XName(smtputf8)
}

View file

@ -5,11 +5,24 @@ import (
"encoding/binary"
"fmt"
mathrand "math/rand"
"sync"
)
// NewRand returns a new PRNG seeded with random bytes from crypto/rand.
func NewRand() *mathrand.Rand {
return mathrand.New(mathrand.NewSource(CryptoRandInt()))
type rand struct {
*mathrand.Rand
sync.Mutex
}
// NewPseudoRand returns a new PRNG seeded with random bytes from crypto/rand.
func NewPseudoRand() *rand {
return &rand{Rand: mathrand.New(mathrand.NewSource(CryptoRandInt()))}
}
// Read can be called concurrently.
func (r *rand) Read(buf []byte) (int, error) {
r.Lock()
defer r.Unlock()
return r.Rand.Read(buf)
}
// CryptoRandInt returns a cryptographically random number.

View file

@ -61,7 +61,7 @@ var (
)
)
var jitter = mox.NewRand()
var jitter = mox.NewPseudoRand()
var DBTypes = []any{Msg{}} // Types stored in DB.
var DB *bstore.DB // Exported for making backups.

View file

@ -40,11 +40,19 @@ import (
var moxService string
func pwgen() string {
rand := mox.NewRand()
chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*-_;:,<.>/"
s := ""
buf := make([]byte, 1)
for i := 0; i < 12; i++ {
s += string(chars[rand.Intn(len(chars))])
for {
cryptorand.Read(buf)
i := int(buf[0])
if i+len(chars) > 255 {
continue // Prevent bias.
}
s += string(chars[i%len(chars)])
break
}
}
return s
}

View file

@ -168,7 +168,7 @@ var (
)
)
var jitterRand = mox.NewRand()
var jitterRand = mox.NewPseudoRand()
func durationDefault(delay *time.Duration, def time.Duration) time.Duration {
if delay == nil {

View file

@ -24,6 +24,7 @@ package store
import (
"context"
"crypto/md5"
cryptorand "crypto/rand"
"crypto/sha1"
"crypto/sha256"
"encoding"
@ -74,8 +75,6 @@ var (
ErrAccountUnknown = errors.New("no such account")
)
var subjectpassRand = mox.NewRand()
var DefaultInitialMailboxes = config.InitialMailboxes{
SpecialUse: config.SpecialUseMailboxes{
Sent: "Sent",
@ -1460,8 +1459,12 @@ func (a *Account) Subjectpass(email string) (key string, err error) {
}
key = ""
const chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i := 0; i < 16; i++ {
key += string(chars[subjectpassRand.Intn(len(chars))])
buf := make([]byte, 16)
if _, err := cryptorand.Read(buf); err != nil {
return err
}
for _, b := range buf {
key += string(chars[int(b)%len(chars)])
}
v.Key = key
return tx.Insert(&v)