github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/fsimpl/signalfd/signalfd.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 signalfd provides basic signalfd file implementations. 16 package signalfd 17 18 import ( 19 "github.com/ttpreport/gvisor-ligolo/pkg/abi/linux" 20 "github.com/ttpreport/gvisor-ligolo/pkg/context" 21 "github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr" 22 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel" 23 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/vfs" 24 "github.com/ttpreport/gvisor-ligolo/pkg/sync" 25 "github.com/ttpreport/gvisor-ligolo/pkg/usermem" 26 "github.com/ttpreport/gvisor-ligolo/pkg/waiter" 27 ) 28 29 // SignalFileDescription implements vfs.FileDescriptionImpl for signal fds. 30 // 31 // +stateify savable 32 type SignalFileDescription struct { 33 vfsfd vfs.FileDescription 34 vfs.FileDescriptionDefaultImpl 35 vfs.DentryMetadataFileDescriptionImpl 36 vfs.NoLockFD 37 vfs.NoAsyncEventFD 38 39 // target is the original signal target task. 40 // 41 // The semantics here are a bit broken. Linux will always use current 42 // for all reads, regardless of where the signalfd originated. We can't 43 // do exactly that because we need to plumb the context through 44 // EventRegister in order to support proper blocking behavior. This 45 // will undoubtedly become very complicated quickly. 46 target *kernel.Task 47 48 // queue is the queue for listeners. 49 queue waiter.Queue 50 51 // mu protects entry. 52 mu sync.Mutex `state:"nosave"` 53 54 // entry is the entry in the task signal queue. 55 entry waiter.Entry 56 } 57 58 var _ vfs.FileDescriptionImpl = (*SignalFileDescription)(nil) 59 60 // New creates a new signal fd. 61 func New(vfsObj *vfs.VirtualFilesystem, target *kernel.Task, mask linux.SignalSet, flags uint32) (*vfs.FileDescription, error) { 62 vd := vfsObj.NewAnonVirtualDentry("[signalfd]") 63 defer vd.DecRef(target) 64 sfd := &SignalFileDescription{ 65 target: target, 66 } 67 sfd.entry.Init(sfd, waiter.EventMask(mask)) 68 sfd.target.SignalRegister(&sfd.entry) 69 if err := sfd.vfsfd.Init(sfd, flags, vd.Mount(), vd.Dentry(), &vfs.FileDescriptionOptions{ 70 UseDentryMetadata: true, 71 DenyPRead: true, 72 DenyPWrite: true, 73 }); err != nil { 74 sfd.target.SignalUnregister(&sfd.entry) 75 return nil, err 76 } 77 return &sfd.vfsfd, nil 78 } 79 80 // Mask returns the signal mask. 81 func (sfd *SignalFileDescription) Mask() linux.SignalSet { 82 sfd.mu.Lock() 83 defer sfd.mu.Unlock() 84 return linux.SignalSet(sfd.entry.Mask()) 85 } 86 87 // SetMask sets the signal mask. 88 func (sfd *SignalFileDescription) SetMask(mask linux.SignalSet) { 89 sfd.mu.Lock() 90 defer sfd.mu.Unlock() 91 sfd.target.SignalUnregister(&sfd.entry) 92 sfd.entry.Init(sfd, waiter.EventMask(mask)) 93 sfd.target.SignalRegister(&sfd.entry) 94 } 95 96 // Read implements vfs.FileDescriptionImpl.Read. 97 func (sfd *SignalFileDescription) Read(ctx context.Context, dst usermem.IOSequence, _ vfs.ReadOptions) (int64, error) { 98 // Attempt to dequeue relevant signals. 99 info, err := sfd.target.Sigtimedwait(sfd.Mask(), 0) 100 if err != nil { 101 // There must be no signal available. 102 return 0, linuxerr.ErrWouldBlock 103 } 104 105 // Copy out the signal info using the specified format. 106 infoNative := linux.SignalfdSiginfo{ 107 Signo: uint32(info.Signo), 108 Errno: info.Errno, 109 Code: info.Code, 110 PID: uint32(info.PID()), 111 UID: uint32(info.UID()), 112 Status: info.Status(), 113 Overrun: uint32(info.Overrun()), 114 Addr: info.Addr(), 115 } 116 n, err := infoNative.WriteTo(dst.Writer(ctx)) 117 if err == usermem.ErrEndOfIOSequence { 118 // Partial copy-out ok. 119 err = nil 120 } 121 return n, err 122 } 123 124 // Readiness implements waiter.Waitable.Readiness. 125 func (sfd *SignalFileDescription) Readiness(mask waiter.EventMask) waiter.EventMask { 126 sfd.mu.Lock() 127 defer sfd.mu.Unlock() 128 if mask&waiter.ReadableEvents != 0 && sfd.target.PendingSignals()&linux.SignalSet(sfd.entry.Mask()) != 0 { 129 return waiter.ReadableEvents // Pending signals. 130 } 131 return 0 132 } 133 134 // EventRegister implements waiter.Waitable.EventRegister. 135 func (sfd *SignalFileDescription) EventRegister(e *waiter.Entry) error { 136 sfd.queue.EventRegister(e) 137 return nil 138 } 139 140 // EventUnregister implements waiter.Waitable.EventUnregister. 141 func (sfd *SignalFileDescription) EventUnregister(e *waiter.Entry) { 142 sfd.queue.EventUnregister(e) 143 } 144 145 // NotifyEvent implements waiter.EventListener.NotifyEvent. 146 func (sfd *SignalFileDescription) NotifyEvent(mask waiter.EventMask) { 147 sfd.queue.Notify(waiter.EventIn) // Always notify data available. 148 } 149 150 // Epollable implements FileDescriptionImpl.Epollable. 151 func (sfd *SignalFileDescription) Epollable() bool { 152 return true 153 } 154 155 // Release implements vfs.FileDescriptionImpl.Release. 156 func (sfd *SignalFileDescription) Release(context.Context) { 157 sfd.target.SignalUnregister(&sfd.entry) 158 } 159 160 // RegisterFileAsyncHandler implements vfs.FileDescriptionImpl.RegisterFileAsyncHandler. 161 func (sfd *SignalFileDescription) RegisterFileAsyncHandler(fd *vfs.FileDescription) error { 162 return sfd.NoAsyncEventFD.RegisterFileAsyncHandler(fd) 163 } 164 165 // UnregisterFileAsyncHandler implements vfs.FileDescriptionImpl.UnregisterFileAsyncHandler. 166 func (sfd *SignalFileDescription) UnregisterFileAsyncHandler(fd *vfs.FileDescription) { 167 sfd.NoAsyncEventFD.UnregisterFileAsyncHandler(fd) 168 }