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