github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_random.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package linux 16 17 import ( 18 "io" 19 "math" 20 21 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 22 "github.com/SagerNet/gvisor/pkg/hostarch" 23 "github.com/SagerNet/gvisor/pkg/rand" 24 "github.com/SagerNet/gvisor/pkg/safemem" 25 "github.com/SagerNet/gvisor/pkg/sentry/arch" 26 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 27 "github.com/SagerNet/gvisor/pkg/syserror" 28 "github.com/SagerNet/gvisor/pkg/usermem" 29 ) 30 31 const ( 32 _GRND_NONBLOCK = 0x1 33 _GRND_RANDOM = 0x2 34 ) 35 36 // GetRandom implements the linux syscall getrandom(2). 37 // 38 // In a multi-tenant/shared environment, the only valid implementation is to 39 // fetch data from the urandom pool, otherwise starvation attacks become 40 // possible. The urandom pool is also expected to have plenty of entropy, thus 41 // the GRND_RANDOM flag is ignored. The GRND_NONBLOCK flag does not apply, as 42 // the pool will already be initialized. 43 func GetRandom(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) { 44 addr := args[0].Pointer() 45 length := args[1].SizeT() 46 flags := args[2].Int() 47 48 // Flags are checked for validity but otherwise ignored. See above. 49 if flags & ^(_GRND_NONBLOCK|_GRND_RANDOM) != 0 { 50 return 0, nil, linuxerr.EINVAL 51 } 52 53 if length > math.MaxInt32 { 54 length = math.MaxInt32 55 } 56 ar, ok := addr.ToRange(uint64(length)) 57 if !ok { 58 return 0, nil, syserror.EFAULT 59 } 60 61 // "If the urandom source has been initialized, reads of up to 256 bytes 62 // will always return as many bytes as requested and will not be 63 // interrupted by signals. No such guarantees apply for larger buffer 64 // sizes." - getrandom(2) 65 min := int(length) 66 if min > 256 { 67 min = 256 68 } 69 n, err := t.MemoryManager().CopyOutFrom(t, hostarch.AddrRangeSeqOf(ar), safemem.FromIOReader{&randReader{-1, min}}, usermem.IOOpts{ 70 AddressSpaceActive: true, 71 }) 72 if n >= int64(min) { 73 return uintptr(n), nil, nil 74 } 75 return 0, nil, err 76 } 77 78 // randReader is a io.Reader that handles partial reads from rand.Reader. 79 type randReader struct { 80 done int 81 min int 82 } 83 84 // Read implements io.Reader.Read. 85 func (r *randReader) Read(dst []byte) (int, error) { 86 if r.done >= r.min { 87 return rand.Reader.Read(dst) 88 } 89 min := r.min - r.done 90 if min > len(dst) { 91 min = len(dst) 92 } 93 return io.ReadAtLeast(rand.Reader, dst, min) 94 }