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

Reading uninitialized memory in Allocator::realloc is unsound #1

Closed
HeroicKatora opened this issue Jan 19, 2020 · 5 comments
Closed
Labels
bug Something isn't working

Comments

@HeroicKatora
Copy link

HeroicKatora commented Jan 19, 2020

First the critical part: In Allocator::realloc, the crate fails to check if the delegate failed reallocation. This is signalled by a returned null pointer and means that the allocation was not reallocated. It is UB to create a slice from a null pointer in any case.

Then also the hash_ptr function wraps arbitrary uninitialized memory into a &[u8] slice. This is unsound and might return inconsistent results which would subvert the usefulness of the hash in the first place.

But it also triggers UB when fxhash reads from any uninitialized part of the memory, potentially sooner.

Workarounds

Turn off the realloc feature.

@udoprog udoprog added the bug Something isn't working label Jan 20, 2020
@udoprog
Copy link
Owner

udoprog commented Jan 20, 2020

Nice catch! I initially had hash_ptr return an Option<bool> and did the null check internally, but forgot to migrate it. (Same issue for #2).

But it also triggers UB when fxhash reads from any uninitialized part of the memory, potentially sooner.

A properly behaving realloc implementation is supposed to migrate and initialize the common prefix, who's length is decided here by min_size. If the allocator leaves it uninitialized you are correct that this might or might not trigger. Hopefully (!) it will. I'll need to think more about the safety implications, but I'll get the null checks fixed ASAP!

@udoprog
Copy link
Owner

udoprog commented Jan 20, 2020

Hm. To my understanding the safety implications of possibly reading uninitialized memory due to a badly implemented would propagate to the underlying application as well, so us doing that for diagnostics purposes would be no better nor worse than having it move into the application. But I suspect we do have a chance of catching it which would be a net positive.

I will do the following:

  • Add a notice to the README and lib.rs that the library should strictly be used for testing with the default set of feature flags, with the implication that it will produce UB if the underlying allocator is badly implemented (read uninitialized memory). With the hope being that we will catch it anyways.
  • I'll add a feature flag zeroed, and also document in the README and lib.rs that if you want to guarantee that checkers doesn't produce UB, both realloc and zeroed need to be disabled.

In a future release, I'll put those checks behind an opt-in feature flag instead of having them on by default.

@HeroicKatora How does that sound to you?

@HeroicKatora
Copy link
Author

Add a notice to the README and lib.rs that the library should strictly be used for testing with the default set of feature flags, with the implication that it will produce UB if the underlying allocator is badly implemented (read uninitialized memory).

That's not strictly true. Contrary to the zeroed method the memory passed into and from realloc need not be initialized. It is also within the discretion of the delegate if a successful reallocation initializes the reallocated memory even for a well-behaved implementation. For example, if realloc merely appends a few pages then any uninitialized portion of the memory of the original allocation remains uninitialized. And semantically, all uninitialized bytes of the allocation remain uninitialized in the new allocation even if implementation-defined ways were used to copy them over and especially if a library-implementation used ptr::copy for that task. It is however not yet determined if reading an uninitialized u8 is UB but it could be ruled that the arithmetic performed to compute the hash sum qualifies as such an invalid use (See rust-lang/unsafe-code-guidelines#71).

@udoprog
Copy link
Owner

udoprog commented Jan 20, 2020

True. Thanks for detailing the issue. I'll reopen until the notices have been amended. I'll make sure they are amended again depending on how rust-lang/unsafe-code-guidelines#71 pans out.

Thank you!

@udoprog udoprog reopened this Jan 20, 2020
@udoprog udoprog changed the title hash_ptr triggers UB and is generally not sound Reading uninitialized memory in realloc is unsound Jan 20, 2020
@udoprog
Copy link
Owner

udoprog commented Jan 20, 2020

I've changed the title since hash_ptr ultimately is unsafe, and should have a safety notice saying that the memory should be initialized. The problem is in realloc in my view.

@udoprog udoprog changed the title Reading uninitialized memory in realloc is unsound Reading uninitialized memory in Allocator::realloc is unsound Jan 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants