From 26188305e3ae86b8ad06b6cd58034ac1e8945686 Mon Sep 17 00:00:00 2001 From: Jaehwang Jerry Jung Date: Fri, 15 Nov 2019 22:59:01 +0900 Subject: [PATCH] fix use-after-free in crossbeam-epoch/sync/queue pop() must completely unlink the popped node from the shared memory before it calls defer_destroy() to prevent use-after-free. This implementation is based on the variation by Doherty et al. where the `head == tail` check is done after a successful CAS, which can be slightly more efficient than the original version. closes #238 --- crossbeam-epoch/src/sync/queue.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crossbeam-epoch/src/sync/queue.rs b/crossbeam-epoch/src/sync/queue.rs index 6fe0bef37..08584002b 100644 --- a/crossbeam-epoch/src/sync/queue.rs +++ b/crossbeam-epoch/src/sync/queue.rs @@ -4,6 +4,9 @@ //! //! Michael and Scott. Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue //! Algorithms. PODC 1996. http://dl.acm.org/citation.cfm?id=248106 +//! +//! Simon Doherty, Lindsay Groves, Victor Luchangco, and Mark Moir. 2004b. Formal Verification of a +//! Practical Lock-Free Queue Algorithm. https://doi.org/10.1007/978-3-540-30232-2_7 use core::mem::{self, ManuallyDrop}; use core::ptr; @@ -117,6 +120,11 @@ impl Queue { self.head .compare_and_set(head, next, Release, guard) .map(|_| { + let tail = self.tail.load(Relaxed, guard); + // Advance the tail so that we don't retire a pointer to a reachable node. + if head == tail { + let _ = self.tail.compare_and_set(tail, next, Release, guard); + } guard.defer_destroy(head); Some(ManuallyDrop::into_inner(ptr::read(&n.data))) }) @@ -142,6 +150,11 @@ impl Queue { self.head .compare_and_set(head, next, Release, guard) .map(|_| { + let tail = self.tail.load(Relaxed, guard); + // Advance the tail so that we don't retire a pointer to a reachable node. + if head == tail { + let _ = self.tail.compare_and_set(tail, next, Release, guard); + } guard.defer_destroy(head); Some(ManuallyDrop::into_inner(ptr::read(&n.data))) })