github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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 "sync" 10 "syscall" 11 12 "github.com/u-root/u-root/pkg/cmdline" 13 "golang.org/x/sys/unix" 14 ) 15 16 var defaultContextReader = &getrandomReader{} 17 18 var backupReader = &urandomReader{} 19 20 type getrandomReader struct { 21 once sync.Once 22 backup bool 23 } 24 25 // ReadContext implements a cancelable read from /dev/urandom. 26 func (r *getrandomReader) ReadContext(ctx context.Context, b []byte) (int, error) { 27 r.once.Do(func() { 28 if cmdline.ContainsFlag("uroot.nohwrng") { 29 r.backup = true 30 return 31 } 32 if _, err := unix.Getrandom(b, unix.GRND_NONBLOCK); err == syscall.ENOSYS { 33 r.backup = true 34 } 35 }) 36 if r.backup { 37 return backupReader.ReadContext(ctx, b) 38 } 39 40 for { 41 // getrandom(2) with GRND_NONBLOCK uses the urandom number 42 // source, but only returns numbers if the crng has been 43 // initialized. 44 // 45 // This is preferrable to /dev/urandom, as /dev/urandom will 46 // make up fake random numbers until the crng has been 47 // initialized. 48 n, err := unix.Getrandom(b, unix.GRND_NONBLOCK) 49 if err == nil { 50 return n, err 51 } 52 select { 53 case <-ctx.Done(): 54 return 0, ctx.Err() 55 56 default: 57 if err != nil && err != syscall.EAGAIN && err != syscall.EINTR { 58 return n, err 59 } 60 } 61 } 62 }