Open mihai1voicescu opened 3 years ago
Have you seen the --allow-hrtime
flag?
If yes and it's not good enough for your purposes, can you explain where it falls short?
If no, then that's probably what you want to use. :-)
Yes I am aware of the flag:
I see the hp timers are guarded by a flag
My point is: are you sure this is enough to mitigate an attack given that this isolate can run for a long time?
I saw Cludflare is building a lambda service and they came to the conclusion that allowing timers is too risky (in their platform Date.now points to the last request received and timeouts and workers are disabled), check here.
Adding an extra layer of protection (for those who can afford the lowered precision) seems like a nice feature.
I'm still not sure what you are requesting or proposing. When running Deno without --allow-hrtime
there is only millisecond granularity, even on performance.now()
. --allow-hrtime
only increases that precision for performance.now()
. setTimer()
and setInterval()
are notoriously inaccurate, even in our implementation, as they are subject to vagaries of the event loop. Date.now()
again only has millisecond granularity. We discussed fuzzing performance.now()
but we have kept it at just millisecond granularity.
The Spectre exploit specifically requires a high-precision timer, and as mentioned, they are disabled by default in Deno. The other way that Spectre was able to create a proxy high-precision timer is to use a SharedArrayBuffer
and have the web worker increment a value in the buffer, which the main process reads. That good/bad news is that SharedArrayBuffer
s don't work in Deno #6433. It does make sense that we look at how to mitigate what if/when we introduce SharedArrayBuffer
s in Deno.
I was proposing adding a flag that limits the precision/resolution (eg: Date.now/performance.now has seconds resolution instead of milliseconds => Date.now = Math.floor(Date.now / 1000) * 1000)
.
As far as I know (fell free to correct me on this, I would be glad if I were wrong on this) no one has proved beyond a reasonable doubt that side channel attacks can not be done with millisecond resolution timers.
For example this paper claims:
our attack requires accurate microsecond measurements. However, usually more pages are attacked and thus less accurate timers are sufficient. For instance, when checking for deduplication of a 600 kilobyte image, even an accurate millisecond-based timer can be used to implement our attack. Thus, performance.now() is sufficient to distinguish copy-on-write page faults from regular write accesses.
In the v8 blog we also have a section which states:
It became clear early on in our offensive research that timer mitigations alone would not be sufficient. One reason why is that an attacker may simply repeatedly execute their gadget so that the cumulative time difference is much larger than a single cache hit or miss. We were able to engineer reliable gadgets that use many cache lines at a time, up to the cache capacity, yielding timing differences as large as 600 microseconds. We later discovered arbitrary amplification techniques that are not limited by the cache capacity. Such amplification techniques rely on multiple attempts to read the secret data.
I am not a security expert, but it seems setting an even more coarse resolution than milliseconds (eg: seconds) could provide an additional layer of security, or at least slow down an attack (even one that is not discovered yet). Of course, only for those who can afford to use it.
Having timers that have a one second resolution is 1000x more inaccurate and would break a lot of code that expects resolution. As I stated before, JavaScript timers are quite unreliable at their current millisecond resolution and are unreliable.
Browsers have only considered addressing performance.now()
. Safari and Firefox reduced it to millisecond grainularity like we have. Chromium is 100us plus jitter. As stated in the v8 article, they have stopped mitigating it further because there are real threats out there than speculative ones that would allow you to read the memory of the isolate you are running on.
My opinion is that millisecond resolution is sufficient mitigation coupled with the rest of the security model for Deno.
I agree, changing the timers may break JS code. But in some cases, such as mine, this is something you can live with if it might add more security to running unsafe code in a process that multiple isolates share.
I think your question then is if we'd be open to adding a feature flag that neuters timers even more?
Speaking for myself, I'm not thrilled by the idea.
In short, yes. Or at least changing the deno/runtime/ops/timers.rs
to allow a custom timer implementations and default to the current implementation GlobalTimer
.
Currently the only way I can think of to modify the resolution without forking deno is basically copy pasting the code from deno/runtime/worker.rs
and replacing the call to ops::timers::init(js_runtime);
with a custom one.
If you think any of the 2 options (specified in the first paragraph of this comment) are acceptable I would be more then happy to make a PR.
That good/bad news is that
SharedArrayBuffer
s don't work in Deno #6433. It does make sense that we look at how to mitigate what if/when we introduceSharedArrayBuffer
s in Deno.
Does look like Deno has SharedArrayBuffer support now. Are there mitigations in place to lock down that API? Was surprised it was enabled by default as in browsers you need all the COEP / COOP opt-ins.
Hello, I am in the process of building a custom lambda platform for my master thesis.
deno and v8 seems to be a perfect candidate for the application level sandbox (good job btw 👍 ).
As far as I know the greater the precision of the timers the faster you can do a Spectre style attack. I see the hp timers are guarded by a flag, but some applications (such as mine) would like to trade precision for an increased degree a security (preferably configurable).
When I say timers I am referring of course to the setInterval/setTimeout and Date.now API.
This is even more important if you extend deno with more native code from Rust, or plan to run multiple Isolates in the same process, such as I do (as far as I know, no other problems except security and process crashes can occur here).