Make EbpfError enum discriminant size explicit #361
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR is on behalf of Trail of Bits.
@VTCAKAVSMoACE let me know of some warnings when running my aarch64 PR (#358) under MSAN. I investigated these, and it turns out that
emit_set_exception_kind
has been writing some uninitialized bytes to the JIT region, even in the current X86 JIT.Enum layouts are generally not well-defined, and currently the compiler is choosing to make the discriminant on
EbpfError
a u8, leaving bytes 1-7 as uninitialized stack memory:These bytes are then written into the jit in emit_set_exception_kind:
https://github.com/solana-labs/rbpf/blob/main/src/jit.rs#L855
This was getting caught in the aarch64 JIT under MSAN because there is branching based on that immediate value before it gets written into the JIT region.
This PR adds
#[repr(u64)]
to the enum, which makes the discriminant size explicit.https://doc.rust-lang.org/reference/type-layout.html#primitive-representation-of-enums-with-fields
I do not believe this has any direct security consequences, since these uninitialized bytes are never read (everything that deals with EbpfError enums only pulls the single discriminant byte out of memory). At worst, if these bytes are controllable (they do not appear to be), this might partially bypass the constant sanitization mitigation implemented in #143.
The JIT also dangerously assumes a similar layout for
std::result::Result
, which probably isn't guaranteed by the compiler either (currently the discriminant on Result appears to be u64, which aligns with the JIT's assumptions in various places). This PR adds tests that will hopefully catch any changes in enum layout in the future.