From nobody Sat Sep 26 20:50:47 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=seu.edu.cn ARC-Seal: i=1; a=rsa-sha256; t=1788496397; cv=none; d=zohomail.com; s=zohoarc; b=AE3P06qi6OyGY+HnhVH09abUjcY7Kah11ympbifzMpeBwIuf6bjxRLiT+gnjwXt7Z1NXyqT2wPk9iCre3aZjocdNs0cbsRkqro0yoAZuNwJmpzbFMUZn9VAihLhQvYW4iEyEP09QlQTglhzw/BmPdMw1gVEJEI8+IFEg5kmWAwE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1788496397; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ShThp4Pj1WfDjUiolMJV9lM58fXo7OorA2sWdh8SrfE=; b=BVBlchLuVx7WTkDr5rLBHlllFmlAsLUdYIk54u2Z80IYhFx42oYV1tLF/FreMxsdcv7tiygp82MLDllCxGzjT1m7N2GJGM3vS3oH7rWG61bFVvTU2R1eaJMUKyIXAtJvHzv8426SApibAdzWCmeVkDZyxzdYkYpMDol9J4KiigY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1788496397633614.734695380387; Thu, 3 Sep 2026 21:33:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x2LbE-0001CH-PG; Fri, 04 Sep 2026 00:32:24 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x2Koi-0004pe-6U; Thu, 03 Sep 2026 23:42:16 -0400 Received: from mail-m49197.qiye.163.com ([45.254.49.197]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x2Kof-0003BI-IC; Thu, 03 Sep 2026 23:42:15 -0400 Received: from LAPTOP-99KJFSET (unknown [36.153.54.56]) by smtp.qiye.163.com (Hmail) with ESMTP id 4c7fb7a24; Fri, 4 Sep 2026 11:33:03 +0800 (GMT+08:00) From: Hongyan Xu To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, Peter Lieven , Hongyan Xu Subject: [RFC PATCH] nbd/server: hold an export reference during option negotiation Date: Fri, 4 Sep 2026 11:33:02 +0800 Message-ID: <20260904033302.1265-1-getshell@seu.edu.cn> X-Mailer: git-send-email 2.50.1.windows.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa06a7a1aba03a1kunm85b2304924174 X-HM-MType: 10 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFITzdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVlCTUtCVktKGEtCS05IHRhJS1YeHw 5VEwETFhoSFyQUDg9ZV1kYEgtZQVlITVVKTkhVTk9VTk1ZV1kWGg8SFR0UWUFZT0tIVUpLSUhOQ0 NVSktLVUtZBg++ DKIM-Signature: a=rsa-sha256; b=gnws+8SrZ9qh9el7URppVuBI381g16AED2PFo9yq6Dc5JdczrbK9M1O84PCwnD+YkBYPnx/er2nAGJq+ZtI3z8o3JgwSsYbf9/Lbs76i/dYVCTEh+NXOkVC8MERZZwh0oWq5OZHeCww32lNdCP2Bs9BY3CAcuhD6XdOe9C4k8lk=; c=relaxed/relaxed; s=default; d=seu.edu.cn; v=1; bh=ShThp4Pj1WfDjUiolMJV9lM58fXo7OorA2sWdh8SrfE=; h=date:mime-version:subject:message-id:from; Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=45.254.49.197; envelope-from=getshell@seu.edu.cn; helo=mail-m49197.qiye.163.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Fri, 04 Sep 2026 00:32:22 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @seu.edu.cn) X-ZM-MESSAGEID: 1788496399434158500 Content-Type: text/plain; charset="utf-8" During NBD_OPT_GO / NBD_OPT_INFO negotiation the server runs in a coroutine that performs blocking I/O with the client. The handlers call nbd_export_find(), which returns a raw NBDExport * with no reference taken (it is a plain QTAILQ lookup), and then dereference that pointer across multiple yields (nbd_write / nbd_negotiate_send_info etc.). A client that is still negotiating is not yet on exp->clients, so it holds no reference. If the management layer runs block-export-del (mode hard) while such a client is parked in I/O, nbd_export_request_shutdown() removes the export from the exports list and the BlockExport is freed; when the negotiating coroutine resumes it dereferences a dangling NBDExport * -> use-after-free of host memory. Take a reference right after the lookup succeeds in nbd_negotiate_handle_export_name() and nbd_negotiate_handle_info(), and drop it on every path that leaves the handler without having handed the export to the client (the client takes its own reference when it is inserted into exp->clients). The success paths are unchanged so the client-owned reference is not double-counted. Known remaining spot, deliberately not changed here: nbd_export_meta_context() stores nbd_export_find()'s result into meta->exp (client->contexts.exp) which is expected to stay consistent with client->exp (see the assert in nbd_co_block_status_payload_read()). The reference semantics of contexts.exp deserve maintainer input before changing them; this patch only covers the two handlers that run before the client owns a reference. This is an RFC: the block/export reference-counting semantics should be confirmed with the NBD maintainers (notably whether a negotiating client should be tracked so that block-export-del SAFE mode reports the export as busy instead of racing with a hard delete). Signed-off-by: Hongyan Xu --- nbd/server.c | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index e6c47f8c2e..8754236a9e 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -517,6 +517,14 @@ nbd_negotiate_handle_export_name(NBDClient *client, bo= ol no_zeroes, error_setg(errp, "export not found"); return -EINVAL; } + /* + * The export can be deleted by the management layer while we are + * blocked in the writes below (before the client is inserted into + * exp->clients and takes its own reference). Hold a reference for + * the whole negotiation so a concurrent block-export-del cannot + * free the export under us. + */ + blk_exp_ref(&client->exp->common); nbd_check_meta_export(client, client->exp); =20 myflags =3D client->exp->nbdflags; @@ -533,11 +541,15 @@ nbd_negotiate_handle_export_name(NBDClient *client, b= ool no_zeroes, ret =3D nbd_write(client->ioc, buf, len, errp); if (ret < 0) { error_prepend(errp, "write failed: "); + blk_exp_unref(&client->exp->common); + client->exp =3D NULL; return ret; } =20 QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); blk_exp_ref(&client->exp->common); + /* Drop the negotiation reference; the client owns one now. */ + blk_exp_unref(&client->exp->common); =20 return 0; } @@ -659,6 +671,13 @@ nbd_negotiate_handle_info(NBDClient *client, Error **e= rrp) errp, "export '%s' not present", sane_name); } + /* + * Hold a reference across the whole info exchange: the export can + * be deleted by the management layer (block-export-del) while we + * are blocked sending replies below and before the client is + * inserted into exp->clients for NBD_OPT_GO. + */ + blk_exp_ref(&exp->common); if (client->opt =3D=3D NBD_OPT_GO) { nbd_check_meta_export(client, exp); } @@ -668,7 +687,7 @@ nbd_negotiate_handle_info(NBDClient *client, Error **er= rp) rc =3D nbd_negotiate_send_info(client, NBD_INFO_NAME, namelen, nam= e, errp); if (rc < 0) { - return rc; + goto out; } } =20 @@ -681,7 +700,7 @@ nbd_negotiate_handle_info(NBDClient *client, Error **er= rp) rc =3D nbd_negotiate_send_info(client, NBD_INFO_DESCRIPTION, len, exp->description, errp); if (rc < 0) { - return rc; + goto out; } } =20 @@ -707,7 +726,7 @@ nbd_negotiate_handle_info(NBDClient *client, Error **er= rp) rc =3D nbd_negotiate_send_info(client, NBD_INFO_BLOCK_SIZE, sizeof(sizes), sizes, errp); if (rc < 0) { - return rc; + goto out; } =20 /* Send NBD_INFO_EXPORT always */ @@ -725,7 +744,7 @@ nbd_negotiate_handle_info(NBDClient *client, Error **er= rp) rc =3D nbd_negotiate_send_info(client, NBD_INFO_EXPORT, sizeof(buf), buf, errp); if (rc < 0) { - return rc; + goto out; } =20 /* @@ -736,17 +755,18 @@ nbd_negotiate_handle_info(NBDClient *client, Error **= errp) */ if (client->opt =3D=3D NBD_OPT_INFO && !blocksize && blk_get_request_alignment(exp->common.blk) > 1) { - return nbd_negotiate_send_rep_err(client, - NBD_REP_ERR_BLOCK_SIZE_REQD, - errp, - "request NBD_INFO_BLOCK_SIZE to " - "use this export"); + rc =3D nbd_negotiate_send_rep_err(client, + NBD_REP_ERR_BLOCK_SIZE_REQD, + errp, + "request NBD_INFO_BLOCK_SIZE to " + "use this export"); + goto out; } =20 /* Final reply */ rc =3D nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); if (rc < 0) { - return rc; + goto out; } =20 if (client->opt =3D=3D NBD_OPT_GO) { @@ -756,6 +776,11 @@ nbd_negotiate_handle_info(NBDClient *client, Error **e= rrp) blk_exp_ref(&client->exp->common); rc =3D 1; } + blk_exp_unref(&exp->common); + return rc; + +out: + blk_exp_unref(&exp->common); return rc; } =20 --=20 2.50.1.windows.1