Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ members = [
"opaque-debug",
"wycheproof2blb",
"zeroize",
"zeroize_derive"
"zeroize_derive",
"zeroize_stack"
]
exclude = ["aarch64-dit"]

Expand Down
27 changes: 27 additions & 0 deletions zeroize_stack/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "zeroize_stack"
version = "0.1.0"
description = """
Securely zeroize the stack with a simple function built on
the Portable Stack Manipulation (psm) crate and zeroize crate.
"""
authors = ["The RustCrypto Project Developers"]
license = "Apache-2.0 OR MIT"
homepage = "https://github.com/RustCrypto/utils/tree/master/stack_sanitizer"
repository = "https://github.com/RustCrypto/utils"
readme = "README.md"
categories = ["cryptography", "memory-management", "no-std", "os"]
keywords = ["memory", "memset", "secure", "volatile", "zero", "stack"]
edition = "2024"
rust-version = "1.85"

[dependencies]
psm = "0.1.26"
zeroize = { version = "1.0" }

[features]
default = ["std"]
std = []

[package.metadata.docs.rs]
all-features = true
65 changes: 65 additions & 0 deletions zeroize_stack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# [RustCrypto]: zeroize_stack

[![Crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
![Apache 2.0/MIT Licensed][license-image]
![MSRV][rustc-image]
[![Build Status][build-image]][build-link]

Securely zero the stack (a.k.a. [zeroize]) while avoiding compiler optimizations.

This crate implements a portable approach to securely zeroing the stack using
techniques which guarantee they won't be "optimized away" by the compiler.

[Documentation]

## About

[Zeroing memory securely is hard] - compilers optimize for performance, and
in doing so they love to "optimize away" unnecessary zeroing calls, as well
as make extra copies of data on the stack that cannot be easily zeroed. That's
what this crate is for.

This crate isn't about tricks: it uses [psm::on_stack] to run a function on
a portable stack, and then uses [zeroize] to zero that stack. `psm` implements
all of the assembly for several different architectures, and the [zeroize]
portion of the task was implemented in pure Rust.

- `#![no_std]` i.e. **embedded-friendly**! (`alloc` is required)
- No functionality besides securely zeroing the a function's stack usage!

## License

Licensed under either of:

* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* [MIT license](http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

[//]: # (badges)

[crate-image]: https://img.shields.io/crates/v/zeroize.svg
[crate-link]: https://crates.io/crates/zeroize
[docs-image]: https://docs.rs/zeroize/badge.svg
[docs-link]: https://docs.rs/zeroize/
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg
[build-image]: https://github.com/RustCrypto/utils/actions/workflows/zeroize.yml/badge.svg?branch=master
[build-link]: https://github.com/RustCrypto/utils/actions/workflows/zeroize.yml?query=branch:master

[//]: # (general links)

[RustCrypto]: https://github.com/RustCrypto
[zeroize]: https://en.wikipedia.org/wiki/Zeroisation
[`Zeroize` trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
[Documentation]: https://docs.rs/zeroize/
[Zeroing memory securely is hard]: http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
[psm::on_stack]: https://docs.rs/psm/latest/psm/fn.on_stack.html
[good cryptographic hygiene]: https://github.com/veorq/cryptocoding#clean-memory-of-secret-data
32 changes: 32 additions & 0 deletions zeroize_stack/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# TODO:

* Add support for async closures, possibly using a macro to define the functions if necessary. Use `futures::executor::block_on(f())` to poll the entire future completion inside the stack switched context, and avoid `.await` that yields control outside of the `on_stack()` boundary. Something like:

```rust
pub unsafe fn exec_async_on_sanitized_stack<Fut, F, R>(
stack: &mut [u8],
f: F,
) -> Result<R, Box<dyn std::any::Any + Send>>
where
F: FnOnce() -> Fut + UnwindSafe,
Fut: Future<Output = R>,
{
let mut result = None;

on_stack(stack, || {
result = Some(catch_unwind(AssertUnwindSafe(|| {
// Block on the future inside the heap stack
futures::executor::block_on(f())
})));
});

result.expect("Closure did not run")
}
```

* Handle unwinds better: currently we return a `Result<R, Box<dyn Any + Send>>`. The error case is a little bit tricky to handle, as dropping the error could cause a panic. The program should either panic, or return the panic payload's message.

* Use stacker crate to handle stack size management: if I read some of the `stacker` docs correctly, that crate should be able to extend the size of the stack when it is about to overflow. If that is correct, we could use their techniques to allocate a new stack and zeroize the old one whenever our allocated stack is about to overflow, eliminating the primary remaining `# Safety` comment. Note: we may not be able to zeroize the old stack immediately as the stack switching process likely attempts to return to the old stack once execution completes; we might have to wait until execution completes before zeroizing all heap-stacks.

* Add an `asm!` alternative method for stack bleaching. In theory, it would be better to use `asm!` as we would not need to worry about the size of the allocated switched stack, and it would keep all of the code running on the actual stack and not the heap, possibly preserving performance. The problem with this is that using pointers from `asm!` and rust code to zero the space between the pointers results in segmentation faults on `x86_64`.
* when testing this, assert that the two pointers are not equal to each other and not null.
Loading
Loading