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

Security-harden the guest's memory allocator #726

Merged
merged 6 commits into from
Dec 16, 2024

Conversation

matthiasgoergens
Copy link
Collaborator

@matthiasgoergens matthiasgoergens commented Dec 10, 2024

Here we harden the security of the guest's memory allocator: we no longer rely on manual initialisation code for its proper operation.

Because we remove code, it also simplifies the allocator. Hopefully making it easier to understand.

Extracted from #631

@@ -4,26 +4,34 @@
use core::alloc::{GlobalAlloc, Layout};

struct SimpleAllocator {
next_alloc: usize,
next_alloc: *mut u8,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This type is more truthful, and simplifies our code.

}
core::hint::assert_unchecked(align.is_power_of_two());
core::hint::assert_unchecked(align != 0);
heap_pos = heap_pos.add(heap_pos.align_offset(align));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We use the proper Rust functions for working with pointers now. That makes both the type checker happier (when working with pointers instead of usize), and hopefully also clues in the optimiser a bit more.

But the latter would just be a welcome side effect, if it does happen.

next_alloc: 0xFFFF_FFFF,
};

pub unsafe fn init_heap() {
Copy link
Collaborator Author

@matthiasgoergens matthiasgoergens Dec 10, 2024

Choose a reason for hiding this comment

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

We no longer need init_heap, because we can directly statically initialise to &raw mut _sheap,.

// (We could also return a null pointer, but only malicious programs would ever hit this.)
heap_pos = heap_pos.strict_add(layout.size());
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Alas, ptr type doesn't have strict_add, but add does nearly the same.

@matthiasgoergens matthiasgoergens changed the title Simplify guest's memory allocator Harden the guest's memory allocator Dec 12, 2024
@matthiasgoergens matthiasgoergens changed the title Harden the guest's memory allocator Security-harden the guest's memory allocator Dec 12, 2024
Copy link
Collaborator

@lispc lispc left a comment

Choose a reason for hiding this comment

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

my understanding of this PR:

previously, we also need to set the _sheap var somewhere(also linking time?), then allocator::init_heap() will use that value to overwrite the default 0xffffffff.

This PR seems a good pure code simplification change. Does it make anything really better or really worse? (if we are not talking about "more robust so in future there may be less bug in code modification", but just talk current code behavior)

@matthiasgoergens
Copy link
Collaborator Author

my understanding of this PR:

previously, we also need to set the _sheap var somewhere(also linking time?), then allocator::init_heap() will use that value to overwrite the default 0xffffffff.

To be really precise: we only ever care about the address of _sheap, not really the value. And, yes, both before and after this PR, that address gets set at linking time.

In this PR, I figured out that we can use Rust's static initialisation to set next_alloc to the address of _sheap. Previously we set next_alloc to a dummy value, and then used normal code to initialise next_alloc to a sensible value (the address of _sheap) at the start of normal runtime.

Then link time optimisation can kick in, and constant propagation can make next_alloc be initialised via program data in the ELF instead of via code.

This PR seems a good pure code simplification change. Does it make anything really better or really worse? (if we are not talking about "more robust so in future there may be less bug in code modification", but just talk current code behavior)

Current behaviour should be the same. The original motivation for this change was to make the standard library support simpler to implement: this way we have to worry less about what happens code wise before we run main.

So to be honest, the motivation given in the PR description is a bit of a retro-fit. It's not wrong, but it's more of a side-benefit of a change we want to make for ease of standard library support.

@matthiasgoergens matthiasgoergens added this pull request to the merge queue Dec 16, 2024
Merged via the queue into master with commit a659b85 Dec 16, 2024
4 checks passed
@matthiasgoergens matthiasgoergens deleted the matthias/simplify-allocator branch December 16, 2024 03:02
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.

2 participants