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

Ucontext creates reference to uninitialized memory #1092

Closed
gnzlbg opened this issue Jun 26, 2019 · 4 comments
Closed

Ucontext creates reference to uninitialized memory #1092

gnzlbg opened this issue Jun 26, 2019 · 4 comments

Comments

@gnzlbg
Copy link

gnzlbg commented Jun 26, 2019

See

let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };

You probably want to use mem::zeroed() here.

Note also that newer ucontext_t have a shadow stack field that's not available in older versions. Since the ucontext_t struct becomes larger, this should be able to work in a backward compatible way.

@gnzlbg
Copy link
Author

gnzlbg commented Jun 26, 2019

Also, Ucontext appears to be untested.

@asomers
Copy link
Member

asomers commented Jul 1, 2019

That shouldn't be a problem. The value is only uninitialized until it gets initialized two lines lower. Or is there something else I'm missing?

@gnzlbg
Copy link
Author

gnzlbg commented Jul 1, 2019

If one uses mem::uninitialized or mem::zeroed, one needs to check for all ucontext_t on all platforms that these bit-patterns are valid. If they aren't, the behavior is undefined, and this is a type of UB that LLVM exploits (e.g. if uncontext_t contains a bool or a fn()->()).

The easiest safest way of creating an uninitialized or zero-initialized libc::ucontext_t is via MaybeUninit, which also provides an API to initialize the bytes of its contents without invoking UB, e.g., due to the creation of references to an invalid value, which is also another type of UB that LLVM exploits (e.g. by assuming dereferenceable).

Since ucontext_t is kind of outside of nix control, I'd say use MaybeUninit if you can, and otherwise do something like this to avoid all UB:

union MaybeUninit_ { x: ucontext_t, y: () }
// initialize the storage of ucontext_t to uninitialized, while initializing the union:
let mut context = MaybeUninit_ { y: () };
// create a raw pointer to ucontext_t without creating a reference to it:
let ptr = &mut context as *mut _ as *mut ucontext_t; 
// ...use ptr...
// Once ucontext_t properly initialized, pull it out
let context = unsafe { context.x };

@asomers
Copy link
Member

asomers commented Jul 7, 2019

Closing in favor of #1096 .

@asomers asomers closed this as completed Jul 7, 2019
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

No branches or pull requests

2 participants