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 return err
} }
var jitterRand = mox.NewRand() var jitterRand = mox.NewPseudoRand()
// time to sleep until next whole hour t, replaced by tests. // 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 // Jitter so we don't cause load at exactly whole hours, other processes may

View file

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

View file

@ -5,11 +5,24 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
mathrand "math/rand" mathrand "math/rand"
"sync"
) )
// NewRand returns a new PRNG seeded with random bytes from crypto/rand. type rand struct {
func NewRand() *mathrand.Rand { *mathrand.Rand
return mathrand.New(mathrand.NewSource(CryptoRandInt())) 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. // 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 DBTypes = []any{Msg{}} // Types stored in DB.
var DB *bstore.DB // Exported for making backups. var DB *bstore.DB // Exported for making backups.

View file

@ -40,11 +40,19 @@ import (
var moxService string var moxService string
func pwgen() string { func pwgen() string {
rand := mox.NewRand()
chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*-_;:,<.>/" chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*-_;:,<.>/"
s := "" s := ""
buf := make([]byte, 1)
for i := 0; i < 12; i++ { 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 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 { func durationDefault(delay *time.Duration, def time.Duration) time.Duration {
if delay == nil { if delay == nil {

View file

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