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

Stable counterpart for core::intrinsics::volatile_set_memory #76892

Open
autumnontape opened this issue Sep 18, 2020 · 4 comments
Open

Stable counterpart for core::intrinsics::volatile_set_memory #76892

autumnontape opened this issue Sep 18, 2020 · 4 comments
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@autumnontape
Copy link
Contributor

A volatile memset function would be useful for efficiently zeroing sensitive data before dropping it so it's less likely to be exposed by bugs like Heartbleed. It's already possible to explicitly zero bytes in Rust by using core::ptr::write_volatile in a loop, but because the writes are volatile, the compiler is forced to emit them exactly as written (one byte at a time in simple implementations) rather than using an optimized memset routine.

@Mark-Simulacrum Mark-Simulacrum added C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Sep 18, 2020
@RalfJung
Copy link
Member

but because the writes are volatile, the compiler is forced to emit them exactly as written (one byte at a time in simple implementations) rather than using an optimized memset routine.

That is exactly what volatile is for, though... wanting volatile and wanting optimizations is somewhat of a contradiction.

In UCG discussions around volatile (rust-lang/unsafe-code-guidelines#33, rust-lang/unsafe-code-guidelines#152) the general consensus was that the language itself should only offer volatile operations that cannot be teared -- currently you can do write_volatile with a type way too big to be written in a single instruction, which runs counter the goal of volatile, which is to exactly control how these memory accesses happen.

If we also offer "volatile accesses that are allowed to tear", then this is basically a whole new class of memory accesses, with guarantees and use-cases rather distinct from regular volatile accesses. Currently, it is all mixed up though.

@autumnontape
Copy link
Contributor Author

volatile_set_memory currently lowers to a memset call, similar to functions like explicit_bzero that exist in C for this purpose. I would be in favor of naming the function something other than "volatile" and perhaps leaving open the possibility for it to do things other than write to exactly one span of memory, e.g. to overwrite registers instead of forcing data that would otherwise be kept in registers to be written to memory.

@elichai
Copy link
Contributor

elichai commented Oct 15, 2020

FYI if the size is preknown you can do something like this:

pub unsafe fn volatile_set_memory(slice: &mut [u8; 32], n: u8) {
    let ptr = slice as *mut [u8; 32];
    ptr.write_volatile([n; 32]);
}

Trying to do this generically over T with [u8; size_of::<T>()] is currently blocked on #68436
but you can still do it non generically:

struct PrivateKey([u8; 32]);
impl PrivateKey {
    pub unsafe fn volatile_zero(&mut self) {
        let ptr = self as *mut Self as *mut [u8; size_of::<PrivateKey>()];
        ptr.write_volatile([0u8; size_of::<PrivateKey>()]);
    }
}

@blckngm
Copy link

blckngm commented Mar 2, 2022

Now that inline assembly is in stable, it can used to preventing “memset” from being optimized out, right?

pub fn zeroize(x: &mut [u8]) {
    x.fill(0);
    unsafe {
        core::arch::asm!(
            "/* {ptr} */",
            ptr = in(reg) x.as_ptr(),
            options(nostack, readonly, preserves_flags),
        );
    }
}

This wastes a register, but generates optimal code for the “memset”, especially when inlined and the size of the buffer is known and a multiple of e.g. xmm register size.

cc RustCrypto/utils#743

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants