Description
@thomasten calling time.Now() (clock_gettime under the hood) and compiling it program with ego:
package main
import (
"fmt"
"time"
)
func main() {
last := int64(0)
start := time.Now()
for i := 0; i < 100000; i++ {
now := time.Now().UnixNano() / 1e6
if last != now {
last = now
fmt.Println(now)
}
}
fmt.Println(time.Now().Sub(start))
}
When running inside the enclave vs. outside of it, I am getting 4ms gaps between time measurements. Also the loop itself takes a lot longer in enclave:
~/ego/samples/clock$ ego run clock
EGo v1.4.1 (009751335951262b22b514412c7b45e33705681b)
[erthost] loading enclave ...
[erthost] entering enclave ...
[ego] starting application ...
1703239563096
1703239563100
1703239563104
1703239563108
11.99988ms
~/ego/samples/clock$ ./clock
1703239569361
1703239569362
1703239569363
1703239569364
1703239569365
3.780436ms
I can see that you have patched out vdso implementation of clock_gettime inside the ertgo - and also disable vdso in the openenclave patch - and instead go for the syscall - the whole point of vdso is so that clock_gettime calls are faster, as the data structures are updated by kernel itself, and therefore syscall doesn't need to happen. I can also see removal of rdtsc calls - these I understand are not supported on production SGX.
I wonder why remove vdso support and go for slower syscall instead?
Regardless, this alone doesnt explain why there are 4ms between clock_gettime calls, as if I run outside of the enclave I can see 1ms increments. I have stepped through the time.now()
call via ego-gdb
(and having the signed binary be configured with debug: true
), and I can see that the patched syscall ends up in custom libc implementation, that does load vdso entry directly.
Is this something that Intel SGX does to prevent timing attacks? Is there a way to get actual accurate time inside the enclave?