Skip to content

crossbeam-channel: prevent double free on Drop #1187

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

Merged
merged 1 commit into from
Apr 8, 2025

Conversation

petrosagg
Copy link
Contributor

This PR is fixing a regression introduced by #1084 that can lead to a double free when dropping the channel.

The method Channel::discard_all_messages has the property that if it observes head.block pointing to a non-null pointer it will attempt to free it.

The same property holds for the Channel::drop method and so it is critical that whenever head.block is freed it must also be set to a null pointer so that it is freed exactly once.

Before #1084 the behavior of discard_all_messages ensured head.block was null after its execution due to the atomic store right before exiting [1].

After #1084 discard_all_messages atomically swaps the current value of head.block with a null pointer at the moment the value is read instead of waiting for the end of the function.

The problem lies in the fact that dicard_all_messages contained two paths that could lead to head.block being read but only one of them would swap the value. This meant that dicard_all_messages could end up observing a non-null block pointer (and therefore attempting to free it) without setting head.block to null. This would then lead to Channel::drop making a second attempt at dropping the same pointer.

The bug is similar to the one previously fixed by #972 and the double free can be reproduced by reverting the reproduction commit from that PR [2].

As with #972 it is quite difficult to trigger this bug without introducing artificial sleeps in critical points so this PR does not include a test.

[1] https://github.com/crossbeam-rs/crossbeam/blob/crossbeam-channel-0.5.11/crossbeam-channel/src/flavors/list.rs#L625
[2] 2d22628

This PR is fixing a regression introduced by crossbeam-rs#1084 that can lead to a
double free when dropping the channel.

The method `Channel::discard_all_messages` has the property that if it
observes `head.block` pointing to a non-null pointer it will attempt to
free it.

The same property holds for the `Channel::drop` method and so it is
critical that whenever `head.block` is freed it must also be set to a
null pointer so that it is freed exactly once.

Before crossbeam-rs#1084 the behavior of `discard_all_messages` ensured `head.block`
was `null` after its execution due to the atomic store right before
exiting [1].

After crossbeam-rs#1084 `discard_all_messages` atomically swaps the current value of
`head.block` with a null pointer at the moment the value is read instead
of waiting for the end of the function.

The problem lies in the fact that `dicard_all_messages` contained two
paths that could lead to `head.block` being read but only one of them
would swap the value. This meant that `dicard_all_messages` could end up
observing a non-null block pointer (and therefore attempting to free it)
without setting `head.block` to null. This would then lead to
`Channel::drop` making a second attempt at dropping the same pointer.

The bug is similar to the one previously fixed by crossbeam-rs#972 and the double
free can be reproduced by reverting the reproduction commit from that PR
[2].

As with crossbeam-rs#972 it is quite difficult to trigger this bug without
introducing artificial sleeps in critical points so this PR does not
include a test.

[1] https://github.com/crossbeam-rs/crossbeam/blob/crossbeam-channel-0.5.11/crossbeam-channel/src/flavors/list.rs#L625
[2] crossbeam-rs@2d22628

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
Copy link
Member

@taiki-e taiki-e left a comment

Choose a reason for hiding this comment

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

Thanks!

@taiki-e taiki-e merged commit 596df78 into crossbeam-rs:master Apr 8, 2025
27 checks passed
taiki-e pushed a commit that referenced this pull request Apr 8, 2025
This PR is fixing a regression introduced by #1084 that can lead to a
double free when dropping the channel.

The method `Channel::discard_all_messages` has the property that if it
observes `head.block` pointing to a non-null pointer it will attempt to
free it.

The same property holds for the `Channel::drop` method and so it is
critical that whenever `head.block` is freed it must also be set to a
null pointer so that it is freed exactly once.

Before #1084 the behavior of `discard_all_messages` ensured `head.block`
was `null` after its execution due to the atomic store right before
exiting [1].

After #1084 `discard_all_messages` atomically swaps the current value of
`head.block` with a null pointer at the moment the value is read instead
of waiting for the end of the function.

The problem lies in the fact that `dicard_all_messages` contained two
paths that could lead to `head.block` being read but only one of them
would swap the value. This meant that `dicard_all_messages` could end up
observing a non-null block pointer (and therefore attempting to free it)
without setting `head.block` to null. This would then lead to
`Channel::drop` making a second attempt at dropping the same pointer.

The bug is similar to the one previously fixed by #972 and the double
free can be reproduced by reverting the reproduction commit from that PR
[2].

As with #972 it is quite difficult to trigger this bug without
introducing artificial sleeps in critical points so this PR does not
include a test.

[1] https://github.com/crossbeam-rs/crossbeam/blob/crossbeam-channel-0.5.11/crossbeam-channel/src/flavors/list.rs#L625
[2] 2d22628

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
taiki-e pushed a commit that referenced this pull request Apr 8, 2025
This PR is fixing a regression introduced by #1084 that can lead to a
double free when dropping the channel.

The method `Channel::discard_all_messages` has the property that if it
observes `head.block` pointing to a non-null pointer it will attempt to
free it.

The same property holds for the `Channel::drop` method and so it is
critical that whenever `head.block` is freed it must also be set to a
null pointer so that it is freed exactly once.

Before #1084 the behavior of `discard_all_messages` ensured `head.block`
was `null` after its execution due to the atomic store right before
exiting [1].

After #1084 `discard_all_messages` atomically swaps the current value of
`head.block` with a null pointer at the moment the value is read instead
of waiting for the end of the function.

The problem lies in the fact that `dicard_all_messages` contained two
paths that could lead to `head.block` being read but only one of them
would swap the value. This meant that `dicard_all_messages` could end up
observing a non-null block pointer (and therefore attempting to free it)
without setting `head.block` to null. This would then lead to
`Channel::drop` making a second attempt at dropping the same pointer.

The bug is similar to the one previously fixed by #972 and the double
free can be reproduced by reverting the reproduction commit from that PR
[2].

As with #972 it is quite difficult to trigger this bug without
introducing artificial sleeps in critical points so this PR does not
include a test.

[1] https://github.com/crossbeam-rs/crossbeam/blob/crossbeam-channel-0.5.11/crossbeam-channel/src/flavors/list.rs#L625
[2] 2d22628

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
@taiki-e
Copy link
Member

taiki-e commented Apr 8, 2025

Published in crossbeam-channel 0.5.15.

@ijackson
Copy link

ijackson commented Apr 9, 2025

FTR, I'm preparing a RUSTSEC advisory.

@djc
Copy link

djc commented Apr 10, 2025

@taiki-e I mentioned you in the advisory PR because we like to get sign-off from a maintainer before merging an advisory. Not sure if you've seen it?

@taiki-e
Copy link
Member

taiki-e commented Apr 10, 2025

Approved.

we like to get sign-off from a maintainer before merging an advisory

By the way, I love this. If NVD CPE team had such a policy, we would not have had problems like github/advisory-database#5064 (comment)...

@mfindra
Copy link

mfindra commented Apr 11, 2025

Red Hat CNA is available to reserve a CVE for this if you would like.

facebook-github-bot pushed a commit to facebookincubator/reindeer that referenced this pull request Apr 12, 2025
… Drop Package: crossbeam-channel 0.5.14

Summary:
VULNERABILITY RUSTSEC-2025-0024 - 2025-04-08: crossbeam-channel: double free on Drop
Package: crossbeam-channel 0.5.14

The internal `Channel` type's `Drop` method has a race
which could, in some circumstances, lead to a double-free.
This could result in memory corruption.

Quoting from the
[upstream description in merge request \#1187](crossbeam-rs/crossbeam#1187 (comment)):

> The problem lies in the fact that `dicard_all_messages` contained two paths that could lead to `head.block` being read but only one of them would swap the value. This meant that `dicard_all_messages` could end up observing a non-null block pointer (and therefore attempting to free it) without setting `head.block` to null. This would then lead to `Channel::drop` making a second attempt at dropping the same pointer.

The bug was introduced while fixing a memory leak, in
upstream [MR \#1084](crossbeam-rs/crossbeam#1084),
first published in 0.5.12.

The fix is in
upstream [MR \#1187](crossbeam-rs/crossbeam#1187)
and has been published in 0.5.15

Reviewed By: dtolnay

Differential Revision: D72915462

fbshipit-source-id: c53113f91eedf478646588a84d0fa3aa85a6d2a0
facebook-github-bot pushed a commit to facebook/pyrefly that referenced this pull request Apr 12, 2025
… Drop Package: crossbeam-channel 0.5.14

Summary:
VULNERABILITY RUSTSEC-2025-0024 - 2025-04-08: crossbeam-channel: double free on Drop
Package: crossbeam-channel 0.5.14

The internal `Channel` type's `Drop` method has a race
which could, in some circumstances, lead to a double-free.
This could result in memory corruption.

Quoting from the
[upstream description in merge request \#1187](crossbeam-rs/crossbeam#1187 (comment)):

> The problem lies in the fact that `dicard_all_messages` contained two paths that could lead to `head.block` being read but only one of them would swap the value. This meant that `dicard_all_messages` could end up observing a non-null block pointer (and therefore attempting to free it) without setting `head.block` to null. This would then lead to `Channel::drop` making a second attempt at dropping the same pointer.

The bug was introduced while fixing a memory leak, in
upstream [MR \#1084](crossbeam-rs/crossbeam#1084),
first published in 0.5.12.

The fix is in
upstream [MR \#1187](crossbeam-rs/crossbeam#1187)
and has been published in 0.5.15

Reviewed By: dtolnay

Differential Revision: D72915462

fbshipit-source-id: c53113f91eedf478646588a84d0fa3aa85a6d2a0
facebook-github-bot pushed a commit to facebook/hhvm that referenced this pull request Apr 12, 2025
… Drop Package: crossbeam-channel 0.5.14

Summary:
VULNERABILITY RUSTSEC-2025-0024 - 2025-04-08: crossbeam-channel: double free on Drop
Package: crossbeam-channel 0.5.14

The internal `Channel` type's `Drop` method has a race
which could, in some circumstances, lead to a double-free.
This could result in memory corruption.

Quoting from the
[upstream description in merge request \#1187](crossbeam-rs/crossbeam#1187 (comment)):

> The problem lies in the fact that `dicard_all_messages` contained two paths that could lead to `head.block` being read but only one of them would swap the value. This meant that `dicard_all_messages` could end up observing a non-null block pointer (and therefore attempting to free it) without setting `head.block` to null. This would then lead to `Channel::drop` making a second attempt at dropping the same pointer.

The bug was introduced while fixing a memory leak, in
upstream [MR \#1084](crossbeam-rs/crossbeam#1084),
first published in 0.5.12.

The fix is in
upstream [MR \#1187](crossbeam-rs/crossbeam#1187)
and has been published in 0.5.15

Reviewed By: dtolnay

Differential Revision: D72915462

fbshipit-source-id: c53113f91eedf478646588a84d0fa3aa85a6d2a0
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Apr 17, 2025
…alfJung,tgross35

sync::mpsc: prevent double free on `Drop`

This PR is fixing a regression introduced by rust-lang#121646 that can lead to a double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR crossbeam-rs/crossbeam#1187
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Apr 17, 2025
…alfJung,tgross35

sync::mpsc: prevent double free on `Drop`

This PR is fixing a regression introduced by rust-lang#121646 that can lead to a double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR crossbeam-rs/crossbeam#1187
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Apr 18, 2025
…alfJung,tgross35

sync::mpsc: prevent double free on `Drop`

This PR is fixing a regression introduced by rust-lang#121646 that can lead to a double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR crossbeam-rs/crossbeam#1187
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Apr 18, 2025
Rollup merge of rust-lang#139553 - petrosagg:channel-double-free, r=RalfJung,tgross35

sync::mpsc: prevent double free on `Drop`

This PR is fixing a regression introduced by rust-lang#121646 that can lead to a double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR crossbeam-rs/crossbeam#1187
cuviper pushed a commit to cuviper/rust that referenced this pull request Apr 18, 2025
This PR is fixing a regression introduced by rust-lang#121646 that can lead to a
double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR
crossbeam-rs/crossbeam#1187

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
(cherry picked from commit b9e2ac5)
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Apr 19, 2025
This PR is fixing a regression introduced by #121646 that can lead to a
double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR
crossbeam-rs/crossbeam#1187

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Apr 19, 2025
…gross35

sync::mpsc: prevent double free on `Drop`

This PR is fixing a regression introduced by #121646 that can lead to a double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR crossbeam-rs/crossbeam#1187
github-actions bot pushed a commit to model-checking/verify-rust-std that referenced this pull request Apr 19, 2025
This PR is fixing a regression introduced by rust-lang#121646 that can lead to a
double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR
crossbeam-rs/crossbeam#1187

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
github-actions bot pushed a commit to model-checking/verify-rust-std that referenced this pull request Apr 19, 2025
…alfJung,tgross35

sync::mpsc: prevent double free on `Drop`

This PR is fixing a regression introduced by rust-lang#121646 that can lead to a double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR crossbeam-rs/crossbeam#1187
tavianator added a commit to sharkdp/fd that referenced this pull request Apr 29, 2025
yoctocell pushed a commit to yoctocell/miri that referenced this pull request Apr 30, 2025
This PR is fixing a regression introduced by #121646 that can lead to a
double free when dropping the channel.

The details of the bug can be found in the corresponding crossbeam PR
crossbeam-rs/crossbeam#1187

Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
hcldan added a commit to hcldan/tracing that referenced this pull request Apr 30, 2025
Upgrade to avoid the double free on drop

Refs: crossbeam-rs/crossbeam#1187
hcldan added a commit to hcldan/tracing that referenced this pull request Apr 30, 2025
Upgrade to avoid the double free on drop

Refs: crossbeam-rs/crossbeam#1187
hcldan added a commit to hcldan/tracing that referenced this pull request Apr 30, 2025
Upgrade to avoid the double free on drop

Refs: crossbeam-rs/crossbeam#1187
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

5 participants