github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/devices/memdev/random.go (about) 1 // Copyright 2020 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 memdev 16 17 import ( 18 "sync/atomic" 19 20 "github.com/SagerNet/gvisor/pkg/context" 21 "github.com/SagerNet/gvisor/pkg/rand" 22 "github.com/SagerNet/gvisor/pkg/safemem" 23 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 24 "github.com/SagerNet/gvisor/pkg/usermem" 25 ) 26 27 const ( 28 randomDevMinor = 8 29 urandomDevMinor = 9 30 ) 31 32 // randomDevice implements vfs.Device for /dev/random and /dev/urandom. 33 // 34 // +stateify savable 35 type randomDevice struct{} 36 37 // Open implements vfs.Device.Open. 38 func (randomDevice) Open(ctx context.Context, mnt *vfs.Mount, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) { 39 fd := &randomFD{} 40 if err := fd.vfsfd.Init(fd, opts.Flags, mnt, vfsd, &vfs.FileDescriptionOptions{ 41 UseDentryMetadata: true, 42 }); err != nil { 43 return nil, err 44 } 45 return &fd.vfsfd, nil 46 } 47 48 // randomFD implements vfs.FileDescriptionImpl for /dev/random. 49 // 50 // +stateify savable 51 type randomFD struct { 52 vfsfd vfs.FileDescription 53 vfs.FileDescriptionDefaultImpl 54 vfs.DentryMetadataFileDescriptionImpl 55 vfs.NoLockFD 56 57 // off is the "file offset". off is accessed using atomic memory 58 // operations. 59 off int64 60 } 61 62 // Release implements vfs.FileDescriptionImpl.Release. 63 func (fd *randomFD) Release(context.Context) { 64 // noop 65 } 66 67 // PRead implements vfs.FileDescriptionImpl.PRead. 68 func (fd *randomFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) { 69 return dst.CopyOutFrom(ctx, safemem.FromIOReader{rand.Reader}) 70 } 71 72 // Read implements vfs.FileDescriptionImpl.Read. 73 func (fd *randomFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) { 74 n, err := dst.CopyOutFrom(ctx, safemem.FromIOReader{rand.Reader}) 75 atomic.AddInt64(&fd.off, n) 76 return n, err 77 } 78 79 // PWrite implements vfs.FileDescriptionImpl.PWrite. 80 func (fd *randomFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) { 81 // In Linux, this mixes the written bytes into the entropy pool; we just 82 // throw them away. 83 return src.NumBytes(), nil 84 } 85 86 // Write implements vfs.FileDescriptionImpl.Write. 87 func (fd *randomFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) { 88 atomic.AddInt64(&fd.off, src.NumBytes()) 89 return src.NumBytes(), nil 90 } 91 92 // Seek implements vfs.FileDescriptionImpl.Seek. 93 func (fd *randomFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) { 94 // Linux: drivers/char/random.c:random_fops.llseek == urandom_fops.llseek 95 // == noop_llseek 96 return atomic.LoadInt64(&fd.off), nil 97 }