insecure_time/
lib.rs

1#![no_std]
2#![cfg_attr(all(feature = "std", target_env = "sgx"), feature(sgx_platform))]
3
4#[cfg(feature = "std")]
5extern crate std;
6
7#[cfg(feature = "std")]
8extern crate alloc;
9
10use alloc::borrow::ToOwned;
11
12#[cfg(feature = "std")]
13use std::time::SystemTime;
14
15#[cfg(all(feature = "std", target_os = "linux"))]
16use std::fs;
17
18#[cfg(not(target_env = "sgx"))]
19use core::arch::x86_64::__cpuid;
20use core::arch::x86_64::__rdtscp;
21use core::cell::RefCell;
22use core::cmp::{self, PartialEq, PartialOrd};
23use core::fmt::{self, Debug, Display, Formatter};
24use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
25use core::time::Duration;
26use core::ops::Add;
27
28const NANOS_PER_SEC: u64 = 1_000_000_000;
29
30pub trait NativeTime: Debug + PartialOrd + Copy + Add<core::time::Duration, Output = Self> + ToOwned {
31    fn minimum() -> Self;
32    fn abs_diff(&self, other: &Self) -> Duration;
33    fn now() -> Self;
34}
35
36#[cfg(feature = "std")]
37impl NativeTime for SystemTime {
38    fn minimum() -> Self {
39        SystemTime::UNIX_EPOCH
40    }
41
42    fn abs_diff(&self, earlier: &Self) -> Duration {
43        // When `earlier` is later than self, `duration_since` returns an error. The error itself
44        // includes the duration between the two `SystemTime`s
45        match self.duration_since(*earlier) {
46            Ok(duration) => duration,
47            Err(e) => e.duration()
48        }
49    }
50
51    fn now() -> Self {
52        SystemTime::now()
53    }
54}
55
56#[derive(Debug)]
57pub enum Error {
58    NoInvariantTsc,
59    NoCrystalFreqReported,
60    UnstableTsc,
61    UnexpectedTscInfo,
62    UnknownFrequency,
63    FrequencyCannotBeDetermined,
64    TypeOverflow,
65}
66
67#[cfg(not(target_env = "sgx"))]
68fn cpuid(leaf: u32, eax: &mut u32, ebx: &mut u32, ecx: &mut u32, edx: &mut u32) {
69    unsafe { 
70        let res = __cpuid(leaf);
71        *eax = res.eax;
72        *ebx = res.ebx;
73        *ecx = res.ecx;
74        *edx = res.edx;
75    }
76}
77
78#[derive(Debug, Default)]
79pub struct Ticks(AtomicU64);
80
81impl PartialEq<Ticks> for Ticks {
82    fn eq(&self, other: &Ticks) -> bool {
83        let t = self.0.load(Ordering::Relaxed);
84        let o = other.0.load(Ordering::Relaxed);
85        t.eq(&o)
86    }
87}
88
89impl PartialOrd<Ticks> for Ticks {
90    fn partial_cmp(&self, other: &Ticks) -> Option<cmp::Ordering> {
91        let t = self.0.load(Ordering::Relaxed);
92        let o = other.0.load(Ordering::Relaxed);
93        t.partial_cmp(&o)
94    }
95}
96
97impl Add for Ticks {
98    type Output = Result<Ticks, Error>;
99
100    fn add(self, other: Self) -> Self::Output {
101        let t0 = self.0.load(Ordering::Relaxed);
102        let t1 = other.0.load(Ordering::Relaxed);
103        t0.checked_add(t1)
104            .ok_or(Error::TypeOverflow)
105            .map(|sum| Ticks(AtomicU64::new(sum)))
106    }
107}
108
109impl Display for Ticks {
110    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
111        write!(f, "{} ticks", self.0.load(Ordering::Relaxed))
112    }
113}
114
115impl Ticks {
116    pub fn new(t: u64) -> Self {
117        Ticks(AtomicU64::new(t))
118    }
119
120    pub const fn max() -> Self {
121        Ticks(AtomicU64::new(u64::MAX))
122    }
123
124    pub fn now() -> Self {
125        // The RDTSC instruction reads the time-stamp counter and is guaranteed to
126        // return a monotonically increasing unique value whenever executed, except
127        // for a 64-bit counter wraparound. Intel guarantees that the time-stamp
128        // counter will not wraparound within 10 years after being reset. The period
129        // for counter wrap is longer for Pentium 4, Intel Xeon, P6 family, and
130        // Pentium processors.
131        // Source: Intel x86 manual Volume 3 Chapter 19.17 (Time-stamp counter)
132        //
133        // However, note that an attacker may arbitarily set this value on the
134        // host/hypervisor
135        Ticks(Rdtscp::read().into())
136    }
137
138    pub fn abs_diff(&self, t1: &Ticks) -> Ticks {
139        let t0 = self.0.load(Ordering::Relaxed);
140        let t1 = t1.0.load(Ordering::Relaxed);
141
142        if t1 > t0 {
143            Ticks::new(t1 - t0)
144        } else {
145            Ticks::new(t0 - t1)
146        }
147    }
148
149    fn set(&self, t: Ticks) {
150        let t = t.0.load(Ordering::Relaxed);
151        self.0.store(t, Ordering::Relaxed);
152    }
153
154    pub fn from_duration(duration: Duration, freq: &Freq) -> Result<Self, Error> {
155        let freq = freq.as_u64();
156        let ticks_secs = duration.as_secs().checked_mul(freq).ok_or(Error::TypeOverflow)?;
157        let ticks_nsecs = (duration.subsec_nanos() as u64)
158            .checked_mul(freq).ok_or(Error::TypeOverflow)? / NANOS_PER_SEC;
159        Ok(Ticks::new(ticks_secs + ticks_nsecs))
160    }
161
162    pub fn as_duration_ex(&self, freq: &Freq) -> Duration {
163        let freq = freq.as_u64();
164        let ticks = self.0.load(Ordering::Relaxed);
165
166        let time_secs = ticks / freq;
167        let time_nsecs = (ticks % freq * NANOS_PER_SEC) / freq;
168        let time_nsecs: u32 = time_nsecs.try_into().expect("must be smaller than 1sec");
169
170        Duration::new(time_secs, time_nsecs)
171    }
172
173    pub fn elapsed(&self, freq: &Freq) -> Duration {
174        let tsc_now = Ticks::now();
175        self.abs_diff(&tsc_now).as_duration_ex(&freq)
176    }
177}
178
179pub struct Rdtscp;
180
181impl Rdtscp {
182    #[inline(never)]
183    pub fn read() -> u64 {
184        let mut aux: u32 = 0;
185        unsafe { __rdtscp(&mut aux) }
186    }
187
188    #[cfg(not(target_env = "sgx"))]
189    pub fn is_supported() -> bool {
190        let mut eax = 0;
191        let mut ebx = 0;
192        let mut ecx = 0;
193        let mut edx = 0;
194
195        cpuid(0x12, &mut eax, &mut ebx, &mut ecx, &mut edx);
196        eax & (0x1 << 1) != 0x0
197
198    }
199}
200
201/// Frequency in ticks per second
202pub struct Freq(AtomicU64);
203
204impl PartialEq<Freq> for Freq {
205    fn eq(&self, other: &Freq) -> bool {
206        let f = self.0.load(Ordering::Relaxed);
207        let o = other.0.load(Ordering::Relaxed);
208        f.eq(&o)
209    }
210}
211
212impl PartialOrd<Freq> for Freq {
213    fn partial_cmp(&self, other: &Freq) -> Option<cmp::Ordering> {
214        let f = self.0.load(Ordering::Relaxed);
215        let o = other.0.load(Ordering::Relaxed);
216        f.partial_cmp(&o)
217    }
218}
219
220impl Debug for Freq {
221    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
222        let freq = self.as_u64();
223        f.debug_struct("Freq")
224         .field("freq", &freq)
225         .finish()
226    }
227}
228
229impl Freq {
230    fn is_zero(&self) -> bool {
231        self.0.load(Ordering::Relaxed) == 0
232    }
233
234    fn set(&self, f: &Freq) {
235        let f = f.0.load(Ordering::Relaxed);
236        self.0.store(f, Ordering::Relaxed);
237    }
238}
239
240#[derive(PartialEq, Eq, Debug)]
241pub enum ClockSource {
242    TSC,
243}
244
245impl Freq {
246    pub fn new(crystal_hz: u32, numerator: u32, denominator: u32) -> Self {
247        Freq::from_u64(crystal_hz as u64 * numerator as u64 / denominator as u64)
248    }
249
250    pub fn from_u64(freq: u64) -> Freq {
251        assert!(freq != 0);
252        Freq(freq.into())
253    }
254
255    pub fn as_u64(&self) -> u64 {
256        self.0.load(Ordering::Relaxed)
257    }
258
259    pub fn estimate(ticks: Ticks, secs: Duration) -> Freq {
260        let nsecs = secs.as_secs() as u128 * NANOS_PER_SEC as u128 + secs.subsec_nanos() as u128;
261        let estimate = ticks.0.load(Ordering::Relaxed) as u128 * NANOS_PER_SEC as u128 / nsecs;
262
263        Freq(AtomicU64::from(estimate as u64))
264    }
265
266    #[cfg(not(target_env = "sgx"))]
267    pub fn invariant_tsc() -> bool {
268        let mut eax = 0;
269        let mut ebx = 0;
270        let mut ecx = 0;
271        let mut edx = 0;
272
273        cpuid(0x80000007, &mut eax, &mut ebx, &mut ecx, &mut edx);
274        edx & (0x1 << 8) != 0
275    }
276
277    #[cfg(all(feature = "std", target_os = "linux"))]
278    fn kernel_clock_source() -> Option<ClockSource> {
279        if fs::read_to_string("/sys/devices/system/clocksource/clocksource0/current_clocksource").ok()?.trim() == "tsc" {
280            Some(ClockSource::TSC)
281        } else {
282            None
283        }
284    }
285
286    // Based on https://github.com/torvalds/linux/blob/master/arch/x86/kernel/tsc.c#L659
287    #[cfg(not(target_env = "sgx"))]
288    pub fn get() -> Result<Self, Error> {
289        let mut eax_denominator: u32 = 0;
290        let mut ebx_numerator: u32 = 0;
291        let mut edx: u32 = 0;
292        let mut crystal_hz = 0;
293
294        #[cfg(all(feature = "std", target_os = "linux"))]
295        if Self::kernel_clock_source() != Some(ClockSource::TSC) {
296            return Err(Error::UnstableTsc)
297        }
298
299        if !Self::invariant_tsc() {
300            return Err(Error::NoInvariantTsc)
301        }
302
303        cpuid(0x15, &mut eax_denominator, &mut ebx_numerator, &mut crystal_hz, &mut edx);
304
305        if eax_denominator == 0 || ebx_numerator == 0 {
306            return Err(Error::UnexpectedTscInfo)
307        }
308
309        // Some Intel SoCs like Skylake and Kabylake don't report the crystal
310        // clock, but we can easily calculate it to a high degree of accuracy
311        // by considering the crystal ratio and the CPU speed.
312        // https://github.com/torvalds/linux/blob/master/arch/x86/kernel/tsc.c#L697-L708
313        #[cfg(feature = "estimate_crystal_clock_freq")]
314        if crystal_hz == 0 {
315            let mut eax_base_mhz = 0;
316            let mut ebx = 0;
317            let mut ecx = 0;
318            let mut edx = 0;
319
320            cpuid(0x16, &mut eax_base_mhz, &mut ebx, &mut ecx, &mut edx);
321            crystal_hz = eax_base_mhz * 1000 * 1000 * eax_denominator / ebx_numerator;
322        }
323
324        if crystal_hz == 0 {
325            Err(Error::NoCrystalFreqReported)
326        } else {
327            Ok(Freq::new(crystal_hz, ebx_numerator, eax_denominator))
328        }
329    }
330}
331
332enum TscMode {
333    Fixed {
334        frequency: Freq,
335    },
336    Learn {
337        // The minimum duration we need to learn the TSC frequency
338        frequency_learning_period: Duration,
339        // The maximum error allowed, before forcing a re-sync
340        max_acceptable_drift: Duration,
341        // The maximum interval between re-syncing with the external clock source
342        max_sync_interval: Duration,
343        // The next time we should contact the external clock source and re-sync
344        next_sync: Ticks,
345        // Learned frequency
346        frequency: Freq,
347    },
348    NoRdtsc,
349}
350
351enum TimeMode<T: NativeTime> {
352    Monotonic {
353        last_time: RefCell<Option<T>>,
354        mutex: AtomicBool,
355    },
356    NonMonotonic,
357}
358
359// RefCell isn't Sync, but we took care of that using the explicity mutex
360unsafe impl<T: NativeTime> Sync for TimeMode<T> {}
361
362impl<T: NativeTime> TimeMode<T> {
363    pub fn monotonic() -> Self {
364        TimeMode::Monotonic {
365            last_time: RefCell::new(None),
366            mutex: AtomicBool::new(false),
367        }
368    }
369
370    pub fn non_monotonic() -> Self {
371        TimeMode::NonMonotonic
372    }
373
374    pub fn observe(&self, now: T) -> T {
375        fn lock<T: NativeTime>(mode: &TimeMode<T>) -> Option<&RefCell<Option<T>>> {
376            if let TimeMode::Monotonic { mutex, last_time } = mode {
377                while mutex.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_err()
378                {}
379                Some(&last_time)
380            } else {
381                None
382            }
383        }
384
385        fn unlock<T: NativeTime>(mode: &TimeMode<T>) {
386            if let TimeMode::Monotonic { mutex, .. } = mode {
387                mutex.store(false, Ordering::Release);
388            }
389        }
390
391        if let Some(last_time) = lock(self) {
392            let mut last_time = last_time.borrow_mut();
393            let now = match last_time.to_owned() {
394                Some(last) if last < now => {
395                    *last_time = Some(now);
396                    now
397                },
398                Some(last) => {
399                    last
400                },
401                None => {
402                    *last_time = Some(now);
403                    now
404                }        
405            };
406            drop(last_time);
407            unlock(self);
408            now
409        } else {
410            now
411        }
412    }
413}
414
415/// Some CPUs do report the speed of their TSC clock. Others do not or do it incomplete. This Tsc
416/// keeps track of the time, and has some capabilities to manage different hardware. Users are able
417/// to specify that the used frequency is more a guideline; that more exact frequency should be
418/// learned over time to avoid clock drift. There's also an initial time frame in which the
419/// frequency is deemed inaccurate, and shouldn't be used.
420pub struct Tsc<T: NativeTime> {
421    t0: (Ticks, T),
422    // The mode in which the Tsc operates
423    tsc_mode: TscMode,
424    // Time is forced to be monotonic, or not
425    time_mode: TimeMode<T>,
426}
427
428pub trait TscBuilder<T: NativeTime> {
429    fn set_monotonic_time(self) -> Self;
430    fn build(self) -> Tsc<T>;
431}
432
433pub struct NoRdtscTscBuilder<T: NativeTime> {
434    // Whether the TSC should be monotonic
435    time_mode: TimeMode<T>,
436}
437
438impl<T: NativeTime> NoRdtscTscBuilder<T> {
439    pub fn new() -> Self {
440        NoRdtscTscBuilder {
441            time_mode: TimeMode::NonMonotonic,
442        }
443    }
444}
445
446impl<T: NativeTime> TscBuilder<T> for NoRdtscTscBuilder<T> {
447    fn set_monotonic_time(mut self) -> Self {
448        self.time_mode = TimeMode::monotonic();
449        self
450    }
451
452    fn build(self) -> Tsc<T> {
453        Tsc::new(TscMode::NoRdtsc, self.time_mode)
454    }
455}
456
457pub struct LearningFreqTscBuilder<T: NativeTime> {
458    // The maximum interval between re-syncing with the external clock source
459    max_sync_interval: Duration,
460    // The maximum error allowed, before forcing a re-sync
461    max_acceptable_drift: Duration,
462    // The minimum duration we need to learn the TSC frequency
463    frequency_learning_period: Duration,
464    // Whether the TSC should be monotonic
465    time_mode: TimeMode<T>,
466    // The frequency learned
467    frequency: Option<Freq>,
468}
469
470impl<T: NativeTime> LearningFreqTscBuilder<T> {
471    pub fn new() -> Self {
472        LearningFreqTscBuilder {
473            frequency_learning_period: Duration::from_secs(1),
474            max_acceptable_drift: Duration::from_millis(1),
475            max_sync_interval: Duration::from_secs(60),
476            time_mode: TimeMode::non_monotonic(),
477            frequency: None,
478        }
479    }
480
481    pub fn set_initial_frequency(mut self, freq: Freq) -> Self {
482        self.frequency = Some(freq);
483        self
484    }
485
486    pub fn initial_frequency(&self) -> &Option<Freq> {
487        &self.frequency
488    }
489
490    pub fn set_max_acceptable_drift(mut self, error: Duration) -> Self {
491        self.max_acceptable_drift = error;
492        self
493    }
494
495    pub fn max_acceptable_drift(&self) -> &Duration {
496        &self.max_acceptable_drift
497    }
498
499    pub fn set_max_sync_interval(mut self, interval: Duration) -> Self {
500        self.max_sync_interval = interval;
501        self
502    }
503
504    pub fn max_sync_interval(&self) -> &Duration {
505        &self.max_sync_interval
506    }
507
508    pub fn set_frequency_learning_period(mut self, period: Duration) -> Self {
509        self.frequency_learning_period = period;
510        self
511    }
512
513    pub fn frequency_learning_period(&self) -> Duration {
514        self.frequency_learning_period
515    }
516}
517
518impl<T: NativeTime> TscBuilder<T> for LearningFreqTscBuilder<T> {
519    fn set_monotonic_time(mut self) -> Self {
520        self.time_mode = TimeMode::monotonic();
521        self
522    }
523
524    fn build(self) -> Tsc<T> {
525        let LearningFreqTscBuilder { frequency, max_sync_interval, max_acceptable_drift, frequency_learning_period, time_mode, } = self;
526        // When the initial frequency is set in the builder, we assume we don't need to resync for
527        // `max_sync_interval` duration
528        let (next_sync, frequency, frequency_learning_period) =
529            if let Some((Ok(next_sync), frequency)) = frequency.map(|f| (Ticks::from_duration(max_sync_interval, &f), f)) {
530                // We won't resync until `max_sync_interval`, use the full period to learn the exact
531                // frequency
532                (next_sync, frequency, frequency_learning_period.max(max_sync_interval))
533            } else {
534                (Ticks::new(0), Freq(AtomicU64::from(0)), frequency_learning_period)
535            };
536        let tsc_mode = TscMode::Learn {
537            max_sync_interval,
538            max_acceptable_drift,
539            frequency_learning_period,
540            next_sync,
541            frequency,
542        };
543        Tsc::new(tsc_mode, time_mode)
544    }
545}
546
547pub struct FixedFreqTscBuilder<T: NativeTime> {
548    frequency: Freq,
549    // Whether the TSC should be monotonic
550    time_mode: TimeMode<T>,
551}
552
553impl<T: NativeTime> TscBuilder<T> for FixedFreqTscBuilder<T> {
554    fn set_monotonic_time(mut self) -> Self {
555        self.time_mode = TimeMode::monotonic();
556        self
557    }
558
559    fn build(self) -> Tsc<T> {
560        let tsc_mode = TscMode::Fixed {
561            frequency: self.frequency,
562        };
563        Tsc::new(tsc_mode, self.time_mode)
564    }
565}
566
567impl<T: NativeTime> FixedFreqTscBuilder<T> {
568    pub fn new(frequency: Freq) -> Self {
569        FixedFreqTscBuilder {
570            frequency,
571            time_mode: TimeMode::non_monotonic(),
572        }
573    }
574}
575
576enum ResyncError<T> {
577    WithinFrequencyLearningPeriod(T)
578}
579
580impl<T: NativeTime> Tsc<T> {
581    fn new(tsc_mode: TscMode, time_mode: TimeMode<T>) -> Self {
582        let now = T::now();
583        let t0 = if let TscMode::NoRdtsc = tsc_mode { Ticks::default() } else { Ticks::now() };
584        Tsc {
585            t0: (t0, now),
586            tsc_mode,
587            time_mode,
588        }
589    }
590
591    fn resync_clocks(&self, current_freq: &Freq, frequency_learning_period: &Duration, max_acceptable_drift: &Duration, max_sync_interval: &Duration) -> Result<(T, Duration, Freq), ResyncError<T>> {
592        // Fetch actual time
593        let system_now = T::now();
594
595        // Calculate new freq
596        let diff_system = system_now.abs_diff(&self.t0.1);
597        if diff_system < *frequency_learning_period {
598            return Err(ResyncError::WithinFrequencyLearningPeriod(system_now));
599        }
600        let tsc_now = Ticks::now();
601        let estimated_freq = Freq::estimate(self.t0.0.abs_diff(&tsc_now), diff_system);
602
603        // Calculate error
604        let now = self.now_ex(current_freq);
605        let error = system_now.abs_diff(&now);
606
607        // Calculate the maximum interval we need to re-sync
608        let max_sync_interval = if error.is_zero() {
609            // We have a very good clock, don't postpone re-sync inevitably (and don't div by zero)
610            max_sync_interval.to_owned()
611        } else {
612            // Common case, estimate interval based on error and max acceptable error
613            diff_system * max_acceptable_drift.div_duration_f64(error) as u32
614        };
615
616        Ok((system_now, max_sync_interval, estimated_freq))
617    }
618
619    fn now_ex(&self, freq: &Freq) -> T {
620        self.t0.1 + self.t0.0.elapsed(freq)
621    }
622
623    pub fn now(&self) -> T {
624        let now = match &self.tsc_mode {
625            TscMode::NoRdtsc => T::now(),
626            TscMode::Learn { frequency_learning_period, max_acceptable_drift, max_sync_interval, next_sync, frequency } => {
627                let (tsc_now, f) = if !frequency.is_zero() {
628                    (Ticks::now(), Freq(frequency.as_u64().into()))
629                } else {
630                    // Calling rdtsc _after_ issuing a insecure_time usercall so frequency
631                    // will be _over_ estimated rather than under estimated when system is
632                    // under heavy load. An under estimated frequency is easier to fix
633                    // afterwards when time needs to be monotonic.
634                    let system_now = T::now();
635                    let tsc_now = Ticks::now();
636                    let diff_system = system_now.abs_diff(&self.t0.1);
637                    if diff_system < *frequency_learning_period {
638                        // We don't have enough data to estimate frequency correctly
639                        return system_now;
640                    }
641
642                    let estimated_freq = Freq::estimate(self.t0.0.abs_diff(&tsc_now), diff_system);
643                    frequency.set(&estimated_freq);
644                    (tsc_now, estimated_freq)
645                };
646
647                let now = self.now_ex(&f);
648
649                if tsc_now < *next_sync {
650                    now
651                } else {
652                    // Re-estimate freq when a time threshold is reached
653                    match self.resync_clocks(&f, &frequency_learning_period, &max_acceptable_drift, &max_sync_interval) {
654                        Ok((now, next_sync_interval, estimated_freq)) => {
655                            // When `next_tsc` overflows, the system has been running for over 10
656                            // years, or an attacker manipulated the TSC value. As we can't trust TSC
657                            // anyway, we do the simple thing and continue trying to sync
658                            let duration = Ticks::from_duration(next_sync_interval, &estimated_freq);
659                            if let Ok(next_tsc) = tsc_now + duration.unwrap_or(Ticks::max()) {
660                                next_sync.set(next_tsc);
661                            }
662                            frequency.set(&estimated_freq);
663                            now
664                        },
665                        Err(ResyncError::WithinFrequencyLearningPeriod(now)) => now,
666                    }
667                }
668            }
669            TscMode::Fixed { frequency } => {
670                self.now_ex(&frequency)
671            }
672        };
673
674        self.time_mode.observe(now)
675    }
676}
677
678#[cfg(test)]
679mod tests {
680    #[cfg(feature = "rdtsc_tests")]
681    use super::LearningFreqTscBuilder;
682    use super::{NativeTime, NoRdtscTscBuilder, TscBuilder};
683    #[cfg(not(target_env = "sgx"))]
684    use super::{FixedFreqTscBuilder, Freq, Tsc, Ticks};
685
686    use core::ops::Add;
687    use core::time::Duration;
688    #[cfg(all(feature = "std", feature = "rdtsc_tests", not(target_env = "sgx")))]
689    use std::borrow::ToOwned;
690    #[cfg(feature = "std")]
691    use {
692        std::time::SystemTime,
693        std::thread,
694    };
695
696    #[cfg(not(target_env = "sgx"))]
697    fn diff_system_time(t0: SystemTime, t1: SystemTime) -> Duration {
698        let diff = if t0 < t1 { t1.duration_since(t0) } else { t0.duration_since(t1) };
699        diff.unwrap()
700    }
701
702    fn test_duration() -> Duration {
703        if cfg!(feature = "long_duration_tests") {
704            Duration::from_secs(60)
705        } else {
706            Duration::from_secs(5)
707        }
708    }
709
710    const ADDITIONAL_DRIFT: Duration = Duration::from_millis(100);
711
712    #[test]
713    #[cfg(feature = "std")]
714    fn max_difference() {
715        let end = SystemTime::now() + test_duration();
716        let mut max = Duration::from_nanos(0);
717
718        while SystemTime::now() < end {
719            let t0 = SystemTime::now();
720            let t1 = SystemTime::now();
721            let diff = t1.duration_since(t0).unwrap();
722            if max < diff {
723                max = diff;
724            }
725
726            assert!(diff < ADDITIONAL_DRIFT, "{:?} difference between calls", diff);
727        }
728        //Seen max differences of up to 28ms
729        //panic!("End of test, max difference = {:?}", max);
730    }
731
732    #[test]
733    #[cfg(target_os = "linux")]
734    fn verify_frequency_reported() {
735        if let Ok(freq) = Freq::get() {
736            let t0 = (SystemTime::now(), Ticks::now());
737            std::thread::sleep(Duration::from_secs(2));
738            let t1 = (SystemTime::now(), Ticks::now());
739
740            let estimated_freq = Freq::estimate(t1.1.abs_diff(&t0.1), t1.0.duration_since(t0.0).unwrap());
741            let low_estimate = Freq::from_u64(estimated_freq.as_u64() * 99 / 100);
742            let high_estimate = Freq::from_u64(estimated_freq.as_u64() * 101 / 100);
743            assert!(low_estimate.as_u64() <= freq.as_u64() && freq.as_u64() <= high_estimate.as_u64(), "Expected frequency between {:?} and {:?}, got {:?}", low_estimate, high_estimate, freq);
744        }
745    }
746
747    #[test]
748    #[cfg(all(feature = "std", target_os = "linux"))]
749    fn verify_cpu_reported_freq() {
750        if let Ok(freq) = Freq::get() {
751            let tsc: Tsc<SystemTime> = FixedFreqTscBuilder::new(freq)
752                .build();
753            let t0 = (SystemTime::now(), tsc.now());
754            loop {
755                let t1 = (SystemTime::now(), tsc.now());
756                let diff = diff_system_time(t1.0, t1.1);
757                assert!(diff < ADDITIONAL_DRIFT, "Found diff between clocks of {:?} after {:?}", diff, diff_system_time(t0.0, t1.0));
758
759                std::thread::sleep(Duration::from_secs(2));
760                if test_duration() < diff_system_time(t1.1, t0.1) {
761                    break;
762                }
763            }
764        }
765    }
766
767    fn clock_drift<T: NativeTime, R: NativeTime>(builder: impl TscBuilder<T>, test_duration: Duration, max_acceptable_drift: &Duration, monotonic_time: bool) {
768        let tsc = builder.build();
769        let reference_start = R::now();
770        let tsc_start = tsc.now();
771        let end = R::now() + test_duration;
772        let mut last = None;
773
774        while R::now() < end {
775            let reference_now = R::now();
776            let tsc_now = tsc.now();
777            let reference_duration = reference_now.abs_diff(&reference_start);
778            let tsc_duration = tsc_now.abs_diff(&tsc_start);
779            let drift = reference_duration.abs_diff(tsc_duration);
780            assert!(drift < *max_acceptable_drift, "Found {:?} drift, (max drift was {:?} after {}ms)", drift, max_acceptable_drift, reference_duration.as_millis());
781            if monotonic_time {
782                assert!(last.unwrap_or(tsc_now) <= tsc_now, "Time ran backwards (last: {:?}, now: {:?})", last, tsc_now);
783                last = Some(tsc_now);
784            }
785
786            #[cfg(feature = "std")]
787            std::thread::sleep(Duration::from_micros(10));
788        }
789    }
790
791    #[test]
792    #[cfg(all(feature = "std", feature = "rdtsc_tests"))]
793    #[cfg(not(target_env = "sgx"))]
794    fn clock_drift_default_learning_freq_builder() {
795        let tsc_builder: LearningFreqTscBuilder<SystemTime> = LearningFreqTscBuilder::new();
796        let max_drift = tsc_builder.max_acceptable_drift().to_owned();
797        clock_drift::<SystemTime, SystemTime>(tsc_builder, test_duration(), &(ADDITIONAL_DRIFT + max_drift), false);
798    }
799
800    #[test]
801    #[cfg(all(feature = "std", feature = "rdtsc_tests"))]
802    #[cfg(not(target_env = "sgx"))]
803    fn clock_drift_learning_freq_monotonic() {
804        let tsc_builder: LearningFreqTscBuilder<SystemTime> = LearningFreqTscBuilder::new()
805            .set_monotonic_time();
806        let max_drift = tsc_builder.max_acceptable_drift().to_owned();
807        clock_drift::<SystemTime, SystemTime>(tsc_builder, test_duration(), &(ADDITIONAL_DRIFT + max_drift), false);
808    }
809
810    #[test]
811    #[cfg(feature = "std")]
812    fn clock_drift_no_rdtsc_monotonic() {
813        let tsc_builder: NoRdtscTscBuilder<SystemTime> = NoRdtscTscBuilder::new()
814            .set_monotonic_time();
815        clock_drift::<SystemTime, SystemTime>(tsc_builder, test_duration(), &ADDITIONAL_DRIFT, true);
816    }
817
818    #[test]
819    #[cfg(target_os = "linux")]
820    #[cfg(all(feature = "std", feature = "rdtsc_tests"))]
821    fn clock_drift_fix_freq_monotonic() {
822        if let Ok(freq) = Freq::get() {
823            let tsc_builder = FixedFreqTscBuilder::<SystemTime>::new(freq)
824                .set_monotonic_time();
825            clock_drift::<SystemTime, SystemTime>(tsc_builder, test_duration(), &ADDITIONAL_DRIFT, true);
826        }
827    }
828
829    #[cfg(all(target_env = "sgx", feature = "rdtsc_tests"))]
830    #[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
831    // Time in nanoseconds since UNIX_EPOCH
832    struct SgxTime(u64);
833
834    #[cfg(all(target_env = "sgx", feature = "rdtsc_tests"))]
835    impl Add<Duration> for SgxTime {
836        type Output = SgxTime;
837
838        fn add(self, other: Duration) -> Self::Output {
839            let t = self.0 + other.as_secs() * super::NANOS_PER_SEC + other.subsec_nanos() as u64;
840            SgxTime(t)
841        }
842    }
843
844    #[cfg(all(target_env = "sgx", feature = "rdtsc_tests"))]
845    impl NativeTime for SgxTime {
846        fn minimum() -> SgxTime {
847            SgxTime(0)
848        }
849
850        fn abs_diff(&self, other: &Self) -> Duration {
851            Duration::from_nanos(self.0.abs_diff(other.0))
852        }
853
854        fn now() -> Self {
855            let t = unsafe { std::os::fortanix_sgx::usercalls::raw::insecure_time() };
856            SgxTime(t)
857        }
858    }
859
860    #[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
861    // A source of time that mimics a system under very heavy load; it takes a very long time
862    // before the result of the time request is serviced.
863    // Time in nanoseconds since UNIX_EPOCH
864    struct LaggingSystemTime(SystemTime);
865
866    impl LaggingSystemTime {
867        const fn system_lag() -> Duration {
868            Duration::from_secs(3)
869        }
870    }
871
872    #[cfg(feature = "std")]
873    impl Add<Duration> for LaggingSystemTime {
874        type Output = LaggingSystemTime;
875
876        fn add(self, other: Duration) -> Self::Output {
877            LaggingSystemTime(self.0 + other)
878        }
879    }
880
881    #[cfg(feature = "std")]
882    impl NativeTime for LaggingSystemTime {
883        fn minimum() -> Self {
884            LaggingSystemTime(SystemTime::minimum())
885        }
886
887        fn abs_diff(&self, earlier: &Self) -> Duration {
888            self.0.abs_diff(&earlier.0)
889        }
890
891        fn now() -> Self {
892            let now = SystemTime::now();
893            thread::sleep(Self::system_lag());
894            LaggingSystemTime(now)
895        }
896    }
897
898    #[test]
899    #[cfg(all(feature = "std", feature = "rdtsc_tests"))]
900    fn very_lagging_system_time() {
901        let tsc_builder: LearningFreqTscBuilder<LaggingSystemTime> = LearningFreqTscBuilder::new()
902            .set_monotonic_time();
903        clock_drift::<_, SystemTime>(tsc_builder, test_duration(), &(LaggingSystemTime::system_lag() * 3), true);
904    }
905
906    #[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
907    // A source of time that mimics a system under very heavy load; it takes a very long time
908    // before the result of the time request is serviced.
909    // Time in nanoseconds since UNIX_EPOCH
910    struct HighVariationSystemTime(SystemTime);
911
912    impl HighVariationSystemTime {
913        pub fn variation() -> Duration {
914            Duration::from_secs(10)
915        }
916    }
917
918    #[cfg(feature = "std")]
919    impl Add<Duration> for HighVariationSystemTime {
920        type Output = HighVariationSystemTime ;
921
922        fn add(self, other: Duration) -> Self::Output {
923            HighVariationSystemTime(self.0 + other)
924        }
925    }
926
927    #[cfg(feature = "std")]
928    impl NativeTime for HighVariationSystemTime {
929        fn minimum() -> Self {
930            HighVariationSystemTime(SystemTime::minimum())
931        }
932
933        fn abs_diff(&self, earlier: &Self) -> Duration {
934            self.0.abs_diff(&earlier.0)
935        }
936
937        fn now() -> Self {
938            let now = SystemTime::now();
939            let variation = Duration::from_secs(rand::random::<u64>() % HighVariationSystemTime::variation().as_secs());
940            if rand::random::<bool>() {
941                HighVariationSystemTime(now + variation)
942            } else {
943                HighVariationSystemTime(now - variation)
944            }
945        }
946    }
947
948    #[test]
949    #[cfg(all(feature = "std", feature = "rdtsc_tests"))]
950    #[cfg(not(target_env = "sgx"))]
951    fn high_variation_system_time_lag() {
952        for monotonic in [false, true] {
953            for _run in 0..30 {
954                let freq = Freq::get().unwrap();
955                let tsc_builder: LearningFreqTscBuilder<HighVariationSystemTime> = LearningFreqTscBuilder::new()
956                        .set_monotonic_time()
957                        .set_initial_frequency(freq);
958                clock_drift::<_, SystemTime>(tsc_builder, Duration::from_secs(1), &(2 * HighVariationSystemTime::variation()), monotonic);
959            }
960        }
961    }
962
963    #[test]
964    #[cfg(all(feature = "std", feature = "rdtsc_tests", feature = "long_duration_tests"))]
965    #[cfg(not(target_env = "sgx"))]
966    fn high_variation_system_time_drift() {
967        let tsc_builder: LearningFreqTscBuilder<HighVariationSystemTime> = LearningFreqTscBuilder::new()
968                .set_initial_frequency(Freq::get().unwrap())
969                .set_frequency_learning_period(Duration::from_secs(120))
970                .set_max_acceptable_drift(Duration::from_millis(1))
971                .set_max_sync_interval(Duration::from_secs(60))
972                .set_monotonic_time();
973
974        // TSC computes the time based on two `HighVariationSystemTime` at worst this means a
975        // variation of `2 * HighVariationSystemTime::variation()` in addition to its max
976        // acceptable drift
977        clock_drift::<_, SystemTime>(tsc_builder, Duration::from_secs(180), &(2 * HighVariationSystemTime::variation() + Duration::from_millis(1)), true);
978    }
979
980    #[test]
981    #[cfg(all(feature = "std", feature = "rdtsc_tests"))]
982    fn build_time_learning_freq_tsc_builder() {
983        let tsc_builder: LearningFreqTscBuilder<HighVariationSystemTime> = LearningFreqTscBuilder::new()
984            .set_monotonic_time();
985        let t0 = SystemTime::now();
986        let tsc = tsc_builder.build();
987        let build_time = SystemTime::now().duration_since(t0).unwrap();
988        assert!(build_time < Duration::from_millis(10), "Building tsc took {} ms", build_time.as_millis());
989
990        let t0 = SystemTime::now();
991        let _t = tsc.now();
992        let now_time =  SystemTime::now().duration_since(t0).unwrap();
993        assert!(now_time < Duration::from_millis(10), "tsc.now() took {} ms", now_time.as_millis());
994    }
995
996    #[test]
997    #[cfg(all(target_env = "sgx", feature = "rdtsc_tests"))]
998    fn sgx_time() {
999        let tsc_builder: LearningFreqTscBuilder<SgxTime> = LearningFreqTscBuilder::new()
1000            .set_monotonic_time();
1001        // WARNING: Its up to the caller to ensure that the enclave runner used for this test does
1002        // not enable rdtsc-based time within the enclave
1003        clock_drift::<_, SystemTime>(tsc_builder, test_duration(), &ADDITIONAL_DRIFT, true);
1004    }
1005}