Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: runtime: implement a DIT/DOIT mode #66450

Open
rolandshoemaker opened this issue Mar 21, 2024 · 7 comments
Open

proposal: runtime: implement a DIT/DOIT mode #66450

rolandshoemaker opened this issue Mar 21, 2024 · 7 comments

Comments

@rolandshoemaker
Copy link
Member

Apple silicon implements "data memory-dependent prefetchers" (DMPs) which attempt to speed up irregular memory access patterns by doing strange things with pointers in memory. It turns out these optimizations can break cryptography code which is designed to operate in constant time (see https://gofetch.fail), by making certain operations non-constant. It is unclear if Apple intends to do anything about this.

Currently the only reasonable countermeasure to this is setting the ARM DIT MSR bit, which disables the DMP optimizations.

While not affected by this particular attack, Intel has a similar MSR bit, DOIT which similarly disables optimizations.

Given in these cases there are no reasonable blanket mitigations that can be applied to all constant-time code (i.e. blinding is effective for RSA, but there are a number of other implementations affected where there is not a clear solution), and since we are unsure about the performance impact of setting DIT/DOIT, it is unclear what we should do.

It is perhaps worthwhile to provide a opt-in DIT/DOIT mode for Go binaries (i.e. GOEXPERIMENT=dit) which causes them to attempt to set these MSRs where possible. This would provide users the highest level of protection, but with the understanding that they are trading some performance in order to prevent these (typically local only) side channels. It would then be up to users to make the determination if they need to take this extra precaution or not.

Note: the Linux kernel merged a patch which sets DIT by default in kernel space, but does not set it in user space, and user space programs can set it as they see fit (user space programs on darwin can also do this), but they currently have not implemented a DOIT version of this. As far as I can tell user space programs cannot set DOIT currently, at least on the systems that I have access to test on.

Related to #49702.

@gopherbot gopherbot added this to the Proposal milestone Mar 21, 2024
@rolandshoemaker
Copy link
Member Author

Another, significantly more involved option, would be adding a function closure, say crypto/subtle.WithDIT(func(){}), which would set DIT for enclosed code. We would then be required to enclose all cryptographic code which relies on constant time properties in said closure. This is obviously not ideal, but seems to be the path ARM expects developers to eventually go down, per their own documentation.

@rolandshoemaker rolandshoemaker changed the title proposal: runtime: implement a DIT/DIOT mode proposal: runtime: implement a DIT/DOIT mode Mar 22, 2024
@FiloSottile
Copy link
Contributor

FiloSottile commented Mar 22, 2024

Apple's documentation also invites setting and restoring DIT around cryptographic code. I am somewhat skeptical of this, because cryptographic keys, plaintext messages, and other secrets are handled and loaded into memory all over a program, not just in the cryptographic code. The reason we see papers attack cryptographic code is that the rest of the program is application-specific (and that it usually makes simple operations like loading and copying, which we used to understand as safe, but apparently are not anymore).

https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Enable-DIT-for-constant-time-cryptographic-operations

/cc @golang/security

@FiloSottile
Copy link
Contributor

An alternative would be to add a -spectre=dit mitigation. See https://go.dev/wiki/Spectre. It's not quite Spectre, but it's a binary-wide mitigation for a CPU side channel that can cause secret extraction from local attackers.

@dottedmag
Copy link
Contributor

@marcan has found M2 DMP disable chicken bit: https://social.treehouse.systems/@marcan/112238385679496096, so at least whole-system workaround is possible.

@rolandshoemaker
Copy link
Member Author

Note from that thread which I forgot to mention when initially writing this issue: Apple does appear to be enclosing their corecrypto code with calls to enable/disable DIT. It seems like this is, really, the "expected" convention moving forward (although I agree with @FiloSottile, that this seems like a problem that is likely to plague many things, not just the specifically "crypto" parts).

See e.g. https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/corecrypto/cc_internal.h#L86.

@ericlagergren
Copy link
Contributor

I'd appreciate if this could be added to subtle so that non-stdlib crypto code could also benefit from it.

@ericlagergren
Copy link
Contributor

Another possible API, similar to runtime.LockOSThread:

// Tries to enable DIT, reporting
// whether it was enabled.
func EnableDIT() bool

// Disables DIT. If DIT is currently
// disabled, it is a no-op.
func DisableDIT()

The compiler could rewrite those as intrinsics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Incoming
Development

No branches or pull requests

6 participants