-
Notifications
You must be signed in to change notification settings - Fork 19
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
Slice fill_explicit #113
Comments
I think the compiler-team should give their ok whether |
Hmm... true, I hadn't thought of that. I had expected most reorderings to
just be blocked by the read, but I guess in theory the whole thing could
just get moved past the fill_explicit.
…On Wed, 28 Sept 2022 at 12:27, the8472 ***@***.***> wrote:
I think the compiler-team should give their ok whether write_volatile
provides the necessary behavior here as a baseline implementation. My
understanding is that volatile only guarantees the absence of reorderings
relative to other volatile operations.
If that is the case then the compiler could reorder fill_explicit *before*
the operation we try to erase, thus rendering it unfit for its stated
purpose. So some additional optimization barrier or an intrinsic with
stronger guarantees is needed.
—
Reply to this email directly, view it on GitHub
<#113 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABGLD27USUKAOXVEHDIM3DLWARWXRANCNFSM6AAAAAAQX6JIVI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
There's an open RFC which should provide the necessary semantics. rust-lang/rfcs#3301 |
atomic memcpy can't be used here because it can be dead-store eliminated. |
it would be useful to also have a function that takes a |
Ah my bad, I thought it was an atomic volatile memcpy. |
one possible implementation is to follow a memcpy with |
The former was
Actually, I'm wondering if that's the case. The reason the compiler can't assume the contents of the asm is SMC, but if the compiler knows that there can't be any SMC (which it could trivially here, because the asm generates no code that could be modified), it could possibly eliminate it under as-if. I'm just speculating here, though. |
Should we worry about BOLT defeating this? (e.g. dead store elimination on the binary) |
the compiler docs specify that the compiler can't look at the assembly string and assume any behavior from that, it has to treat it as opaque. this means the compiler can't eliminate it as dead code purely because the assembly string is empty:
|
The compiler can surely assume the number of bytes between its own code, and thus can assume that a span of zero instructions would never become longer than zero. I certainly assume I can compute the offset between any two XIR instructions at codegen time. |
well, zero bytes doesn't necessarily mean zero instructions -- the cpu could be set to trap at that address and do something. that said, if you don't buy the above argument, you could easily put a |
Does BOLT do that? I thought it was about binary layout... Assuming it does that kind of thing, how does anybody use it in secure code? Also, do we invoke BOLT on the user's behalf (or rather, is this something we eventually hope to do), or is it something they have to invoke manually -- if they're invoking it manually on |
It's more than that: Table 1 in the CGO'19 paper shows the optimizations at the time. DSE was not there yet, but maybe it could be done someday -- it seems possible. Maybe a hardware barrier or flush would prevent that (and might be a good idea anyway).
No, not yet, but rust-lang/rust#94381 and rust-lang/rust#102487 are trying it on the compiler itself. |
Depending on what it does, that seems like it might have problems with |
Maybe stuff like |
I asked on the LLVM Discord about this, this is the response from maksfb, one of the BOLT maintainers:
|
We discussed this in the libs meeting today: we can't make these provide any hard guarantees, that's not possible with the current semantics of the Rust language. However we are happy to add these as optimizer hints in the same vein as |
Proposal
Problem statement
This adds a
fill_explicit
function, which allows a slice ofT
to be cleared, which the guarantee or strong recommendation that implementations do not elide any store. This is useful in secure code where cleaning secrets from memory is necessary, and failing to do so by accident or by malicious compiler optimization.Motivation, use-cases
The primary motivation is secure/cryptographic code. Specific crates that could benefit would be the zeroize crate (as it could replace use of
write_volatile
), and any rust implementation of cryptographic algorithms, especially ciphers.Solution sketches
Two apis are proposed, one for mutable references to slices (mirroring the
[T]::set
function) and one for pointers (mirroring thecore::ptr::write_bytes
function). Both are suggested together, though if not both is accepted, the strong recommendation is the pointer one. The functions are not the same aswrite_volatile
orread_volatile
(in particular, it should be permissible to reorder them relative to unrelated side effects) and are not suited for use on MMIO.The proposed APIs are
Implementation wise, the functions are quite flexible. A naive, pure rust, implementation could simply use a loop to write the bytes/values.
write_bytes_explicit
could also be vectorized in pure rust (either using existing SIMD intrinsics, or merely a large type). A more efficient implementation could call a compiler-specific intrinsic, but this proposal does not specify such an intrinsic. The most basic implementation offill_explict
is:As an alternative solution,
fill_explicit
could have a signature that takes au8
(if also declared unsafe), which acts as a slice version ofwrite_bytes_explicit
. This would be relatively less useful than the current signature, asslice.fill_bytes_explict(0u8)
could be written aslet len = slice.len(); core::ptr::write_bytes_explicit(slice.as_mut_ptr(),0u8,len)
.The APIs above require an implementation not remove them. As a relaxation, it could be similar in nature to
core::hint::black_box
, where removing the function is a QoI issue, rather than a compliance issue. I would expect that there would be limited to no distinction, as, unlikeblack_box
, it seems difficult to rely on for soundness and any implementation that removed the call would most likely have a bug filed within weeks or days if not hours or minutes. No further requirements are placed on the functions, but it should be recommended that no copies of the data that are made for w/e reason persist beyond the return of the function.Links and related work
C paper (accepted in C23): N2897.
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
An ACP was chosen rather than an RFC because a pure rust implementation exists (and use of intrinsics)
The text was updated successfully, but these errors were encountered: