From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mta1.migadu.com (out-157.mta1.migadu.com [95.215.58.157]) (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 315891EFFA1 for ; Mon, 5 Oct 2026 00:29:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.157 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791160193; cv=none; b=uNek6XS/gSh7cp6weAbaY9vjyqIpUx6U9qXkHMXMPCg20uw3BCZeOygBVxJQ9Z+9vWekpASG8S3p+zdN4yO0RIaX/q8XLzapIVJYxp+5IDQ29EN1zBNpypmQkrfEfLNxXKOf7/T+AqeBoH7kQS1DQ0sfVVJFHlhM9vLzWyF5pK0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791160193; c=relaxed/simple; bh=B3/DFcp+SyH8b+Kah5V3t9QdusNse+6V3nxVXGVaM10=; h=Message-ID:Date:MIME-Version:Subject:To:References:From: In-Reply-To:Content-Type; b=e57Fc/Tr8ui6LbGu8XHtBv4bezAEEaaVc0TswZS/B7sAch5ox8UFQtRlIwbSVZRh9I/X/B2nQMxAfIVK9ceFjxvuAbSduiBBXStCLKLGHJ4mj0F/JO1aDagePefBqQuTMvZ1OuSjjjQcRQKA4IbXc+ZIzQ49KfBGtP0qX249Kfw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=GekuV4fl; arc=none smtp.client-ip=95.215.58.157 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="GekuV4fl" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=B3/DFcp+SyH8b+Kah5V3t9QdusNse+6V3nxVXGVaM10=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1791160186; v=1; x=1791764986; b=GekuV4flybzCCwWCfshcp9Ik9T1cjnVmroys/xX9qMmhG7/TJH4VjsVWFAwK4hwj4j/mEWen GWjalnvcNCVZxbNt2VTifjVEQCkoE70BOsPIg443s76uP/TGHMy3p7ivCubGCcNmhg1QIVkOAJP GJOxMTGzO9NhvVV1NzISGYdg= X-Envelope-To: linux-kernel@vger.kernel.org Received: by smtp.migadu.com with ESMTPS id 8d3e8eaf5c7ddbfd; Mon, 05 Oct 2026 00:29:46 +0000 X-Mizu-Trace-ID: 8d3e8eaf5c7ddbfd X-Migadu-Flow: FLOW_OUT Message-ID: <009f918c-f77a-4b46-ab6d-96d81e1ed87d@linux.dev> Date: Sun, 4 Oct 2026 17:29:42 -0700 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v3] RDMA/rxe: Validate inline data range in user WQEs To: Jiale Yao , Zhu Yanjun , Jason Gunthorpe , Leon Romanovsky , Doug Ledford , Moni Shoua , Haggai Eran , Kamal Heib , Amir Vadai , linux-rdma@vger.kernel.org, linux-kernel@vger.kernel.org, "yanjun.zhu@linux.dev" References: <20261004064445.1488753-1-yaojiale02@163.com> From: Zhu Yanjun In-Reply-To: <20261004064445.1488753-1-yaojiale02@163.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit 在 2026/10/3 23:44, Jiale Yao 写道: > For a user QP, the send queue is an mmap'd ring which userspace writes > directly. rxe_post_send() only schedules the send task for such a QP, > so userspace can also change WQE fields while rxe_requester() processes > the WQE. > > Commit 126c757e4cd46f866ddc283143b58eb4d9bf52cd ("RDMA/rxe: > Validate num_sge/cur_sge before indexing wqe->dma.sge[]") added bounds > checks for two members of the userspace-controlled dma structure, but > left sge_offset unchecked. For an inline WQE, finish_packet() uses that > value directly as an index into inline_data[] and copies dma.resid bytes > from the resulting pointer into the packet payload. > > A local user with access to uverbs can therefore put an out-of-range > sge_offset in the mmap'd SQ ring. This can disclose kernel memory in the > outgoing packet or cause a vmalloc out-of-bounds access. > > Since sge_offset comes from shared memory, validating it in > rxe_requester() and then reading it again in finish_packet() leaves a > TOCTOU window. Load it exactly once with READ_ONCE() in finish_packet(), > validate that local value, and use the same value for the copy and update. > Check the offset first and use subtraction for the length check to avoid > an integer overflow. > > I reproduced this on Linux 7.3-rc4 with an RC user QP, IB_SEND_INLINE, > a 64-byte residual length, and sge_offset set to 0x100000. KASAN > reported: > > BUG: KASAN: vmalloc-out-of-bounds in rxe_requester+0x1f27/0x4940 > Read of size 64 at addr ffffc90000191250 by task kworker/u16:0/12 > Workqueue: rxe_wq do_work > Call Trace: > __asan_memcpy > rxe_requester+0x1f27/0x4940 > rxe_sender+0xe/0x30 > do_work+0x184/0x3d0 > process_scheduled_works+0x7c0/0xf10 Conceptually, wqe->dma.sge_offset is runtime state that should be exclusively managed by the kernel, but mapping the SQ into user space via mmap exposes it to untrusted asynchronous writes. Beyond finish_packet(), every reader of sge_offset across the driver (such as in rxe_sge.c and rxe_resp.c) must treat it as untrusted input. We should audit all access points to ensure they consistently use a READ_ONCE() local snapshot followed by underflow-safe bounds checks. Longer term, moving kernel-managed progress state into kernel-private memory would eliminate this attack surface entirely. Yanjun Zhu > > Fixes: 8700e3e7c485 ("Soft RoCE driver") > Link: https://lore.kernel.org/all/20260708224534.1206-1-security@auditcode.ai/ > Signed-off-by: Jiale Yao > --- > > Notes: > Changes in v3: > - Read sge_offset from the shared WQE with READ_ONCE(), as requested. > > Changes in v2: > - Copy sge_offset into a local variable in finish_packet(), validate that > value, and reuse it for the memcpy and update. > > drivers/infiniband/sw/rxe/rxe_req.c | 14 +++++++++++--- > 1 file changed, 11 insertions(+), 3 deletions(-) > > diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c > index 24f5c044363f..9be753d2e5dd 100644 > --- a/drivers/infiniband/sw/rxe/rxe_req.c > +++ b/drivers/infiniband/sw/rxe/rxe_req.c > @@ -503,6 +503,7 @@ static int finish_packet(struct rxe_qp *qp, struct rxe_av *av, > struct sk_buff *skb, u32 payload) > { > int err; > + u32 sge_offset; > > err = rxe_prepare(av, pkt, skb); > if (err) > @@ -510,12 +511,19 @@ static int finish_packet(struct rxe_qp *qp, struct rxe_av *av, > > if (pkt->mask & RXE_WRITE_OR_SEND_MASK) { > if (wqe->wr.send_flags & IB_SEND_INLINE) { > - u8 *tmp = &wqe->dma.inline_data[wqe->dma.sge_offset]; > + sge_offset = READ_ONCE(wqe->dma.sge_offset); > + if (unlikely(sge_offset > qp->sq.max_inline || > + payload > > + qp->sq.max_inline - sge_offset)) { > + rxe_dbg_qp(qp, "invalid inline data range in send wqe\n"); > + return -EINVAL; > + } > > - memcpy(payload_addr(pkt), tmp, payload); > + memcpy(payload_addr(pkt), > + &wqe->dma.inline_data[sge_offset], payload); > > wqe->dma.resid -= payload; > - wqe->dma.sge_offset += payload; > + wqe->dma.sge_offset = sge_offset + payload; > } else { > err = copy_data(qp->pd, 0, &wqe->dma, > payload_addr(pkt), payload,