-
Notifications
You must be signed in to change notification settings - Fork 490
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
Conversation
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>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
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>
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>
Published in crossbeam-channel 0.5.15. |
FTR, I'm preparing a RUSTSEC advisory. |
@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? |
Approved.
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)... |
Red Hat CNA is available to reserve a CVE for this if you would like. |
… 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
… 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
… 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
…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
…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
…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
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
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)
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>
…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
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>
…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
To grab a double-free fix. Link: crossbeam-rs/crossbeam#1187
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>
Upgrade to avoid the double free on drop Refs: crossbeam-rs/crossbeam#1187
Upgrade to avoid the double free on drop Refs: crossbeam-rs/crossbeam#1187
Upgrade to avoid the double free on drop Refs: crossbeam-rs/crossbeam#1187
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 observeshead.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 wheneverhead.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
ensuredhead.block
wasnull
after its execution due to the atomic store right before exiting [1].After #1084
discard_all_messages
atomically swaps the current value ofhead.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 tohead.block
being read but only one of them would swap the value. This meant thatdicard_all_messages
could end up observing a non-null block pointer (and therefore attempting to free it) without settinghead.block
to null. This would then lead toChannel::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