-
Notifications
You must be signed in to change notification settings - Fork 1
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
random_seed is UB #2
Comments
Hello, thank you for the issue! For my understanding, is the concern that there is a usage of unsafe code? I left it that way so that, in some nonoptimized contexts, it would behave less predictably, but it is clear that |
The issue is not unsafe code, the issue is incorrect code. It's undefined behaviour to use a variable that has not been initialised (there's... some subtle points around what exactly "use" is, but doing a bitwise xor, or returning it from a function is definitely use). If the uninit variable was being used as a "i will initialise this later" slot, then you could use MaybeUninit. But it's not, it's being used as a value and you're trying to get entropy from there. That will never be allowed, and the compiler is allowed to assume you don't do that (hence it being optimised out to a [0, 0] return in release mode) Honestly, I'd add a dependency on This crate acts completely predictably with optimised mode (as I noted in my advisory for this crate: rustsec/advisory-db#1196), and some libraries do run their tests in release mode for performance gains. I'm not terribly concerned about this crate because it's generally used only for tests, so at least this isn't being run "in the wild". Still, I'd make it use |
Thank you for the response. Can you please give an example of how it might lead to problems in this case? |
Well, if you run tests in release, your names are always the same. So you cannot run 2 tests that rely on unique names in release. And in general you're relying on the compiler to happen to not notice what you're doing. (These might even be turned into unconditional panics in the future, but work towards doing that is ongoing and somewhat slow, because people write stuff that happens to work most of the time.) |
Sorry, maybe it was not clear from before. This is the expected behavior. Of course, it will return the same name. This is partially the reason there is a retry loop: https://github.com/stainless-steel/temporary/blob/master/src/lib.rs#L59 Eventually it will run out of retries, but the probability of this happening is low, especially given we are talking about testing. One can push it even further by updating |
I guess, but in that case, why not just not have the entropy in the first place? If you have the retries, and tests run in release will never get any entropy, that's equal to using Edit: either not have entropy or collect it properly ( |
No, there is nothing wrong with using unsafe when you need it. The concern is specifically that the unsafe code is Undefined Behaviour (a.k.a wrong/incorrect). To quote the reference (https://doc.rust-lang.org/reference/behavior-considered-undefined.html):
It also explicitly calls out this case:
Like 522 mentioned, this is not guaranteed to work. The compiler is free to remove this function, or turn it into an undefined instruction like ud2, or turn it into an unconditional panic. For an example of the compiler turning this kind of thing into an unconditional panic for some types (Specifically types that do not permit zero-initialization) see rust-lang/rust#66059
I will repeat a part of the quote from the docs in my first comment:
Which means this could be relaxed in the future but it is currently considered UB. As far as I know the last discussion about that question happened here (rust-lang/unsafe-code-guidelines#71). Regardless, it's a good idea to fix this code under the rules from the current documentation instead of assuming it will eventually be considered valid. |
It's not just that, Regardless, doing operations on uninit values will never be not UB. You'd need |
I have updated the function to have no undefined behavior. Thank you for your input! |
cool, thank you very much! I updated the advisory to list the patched version, so anyone on older versions can upgrade / get their dependencies to upgrade. |
Here:
temporary/src/lib.rs
Lines 143 to 146 in 6821517
According to the std::mem::uninitialized docs this is UB: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
This crate could possibly give you an easy way to get a real entropy source, if desireable: https://github.com/rust-random/getrandom
Otherwise, you could just use hardcoded values like
[0 ^0x12345678, 0 ^ 0x87654321]
If you still want a hacky inbetween, maybe consider using a function address and relying on ASLR being enabled (Like
random_seed as usize as u64
).Also notice that sometimes the compiler just replaces uninitialized() with a fixed value (Like
0
), so it would be no better than a fixed value entropy-wise despite being UB.EDIT: Maybe it could also be replaced with inline asm to read the stack, but that would require a different asm block for each ISA and not a real source of entropy.
The text was updated successfully, but these errors were encountered: