github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/rand/random_linux.go (about) 1 // Copyright 2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rand 6 7 import ( 8 "context" 9 "log" 10 "sync" 11 "syscall" 12 "time" 13 14 "github.com/u-root/u-root/pkg/cmdline" 15 "golang.org/x/sys/unix" 16 ) 17 18 var defaultContextReader = &getrandomReader{} 19 20 var backupReader = &urandomReader{} 21 22 type getrandomReader struct { 23 once sync.Once 24 backup bool 25 } 26 27 // ReadContext implements a cancelable read from /dev/urandom. 28 func (r *getrandomReader) ReadContext(ctx context.Context, b []byte) (int, error) { 29 r.once.Do(func() { 30 if cmdline.ContainsFlag("uroot.nohwrng") { 31 r.backup = true 32 return 33 } 34 if _, err := unix.Getrandom(b, unix.GRND_NONBLOCK); err == syscall.ENOSYS { 35 r.backup = true 36 } 37 }) 38 if r.backup { 39 return backupReader.ReadContext(ctx, b) 40 } 41 42 for { 43 // getrandom(2) with GRND_NONBLOCK uses the urandom number 44 // source, but only returns numbers if the crng has been 45 // initialized. 46 // 47 // This is preferrable to /dev/urandom, as /dev/urandom will 48 // make up fake random numbers until the crng has been 49 // initialized. 50 n, err := unix.Getrandom(b, unix.GRND_NONBLOCK) 51 if err == nil { 52 return n, err 53 } 54 select { 55 case <-ctx.Done(): 56 return 0, ctx.Err() 57 58 default: 59 if err != nil && err != syscall.EAGAIN && err != syscall.EINTR { 60 return n, err 61 } 62 } 63 } 64 } 65 66 // ReadContextWithSlowLogs logs a helpful message if it takes a significant 67 // amount of time (>2s) to produce random data. 68 func (r *getrandomReader) ReadContextWithSlowLogs(ctx context.Context, b []byte) (int, error) { 69 d := 2 * time.Second 70 t := time.AfterFunc(d, func() { 71 log.Printf("getrandom is taking a long time (>%v). "+ 72 "If running on hardware, consider enabling Linux's CONFIG_RANDOM_TRUST_CPU=y. "+ 73 "If running in a VM/emulator, try setting up virtio-rng.", d) 74 }) 75 defer t.Stop() 76 return r.ReadContext(ctx, b) 77 }