From: Peter Xu <peterx@redhat.com>
To: Akihiko Odaki <akihiko.odaki@daynix.com>
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
"Stefan Weil" <sw@weilnetz.de>, "Fabiano Rosas" <farosas@suse.de>,
"Hailiang Zhang" <zhanghailiang@xfusion.com>,
"Phil Dennis-Jordan" <phil@philjordan.eu>,
qemu-devel@nongnu.org, devel@daynix.com,
"Marc-André Lureau" <marcandre.lureau@redhat.com>,
"Daniel P. Berrangé" <berrange@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>
Subject: Re: [PATCH v3 01/10] futex: Check value after qemu_futex_wait()
Date: Tue, 13 May 2025 10:39:15 -0400 [thread overview]
Message-ID: <aCNZk73GuEaU-gcK@x1.local> (raw)
In-Reply-To: <20250511-event-v3-1-f7f69247d303@daynix.com>
On Sun, May 11, 2025 at 03:08:18PM +0900, Akihiko Odaki wrote:
> futex(2) - Linux manual page
> https://man7.org/linux/man-pages/man2/futex.2.html
> > Note that a wake-up can also be caused by common futex usage patterns
> > in unrelated code that happened to have previously used the futex
> > word's memory location (e.g., typical futex-based implementations of
> > Pthreads mutexes can cause this under some conditions). Therefore,
> > callers should always conservatively assume that a return value of 0
> > can mean a spurious wake-up, and use the futex word's value (i.e.,
> > the user-space synchronization scheme) to decide whether to continue
> > to block or not.
I'm just curious - do you know when this will happen?
AFAIU, QEMU uses futex always on private mappings, internally futex does
use (mm, HVA) tuple to index a futex, afaict. Hence, I don't see how it
can get spurious wakeups.. And _if_ it happens, since mm pointer can't
change it must mean the HVA of the futex word is reused, it sounds like an
UAF user bug to me instead.
I checked the man-pages git repo, this line was introduced in:
https://github.com/mkerrisk/man-pages/commit/4b35dc5dabcf356ce6dcb1f949f7b00e76c7587d
I also didn't see details yet in commit message on why that paragraph was
added.
And..
>
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
> include/qemu/futex.h | 9 +++++++++
> tests/unit/test-aio-multithread.c | 4 +++-
> util/qemu-thread-posix.c | 28 ++++++++++++++++------------
> 3 files changed, 28 insertions(+), 13 deletions(-)
>
> diff --git a/include/qemu/futex.h b/include/qemu/futex.h
> index 91ae88966e12..f57774005330 100644
> --- a/include/qemu/futex.h
> +++ b/include/qemu/futex.h
> @@ -24,6 +24,15 @@ static inline void qemu_futex_wake(void *f, int n)
> qemu_futex(f, FUTEX_WAKE, n, NULL, NULL, 0);
> }
>
> +/*
> + * Note that a wake-up can also be caused by common futex usage patterns in
> + * unrelated code that happened to have previously used the futex word's
> + * memory location (e.g., typical futex-based implementations of Pthreads
> + * mutexes can cause this under some conditions). Therefore, callers should
.. another thing that was unclear to me is, here it's mentioning "typical
futex-based implementations of pthreads mutexes..", but here
qemu_futex_wait() is using raw futex without any pthread impl. Does it
also mean that this may not be applicable to whatever might cause a
spurious wakeup?
> + * always conservatively assume that it is a spurious wake-up, and use the futex
> + * word's value (i.e., the user-space synchronization scheme) to decide whether
> + * to continue to block or not.
> + */
> static inline void qemu_futex_wait(void *f, unsigned val)
> {
> while (qemu_futex(f, FUTEX_WAIT, (int) val, NULL, NULL, 0)) {
> diff --git a/tests/unit/test-aio-multithread.c b/tests/unit/test-aio-multithread.c
> index 08d4570ccb14..8c2e41545a29 100644
> --- a/tests/unit/test-aio-multithread.c
> +++ b/tests/unit/test-aio-multithread.c
> @@ -305,7 +305,9 @@ static void mcs_mutex_lock(void)
> prev = qatomic_xchg(&mutex_head, id);
> if (prev != -1) {
> qatomic_set(&nodes[prev].next, id);
> - qemu_futex_wait(&nodes[id].locked, 1);
> + while (qatomic_read(&nodes[id].locked) == 1) {
> + qemu_futex_wait(&nodes[id].locked, 1);
> + }
> }
> }
>
> diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
> index b2e26e21205b..eade5311d175 100644
> --- a/util/qemu-thread-posix.c
> +++ b/util/qemu-thread-posix.c
> @@ -428,17 +428,21 @@ void qemu_event_wait(QemuEvent *ev)
>
> assert(ev->initialized);
>
> - /*
> - * qemu_event_wait must synchronize with qemu_event_set even if it does
> - * not go down the slow path, so this load-acquire is needed that
> - * synchronizes with the first memory barrier in qemu_event_set().
> - *
> - * If we do go down the slow path, there is no requirement at all: we
> - * might miss a qemu_event_set() here but ultimately the memory barrier in
> - * qemu_futex_wait() will ensure the check is done correctly.
> - */
> - value = qatomic_load_acquire(&ev->value);
> - if (value != EV_SET) {
> + while (true) {
> + /*
> + * qemu_event_wait must synchronize with qemu_event_set even if it does
> + * not go down the slow path, so this load-acquire is needed that
> + * synchronizes with the first memory barrier in qemu_event_set().
> + *
> + * If we do go down the slow path, there is no requirement at all: we
> + * might miss a qemu_event_set() here but ultimately the memory barrier
> + * in qemu_futex_wait() will ensure the check is done correctly.
> + */
> + value = qatomic_load_acquire(&ev->value);
> + if (value == EV_SET) {
> + break;
> + }
> +
> if (value == EV_FREE) {
> /*
> * Leave the event reset and tell qemu_event_set that there are
> @@ -452,7 +456,7 @@ void qemu_event_wait(QemuEvent *ev)
> * like the load above.
> */
> if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
> - return;
> + break;
> }
> }
>
>
> --
> 2.49.0
>
--
Peter Xu
next prev parent reply other threads:[~2025-05-13 14:40 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-11 6:08 [PATCH v3 00/10] Improve futex usage Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 01/10] futex: Check value after qemu_futex_wait() Akihiko Odaki
2025-05-13 14:39 ` Peter Xu [this message]
2025-05-14 7:34 ` Akihiko Odaki
2025-05-14 17:06 ` Peter Xu
2025-05-16 5:34 ` Akihiko Odaki
2025-05-16 14:53 ` Peter Xu
2025-05-17 5:01 ` Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 02/10] futex: Support Windows Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 03/10] futex: Replace __linux__ with CONFIG_LINUX Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 04/10] qemu-thread: Avoid futex abstraction for non-Linux Akihiko Odaki
2025-05-14 0:51 ` Paolo Bonzini
2025-05-14 12:57 ` Akihiko Odaki
2025-05-16 11:09 ` Paolo Bonzini
2025-05-16 12:58 ` Akihiko Odaki
2025-05-16 14:25 ` Paolo Bonzini
2025-05-17 5:40 ` Akihiko Odaki
2025-05-17 10:24 ` Paolo Bonzini
2025-05-17 16:30 ` Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 05/10] qemu-thread: Use futex for QemuEvent on Windows Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 06/10] qemu-thread: Use futex if available for QemuLockCnt Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 07/10] migration: Replace QemuSemaphore with QemuEvent Akihiko Odaki
2025-05-13 19:13 ` Peter Xu
2025-05-14 12:36 ` Akihiko Odaki
2025-05-11 6:08 ` [PATCH v3 08/10] migration/colo: " Akihiko Odaki
2025-05-12 15:12 ` Fabiano Rosas
2025-05-11 6:08 ` [PATCH v3 09/10] migration/postcopy: " Akihiko Odaki
2025-05-12 15:12 ` Fabiano Rosas
2025-05-11 6:08 ` [PATCH v3 10/10] hw/display/apple-gfx: " Akihiko Odaki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aCNZk73GuEaU-gcK@x1.local \
--to=peterx@redhat.com \
--cc=akihiko.odaki@daynix.com \
--cc=berrange@redhat.com \
--cc=devel@daynix.com \
--cc=farosas@suse.de \
--cc=marcandre.lureau@redhat.com \
--cc=pbonzini@redhat.com \
--cc=phil@philjordan.eu \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=sw@weilnetz.de \
--cc=zhanghailiang@xfusion.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.