Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Undefined behavior due to unsafe pinning of BodyStream #1321

Closed
Tracked by #327
sebzim4500 opened this issue Jan 24, 2020 · 9 comments · Fixed by #1328
Closed
Tracked by #327

Undefined behavior due to unsafe pinning of BodyStream #1321

sebzim4500 opened this issue Jan 24, 2020 · 9 comments · Fixed by #1328
Labels
C-bug Category: bug UB undefined behavior unsafe related to unsafe code

Comments

@sebzim4500
Copy link

Expected Behavior

The program below should not segfault when I only write 'safe' code.

Current Behavior

The program below segfaults.

Possible Solution

Change the MessageBody trait to take a Pin<&mut self> instead of a &mut self.

Steps to Reproduce (for bugs)

Run the following code in debug mode.

use futures::task::{noop_waker, Context};
use futures::stream::once;
use actix_http::body::{MessageBody, BodyStream};
use bytes::Bytes;

fn main() {
    let (sender, receiver) = futures::channel::oneshot::channel();
    let mut body_stream = Ok(BodyStream::new(once(async {
        let x = Box::new(0);
        let y = &x;
        receiver.await.unwrap();
        let z = **y;
        Ok::<_, ()>(Bytes::new())
    })));

    let waker = noop_waker();
    let mut context = Context::from_waker(&waker);

    let _ = body_stream.as_mut().unwrap().poll_next(&mut context);
    sender.send(()).unwrap();
    let _ = std::mem::replace(&mut body_stream, Err([0; 32])).unwrap().poll_next(&mut context);
}

Context

I found this problem by searching for 'unsafe' in the actix-web repo.

  • Rust Version (I.e, output of rustc -V): rustc 1.41.0-nightly
  • Actix Web Version: actix-http v1.0.1
@robjtede robjtede added C-bug Category: bug UB undefined behavior unsafe related to unsafe code labels Jan 24, 2020
dunnock added a commit to dunnock/actix-web that referenced this issue Jan 28, 2020
@dunnock
Copy link
Contributor

dunnock commented Jan 28, 2020

Confirmed the test is crashing test runner.

Provided possible fix will be massive and break actix-web back compatibility as MessageBody trait is used in actix-http, awc and actix-web crates. Is there any other solution?

@tyranron
Copy link
Member

tyranron commented Jan 28, 2020

I dunno atm. But it feels that we will have to refactor all the poll-like methods to accept Pin<&mut Self> eventually, one way or another. It's to hard to control and keep in mind all the &mut self<->Pin<&mut Self> bridges with their invariants/tradeoffs. Even more, future contributions will definitely break the invariants, accidentally and quite often. Here the type system should do its job.

Aaron1011 added a commit to Aaron1011/actix-web that referenced this issue Jan 28, 2020
Fixes actix#1321

A better fix would be to change `MessageBody` to take a `Pin<&mut
Self>`, rather than a `Pin<&mut Self>`. This will avoid requiring the
use of `Box` for all consumers by allowing the caller to determine how
to pin the `MessageBody` implementation (e.g. via stack pinning).

However, doing so is a breaking change that will affect every user of
`MessageBody`. By pinning the inner stream ourselves, we can fix the
undefined behavior without breaking the API.

I've included @sebzim4500's reproduction case as a new test case.
However, due to the nature of undefined behavior, this could pass (and
not segfault) even if underlying issue were to regress.

Unfortunately, until rust-lang/unsafe-code-guidelines#148 is resolved,
it's not even possible to write a Miri test that will pass when the bug
is fixed.
Aaron1011 added a commit to Aaron1011/actix-web that referenced this issue Jan 28, 2020
Fixes actix#1321

A better fix would be to change `MessageBody` to take a `Pin<&mut
Self>`, rather than a `Pin<&mut Self>`. This will avoid requiring the
use of `Box` for all consumers by allowing the caller to determine how
to pin the `MessageBody` implementation (e.g. via stack pinning).

However, doing so is a breaking change that will affect every user of
`MessageBody`. By pinning the inner stream ourselves, we can fix the
undefined behavior without breaking the API.

I've included @sebzim4500's reproduction case as a new test case.
However, due to the nature of undefined behavior, this could pass (and
not segfault) even if underlying issue were to regress.

Unfortunately, until rust-lang/unsafe-code-guidelines#148 is resolved,
it's not even possible to write a Miri test that will pass when the bug
is fixed.
@sebzim4500
Copy link
Author

I found a similar issue in actix-codec, if you are going to make a breaking change here then you will probably need one there as well.

actix/actix-net#91

@cdbattags
Copy link
Member

Would this be a 2.x release though if we decide to do this?

Should we refactor and shoot for a 3.0 transition for this? I think 2+ has been a good halfway point but I really want to make async/await first order if possible soon.

@robjtede
Copy link
Member

IMO we should refactor these unsafe's and shoot for a 3.0 release with a reasonably long alpha/beta period.

@cdbattags
Copy link
Member

I think that's the best path forward as well now that Future is stable but it'll be hard to "backport" any new work. We most likely wouldn't be able to work on 2+ changes and 3.0 release simultaneously.

JohnTitor added a commit that referenced this issue Jan 31, 2020
Fixes #1321

A better fix would be to change `MessageBody` to take a `Pin<&mut
Self>`, rather than a `Pin<&mut Self>`. This will avoid requiring the
use of `Box` for all consumers by allowing the caller to determine how
to pin the `MessageBody` implementation (e.g. via stack pinning).

However, doing so is a breaking change that will affect every user of
`MessageBody`. By pinning the inner stream ourselves, we can fix the
undefined behavior without breaking the API.

I've included @sebzim4500's reproduction case as a new test case.
However, due to the nature of undefined behavior, this could pass (and
not segfault) even if underlying issue were to regress.

Unfortunately, until rust-lang/unsafe-code-guidelines#148 is resolved,
it's not even possible to write a Miri test that will pass when the bug
is fixed.

Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
jmjoy pushed a commit to jmjoy/actix-web that referenced this issue Feb 27, 2020
jmjoy pushed a commit to jmjoy/actix-web that referenced this issue Feb 27, 2020
@wolverian
Copy link

Is this still relevant in 3.0.0-beta.9, or is the advisory DB buggy?

@robjtede
Copy link
Member

The advisory is not applicable to 3.0 and up.

There is a bug in cargo audit where it fails to correctly compare pre release versions.

@wolverian
Copy link

@robjtede Thank you and sorry for the noise. For others who might be interested, the upstream issue is rustsec/rustsec#300.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
C-bug Category: bug UB undefined behavior unsafe related to unsafe code
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants