Skip to content

Conversation

nstilt1
Copy link
Contributor

@nstilt1 nstilt1 commented Sep 13, 2025

Uses psm to run a function/closure on a stack that is allocated on the heap, then zeroizes that separate stack when the execution finishes.

I attempted to zeroize the space between two pointers: one captured before the closure's call and one after, but upon zeroing the stack, there was a segmentation fault. I will have to remove that code, but it's there in the first commit if anyone thinks they can get it to run without a segmentation fault.

Closes #810 if this is up to standards.

@tarcieri
Copy link
Member

I think it might be better if something like this started out as its own experimental crate, especially as zeroize is post-v1.0

@nstilt1
Copy link
Contributor Author

nstilt1 commented Sep 13, 2025

What should the crate be called? stack_sanitizer? And should this crate require alloc given that using the main function sort of requires the stack input to be on the heap? Should the call to create_aligned_vec() be included in secure_crypto_call_heap()? And secure_crypto_call isn't necessarily secure. Maybe it should be called sanitize_crypto_call_stack?

@tarcieri
Copy link
Member

What should the crate be called?

zeroize-stack perhaps? Or zeroize_stack to match zeroize_derive.

Regarding the rest, spike it out however you'd like, but the difficult part will be the rationale for why it's sound.

@nstilt1
Copy link
Contributor Author

nstilt1 commented Sep 13, 2025

I can go with zeroize_stack. It fits. As for the rationale, the premise is exactly the same as another Rust crate, but it was only implemented for x86_64: https://github.com/dsprenkels/eraser.

With psm, we do not have to write the stack switching function in assemblies because it's already implemented for a number of architectures.

@tarcieri
Copy link
Member

Yeah, I've seen eraser in the past, it was mentioned in this paper: https://eprint.iacr.org/2023/1713.pdf

Interesting prototype of the idea.

@nstilt1 nstilt1 marked this pull request as ready for review September 14, 2025 00:22
@newpavlov
Copy link
Member

Does it pass Miri?

I left some ideas in the original issue.

@nstilt1
Copy link
Contributor Author

nstilt1 commented Sep 14, 2025

Darn. Miri wants me to use the following syntax due to how the psm crate is set up:

psm::psm_stack_manipulation! {
    yes {
        /// define fn with psm::on_stack
        pub unsafe fn blah(...) {...}
    }
    no {
        /// define fn without psm::on_stack, likely panic
        pub unsafe fn blah(...) { panic!("Stack manipulation not available on this platform")}
    }
}

After defining it like this, miri fails with the message "Stack manipulation not available on this platform". Likely because miri doesn't have a stack pointer or something... given that this crate was tied to the rust-lang account, I'd say their code is probably legit, and I'm not sure if Miri would be able to analyze all of the assembly without manually using different targets

@nstilt1
Copy link
Contributor Author

nstilt1 commented Sep 14, 2025

You can confirm that the test passes normally using cargo test but fails with cargo miri test due to the panic. Therefore this code is impossible to analyze with miri, and likely impossible to analyze with rudra given that it's edition 2024. But idek if rudra can analyze assembly files

@nstilt1
Copy link
Contributor Author

nstilt1 commented Sep 14, 2025

Further evidence for miri not working can be found in psm's build.rs:

https://github.com/rust-lang/stacker/blob/7a3ff32d72bcd0a12a938abb21deddf9f1449cdc/psm/build.rs#L66

… comment to debugging section; make no-panic feature for no branch of psm macro? handle closure panic with match?
… with futures::executor::block_on(f()), add asm alternative(?), handle unwind better(?), use stacker crate to handle stack size management(?) or at least use their code(?)
…marked out TODO task for details; next up: better panics
@nstilt1 nstilt1 marked this pull request as draft September 24, 2025 14:13
Comment on lines +3 to +29
## Likely impossible and/or unsafe

* 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")
}
```

Copilot provided that code, but Gemini says that after the future is awaited, there will be no way for the program to know which stack to return to. Also, there is an open issue regarding async closures in `stacker` that has not been resolved after 7 months. https://github.com/rust-lang/stacker/issues/111
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we agree with Gemini that this is either impossible or unsafe to perform? I can try to implement it and see if I get any segfaults, but async code is a low priority for me since basically all crypto operations are synchronous, and it can be ran in a way such that only crypto operations are done on separate stacks

@newpavlov
Copy link
Member

Personally, I do not plan to merge this PR in the near future. Instead I would like to play with the idea I mentioned in the issue.

@nstilt1
Copy link
Contributor Author

nstilt1 commented Sep 24, 2025

Personally, I do not plan to merge this PR in the near future. Instead I would like to play with the idea I mentioned in the issue.

That's fine, but asm! is just outside of my scope. If you want to tackle safe stack bleaching, I would prefer to use your method over using the heap, but I just can't reliably prompt chat bots for asm! given that they frequently make things up, and since there are so many platforms that would need to be supported. If you have a good plan, then please go ahead and make a crate. I'll probably just use my solution until a better method is available.

@nstilt1 nstilt1 closed this Sep 24, 2025
@tarcieri
Copy link
Member

@nstilt1 as some general advice, if you want to work on this sort of concept, I'd suggest keeping it as minimal as possible for an MVP. No async. Just the simplest thing that works.

Also instead of asking LLMs, which don't actually know anything and can hallucinate answers, I think you'd get a lot more mileage out of actually asking the psm devs directly /cc @nagisa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

zeroize: stack zeroization support
3 participants