github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/fsimpl/timerfd/timerfd.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 timerfd implements timer fds. 16 package timerfd 17 18 import ( 19 "github.com/ttpreport/gvisor-ligolo/pkg/atomicbitops" 20 "github.com/ttpreport/gvisor-ligolo/pkg/context" 21 "github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr" 22 "github.com/ttpreport/gvisor-ligolo/pkg/hostarch" 23 ktime "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/time" 24 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/vfs" 25 "github.com/ttpreport/gvisor-ligolo/pkg/usermem" 26 "github.com/ttpreport/gvisor-ligolo/pkg/waiter" 27 ) 28 29 // TimerFileDescription implements vfs.FileDescriptionImpl for timer fds. It also 30 // implements ktime.TimerListener. 31 // 32 // +stateify savable 33 type TimerFileDescription struct { 34 vfsfd vfs.FileDescription 35 vfs.FileDescriptionDefaultImpl 36 vfs.DentryMetadataFileDescriptionImpl 37 vfs.NoLockFD 38 39 events waiter.Queue 40 timer *ktime.Timer 41 42 // val is the number of timer expirations since the last successful 43 // call to PRead, or SetTime. val must be accessed using atomic memory 44 // operations. 45 val atomicbitops.Uint64 46 } 47 48 var _ vfs.FileDescriptionImpl = (*TimerFileDescription)(nil) 49 var _ ktime.Listener = (*TimerFileDescription)(nil) 50 51 // New returns a new timer fd. 52 func New(ctx context.Context, vfsObj *vfs.VirtualFilesystem, clock ktime.Clock, flags uint32) (*vfs.FileDescription, error) { 53 vd := vfsObj.NewAnonVirtualDentry("[timerfd]") 54 defer vd.DecRef(ctx) 55 tfd := &TimerFileDescription{} 56 tfd.timer = ktime.NewTimer(clock, tfd) 57 if err := tfd.vfsfd.Init(tfd, flags, vd.Mount(), vd.Dentry(), &vfs.FileDescriptionOptions{ 58 UseDentryMetadata: true, 59 DenyPRead: true, 60 DenyPWrite: true, 61 }); err != nil { 62 return nil, err 63 } 64 return &tfd.vfsfd, nil 65 } 66 67 // Read implements vfs.FileDescriptionImpl.Read. 68 func (tfd *TimerFileDescription) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) { 69 const sizeofUint64 = 8 70 if dst.NumBytes() < sizeofUint64 { 71 return 0, linuxerr.EINVAL 72 } 73 if val := tfd.val.Swap(0); val != 0 { 74 var buf [sizeofUint64]byte 75 hostarch.ByteOrder.PutUint64(buf[:], val) 76 if _, err := dst.CopyOut(ctx, buf[:]); err != nil { 77 // Linux does not undo consuming the number of 78 // expirations even if writing to userspace fails. 79 return 0, err 80 } 81 return sizeofUint64, nil 82 } 83 return 0, linuxerr.ErrWouldBlock 84 } 85 86 // Clock returns the timer fd's Clock. 87 func (tfd *TimerFileDescription) Clock() ktime.Clock { 88 return tfd.timer.Clock() 89 } 90 91 // GetTime returns the associated Timer's setting and the time at which it was 92 // observed. 93 func (tfd *TimerFileDescription) GetTime() (ktime.Time, ktime.Setting) { 94 return tfd.timer.Get() 95 } 96 97 // SetTime atomically changes the associated Timer's setting, resets the number 98 // of expirations to 0, and returns the previous setting and the time at which 99 // it was observed. 100 func (tfd *TimerFileDescription) SetTime(s ktime.Setting) (ktime.Time, ktime.Setting) { 101 return tfd.timer.SwapAnd(s, func() { tfd.val.Store(0) }) 102 } 103 104 // Readiness implements waiter.Waitable.Readiness. 105 func (tfd *TimerFileDescription) Readiness(mask waiter.EventMask) waiter.EventMask { 106 var ready waiter.EventMask 107 if tfd.val.Load() != 0 { 108 ready |= waiter.ReadableEvents 109 } 110 return ready 111 } 112 113 // EventRegister implements waiter.Waitable.EventRegister. 114 func (tfd *TimerFileDescription) EventRegister(e *waiter.Entry) error { 115 tfd.events.EventRegister(e) 116 return nil 117 } 118 119 // EventUnregister implements waiter.Waitable.EventUnregister. 120 func (tfd *TimerFileDescription) EventUnregister(e *waiter.Entry) { 121 tfd.events.EventUnregister(e) 122 } 123 124 // Epollable implements FileDescriptionImpl.Epollable. 125 func (tfd *TimerFileDescription) Epollable() bool { 126 return true 127 } 128 129 // PauseTimer pauses the associated Timer. 130 func (tfd *TimerFileDescription) PauseTimer() { 131 tfd.timer.Pause() 132 } 133 134 // ResumeTimer resumes the associated Timer. 135 func (tfd *TimerFileDescription) ResumeTimer() { 136 tfd.timer.Resume() 137 } 138 139 // Release implements vfs.FileDescriptionImpl.Release. 140 func (tfd *TimerFileDescription) Release(context.Context) { 141 tfd.timer.Destroy() 142 } 143 144 // NotifyTimer implements ktime.TimerListener.NotifyTimer. 145 func (tfd *TimerFileDescription) NotifyTimer(exp uint64, setting ktime.Setting) (ktime.Setting, bool) { 146 tfd.val.Add(exp) 147 tfd.events.Notify(waiter.ReadableEvents) 148 return ktime.Setting{}, false 149 }