mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Ensure at least page size bytes are read from /dev/{u}random and getrandom(2).
This undocumented behavior manifests in Linux and some apps depend on it. See drivers/char/random.c:get_random_bytes_user(). Fixes #9445 Fixes #4988 PiperOrigin-RevId: 570833447
This commit is contained in:
+10
-3
@@ -54,10 +54,17 @@ type bufferedReader struct {
|
||||
|
||||
// Read implements io.Reader.Read.
|
||||
func (b *bufferedReader) Read(p []byte) (int, error) {
|
||||
// In Linux, reads of up to page size bytes will always complete fully.
|
||||
// See drivers/char/random.c:get_random_bytes_user().
|
||||
// NOTE(gvisor.dev/issue/9445): Some applications rely on this behavior.
|
||||
const pageSize = 4096
|
||||
min := len(p)
|
||||
if min > pageSize {
|
||||
min = pageSize
|
||||
}
|
||||
b.mu.Lock()
|
||||
n, err := b.r.Read(p)
|
||||
b.mu.Unlock()
|
||||
return n, err
|
||||
defer b.mu.Unlock()
|
||||
return io.ReadAtLeast(b.r, p, min)
|
||||
}
|
||||
|
||||
// Reader is the default reader.
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package linux
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
@@ -57,37 +56,11 @@ func GetRandom(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintp
|
||||
return 0, nil, linuxerr.EFAULT
|
||||
}
|
||||
|
||||
// "If the urandom source has been initialized, reads of up to 256 bytes
|
||||
// will always return as many bytes as requested and will not be
|
||||
// interrupted by signals. No such guarantees apply for larger buffer
|
||||
// sizes." - getrandom(2)
|
||||
min := int(length)
|
||||
if min > 256 {
|
||||
min = 256
|
||||
}
|
||||
n, err := t.MemoryManager().CopyOutFrom(t, hostarch.AddrRangeSeqOf(ar), safemem.FromIOReader{&randReader{-1, min}}, usermem.IOOpts{
|
||||
n, err := t.MemoryManager().CopyOutFrom(t, hostarch.AddrRangeSeqOf(ar), safemem.FromIOReader{rand.Reader}, usermem.IOOpts{
|
||||
AddressSpaceActive: true,
|
||||
})
|
||||
if n >= int64(min) {
|
||||
if n > 0 {
|
||||
return uintptr(n), nil, nil
|
||||
}
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
// randReader is a io.Reader that handles partial reads from rand.Reader.
|
||||
type randReader struct {
|
||||
done int
|
||||
min int
|
||||
}
|
||||
|
||||
// Read implements io.Reader.Read.
|
||||
func (r *randReader) Read(dst []byte) (int, error) {
|
||||
if r.done >= r.min {
|
||||
return rand.Reader.Read(dst)
|
||||
}
|
||||
min := r.min - r.done
|
||||
if min > len(dst) {
|
||||
min = len(dst)
|
||||
}
|
||||
return io.ReadAtLeast(rand.Reader, dst, min)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user