@@ -61,6 +61,7 @@ pub enum Error {
61
61
UnexpectedTscInfo ,
62
62
UnknownFrequency ,
63
63
FrequencyCannotBeDetermined ,
64
+ TypeOverflow ,
64
65
}
65
66
66
67
#[ cfg( not( target_env = "sgx" ) ) ]
@@ -94,10 +95,14 @@ impl PartialOrd<Ticks> for Ticks {
94
95
}
95
96
96
97
impl Add for Ticks {
97
- type Output = Ticks ;
98
+ type Output = Result < Ticks , Error > ;
98
99
99
100
fn add ( self , other : Self ) -> Self :: Output {
100
- Ticks ( AtomicU64 :: new ( self . 0 . load ( Ordering :: Relaxed ) + other. 0 . load ( Ordering :: Relaxed ) ) )
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) ) )
101
106
}
102
107
}
103
108
@@ -112,7 +117,21 @@ impl Ticks {
112
117
Ticks ( AtomicU64 :: new ( t) )
113
118
}
114
119
120
+ pub const fn max ( ) -> Self {
121
+ Ticks ( AtomicU64 :: new ( u64:: MAX ) )
122
+ }
123
+
115
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
116
135
Ticks ( Rdtscp :: read ( ) . into ( ) )
117
136
}
118
137
@@ -132,11 +151,12 @@ impl Ticks {
132
151
self . 0 . store ( t, Ordering :: Relaxed ) ;
133
152
}
134
153
135
- pub fn from_duration ( duration : Duration , freq : & Freq ) -> Self {
154
+ pub fn from_duration ( duration : Duration , freq : & Freq ) -> Result < Self , Error > {
136
155
let freq = freq. as_u64 ( ) ;
137
- let ticks_secs = duration. as_secs ( ) * freq;
138
- let ticks_nsecs = duration. subsec_nanos ( ) as u64 * freq / NANOS_PER_SEC ;
139
- Ticks :: new ( ticks_secs + ticks_nsecs)
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) )
140
160
}
141
161
142
162
pub fn as_duration_ex ( & self , freq : & Freq ) -> Duration {
@@ -613,7 +633,13 @@ impl<T: NativeTime> Tsc<T> {
613
633
} else {
614
634
// Re-estimate freq when a time threshold is reached
615
635
if let Ok ( Some ( ( now, next_sync_interval, estimated_freq) ) ) = self . resync_clocks ( & f, & frequency_learning_period, & max_acceptable_drift, & max_sync_interval) {
616
- next_sync. set ( tsc_now + Ticks :: from_duration ( next_sync_interval, & estimated_freq) ) ;
636
+ // When `next_tsc` overflows, the system has been running for over 10
637
+ // years, or an attacker manipulated the TSC value. As we can't trust TSC
638
+ // anyway, we do the simple thing and continue trying to sync
639
+ let duration = Ticks :: from_duration ( next_sync_interval, & estimated_freq) ;
640
+ if let Ok ( next_tsc) = tsc_now + duration. unwrap_or ( Ticks :: max ( ) ) {
641
+ next_sync. set ( next_tsc) ;
642
+ }
617
643
frequency. set ( & estimated_freq) ;
618
644
return now;
619
645
}
0 commit comments