github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/kernel/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 an implementation of signal file descriptors. 16 package signalfd 17 18 import ( 19 "github.com/SagerNet/gvisor/pkg/abi/linux" 20 "github.com/SagerNet/gvisor/pkg/context" 21 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 22 "github.com/SagerNet/gvisor/pkg/sentry/fs" 23 "github.com/SagerNet/gvisor/pkg/sentry/fs/anon" 24 "github.com/SagerNet/gvisor/pkg/sentry/fs/fsutil" 25 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 26 "github.com/SagerNet/gvisor/pkg/sync" 27 "github.com/SagerNet/gvisor/pkg/syserror" 28 "github.com/SagerNet/gvisor/pkg/usermem" 29 "github.com/SagerNet/gvisor/pkg/waiter" 30 ) 31 32 // SignalOperations represent a file with signalfd semantics. 33 // 34 // +stateify savable 35 type SignalOperations struct { 36 fsutil.FileNoopRelease `state:"nosave"` 37 fsutil.FilePipeSeek `state:"nosave"` 38 fsutil.FileNotDirReaddir `state:"nosave"` 39 fsutil.FileNoIoctl `state:"nosave"` 40 fsutil.FileNoFsync `state:"nosave"` 41 fsutil.FileNoMMap `state:"nosave"` 42 fsutil.FileNoSplice `state:"nosave"` 43 fsutil.FileNoWrite `state:"nosave"` 44 fsutil.FileNoopFlush `state:"nosave"` 45 fsutil.FileUseInodeUnstableAttr `state:"nosave"` 46 47 // target is the original task target. 48 // 49 // The semantics here are a bit broken. Linux will always use current 50 // for all reads, regardless of where the signalfd originated. We can't 51 // do exactly that because we need to plumb the context through 52 // EventRegister in order to support proper blocking behavior. This 53 // will undoubtedly become very complicated quickly. 54 target *kernel.Task 55 56 // mu protects below. 57 mu sync.Mutex `state:"nosave"` 58 59 // mask is the signal mask. Protected by mu. 60 mask linux.SignalSet 61 } 62 63 // New creates a new signalfd object with the supplied mask. 64 func New(ctx context.Context, mask linux.SignalSet) (*fs.File, error) { 65 t := kernel.TaskFromContext(ctx) 66 if t == nil { 67 // No task context? Not valid. 68 return nil, linuxerr.EINVAL 69 } 70 // name matches fs/signalfd.c:signalfd4. 71 dirent := fs.NewDirent(ctx, anon.NewInode(ctx), "anon_inode:[signalfd]") 72 return fs.NewFile(ctx, dirent, fs.FileFlags{Read: true, Write: true}, &SignalOperations{ 73 target: t, 74 mask: mask, 75 }), nil 76 } 77 78 // Release implements fs.FileOperations.Release. 79 func (s *SignalOperations) Release(context.Context) {} 80 81 // Mask returns the signal mask. 82 func (s *SignalOperations) Mask() linux.SignalSet { 83 s.mu.Lock() 84 mask := s.mask 85 s.mu.Unlock() 86 return mask 87 } 88 89 // SetMask sets the signal mask. 90 func (s *SignalOperations) SetMask(mask linux.SignalSet) { 91 s.mu.Lock() 92 s.mask = mask 93 s.mu.Unlock() 94 } 95 96 // Read implements fs.FileOperations.Read. 97 func (s *SignalOperations) Read(ctx context.Context, _ *fs.File, dst usermem.IOSequence, _ int64) (int64, error) { 98 // Attempt to dequeue relevant signals. 99 info, err := s.target.Sigtimedwait(s.Mask(), 0) 100 if err != nil { 101 // There must be no signal available. 102 return 0, syserror.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 (s *SignalOperations) Readiness(mask waiter.EventMask) waiter.EventMask { 126 if mask&waiter.ReadableEvents != 0 && s.target.PendingSignals()&s.Mask() != 0 { 127 return waiter.ReadableEvents // Pending signals. 128 } 129 return 0 130 } 131 132 // EventRegister implements waiter.Waitable.EventRegister. 133 func (s *SignalOperations) EventRegister(entry *waiter.Entry, _ waiter.EventMask) { 134 // Register for the signal set; ignore the passed events. 135 s.target.SignalRegister(entry, waiter.EventMask(s.Mask())) 136 } 137 138 // EventUnregister implements waiter.Waitable.EventUnregister. 139 func (s *SignalOperations) EventUnregister(entry *waiter.Entry) { 140 // Unregister the original entry. 141 s.target.SignalUnregister(entry) 142 }