github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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/nicocha30/gvisor-ligolo/pkg/abi/linux"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr"
    22  	ktime "github.com/nicocha30/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  }