From: "Denis V. Lunev" <den@openvz.org>
To: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org, "Denis V. Lunev" <den@openvz.org>,
Eric Blake <eblake@redhat.com>,
Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Subject: [PATCH 1/3] block/nbd: clear reply.cookie when the reply is rejected
Date: Wed, 12 Aug 2026 12:29:04 +0200 [thread overview]
Message-ID: <20260812102906.894063-2-den@openvz.org> (raw)
In-Reply-To: <20260812102906.894063-1-den@openvz.org>
nbd_receive_replies() reads a reply header into s->reply and, when the
header turns out to be unusable, reports a channel error and returns
without touching it. The cookie stays there until the request which
owns the reply clears it, and until then the waiters are explicitly
allowed to look at a cookie which is not theirs:
if (s->reply.cookie != 0) {
ind2 = COOKIE_TO_INDEX(s->reply.cookie);
assert(!s->requests[ind2].receiving);
Two of the error paths leave a value chosen by the server behind: one
returns before the cookie is validated at all, the other returns
because that validation has failed. A waiter which picks such a cookie
up turns it into an index which is not in requests[] and accesses the
array out of bounds, at an offset the server controls.
The reply is of no use to anybody at this point, so clear the cookie
before the mutex is released and keep the invariant that a non-zero
s->reply.cookie is always an index of a live request.
Observing the stale cookie takes a second thread, which a multiqueue
configuration provides. Within one AioContext there is no yield point
between the failed read and the clearing done by the owner in
nbd_co_receive_one_chunk(), so nothing else of this node runs in
between. The parked waiters cannot see it either, as they are woken
only after the cookie has been cleared. What can get in is a request
entering nbd_receive_replies() afresh, one just sent or one back for
its next reply chunk, because that path takes the mutex without
looking at the state.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Cc: Eric Blake <eblake@redhat.com>
Cc: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
block/nbd.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/block/nbd.c b/block/nbd.c
index 5d231d5c4e..d9b776283f 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -466,20 +466,19 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie,
error_setg(errp, "server dropped connection");
}
if (ret < 0) {
- nbd_channel_error(s, ret);
- return ret;
+ goto err;
}
if (nbd_reply_is_structured(&s->reply) &&
s->info.mode < NBD_MODE_STRUCTURED) {
- nbd_channel_error(s, -EINVAL);
+ ret = -EINVAL;
error_setg(errp, "unexpected structured reply");
- return -EINVAL;
+ goto err;
}
ind2 = COOKIE_TO_INDEX(s->reply.cookie);
if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) {
- nbd_channel_error(s, -EINVAL);
+ ret = -EINVAL;
error_setg(errp, "unexpected cookie value");
- return -EINVAL;
+ goto err;
}
if (s->reply.cookie == cookie) {
/* We are done */
@@ -487,6 +486,13 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie,
}
nbd_recv_coroutine_wake_one(&s->requests[ind2]);
}
+
+err:
+ /* Waiters look at this cookie, so do not leave a rejected one behind. */
+ s->reply.cookie = 0;
+ nbd_channel_error(s, ret);
+
+ return ret;
}
static int coroutine_fn GRAPH_RDLOCK
--
2.53.0
next prev parent reply other threads:[~2026-08-12 10:30 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 10:29 [PATCH 0/3] block/nbd: fix a race in reply processing Denis V. Lunev
2026-08-12 10:29 ` Denis V. Lunev [this message]
2026-08-19 11:51 ` [PATCH 1/3] block/nbd: clear reply.cookie when the reply is rejected Vladimir Sementsov-Ogievskiy
2026-08-12 10:29 ` [PATCH 2/3] block/nbd: never index requests[] with an unchecked cookie Denis V. Lunev
2026-08-19 12:09 ` Vladimir Sementsov-Ogievskiy
2026-08-12 10:29 ` [PATCH 3/3] block/nbd: clear reply.cookie under receive_mutex Denis V. Lunev
2026-08-19 12:17 ` Vladimir Sementsov-Ogievskiy
2026-08-19 9:34 ` [PATCH 0/3] block/nbd: fix a race in reply processing Denis V. Lunev
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=20260812102906.894063-2-den@openvz.org \
--to=den@openvz.org \
--cc=eblake@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=vsementsov@yandex-team.ru \
/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.