From nobody Mon Feb 9 00:54:54 2026 Received: from mail-pl1-f227.google.com (mail-pl1-f227.google.com [209.85.214.227]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A2F4C1DDC28 for ; Fri, 30 Jan 2026 17:14:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.227 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769793273; cv=none; b=LucVridzR+eWR6u6G8SXsfITbgF1KefTDt0SgMx91wwmEsF2YY72e+dK4BIpxMkO9phPSVB2JDb+ZB44LbhiqGyDQXfdUKfeLIhZT3nP4yTs0y58Y25W36K8DvX7jRc/aA90PoIJGSshDAFUPL2VKBYsEA2VwkCYS8AJpsmPB+0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769793273; c=relaxed/simple; bh=0cZw4WoTg3BdK7j57W9095lLp2dvzuFS4CxIHf8f6HU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=r1owytop1mSaJyzIv3W68cKUdg6LoSEr+raJFvD98Bo8u0+WIkK12+tPyomdNu0rUaS6fQRKh2rbQ+BXX+r9qbUtVdtWCHhICZkDrd8zDe6JyPmiUb8U84GTAmhSefNcjNh9VuV4XPNQ8e18vAhvlQHmtsxmtFU3Whayl/ShJ7E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=purestorage.com; spf=fail smtp.mailfrom=purestorage.com; dkim=pass (2048-bit key) header.d=purestorage.com header.i=@purestorage.com header.b=X5KK5dei; arc=none smtp.client-ip=209.85.214.227 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=purestorage.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=purestorage.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=purestorage.com header.i=@purestorage.com header.b="X5KK5dei" Received: by mail-pl1-f227.google.com with SMTP id d9443c01a7336-2a8720818aeso942645ad.1 for ; Fri, 30 Jan 2026 09:14:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=purestorage.com; s=google2022; t=1769793271; x=1770398071; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=qzKEcCAgobrhhmQRZuiW3ilTQpyqp+GPnanCxT2FyvI=; b=X5KK5deiJW7bRr4YflAN7LlnrKIMu7MwAbRmOywk2JfwXJCwQE+IFpSI2m5j1dsu6y 1hjdUSrW18xtefzWN7aHuqjZIxqCBIwQMnjR06j2jat85BVcjet5KMoGgELQubhOMYFP hCTjZXKthN0qJcij+wRNt68LfYbjmqyqxcBXNvKLE857E2vidPSlCc6vOQ7oqHY6k1dN OnglobwGbdgRhHRkL9myp/7IWqgWgo5aqfwQaYM2Oh5osC0k4w+AoMQpawvBFWJFqaC7 2RzBqt+txLDLLPzTNJBaNC5wgllMmjoQyKIRG5Bcv39rR2/YLnXNQpUKAK7PUFVXOMy9 q6yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769793271; x=1770398071; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=qzKEcCAgobrhhmQRZuiW3ilTQpyqp+GPnanCxT2FyvI=; b=GPE6GhhnBO62djMrwwcfzfQQWPi8AHtQeGRn2OVVURI7ZbSQdqJpGq03HR6JjZEr59 +gRFe078gWz2vsZ7YSFKW1h6yyVF01hoi3G7gdXAyMQmLKJeFBis4NkUkQK5lzw+O6FM nsagOiIJX/1GDP06M53WOa48Y2aPLHOtd0b35yWpsonhTKC5i8Y+qVyIWZVSu+yNogQL +kEfnTiuQEHv026Mq8KL61weHP9dp4UqUdWtEffGQg1yNlHtnRaCXEzJe83PzNgRMesZ /XxvFQa2HpZZmzBEODJuWOJUB2qW38wYc5n+qCmxH3H9GiLnzx9hgm1x82F0TCAS9iFE N2Zg== X-Forwarded-Encrypted: i=1; AJvYcCX3I4d0ZnZ4rDjVvZUSBw6lucl2+VKh4r+wI3MTZsf9YGy08rT3ae2MVeTKfvxkK85fr47jnJCj/Op3eQ4=@vger.kernel.org X-Gm-Message-State: AOJu0YwnISrY4Hcn2Xb6ceN4tbsarym90jqxe4hNh6fAYE+gu0R9xaDI tYYFcQOPLH3uzytvNYV8wVrI0iL7SV09g3aGOaRW0IouvgMZUU+hc2mZ/N6Bcuy+eHIwDFcASOQ KjDgsrBcX2TazpL7EbE+dN4dYup23LyJzIUIP X-Gm-Gg: AZuq6aL5SJaMI1WwWhw8Q/U8CiU548xNjT/6r6RvFyyBM8XznAGN3+1WtNJbFko1lvJ DlmysVhUsVlgquALLIua/g+gJPRwVWP+b0rNVq0eGHBqQlGYz5PSd5GKsYIM5r3QqAOtL1vXWz7 P+dZ5ZY7m9cPICaRw1auEXvd7JOXqnR3t3VwMeLPH/xv74/Et68/NllQSTr6gtOoQyanHD69fer 0dfwcjAfZRc8SKT2r5ScErQkRGi1tqtJLh2FqzOjBgjMAkmSRH4K98d0OkZ+yg834L2JOOMFjLD 5VdyomF4/ncS6S7GB5RDD4GJUvAJa99708rcRRkKuztTevHDlR+fMNRgRI4JS+NlWWPV4DD2rtK geprY7o5NymRZaZwK4PMpAGPV3buWB0bi6n9DNKfM9g== X-Received: by 2002:a17:902:e003:b0:2a0:ccee:b356 with SMTP id d9443c01a7336-2a8d958e55dmr19048675ad.1.1769793270921; Fri, 30 Jan 2026 09:14:30 -0800 (PST) Received: from c7-smtp-2023.dev.purestorage.com ([208.88.159.128]) by smtp-relay.gmail.com with ESMTPS id d9443c01a7336-2a88b7f86c3sm10838705ad.53.2026.01.30.09.14.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 30 Jan 2026 09:14:30 -0800 (PST) X-Relaying-Domain: purestorage.com Received: from dev-csander.dev.purestorage.com (dev-csander.dev.purestorage.com [10.112.29.101]) by c7-smtp-2023.dev.purestorage.com (Postfix) with ESMTP id 1856B340603; Fri, 30 Jan 2026 10:14:30 -0700 (MST) Received: by dev-csander.dev.purestorage.com (Postfix, from userid 1557716354) id 13438E40249; Fri, 30 Jan 2026 10:14:30 -0700 (MST) From: Caleb Sander Mateos To: Ming Lei , Jens Axboe Cc: Govindarajulu Varadarajan , linux-block@vger.kernel.org, linux-kernel@vger.kernel.org, Caleb Sander Mateos Subject: [PATCH v2 2/3] ublk: use READ_ONCE() to read struct ublksrv_ctrl_cmd Date: Fri, 30 Jan 2026 10:14:13 -0700 Message-ID: <20260130171414.1376543-3-csander@purestorage.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20260130171414.1376543-1-csander@purestorage.com> References: <20260130171414.1376543-1-csander@purestorage.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" struct ublksrv_ctrl_cmd is part of the io_uring_sqe, which may lie in userspace-mapped memory. It's racy to access its fields with normal loads, as userspace may write to them concurrently. Use READ_ONCE() to copy the ublksrv_ctrl_cmd from the io_uring_sqe to the stack. Use the local copy in place of the one in the io_uring_sqe. Fixes: 87213b0d847c ("ublk: allow non-blocking ctrl cmds in IO_URING_F_NONB= LOCK issue") Signed-off-by: Caleb Sander Mateos Reviewed-by: Ming Lei --- drivers/block/ublk_drv.c | 56 ++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 01088194c8d3..8122b012a7ae 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -4729,16 +4729,15 @@ static int ublk_ctrl_del_dev(struct ublk_device **p= _ub, bool wait) if (wait && wait_event_interruptible(ublk_idr_wq, ublk_idr_freed(idx))) return -EINTR; return 0; } =20 -static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd) +static inline void ublk_ctrl_cmd_dump(u32 cmd_op, + const struct ublksrv_ctrl_cmd *header) { - const struct ublksrv_ctrl_cmd *header =3D io_uring_sqe_cmd(cmd->sqe); - pr_devel("%s: cmd_op %x, dev id %d qid %d data %llx buf %llx len %u\n", - __func__, cmd->cmd_op, header->dev_id, header->queue_id, + __func__, cmd_op, header->dev_id, header->queue_id, header->data[0], header->addr, header->len); } =20 static void ublk_ctrl_stop_dev(struct ublk_device *ub) { @@ -5117,13 +5116,12 @@ static int ublk_char_dev_permission(struct ublk_dev= ice *ub, path_put(&path); return err; } =20 static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, - struct io_uring_cmd *cmd) + u32 cmd_op, struct ublksrv_ctrl_cmd *header) { - struct ublksrv_ctrl_cmd *header =3D (struct ublksrv_ctrl_cmd *)io_uring_s= qe_cmd(cmd->sqe); bool unprivileged =3D ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV; void __user *argp =3D (void __user *)(unsigned long)header->addr; char *dev_path =3D NULL; int ret =3D 0; int mask; @@ -5135,11 +5133,11 @@ static int ublk_ctrl_uring_cmd_permission(struct ub= lk_device *ub, * The new added command of UBLK_CMD_GET_DEV_INFO2 includes * char_dev_path in payload too, since userspace may not * know if the specified device is created as unprivileged * mode. */ - if (_IOC_NR(cmd->cmd_op) !=3D UBLK_CMD_GET_DEV_INFO2) + if (_IOC_NR(cmd_op) !=3D UBLK_CMD_GET_DEV_INFO2) return 0; } =20 /* * User has to provide the char device path for unprivileged ublk @@ -5156,11 +5154,11 @@ static int ublk_ctrl_uring_cmd_permission(struct ub= lk_device *ub, dev_path =3D memdup_user_nul(argp, header->dev_path_len); if (IS_ERR(dev_path)) return PTR_ERR(dev_path); =20 ret =3D -EINVAL; - switch (_IOC_NR(cmd->cmd_op)) { + switch (_IOC_NR(cmd_op)) { case UBLK_CMD_GET_DEV_INFO: case UBLK_CMD_GET_DEV_INFO2: case UBLK_CMD_GET_QUEUE_AFFINITY: case UBLK_CMD_GET_PARAMS: case (_IOC_NR(UBLK_U_CMD_GET_FEATURES)): @@ -5186,11 +5184,11 @@ static int ublk_ctrl_uring_cmd_permission(struct ub= lk_device *ub, if (!ret) { header->len -=3D header->dev_path_len; header->addr +=3D header->dev_path_len; } pr_devel("%s: dev id %d cmd_op %x uid %d gid %d path %s ret %d\n", - __func__, ub->ub_number, cmd->cmd_op, + __func__, ub->ub_number, cmd_op, ub->dev_info.owner_uid, ub->dev_info.owner_gid, dev_path, ret); exit: kfree(dev_path); return ret; @@ -5210,11 +5208,13 @@ static bool ublk_ctrl_uring_cmd_may_sleep(u32 cmd_o= p) } =20 static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) { - const struct ublksrv_ctrl_cmd *header =3D io_uring_sqe_cmd(cmd->sqe); + /* May point to userspace-mapped memory */ + const struct ublksrv_ctrl_cmd *ub_src =3D io_uring_sqe_cmd(cmd->sqe); + struct ublksrv_ctrl_cmd header; struct ublk_device *ub =3D NULL; u32 cmd_op =3D cmd->cmd_op; int ret =3D -EINVAL; =20 if (ublk_ctrl_uring_cmd_may_sleep(cmd_op) && @@ -5222,74 +5222,80 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd = *cmd, return -EAGAIN; =20 if (!(issue_flags & IO_URING_F_SQE128)) return -EINVAL; =20 - ublk_ctrl_cmd_dump(cmd); + header.dev_id =3D READ_ONCE(ub_src->dev_id); + header.queue_id =3D READ_ONCE(ub_src->queue_id); + header.len =3D READ_ONCE(ub_src->len); + header.addr =3D READ_ONCE(ub_src->addr); + header.data[0] =3D READ_ONCE(ub_src->data[0]); + header.dev_path_len =3D READ_ONCE(ub_src->dev_path_len); + ublk_ctrl_cmd_dump(cmd_op, &header); =20 ret =3D ublk_check_cmd_op(cmd_op); if (ret) goto out; =20 if (cmd_op =3D=3D UBLK_U_CMD_GET_FEATURES) { - ret =3D ublk_ctrl_get_features(header); + ret =3D ublk_ctrl_get_features(&header); goto out; } =20 if (_IOC_NR(cmd_op) !=3D UBLK_CMD_ADD_DEV) { ret =3D -ENODEV; - ub =3D ublk_get_device_from_id(header->dev_id); + ub =3D ublk_get_device_from_id(header.dev_id); if (!ub) goto out; =20 - ret =3D ublk_ctrl_uring_cmd_permission(ub, cmd); + ret =3D ublk_ctrl_uring_cmd_permission(ub, cmd_op, &header); if (ret) goto put_dev; } =20 switch (_IOC_NR(cmd_op)) { case UBLK_CMD_START_DEV: - ret =3D ublk_ctrl_start_dev(ub, header); + ret =3D ublk_ctrl_start_dev(ub, &header); break; case UBLK_CMD_STOP_DEV: ublk_ctrl_stop_dev(ub); ret =3D 0; break; case UBLK_CMD_GET_DEV_INFO: case UBLK_CMD_GET_DEV_INFO2: - ret =3D ublk_ctrl_get_dev_info(ub, header); + ret =3D ublk_ctrl_get_dev_info(ub, &header); break; case UBLK_CMD_ADD_DEV: - ret =3D ublk_ctrl_add_dev(header); + ret =3D ublk_ctrl_add_dev(&header); break; case UBLK_CMD_DEL_DEV: ret =3D ublk_ctrl_del_dev(&ub, true); break; case UBLK_CMD_DEL_DEV_ASYNC: ret =3D ublk_ctrl_del_dev(&ub, false); break; case UBLK_CMD_GET_QUEUE_AFFINITY: - ret =3D ublk_ctrl_get_queue_affinity(ub, header); + ret =3D ublk_ctrl_get_queue_affinity(ub, &header); break; case UBLK_CMD_GET_PARAMS: - ret =3D ublk_ctrl_get_params(ub, header); + ret =3D ublk_ctrl_get_params(ub, &header); break; case UBLK_CMD_SET_PARAMS: - ret =3D ublk_ctrl_set_params(ub, header); + ret =3D ublk_ctrl_set_params(ub, &header); break; case UBLK_CMD_START_USER_RECOVERY: - ret =3D ublk_ctrl_start_recovery(ub, header); + ret =3D ublk_ctrl_start_recovery(ub, &header); break; case UBLK_CMD_END_USER_RECOVERY: - ret =3D ublk_ctrl_end_recovery(ub, header); + ret =3D ublk_ctrl_end_recovery(ub, &header); break; case UBLK_CMD_UPDATE_SIZE: - ublk_ctrl_set_size(ub, header); + ublk_ctrl_set_size(ub, &header); ret =3D 0; break; case UBLK_CMD_QUIESCE_DEV: - ret =3D ublk_ctrl_quiesce_dev(ub, header); + ret =3D ublk_ctrl_quiesce_dev(ub, &header); break; case UBLK_CMD_TRY_STOP_DEV: ret =3D ublk_ctrl_try_stop_dev(ub); break; default: @@ -5300,11 +5306,11 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd = *cmd, put_dev: if (ub) ublk_put_device(ub); out: pr_devel("%s: cmd done ret %d cmd_op %x, dev id %d qid %d\n", - __func__, ret, cmd->cmd_op, header->dev_id, header->queue_id); + __func__, ret, cmd_op, header.dev_id, header.queue_id); return ret; } =20 static const struct file_operations ublk_ctl_fops =3D { .open =3D nonseekable_open, --=20 2.45.2