Alternatives to volatile_set_memory


#1

As I understand it std::intrinsics::volatile_set_memory is going away.

There’s a very specific use case I want it for: zeroing drop for cryptographic buffers.

Instead of trying to stabilize the idea of “volatile_set_memory”, I think what I’d actually like, at least for crypto purposes, is something like Zeroing<T> that ensures a volatile zero on drop.


#2

To be clear, it isn’t going away, just becoming inaccessible from the 1.0 stable compiler; it will still be accessible via the nightly compilers. We are expecting non-trivial number of users to have to wait until 1.1, 1.2, …, 1.x to be able to have their complete application running with the stable branch, but the 6 week release cycles means the new features will come quickly (and the nightlies will continue to work in the meantime).

I’m not commenting about the particular specifics here, merely ensuring everyone’s on the same page: functionality unstable at 1.0 is not dead-in-the-water once that release is cut. :smile:

(Of course, we’d definitely like to keep small the number of people who are forced to use the nightly by unstable features, so it would be interesting if something like this could land… but there isn’t much time until the beta.)


#3

I’m not sure it’s possible to implement Zeroing<T> except as a marker trait in the compiler. Consider:

struct Zeroing<T> { data: T }
impl<T> Deref for Zeroing<T> { ... }
// etc
impl<T> Drop for Zeroing<T> {
     fn drop(&mut self) {
          // need to drop the value...
         let x: T = unsafe { ptr::read(&self.data) };
         drop(x);
         // now we need to zero: self.data, x, AND wherever x was put when passed to drop.
     }
 }

It might be possible with negative bounds, implementing for T: !Drop, but I’m not sure. It’d be much easier as a special struct Zeroing<T: Copy> { data: Vec<T> } or Box<T> where T: Copy + ?Sized (as an owned buffer that will be zeroed and never copied).

If we were going to ship something for 1.0, it either needs to be ZeroingBuf { data: Vec<u8> } or a magical lang item.

EDIT: And, a more comprehensive design would have a ZeroSelf trait, so containers like Vec would know how to zero their contents. I think ZeroingBuf is probably a better idea… EDIT2: To clarify, I think we should totally implement ZeroingBuf for 1.0.


#4

If we’re talking hypothetical features, providing a function to run the destructor without having to copy on to the stack seems nicer than negative bounds or a limited ZeroingBuf: https://github.com/rust-lang/rfcs/issues/753


#5

You’re right. That facility would be very nice.


#6

ZeroingBuf { data: Vec<u8> } solves the general problem I have: expressing the desire to zero using the type system rather than adding an explicit destructor to each type we want to contain a buffer that gets zeroed on drop. Unsigned byte vectors are pretty much all I care about… I don’t actually need to do this generically.

As an anecdotal data point, sodiumoxide presently handles this with macros and I think it’s kind of ugly:


#7

I’m sorry to answer to this old question. However I’m wondering why you can’t use std::ptr::write_bytes, which is stablelized. Is it not secure for cryptographic applications because the implementation has not the volatile-flag?

Moreover the documentation state that intrinsics will probably never get stable status but is there an stablelized interface for volatile_set_memory?

Disclaimer: This post is related to my question in the users forum: https://users.rust-lang.org/t/optimization-by-the-compiler-of-non-volatile-and-volatile-io-operations/3181/1


#8

It’s not volatile, which means it will likely get eliminated by LLVM optimization (and IME, it does disappear in simple cases).