From nobody Mon Jun 8 05:25:24 2026 Received: from mail-qk1-f181.google.com (mail-qk1-f181.google.com [209.85.222.181]) (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 AA444175A7C for ; Tue, 2 Jun 2026 19:47:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780429632; cv=none; b=uHtRoCMDY2zw/7jrLSEjh6Dx9oynqtmsuONJTZ5aAjZJXv6pVUevNlaU+LjQf7zFd+xwd/DbnJvLv/TmGKd6fuaxEgY4wX2oUSl9BRM4q9azAAv5ionLHzQJJIvYdlthGicRz+O4lfy4+DDRIJEEk9P1N2jZecVFWUZaxUhtDX8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780429632; c=relaxed/simple; bh=5AgpAAnS8cDR3zedlpI0Z2zKJHna6jr8Y/0zpoo9Qfw=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=UB3CU+sS2XjLNUa/luRpyfGIsDjGSZ6ZU4kwLziBO658T/N8f3DPmEPl0Sz2irNL+xZ91ihqlCeUAzpmHfi+VkqhJ+G709ST2Q7eItlTVvgZXZa3VgEa5zQHLm2iJNDvjPQrQRmafwvdcCC8KLp9xGkAUTMbZRC6+l5KapqbERs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=KfL8p2Gn; arc=none smtp.client-ip=209.85.222.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KfL8p2Gn" Received: by mail-qk1-f181.google.com with SMTP id af79cd13be357-91563382bcfso263463485a.0 for ; Tue, 02 Jun 2026 12:47:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780429630; x=1781034430; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=rL91njhnIv1gQ98/IXo5V10Wtcv77BWj1gHeGmHN2C4=; b=KfL8p2GndcpqnIfB3IjClH/oo2I3GbWFL4ki28L3GLuatwsEktYo3aPekudp09tBip 13oZJ2iaaqnQNrkhPtpNPNds/AfoVDF2F7aeEOQT6Wid5ewGyqJ7FIKS1XiKbBsZ9PQQ Q5OELQMVT3HVxfvgisdCNEqSWd9rpaliztzLvUuuHWLPY9UzFDytOBQS+AMGIbQ66XbG sa3SQoGBBCZsk2xq1Lt9LZtekLb/7NxF35xdbQH0CVE2iO6qHazZa3JOte2mz0RQBnj7 CM2BHU336uJevg1fvTIcshMRoTLXAyPDKxgCUqrOqzNnXOXJuTTtSFSfxAERYjA2BPGC tSag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780429630; x=1781034430; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=rL91njhnIv1gQ98/IXo5V10Wtcv77BWj1gHeGmHN2C4=; b=W6CmyNkorjo2aKkUMYvMSTRkTxRBud7AOLnktDwk689mPR4+pj1qcu9McrsXeo2cdN +yJj2bpHLVgyzbhdgQ9cvz/lmBREAUM1UiQ1njfNzU/Cy1FU33DY5a2dMxfGRICVr60x 0am0NdAG1JQ4ezuXl004+g0B/2wl/i2lQ2QP0n9Ddk2jvDY9OG1VO6UOKJo/Gp9cAOy/ 2FqlBUGmuAsRGRwuMFrTKCMxdOvxZ1kdg7sAqleBtt3HO/Hz4xCSJtgnPQyLoxLcmuKa yKAmvFTtOnPmJciez9pciwS/t7hfZPSNGXo3FGMGgv5GAfRRqci3ovtH2nulDvByZFGs 8jZA== X-Forwarded-Encrypted: i=1; AFNElJ9LC+krPYiKWXCbvj2ohGDZub7KpOaZtJrjURtFyFtDaqWjCMCY6zUqAgQVvUcBtaZU07TFsCHS0LbIh+M=@vger.kernel.org X-Gm-Message-State: AOJu0Yx4L/JQ1tQnh/F/TkiFq7l7O8jyY6r3jewAFoHGHYwjIQSbRKAR hQyBtCMLVYaf3lwYbbq31e0bOcSmXykJ51DduPcTCtHZJXIh/2mp6HpP X-Gm-Gg: Acq92OEWF0g/OKKs1HrWA9H0q9UJ3w79XmX8CgQk7y7W1UJq5hCuVn2WUoeJH6jdOq+ cFnhS8m2tqdSId91Jjfb/jVfVXTlQ8Q4lo2dDNfmfA+x+8217RlVvlsFsSrEBaSuCGPRRioRXXi p447t7anHJrcGc+J4EkKvMRgRLpPgHk1IElGUhxcwrw7cRFamxFZTzgue7H9pFAEuMQlfIk3ooi QQWAIQTFNo7a8xZigXnAjycTeCDJuUM6+MOYYOtIcRkK0qz4ZboKOUMT4eD9xAasLTuHMZihpkw xOa6EoxOFoqYdwiLlFhUTCBnuwgqypq/69oK6U4TgdF+0gfynAXTtuPheldK3Xg/AIYuAuiEr3P xtKO9zLOpl6dU1v5mFb0OIIr1yc70Mk14QqMqkvG7S8Dyq7D7whxmR/VazaO0+Cfuk5DCvKbG81 VvbkwGwlxXUomDxHLtpG6uQc37lvN/Mz8D28guuPadCoenwrzYm5rcAaGj/deCOdZbwKHZHpHAn 7jy0Jj1T5kRtzARiTTDOMz2SlgV8Aw= X-Received: by 2002:a05:622a:d03:b0:516:e047:2f30 with SMTP id d75a77b69052e-517786c877dmr6334561cf.38.1780429629575; Tue, 02 Jun 2026 12:47:09 -0700 (PDT) Received: from server0 (c-68-48-65-54.hsd1.mi.comcast.net. [68.48.65.54]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8cecd06b701sm741816d6.34.2026.06.02.12.47.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Jun 2026 12:47:09 -0700 (PDT) From: Michael Bommarito To: Bernard Metzler , Jason Gunthorpe , Leon Romanovsky Cc: linux-rdma@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] RDMA/siw: bound Read Response placement to the RREAD length Date: Tue, 2 Jun 2026 15:47:00 -0400 Message-ID: <20260602194700.2273758-1-michael.bommarito@gmail.com> X-Mailer: git-send-email 2.53.0 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" In drivers/infiniband/sw/siw/siw_qp_rx.c, siw_proc_rresp() places each inbound Read Response DDP segment at sge->laddr + wqe->processed and then accumulates wqe->processed, but it never checks the running total against the sink buffer length on continuation segments. siw_check_sge() resolves and validates the sink memory only on the first fragment (the if (!*mem) branch), and siw_rresp_check_ntoh() compares the cumulative length against wqe->bytes only on the final segment (the !frx->more_ddp_segs guard). A connected siw peer that answers an outstanding RREAD with Read Response segments that keep the DDP Last flag clear, carrying more total payload than the RREAD requested, drives wqe->processed past the validated sink buffer; the next siw_rx_data() call writes out of bounds at sge->laddr + wqe->processed. siw runs iWARP over ordinary routable TCP, so the peer is the remote end of an established RDMA connection and needs no local privilege. Bound every segment before placement, exactly as siw_proc_send() and siw_proc_write() already do for their tagged and untagged paths, and terminate the connection with a base-or-bounds DDP error when the Read Response would overrun the sink buffer. This is the second receive-path length fix for this file. A separate change rejects an MPA FPDU length that underflows the per-fragment remainder in the header decode; that guard does not cover this case, because here each individual segment length is self-consistent and only the accumulated placement offset overruns the buffer. Fixes: 8b6a361b8c48 ("rdma/siw: receive path") Cc: stable@vger.kernel.org Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito --- Impact: the remote peer of an established Soft-iWARP connection can write out of bounds past the RREAD sink (global DMA MR sink) or force a connection-terminating fault (default FRWR sink) by streaming Read Response segments whose cumulative length exceeds the requested length with the DDP Last flag clear. Relationship to the in-flight siw receive-path fix This is the second receive-path length fix I have for this file. The first, currently under review on this list, rejects an MPA FPDU length that underflows the per-fragment remainder during header decode in siw_get_hdr(). That guard sits in the header-length path and does not cover the case here: in this report every individual segment length is self-consistent and non-negative, and only the accumulated placement offset (wqe->processed across continuation segments) overruns the sink buffer. The two fixes touch different functions and are independent; either can be applied without the other. I am sending this as a fresh top-level thread rather than threading it under the earlier series to keep the two changes separable for review and for stable selection. Analysis Verified by reading siw_qp_rx.c at v7.1-rc4 (a1f173eb51db): - siw_proc_rresp() resolves and range-checks the sink memory region once, on the first fragment only (the if (!*mem) branch calling siw_check_sge() with the full requested length). - The cumulative-length consistency check in siw_rresp_check_ntoh() is gated on !more_ddp_segs, so it fires only on the segment that carries the DDP Last flag, and siw_rresp_check_ntoh() itself runs only on the first DDP segment. - Each segment is then placed at sge->laddr + wqe->processed and wqe->processed is accumulated, with no per-segment bound against wqe->bytes. A peer that keeps the DDP Last flag clear across continuation segments and streams more total payload than the outstanding RREAD requested therefore drives wqe->processed past the validated sink region; the next placement writes peer-supplied bytes out of bounds. For a sink backed by a global DMA / kernel-virtual MR (mem_obj NULL, the siw_rx_kva() path) this is a direct kernel-heap out-of-bounds write. For a user-memory or fast-registration/PBL MR (siw_rx_umem() / siw_rx_pbl(), the mode kernel ULPs use by default) the over-walk is caught when the page or PBL index runs out and is converted to a connection-terminating fault. The missing per-segment bound should be added regardless of sink type. siw_proc_send() and siw_proc_write() already bound every segment with the equivalent wqe->bytes < wqe->processed + srx->fpdu_part_rem check; this patch brings siw_proc_rresp() in line with them. Conditions: CONFIG_RDMA_SIW=3Dm or =3Dy, siw loaded and a link configured (modprobe siw; rdma link add ... type siw), and a local ULP with an outstanding RDMA READ to the peer. The out-of-bounds write requires the READ sink to be a global DMA / kernel-virtual MR; ULPs using the default fast-registration (FRWR) sink instead see a connection-terminating fault. No special sysctls or local privilege on the victim are required beyond the configured fabric. Mitigations: until the patch is applied, do not configure Soft-iWARP toward untrusted peers, or restrict the RDMA-CM listener to trusted peers at the network layer. Removing the module (rmmod siw) is sufficient when no application is using it. A function-level reproducer that drives siw_proc_rresp() over the real kernel TCP receive path with a primed ORQ and a two-segment malformed Read Response reproduces a KASAN slab-out-of-bounds write on a global DMA MR sink; it can be shared off-list on request. Fixes: 8b6a361b8c48 ("rdma/siw: receive path"), reachable from v5.10 and all later releases; all stable branches carrying siw are affected. drivers/infiniband/sw/siw/siw_qp_rx.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/= siw/siw_qp_rx.c index e8a88b378d51d..ec4aadef3dfe2 100644 --- a/drivers/infiniband/sw/siw/siw_qp_rx.c +++ b/drivers/infiniband/sw/siw/siw_qp_rx.c @@ -844,6 +844,25 @@ int siw_proc_rresp(struct siw_qp *qp) } mem_p =3D *mem; =20 + /* + * siw_rresp_check_ntoh() validates the cumulative length only on + * the last DDP segment (!more_ddp_segs), and siw_check_sge() above + * resolves the sink memory only on the first fragment. A peer that + * keeps DDP_FLAG_LAST clear and streams more payload than the + * outstanding RREAD requested therefore drives wqe->processed past + * the validated sink buffer, writing out of bounds. Bound every + * segment as siw_proc_send()/siw_proc_write() already do. + */ + if (unlikely(wqe->processed + srx->fpdu_part_rem > wqe->bytes)) { + siw_dbg_qp(qp, "rresp len: %d + %d > %d\n", + wqe->processed, srx->fpdu_part_rem, wqe->bytes); + wqe->wc_status =3D SIW_WC_LOC_LEN_ERR; + siw_init_terminate(qp, TERM_ERROR_LAYER_DDP, + DDP_ETYPE_TAGGED_BUF, + DDP_ECODE_T_BASE_BOUNDS, 0); + return -EINVAL; + } + bytes =3D min(srx->fpdu_part_rem, srx->skb_new); rv =3D siw_rx_data(mem_p, srx, &frx->pbl_idx, sge->laddr + wqe->processed, bytes); --=20 2.53.0