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  }