gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/kernel/pipe/pipe_util.go (about) 1 // Copyright 2019 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 pipe 16 17 import ( 18 "io" 19 "math" 20 21 "golang.org/x/sys/unix" 22 "gvisor.dev/gvisor/pkg/abi/linux" 23 "gvisor.dev/gvisor/pkg/context" 24 "gvisor.dev/gvisor/pkg/errors/linuxerr" 25 "gvisor.dev/gvisor/pkg/marshal/primitive" 26 "gvisor.dev/gvisor/pkg/safemem" 27 "gvisor.dev/gvisor/pkg/sentry/arch" 28 "gvisor.dev/gvisor/pkg/usermem" 29 "gvisor.dev/gvisor/pkg/waiter" 30 ) 31 32 // This file contains Pipe file functionality that is tied to neither VFS nor 33 // the old fs architecture. 34 35 // Release cleans up the pipe's state. 36 func (p *Pipe) Release(context.Context) { 37 p.rClose() 38 p.wClose() 39 40 // Wake up readers and writers. 41 p.queue.Notify(waiter.ReadableEvents | waiter.WritableEvents) 42 } 43 44 // Read reads from the Pipe into dst. 45 func (p *Pipe) Read(ctx context.Context, dst usermem.IOSequence) (int64, error) { 46 n, err := p.read(dst.NumBytes(), func(srcs safemem.BlockSeq) (uint64, error) { 47 var done uint64 48 for !srcs.IsEmpty() { 49 src := srcs.Head() 50 n, err := dst.CopyOut(ctx, src.ToSlice()) 51 done += uint64(n) 52 if err != nil { 53 return done, err 54 } 55 dst = dst.DropFirst(n) 56 srcs = srcs.Tail() 57 } 58 return done, nil 59 }, true /* removeFromSrc */) 60 if n > 0 { 61 p.queue.Notify(waiter.WritableEvents) 62 } 63 return n, err 64 } 65 66 func (p *Pipe) read(count int64, f func(srcs safemem.BlockSeq) (uint64, error), removeFromSrc bool) (int64, error) { 67 p.mu.Lock() 68 defer p.mu.Unlock() 69 n, err := p.peekLocked(0, count, f) 70 if n > 0 && removeFromSrc { 71 p.consumeLocked(n) 72 } 73 return n, err 74 } 75 76 // WriteTo writes to w from the Pipe. 77 func (p *Pipe) WriteTo(ctx context.Context, w io.Writer, count int64, dup bool) (int64, error) { 78 n, err := p.read(count, func(srcs safemem.BlockSeq) (uint64, error) { 79 return safemem.FromIOWriter{w}.WriteFromBlocks(srcs) 80 }, !dup /* removeFromSrc */) 81 if n > 0 && !dup { 82 p.queue.Notify(waiter.WritableEvents) 83 } 84 return n, err 85 } 86 87 // Write writes to the Pipe from src. 88 func (p *Pipe) Write(ctx context.Context, src usermem.IOSequence) (int64, error) { 89 n, err := p.write(src.NumBytes(), func(dsts safemem.BlockSeq) (uint64, error) { 90 var done uint64 91 for !dsts.IsEmpty() { 92 dst := dsts.Head() 93 n, err := src.CopyIn(ctx, dst.ToSlice()) 94 done += uint64(n) 95 if err != nil { 96 return done, err 97 } 98 src = src.DropFirst(n) 99 dsts = dsts.Tail() 100 } 101 return done, nil 102 }) 103 if n > 0 { 104 p.queue.Notify(waiter.ReadableEvents) 105 } 106 if linuxerr.Equals(linuxerr.EPIPE, err) { 107 // If we are returning EPIPE send SIGPIPE to the task. 108 if sendSig := linux.SignalNoInfoFuncFromContext(ctx); sendSig != nil { 109 sendSig(linux.SIGPIPE) 110 } 111 } 112 return n, err 113 } 114 115 func (p *Pipe) write(count int64, f func(safemem.BlockSeq) (uint64, error)) (int64, error) { 116 p.mu.Lock() 117 defer p.mu.Unlock() 118 return p.writeLocked(count, f) 119 } 120 121 // ReadFrom reads from r to the Pipe. 122 func (p *Pipe) ReadFrom(ctx context.Context, r io.Reader, count int64) (int64, error) { 123 n, err := p.write(count, func(dsts safemem.BlockSeq) (uint64, error) { 124 return safemem.FromIOReader{r}.ReadToBlocks(dsts) 125 }) 126 if n > 0 { 127 p.queue.Notify(waiter.ReadableEvents) 128 } 129 return n, err 130 } 131 132 // Readiness returns the ready events in the underlying pipe. 133 func (p *Pipe) Readiness(mask waiter.EventMask) waiter.EventMask { 134 return p.rwReadiness() & mask 135 } 136 137 // Ioctl implements ioctls on the Pipe. 138 func (p *Pipe) Ioctl(ctx context.Context, io usermem.IO, sysno uintptr, args arch.SyscallArguments) (uintptr, error) { 139 // Switch on ioctl request. 140 switch int(args[1].Int()) { 141 case linux.FIONREAD: 142 v := p.queued() 143 if v > math.MaxInt32 { 144 v = math.MaxInt32 // Silently truncate. 145 } 146 // Copy result to userspace. 147 iocc := usermem.IOCopyContext{ 148 IO: io, 149 Ctx: ctx, 150 Opts: usermem.IOOpts{ 151 AddressSpaceActive: true, 152 }, 153 } 154 _, err := primitive.CopyInt32Out(&iocc, args[2].Pointer(), int32(v)) 155 return 0, err 156 default: 157 return 0, unix.ENOTTY 158 } 159 }