github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/kernel/fasync/fasync.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 fasync provides FIOASYNC related functionality. 16 package fasync 17 18 import ( 19 "github.com/SagerNet/gvisor/pkg/abi/linux" 20 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 21 "github.com/SagerNet/gvisor/pkg/sentry/fs" 22 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 23 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 24 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 25 "github.com/SagerNet/gvisor/pkg/sync" 26 "github.com/SagerNet/gvisor/pkg/waiter" 27 ) 28 29 // Table to convert waiter event masks into si_band siginfo codes. 30 // Taken from fs/fcntl.c:band_table. 31 var bandTable = map[waiter.EventMask]int64{ 32 // POLL_IN 33 waiter.EventIn: linux.EPOLLIN | linux.EPOLLRDNORM, 34 // POLL_OUT 35 waiter.EventOut: linux.EPOLLOUT | linux.EPOLLWRNORM | linux.EPOLLWRBAND, 36 // POLL_ERR 37 waiter.EventErr: linux.EPOLLERR, 38 // POLL_PRI 39 waiter.EventPri: linux.EPOLLPRI | linux.EPOLLRDBAND, 40 // POLL_HUP 41 waiter.EventHUp: linux.EPOLLHUP | linux.EPOLLERR, 42 } 43 44 // New returns a function that creates a new fs.FileAsync with the given file 45 // descriptor. 46 func New(fd int) func() fs.FileAsync { 47 return func() fs.FileAsync { 48 return &FileAsync{fd: fd} 49 } 50 } 51 52 // NewVFS2 returns a function that creates a new vfs.FileAsync with the given 53 // file descriptor. 54 func NewVFS2(fd int) func() vfs.FileAsync { 55 return func() vfs.FileAsync { 56 return &FileAsync{fd: fd} 57 } 58 } 59 60 // FileAsync sends signals when the registered file is ready for IO. 61 // 62 // +stateify savable 63 type FileAsync struct { 64 // e is immutable after first use (which is protected by mu below). 65 e waiter.Entry 66 67 // fd is the file descriptor to notify about. 68 // It is immutable, set at allocation time. This matches Linux semantics in 69 // fs/fcntl.c:fasync_helper. 70 // The fd value is passed to the signal recipient in siginfo.si_fd. 71 fd int 72 73 // regMu protects registeration and unregistration actions on e. 74 // 75 // regMu must be held while registration decisions are being made 76 // through the registration action itself. 77 // 78 // Lock ordering: regMu, mu. 79 regMu sync.Mutex `state:"nosave"` 80 81 // mu protects all following fields. 82 // 83 // Lock ordering: e.mu, mu. 84 mu sync.Mutex `state:"nosave"` 85 requester *auth.Credentials 86 registered bool 87 // signal is the signal to deliver upon I/O being available. 88 // The default value ("zero signal") means the default SIGIO signal will be 89 // delivered. 90 signal linux.Signal 91 92 // Only one of the following is allowed to be non-nil. 93 recipientPG *kernel.ProcessGroup 94 recipientTG *kernel.ThreadGroup 95 recipientT *kernel.Task 96 } 97 98 // Callback sends a signal. 99 func (a *FileAsync) Callback(e *waiter.Entry, mask waiter.EventMask) { 100 a.mu.Lock() 101 defer a.mu.Unlock() 102 if !a.registered { 103 return 104 } 105 t := a.recipientT 106 tg := a.recipientTG 107 if a.recipientPG != nil { 108 tg = a.recipientPG.Originator() 109 } 110 if tg != nil { 111 t = tg.Leader() 112 } 113 if t == nil { 114 // No recipient has been registered. 115 return 116 } 117 c := t.Credentials() 118 // Logic from sigio_perm in fs/fcntl.c. 119 permCheck := (a.requester.EffectiveKUID == 0 || 120 a.requester.EffectiveKUID == c.SavedKUID || 121 a.requester.EffectiveKUID == c.RealKUID || 122 a.requester.RealKUID == c.SavedKUID || 123 a.requester.RealKUID == c.RealKUID) 124 if !permCheck { 125 return 126 } 127 signalInfo := &linux.SignalInfo{ 128 Signo: int32(linux.SIGIO), 129 Code: linux.SI_KERNEL, 130 } 131 if a.signal != 0 { 132 signalInfo.Signo = int32(a.signal) 133 signalInfo.SetFD(uint32(a.fd)) 134 var band int64 135 for m, bandCode := range bandTable { 136 if m&mask != 0 { 137 band |= bandCode 138 } 139 } 140 signalInfo.SetBand(band) 141 } 142 t.SendSignal(signalInfo) 143 } 144 145 // Register sets the file which will be monitored for IO events. 146 // 147 // The file must not be currently registered. 148 func (a *FileAsync) Register(w waiter.Waitable) { 149 a.regMu.Lock() 150 defer a.regMu.Unlock() 151 a.mu.Lock() 152 153 if a.registered { 154 a.mu.Unlock() 155 panic("registering already registered file") 156 } 157 158 if a.e.Callback == nil { 159 a.e.Callback = a 160 } 161 a.registered = true 162 163 a.mu.Unlock() 164 w.EventRegister(&a.e, waiter.ReadableEvents|waiter.WritableEvents|waiter.EventErr|waiter.EventHUp) 165 } 166 167 // Unregister stops monitoring a file. 168 // 169 // The file must be currently registered. 170 func (a *FileAsync) Unregister(w waiter.Waitable) { 171 a.regMu.Lock() 172 defer a.regMu.Unlock() 173 a.mu.Lock() 174 175 if !a.registered { 176 a.mu.Unlock() 177 panic("unregistering unregistered file") 178 } 179 180 a.registered = false 181 182 a.mu.Unlock() 183 w.EventUnregister(&a.e) 184 } 185 186 // Owner returns who is currently getting signals. All return values will be 187 // nil if no one is set to receive signals. 188 func (a *FileAsync) Owner() (*kernel.Task, *kernel.ThreadGroup, *kernel.ProcessGroup) { 189 a.mu.Lock() 190 defer a.mu.Unlock() 191 return a.recipientT, a.recipientTG, a.recipientPG 192 } 193 194 // SetOwnerTask sets the owner (who will receive signals) to a specified task. 195 // Only this owner will receive signals. 196 func (a *FileAsync) SetOwnerTask(requester *kernel.Task, recipient *kernel.Task) { 197 a.mu.Lock() 198 defer a.mu.Unlock() 199 a.requester = requester.Credentials() 200 a.recipientT = recipient 201 a.recipientTG = nil 202 a.recipientPG = nil 203 } 204 205 // SetOwnerThreadGroup sets the owner (who will receive signals) to a specified 206 // thread group. Only this owner will receive signals. 207 func (a *FileAsync) SetOwnerThreadGroup(requester *kernel.Task, recipient *kernel.ThreadGroup) { 208 a.mu.Lock() 209 defer a.mu.Unlock() 210 a.requester = requester.Credentials() 211 a.recipientT = nil 212 a.recipientTG = recipient 213 a.recipientPG = nil 214 } 215 216 // SetOwnerProcessGroup sets the owner (who will receive signals) to a 217 // specified process group. Only this owner will receive signals. 218 func (a *FileAsync) SetOwnerProcessGroup(requester *kernel.Task, recipient *kernel.ProcessGroup) { 219 a.mu.Lock() 220 defer a.mu.Unlock() 221 a.requester = requester.Credentials() 222 a.recipientT = nil 223 a.recipientTG = nil 224 a.recipientPG = recipient 225 } 226 227 // ClearOwner unsets the current signal recipient. 228 func (a *FileAsync) ClearOwner() { 229 a.mu.Lock() 230 defer a.mu.Unlock() 231 a.requester = nil 232 a.recipientT = nil 233 a.recipientTG = nil 234 a.recipientPG = nil 235 } 236 237 // Signal returns which signal will be sent to the signal recipient. 238 // A value of zero means the signal to deliver wasn't customized, which means 239 // the default signal (SIGIO) will be delivered. 240 func (a *FileAsync) Signal() linux.Signal { 241 a.mu.Lock() 242 defer a.mu.Unlock() 243 return a.signal 244 } 245 246 // SetSignal overrides which signal to send when I/O is available. 247 // The default behavior can be reset by specifying signal zero, which means 248 // to send SIGIO. 249 func (a *FileAsync) SetSignal(signal linux.Signal) error { 250 if signal != 0 && !signal.IsValid() { 251 return linuxerr.EINVAL 252 } 253 a.mu.Lock() 254 defer a.mu.Unlock() 255 a.signal = signal 256 return nil 257 }