github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/kernel/posixtimer.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 kernel 16 17 import ( 18 "math" 19 20 "github.com/ttpreport/gvisor-ligolo/pkg/abi/linux" 21 "github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr" 22 ktime "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/time" 23 ) 24 25 // IntervalTimer represents a POSIX interval timer as described by 26 // timer_create(2). 27 // 28 // +stateify savable 29 type IntervalTimer struct { 30 timer *ktime.Timer 31 32 // If target is not nil, it receives signo from timer expirations. If group 33 // is true, these signals are thread-group-directed. These fields are 34 // immutable. 35 target *Task 36 signo linux.Signal 37 id linux.TimerID 38 sigval uint64 39 group bool 40 41 // If sigpending is true, a signal to target is already queued, and timer 42 // expirations should increment overrunCur instead of sending another 43 // signal. sigpending is protected by target's signal mutex. (If target is 44 // nil, the timer will never send signals, so sigpending will be unused.) 45 sigpending bool 46 47 // If sigorphan is true, timer's setting has been changed since sigpending 48 // last became true, such that overruns should no longer be counted in the 49 // pending signals si_overrun. sigorphan is protected by target's signal 50 // mutex. 51 sigorphan bool 52 53 // overrunCur is the number of overruns that have occurred since the last 54 // time a signal was sent. overrunCur is protected by target's signal 55 // mutex. 56 overrunCur uint64 57 58 // Consider the last signal sent by this timer that has been dequeued. 59 // overrunLast is the number of overruns that occurred between when this 60 // signal was sent and when it was dequeued. Equivalently, overrunLast was 61 // the value of overrunCur when this signal was dequeued. overrunLast is 62 // protected by target's signal mutex. 63 overrunLast uint64 64 } 65 66 // DestroyTimer releases it's resources. 67 func (it *IntervalTimer) DestroyTimer() { 68 it.timer.Destroy() 69 it.timerSettingChanged() 70 // A destroyed IntervalTimer is still potentially reachable via a 71 // pendingSignal; nil out timer so that it won't be saved. 72 it.timer = nil 73 } 74 75 func (it *IntervalTimer) timerSettingChanged() { 76 if it.target == nil { 77 return 78 } 79 it.target.tg.pidns.owner.mu.RLock() 80 defer it.target.tg.pidns.owner.mu.RUnlock() 81 it.target.tg.signalHandlers.mu.Lock() 82 defer it.target.tg.signalHandlers.mu.Unlock() 83 it.sigorphan = true 84 it.overrunCur = 0 85 it.overrunLast = 0 86 } 87 88 // PauseTimer pauses the associated Timer. 89 func (it *IntervalTimer) PauseTimer() { 90 it.timer.Pause() 91 } 92 93 // ResumeTimer resumes the associated Timer. 94 func (it *IntervalTimer) ResumeTimer() { 95 it.timer.Resume() 96 } 97 98 // Preconditions: it.target's signal mutex must be locked. 99 func (it *IntervalTimer) updateDequeuedSignalLocked(si *linux.SignalInfo) { 100 it.sigpending = false 101 if it.sigorphan { 102 return 103 } 104 it.overrunLast = it.overrunCur 105 it.overrunCur = 0 106 si.SetOverrun(saturateI32FromU64(it.overrunLast)) 107 } 108 109 // Preconditions: it.target's signal mutex must be locked. 110 func (it *IntervalTimer) signalRejectedLocked() { 111 it.sigpending = false 112 if it.sigorphan { 113 return 114 } 115 it.overrunCur++ 116 } 117 118 // NotifyTimer implements ktime.TimerListener.NotifyTimer. 119 func (it *IntervalTimer) NotifyTimer(exp uint64, setting ktime.Setting) (ktime.Setting, bool) { 120 if it.target == nil { 121 return ktime.Setting{}, false 122 } 123 124 it.target.tg.pidns.owner.mu.RLock() 125 defer it.target.tg.pidns.owner.mu.RUnlock() 126 it.target.tg.signalHandlers.mu.Lock() 127 defer it.target.tg.signalHandlers.mu.Unlock() 128 129 if it.sigpending { 130 it.overrunCur += exp 131 return ktime.Setting{}, false 132 } 133 134 // sigpending must be set before sendSignalTimerLocked() so that it can be 135 // unset if the signal is discarded (in which case sendSignalTimerLocked() 136 // will return nil). 137 it.sigpending = true 138 it.sigorphan = false 139 it.overrunCur += exp - 1 140 si := &linux.SignalInfo{ 141 Signo: int32(it.signo), 142 Code: linux.SI_TIMER, 143 } 144 si.SetTimerID(it.id) 145 si.SetSigval(it.sigval) 146 // si_overrun is set when the signal is dequeued. 147 if err := it.target.sendSignalTimerLocked(si, it.group, it); err != nil { 148 it.signalRejectedLocked() 149 } 150 151 return ktime.Setting{}, false 152 } 153 154 // IntervalTimerCreate implements timer_create(2). 155 func (t *Task) IntervalTimerCreate(c ktime.Clock, sigev *linux.Sigevent) (linux.TimerID, error) { 156 t.tg.timerMu.Lock() 157 defer t.tg.timerMu.Unlock() 158 159 // Allocate a timer ID. 160 var id linux.TimerID 161 end := t.tg.nextTimerID 162 for { 163 id = t.tg.nextTimerID 164 _, ok := t.tg.timers[id] 165 t.tg.nextTimerID++ 166 if t.tg.nextTimerID < 0 { 167 t.tg.nextTimerID = 0 168 } 169 if !ok { 170 break 171 } 172 if t.tg.nextTimerID == end { 173 return 0, linuxerr.EAGAIN 174 } 175 } 176 177 // "The implementation of the default case where evp [sic] is NULL is 178 // handled inside glibc, which invokes the underlying system call with a 179 // suitably populated sigevent structure." - timer_create(2). This is 180 // misleading; the timer_create syscall also handles a NULL sevp as 181 // described by the man page 182 // (kernel/time/posix-timers.c:sys_timer_create(), do_timer_create()). This 183 // must be handled here instead of the syscall wrapper since sigval is the 184 // timer ID, which isn't available until we allocate it in this function. 185 if sigev == nil { 186 sigev = &linux.Sigevent{ 187 Signo: int32(linux.SIGALRM), 188 Notify: linux.SIGEV_SIGNAL, 189 Value: uint64(id), 190 } 191 } 192 193 // Construct the timer. 194 it := &IntervalTimer{ 195 id: id, 196 sigval: sigev.Value, 197 } 198 switch sigev.Notify { 199 case linux.SIGEV_NONE: 200 // leave it.target = nil 201 case linux.SIGEV_SIGNAL, linux.SIGEV_THREAD: 202 // POSIX SIGEV_THREAD semantics are implemented in userspace by libc; 203 // to the kernel, SIGEV_THREAD and SIGEV_SIGNAL are equivalent. (See 204 // Linux's kernel/time/posix-timers.c:good_sigevent().) 205 it.target = t.tg.leader 206 it.group = true 207 case linux.SIGEV_THREAD_ID: 208 t.tg.pidns.owner.mu.RLock() 209 target, ok := t.tg.pidns.tasks[ThreadID(sigev.Tid)] 210 t.tg.pidns.owner.mu.RUnlock() 211 if !ok || target.tg != t.tg { 212 return 0, linuxerr.EINVAL 213 } 214 it.target = target 215 default: 216 return 0, linuxerr.EINVAL 217 } 218 if sigev.Notify != linux.SIGEV_NONE { 219 it.signo = linux.Signal(sigev.Signo) 220 if !it.signo.IsValid() { 221 return 0, linuxerr.EINVAL 222 } 223 } 224 it.timer = ktime.NewTimer(c, it) 225 226 t.tg.timers[id] = it 227 return id, nil 228 } 229 230 // IntervalTimerDelete implements timer_delete(2). 231 func (t *Task) IntervalTimerDelete(id linux.TimerID) error { 232 t.tg.timerMu.Lock() 233 defer t.tg.timerMu.Unlock() 234 it := t.tg.timers[id] 235 if it == nil { 236 return linuxerr.EINVAL 237 } 238 delete(t.tg.timers, id) 239 it.DestroyTimer() 240 return nil 241 } 242 243 // IntervalTimerSettime implements timer_settime(2). 244 func (t *Task) IntervalTimerSettime(id linux.TimerID, its linux.Itimerspec, abs bool) (linux.Itimerspec, error) { 245 t.tg.timerMu.Lock() 246 defer t.tg.timerMu.Unlock() 247 it := t.tg.timers[id] 248 if it == nil { 249 return linux.Itimerspec{}, linuxerr.EINVAL 250 } 251 252 newS, err := ktime.SettingFromItimerspec(its, abs, it.timer.Clock()) 253 if err != nil { 254 return linux.Itimerspec{}, err 255 } 256 tm, oldS := it.timer.SwapAnd(newS, it.timerSettingChanged) 257 its = ktime.ItimerspecFromSetting(tm, oldS) 258 return its, nil 259 } 260 261 // IntervalTimerGettime implements timer_gettime(2). 262 func (t *Task) IntervalTimerGettime(id linux.TimerID) (linux.Itimerspec, error) { 263 t.tg.timerMu.Lock() 264 defer t.tg.timerMu.Unlock() 265 it := t.tg.timers[id] 266 if it == nil { 267 return linux.Itimerspec{}, linuxerr.EINVAL 268 } 269 270 tm, s := it.timer.Get() 271 its := ktime.ItimerspecFromSetting(tm, s) 272 return its, nil 273 } 274 275 // IntervalTimerGetoverrun implements timer_getoverrun(2). 276 // 277 // Preconditions: The caller must be running on the task goroutine. 278 func (t *Task) IntervalTimerGetoverrun(id linux.TimerID) (int32, error) { 279 t.tg.timerMu.Lock() 280 defer t.tg.timerMu.Unlock() 281 it := t.tg.timers[id] 282 if it == nil { 283 return 0, linuxerr.EINVAL 284 } 285 // By timer_create(2) invariant, either it.target == nil (in which case 286 // it.overrunLast is immutably 0) or t.tg == it.target.tg; and the fact 287 // that t is executing timer_getoverrun(2) means that t.tg can't be 288 // completing execve, so t.tg.signalHandlers can't be changing, allowing us 289 // to lock t.tg.signalHandlers.mu without holding the TaskSet mutex. 290 t.tg.signalHandlers.mu.Lock() 291 defer t.tg.signalHandlers.mu.Unlock() 292 // This is consistent with Linux after 78c9c4dfbf8c ("posix-timers: 293 // Sanitize overrun handling"). 294 return saturateI32FromU64(it.overrunLast), nil 295 } 296 297 func saturateI32FromU64(x uint64) int32 { 298 if x > math.MaxInt32 { 299 return math.MaxInt32 300 } 301 return int32(x) 302 }