github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/kernel/timekeeper.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  	"fmt"
    19  	"time"
    20  
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/atomicbitops"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/log"
    23  	ktime "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/time"
    24  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/memmap"
    25  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/pgalloc"
    26  	sentrytime "github.com/nicocha30/gvisor-ligolo/pkg/sentry/time"
    27  	"github.com/nicocha30/gvisor-ligolo/pkg/sync"
    28  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip"
    29  )
    30  
    31  // Timekeeper manages all of the kernel clocks.
    32  //
    33  // +stateify savable
    34  type Timekeeper struct {
    35  	// clocks are the clock sources.
    36  	//
    37  	// These are not saved directly, as the new machine's clock may behave
    38  	// differently.
    39  	//
    40  	// It is set only once, by SetClocks.
    41  	clocks sentrytime.Clocks `state:"nosave"`
    42  
    43  	// realtimeClock is a ktime.Clock based on timekeeper's Realtime.
    44  	realtimeClock *timekeeperClock
    45  
    46  	// monotonicClock is a ktime.Clock based on timekeeper's Monotonic.
    47  	monotonicClock *timekeeperClock
    48  
    49  	// bootTime is the realtime when the system "booted". i.e., when
    50  	// SetClocks was called in the initial (not restored) run.
    51  	bootTime ktime.Time
    52  
    53  	// monotonicOffset is the offset to apply to the monotonic clock output
    54  	// from clocks.
    55  	//
    56  	// It is set only once, by SetClocks.
    57  	monotonicOffset int64 `state:"nosave"`
    58  
    59  	// monotonicLowerBound is the lowerBound for monotonic time.
    60  	monotonicLowerBound atomicbitops.Int64 `state:"nosave"`
    61  
    62  	// restored, if non-nil, indicates that this Timekeeper was restored
    63  	// from a state file. The clocks are not set until restored is closed.
    64  	restored chan struct{} `state:"nosave"`
    65  
    66  	// saveMonotonic is the (offset) value of the monotonic clock at the
    67  	// time of save.
    68  	//
    69  	// It is only valid if restored is non-nil.
    70  	//
    71  	// It is only used in SetClocks after restore to compute the new
    72  	// monotonicOffset.
    73  	saveMonotonic int64
    74  
    75  	// saveRealtime is the value of the realtime clock at the time of save.
    76  	//
    77  	// It is only valid if restored is non-nil.
    78  	//
    79  	// It is only used in SetClocks after restore to compute the new
    80  	// monotonicOffset.
    81  	saveRealtime int64
    82  
    83  	// params manages the parameter page.
    84  	params *VDSOParamPage
    85  
    86  	// mu protects destruction with stop and wg.
    87  	mu sync.Mutex `state:"nosave"`
    88  
    89  	// stop is used to tell the update goroutine to exit.
    90  	stop chan struct{} `state:"nosave"`
    91  
    92  	// wg is used to indicate that the update goroutine has exited.
    93  	wg sync.WaitGroup `state:"nosave"`
    94  }
    95  
    96  // NewTimekeeper returns a Timekeeper that is automatically kept up-to-date.
    97  // NewTimekeeper does not take ownership of paramPage.
    98  //
    99  // SetClocks must be called on the returned Timekeeper before it is usable.
   100  func NewTimekeeper(mfp pgalloc.MemoryFileProvider, paramPage memmap.FileRange) *Timekeeper {
   101  	t := Timekeeper{
   102  		params: NewVDSOParamPage(mfp, paramPage),
   103  	}
   104  	t.realtimeClock = &timekeeperClock{tk: &t, c: sentrytime.Realtime}
   105  	t.monotonicClock = &timekeeperClock{tk: &t, c: sentrytime.Monotonic}
   106  	return &t
   107  }
   108  
   109  // SetClocks the backing clock source.
   110  //
   111  // SetClocks must be called before the Timekeeper is used, and it may not be
   112  // called more than once, as changing the clock source without extra correction
   113  // could cause time discontinuities.
   114  //
   115  // It must also be called after Load.
   116  func (t *Timekeeper) SetClocks(c sentrytime.Clocks) {
   117  	// Update the params, marking them "not ready", as we may need to
   118  	// restart calibration on this new machine.
   119  	if t.restored != nil {
   120  		if err := t.params.Write(func() vdsoParams {
   121  			return vdsoParams{}
   122  		}); err != nil {
   123  			panic("unable to reset VDSO params: " + err.Error())
   124  		}
   125  	}
   126  
   127  	if t.clocks != nil {
   128  		panic("SetClocks called on previously-initialized Timekeeper")
   129  	}
   130  
   131  	t.clocks = c
   132  
   133  	// Compute the offset of the monotonic clock from the base Clocks.
   134  	//
   135  	// In a fresh (not restored) sentry, monotonic time starts at zero.
   136  	//
   137  	// In a restored sentry, monotonic time jumps forward by approximately
   138  	// the same amount as real time. There are no guarantees here, we are
   139  	// just making a best-effort attempt to make it appear that the app
   140  	// was simply not scheduled for a long period, rather than that the
   141  	// real time clock was changed.
   142  	//
   143  	// If real time went backwards, it remains the same.
   144  	wantMonotonic := int64(0)
   145  
   146  	nowMonotonic, err := t.clocks.GetTime(sentrytime.Monotonic)
   147  	if err != nil {
   148  		panic("Unable to get current monotonic time: " + err.Error())
   149  	}
   150  
   151  	nowRealtime, err := t.clocks.GetTime(sentrytime.Realtime)
   152  	if err != nil {
   153  		panic("Unable to get current realtime: " + err.Error())
   154  	}
   155  
   156  	if t.restored != nil {
   157  		wantMonotonic = t.saveMonotonic
   158  		elapsed := nowRealtime - t.saveRealtime
   159  		if elapsed > 0 {
   160  			wantMonotonic += elapsed
   161  		}
   162  	}
   163  
   164  	t.monotonicOffset = wantMonotonic - nowMonotonic
   165  
   166  	if t.restored == nil {
   167  		// Hold on to the initial "boot" time.
   168  		t.bootTime = ktime.FromNanoseconds(nowRealtime)
   169  	}
   170  
   171  	t.mu.Lock()
   172  	defer t.mu.Unlock()
   173  	t.startUpdater()
   174  
   175  	if t.restored != nil {
   176  		close(t.restored)
   177  	}
   178  }
   179  
   180  var _ tcpip.Clock = (*Timekeeper)(nil)
   181  
   182  // Now implements tcpip.Clock.
   183  func (t *Timekeeper) Now() time.Time {
   184  	nsec, err := t.GetTime(sentrytime.Realtime)
   185  	if err != nil {
   186  		panic("timekeeper.GetTime(sentrytime.Realtime): " + err.Error())
   187  	}
   188  	return time.Unix(0, nsec)
   189  }
   190  
   191  // NowMonotonic implements tcpip.Clock.
   192  func (t *Timekeeper) NowMonotonic() tcpip.MonotonicTime {
   193  	nsec, err := t.GetTime(sentrytime.Monotonic)
   194  	if err != nil {
   195  		panic("timekeeper.GetTime(sentrytime.Monotonic): " + err.Error())
   196  	}
   197  	var mt tcpip.MonotonicTime
   198  	return mt.Add(time.Duration(nsec) * time.Nanosecond)
   199  }
   200  
   201  // AfterFunc implements tcpip.Clock.
   202  func (t *Timekeeper) AfterFunc(d time.Duration, f func()) tcpip.Timer {
   203  	return ktime.AfterFunc(t.realtimeClock, d, f)
   204  }
   205  
   206  // startUpdater starts an update goroutine that keeps the clocks updated.
   207  //
   208  // mu must be held.
   209  func (t *Timekeeper) startUpdater() {
   210  	if t.stop != nil {
   211  		// Timekeeper already started
   212  		return
   213  	}
   214  	t.stop = make(chan struct{})
   215  
   216  	// Keep the clocks up to date.
   217  	//
   218  	// Note that the Go runtime uses host CLOCK_MONOTONIC to service the
   219  	// timer, so it may run at a *slightly* different rate from the
   220  	// application CLOCK_MONOTONIC. That is fine, as we only need to update
   221  	// at approximately this rate.
   222  	timer := time.NewTicker(sentrytime.ApproxUpdateInterval)
   223  	t.wg.Add(1)
   224  	go func() { // S/R-SAFE: stopped during save.
   225  		defer t.wg.Done()
   226  		for {
   227  			// Start with an update immediately, so the clocks are
   228  			// ready ASAP.
   229  
   230  			// Call Update within a Write block to prevent the VDSO
   231  			// from using the old params between Update and
   232  			// Write.
   233  			if err := t.params.Write(func() vdsoParams {
   234  				monotonicParams, monotonicOk, realtimeParams, realtimeOk := t.clocks.Update()
   235  
   236  				var p vdsoParams
   237  				if monotonicOk {
   238  					p.monotonicReady = 1
   239  					p.monotonicBaseCycles = int64(monotonicParams.BaseCycles)
   240  					p.monotonicBaseRef = int64(monotonicParams.BaseRef) + t.monotonicOffset
   241  					p.monotonicFrequency = monotonicParams.Frequency
   242  				}
   243  				if realtimeOk {
   244  					p.realtimeReady = 1
   245  					p.realtimeBaseCycles = int64(realtimeParams.BaseCycles)
   246  					p.realtimeBaseRef = int64(realtimeParams.BaseRef)
   247  					p.realtimeFrequency = realtimeParams.Frequency
   248  				}
   249  				return p
   250  			}); err != nil {
   251  				log.Warningf("Unable to update VDSO parameter page: %v", err)
   252  			}
   253  
   254  			select {
   255  			case <-timer.C:
   256  			case <-t.stop:
   257  				return
   258  			}
   259  		}
   260  	}()
   261  }
   262  
   263  // stopUpdater stops the update goroutine, blocking until it exits.
   264  //
   265  // mu must be held.
   266  func (t *Timekeeper) stopUpdater() {
   267  	if t.stop == nil {
   268  		// Updater not running.
   269  		return
   270  	}
   271  
   272  	close(t.stop)
   273  	t.wg.Wait()
   274  	t.stop = nil
   275  }
   276  
   277  // Destroy destroys the Timekeeper, freeing all associated resources.
   278  func (t *Timekeeper) Destroy() {
   279  	t.mu.Lock()
   280  	defer t.mu.Unlock()
   281  
   282  	t.stopUpdater()
   283  }
   284  
   285  // PauseUpdates stops clock parameter updates. This should only be used when
   286  // Tasks are not running and thus cannot access the clock.
   287  func (t *Timekeeper) PauseUpdates() {
   288  	t.mu.Lock()
   289  	defer t.mu.Unlock()
   290  	t.stopUpdater()
   291  }
   292  
   293  // ResumeUpdates restarts clock parameter updates stopped by PauseUpdates.
   294  func (t *Timekeeper) ResumeUpdates() {
   295  	t.mu.Lock()
   296  	defer t.mu.Unlock()
   297  	t.startUpdater()
   298  }
   299  
   300  // GetTime returns the current time in nanoseconds.
   301  func (t *Timekeeper) GetTime(c sentrytime.ClockID) (int64, error) {
   302  	if t.clocks == nil {
   303  		if t.restored == nil {
   304  			panic("Timekeeper used before initialized with SetClocks")
   305  		}
   306  		<-t.restored
   307  	}
   308  	now, err := t.clocks.GetTime(c)
   309  	if err == nil && c == sentrytime.Monotonic {
   310  		now += t.monotonicOffset
   311  		for {
   312  			// It's possible that the clock is shaky. This may be due to
   313  			// platform issues, e.g. the KVM platform relies on the guest
   314  			// TSC and host TSC, which may not be perfectly in sync. To
   315  			// work around this issue, ensure that the monotonic time is
   316  			// always bounded by the last time read.
   317  			oldLowerBound := t.monotonicLowerBound.Load()
   318  			if now < oldLowerBound {
   319  				now = oldLowerBound
   320  				break
   321  			}
   322  			if t.monotonicLowerBound.CompareAndSwap(oldLowerBound, now) {
   323  				break
   324  			}
   325  		}
   326  	}
   327  	return now, err
   328  }
   329  
   330  // BootTime returns the system boot real time.
   331  func (t *Timekeeper) BootTime() ktime.Time {
   332  	return t.bootTime
   333  }
   334  
   335  // timekeeperClock is a ktime.Clock that reads time from a
   336  // kernel.Timekeeper-managed clock.
   337  //
   338  // +stateify savable
   339  type timekeeperClock struct {
   340  	tk *Timekeeper
   341  	c  sentrytime.ClockID
   342  
   343  	// Implements ktime.Clock.WallTimeUntil.
   344  	ktime.WallRateClock `state:"nosave"`
   345  
   346  	// Implements waiter.Waitable. (We have no ability to detect
   347  	// discontinuities from external changes to CLOCK_REALTIME).
   348  	ktime.NoClockEvents `state:"nosave"`
   349  }
   350  
   351  // Now implements ktime.Clock.Now.
   352  func (tc *timekeeperClock) Now() ktime.Time {
   353  	now, err := tc.tk.GetTime(tc.c)
   354  	if err != nil {
   355  		panic(fmt.Sprintf("timekeeperClock(ClockID=%v)).Now: %v", tc.c, err))
   356  	}
   357  	return ktime.FromNanoseconds(now)
   358  }