{"id":"CVE-2026-89533","state":"PUBLISHED","title":"svcrdma: Fix offset arithmetic in read_chunk_range","description":"In the Linux kernel, the following vulnerability has been resolved:\n\nsvcrdma: Fix offset arithmetic in read_chunk_range\n\nsvc_rdma_read_chunk_range() walks a Read chunk's segment list to\nbuild a sub-range starting at byte offset and spanning length bytes\nfor a Position-Zero or Call chunk. Two arithmetic defects in the\nper-segment loop produce wrong DMA lengths and a u32 underflow:\n\n    pcl_for_each_segment(segment, chunk) {\n            if (offset > segment->rs_length) {\n                    offset -= segment->rs_length;\n                    continue;\n            }\n\n            dummy.rs_handle = segment->rs_handle;\n            dummy.rs_length = min_t(u32, length,\n                                    segment->rs_length) - offset;\n            dummy.rs_offset = segment->rs_offset + offset;\n\nFirst, the skip predicate uses '>' instead of '>='. When offset\nequals the segment's full rs_length, the segment is fully consumed\nand should be skipped, but the loop falls through into the body.\nThe resulting dummy.rs_length is min_t(u32, length, rs_length) -\nrs_length, which underflows to a near-UINT_MAX u32 when length is\nsmaller than rs_length, or is zero otherwise.\n\nSecond, the length formula subtracts offset from the min_t() result\nrather than from segment->rs_length before the cap. For offset > 0\nthe segment's residual is rs_length - offset, not rs_length, so the\ncap must be applied to the residual. With the current bracketing,\nwhenever length is smaller than rs_length - offset the per-segment\nlength becomes length - offset instead of length, silently dropping\noffset bytes from the rebuilt chunk. Combined with the boundary\ncase above it also enables the u32 underflow path, which propagates\na huge nr_bvec into svc_rdma_build_read_segment() and a multi-MiB\nkmalloc_array_node() in svc_rdma_get_rw_ctxt().\n\nAdditionally, svc_rdma_read_call_chunk() can invoke this function\nwith length == 0 when the last Read chunk ends exactly at the end\nof the Call chunk. With the corrected >= predicate, every segment\nis skipped and the function returns the initial -EINVAL, rejecting\na valid request. Return success immediately when length is zero.\nAlso break out of the loop once length is fully consumed to avoid\npassing zero-length segments to svc_rdma_build_read_segment().\n\nFix by using '>=' so a fully-consumed segment is skipped, by\nmoving '- offset' inside min_t() so the cap is applied to the\nsegment's residual length, by returning success for zero-length\nrequests, and by stopping iteration when the requested range has\nbeen consumed.","publishedAt":"2026-09-11T19:44:12.236Z","updatedAt":"2026-10-19T08:48:24.875Z","severity":{"score":9.8,"label":"Critical","version":"3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","source":"Linux"},"assigner":"Linux","products":["Linux Linux"],"affected":[{"vendor":"Linux","product":"Linux","defaultStatus":"unaffected","versions":[{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"10873311f91db9454e2fadbf9866bc819e0646d9","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"addbf02dfe3b25e7e38e03bbd4e2a6ed86a14be7","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"cba8543c18cf42fd80fd63effb6df6ff4f7e73ce","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"6ee4dc7476b3abc92ec1d444533a559f33f59561","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"a46b35f213c2426f5d6a0458a8f7e873fc59cdfd","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"4493c96bbd0068fadf69cbae8d13426202e34cdc","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"4a44c140cc2f3643a39e258bb0c0ab9d0f494f5e","versionType":"git"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["net/sunrpc/xprtrdma/svc_rdma_rw.c"]},{"vendor":"Linux","product":"Linux","defaultStatus":"affected","versions":[{"version":"5.11","status":"affected"},{"version":"0","status":"unaffected","lessThan":"5.11","versionType":"semver"},{"version":"5.15.221","status":"unaffected","lessThanOrEqual":"5.15.*","versionType":"semver"},{"version":"6.1.188","status":"unaffected","lessThanOrEqual":"6.1.*","versionType":"semver"},{"version":"6.6.157","status":"unaffected","lessThanOrEqual":"6.6.*","versionType":"semver"},{"version":"6.12.109","status":"unaffected","lessThanOrEqual":"6.12.*","versionType":"semver"},{"version":"6.18.50","status":"unaffected","lessThanOrEqual":"6.18.*","versionType":"semver"},{"version":"7.2.4","status":"unaffected","lessThanOrEqual":"7.2.*","versionType":"semver"},{"version":"7.3","status":"unaffected","lessThanOrEqual":"*","versionType":"original_commit_for_fix"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["net/sunrpc/xprtrdma/svc_rdma_rw.c"]}],"references":["https://git.kernel.org/stable/c/10873311f91db9454e2fadbf9866bc819e0646d9","https://git.kernel.org/stable/c/addbf02dfe3b25e7e38e03bbd4e2a6ed86a14be7","https://git.kernel.org/stable/c/cba8543c18cf42fd80fd63effb6df6ff4f7e73ce","https://git.kernel.org/stable/c/6ee4dc7476b3abc92ec1d444533a559f33f59561","https://git.kernel.org/stable/c/a46b35f213c2426f5d6a0458a8f7e873fc59cdfd","https://git.kernel.org/stable/c/4493c96bbd0068fadf69cbae8d13426202e34cdc","https://git.kernel.org/stable/c/4a44c140cc2f3643a39e258bb0c0ab9d0f494f5e"],"weaknesses":[],"ingestedAt":"2026-10-29T20:13:26.108Z","source":{"repository":"CVEProject/cvelistV5","path":"cves/2026/89xxx/CVE-2026-89533.json","commit":"556c9d3a8cd17e218bb8e452ba7cd619a384ff47"},"raw":{"dataType":"CVE_RECORD","dataVersion":"5.2","cveMetadata":{"cveId":"CVE-2026-89533","state":"PUBLISHED","datePublished":"2026-09-11T19:44:12.236Z","dateUpdated":"2026-10-19T08:48:24.875Z","assignerShortName":"Linux","assignerOrgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","dateReserved":"2026-09-11T19:38:34.720Z"},"containers":{"cna":{"title":"svcrdma: Fix offset arithmetic in read_chunk_range","descriptions":[{"lang":"en","value":"In the Linux kernel, the following vulnerability has been resolved:\n\nsvcrdma: Fix offset arithmetic in read_chunk_range\n\nsvc_rdma_read_chunk_range() walks a Read chunk's segment list to\nbuild a sub-range starting at byte offset and spanning length bytes\nfor a Position-Zero or Call chunk. Two arithmetic defects in the\nper-segment loop produce wrong DMA lengths and a u32 underflow:\n\n    pcl_for_each_segment(segment, chunk) {\n            if (offset > segment->rs_length) {\n                    offset -= segment->rs_length;\n                    continue;\n            }\n\n            dummy.rs_handle = segment->rs_handle;\n            dummy.rs_length = min_t(u32, length,\n                                    segment->rs_length) - offset;\n            dummy.rs_offset = segment->rs_offset + offset;\n\nFirst, the skip predicate uses '>' instead of '>='. When offset\nequals the segment's full rs_length, the segment is fully consumed\nand should be skipped, but the loop falls through into the body.\nThe resulting dummy.rs_length is min_t(u32, length, rs_length) -\nrs_length, which underflows to a near-UINT_MAX u32 when length is\nsmaller than rs_length, or is zero otherwise.\n\nSecond, the length formula subtracts offset from the min_t() result\nrather than from segment->rs_length before the cap. For offset > 0\nthe segment's residual is rs_length - offset, not rs_length, so the\ncap must be applied to the residual. With the current bracketing,\nwhenever length is smaller than rs_length - offset the per-segment\nlength becomes length - offset instead of length, silently dropping\noffset bytes from the rebuilt chunk. Combined with the boundary\ncase above it also enables the u32 underflow path, which propagates\na huge nr_bvec into svc_rdma_build_read_segment() and a multi-MiB\nkmalloc_array_node() in svc_rdma_get_rw_ctxt().\n\nAdditionally, svc_rdma_read_call_chunk() can invoke this function\nwith length == 0 when the last Read chunk ends exactly at the end\nof the Call chunk. With the corrected >= predicate, every segment\nis skipped and the function returns the initial -EINVAL, rejecting\na valid request. Return success immediately when length is zero.\nAlso break out of the loop once length is fully consumed to avoid\npassing zero-length segments to svc_rdma_build_read_segment().\n\nFix by using '>=' so a fully-consumed segment is skipped, by\nmoving '- offset' inside min_t() so the cap is applied to the\nsegment's residual length, by returning success for zero-length\nrequests, and by stopping iteration when the requested range has\nbeen consumed."}],"affected":[{"vendor":"Linux","product":"Linux","defaultStatus":"unaffected","versions":[{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"10873311f91db9454e2fadbf9866bc819e0646d9","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"addbf02dfe3b25e7e38e03bbd4e2a6ed86a14be7","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"cba8543c18cf42fd80fd63effb6df6ff4f7e73ce","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"6ee4dc7476b3abc92ec1d444533a559f33f59561","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"a46b35f213c2426f5d6a0458a8f7e873fc59cdfd","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"4493c96bbd0068fadf69cbae8d13426202e34cdc","versionType":"git"},{"version":"d7cc73972661be4a02a1b09f1d9b3283c6c05154","status":"affected","lessThan":"4a44c140cc2f3643a39e258bb0c0ab9d0f494f5e","versionType":"git"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["net/sunrpc/xprtrdma/svc_rdma_rw.c"]},{"vendor":"Linux","product":"Linux","defaultStatus":"affected","versions":[{"version":"5.11","status":"affected"},{"version":"0","status":"unaffected","lessThan":"5.11","versionType":"semver"},{"version":"5.15.221","status":"unaffected","lessThanOrEqual":"5.15.*","versionType":"semver"},{"version":"6.1.188","status":"unaffected","lessThanOrEqual":"6.1.*","versionType":"semver"},{"version":"6.6.157","status":"unaffected","lessThanOrEqual":"6.6.*","versionType":"semver"},{"version":"6.12.109","status":"unaffected","lessThanOrEqual":"6.12.*","versionType":"semver"},{"version":"6.18.50","status":"unaffected","lessThanOrEqual":"6.18.*","versionType":"semver"},{"version":"7.2.4","status":"unaffected","lessThanOrEqual":"7.2.*","versionType":"semver"},{"version":"7.3","status":"unaffected","lessThanOrEqual":"*","versionType":"original_commit_for_fix"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["net/sunrpc/xprtrdma/svc_rdma_rw.c"]}],"references":[{"url":"https://git.kernel.org/stable/c/10873311f91db9454e2fadbf9866bc819e0646d9"},{"url":"https://git.kernel.org/stable/c/addbf02dfe3b25e7e38e03bbd4e2a6ed86a14be7"},{"url":"https://git.kernel.org/stable/c/cba8543c18cf42fd80fd63effb6df6ff4f7e73ce"},{"url":"https://git.kernel.org/stable/c/6ee4dc7476b3abc92ec1d444533a559f33f59561"},{"url":"https://git.kernel.org/stable/c/a46b35f213c2426f5d6a0458a8f7e873fc59cdfd"},{"url":"https://git.kernel.org/stable/c/4493c96bbd0068fadf69cbae8d13426202e34cdc"},{"url":"https://git.kernel.org/stable/c/4a44c140cc2f3643a39e258bb0c0ab9d0f494f5e"}],"metrics":[{"cvssV3_1":{"version":"3.1","vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","baseScore":9.8,"baseSeverity":"CRITICAL"},"scenarios":[{"lang":"en","value":"AV:N - svcrdma is nfsd's RPC-over-RDMA server transport; a remote peer reaches svc_rdma_read_chunk_range() by sending a Call with a Position-Zero/Call chunk and Read list over routable iWARP or RoCEv2, matching prior kernel CNA scores for this subsystem.\nAC:L - The attacker fully controls Call-chunk segment lengths and Read-chunk positions and can place a Read chunk on a segment boundary with a smaller remaining range so dummy.rs_length underflows a u32 deterministically, with no race or uncontrollable layout.\nPR:N - svc_rdma_process_read_list() runs in svc_rdma_recvfrom() while assembling the transport message, before svc_process() performs RPC or NFS authentication, and RDMA CM accept has no credential check.\nUI:N - Sending a crafted RPC-over-RDMA message with a malicious Call chunk and Read list to an already-listening NFS/RDMA service is sufficient; no victim mount, click, or other user action is required.\nS:U - The vulnerable NFS/RDMA service and affected kernel memory belong to the same host kernel security authority; this is not a VM, IOMMU, or sandbox escape.\nC:H - The underflowed length is added to rc_readbytes and, when Reads complete, svc_rdma_read_complete_pzrc() sets xdr_buf.page_len to a near-4GiB value, so XDR walks far past the rq_pages allocation and reads adjacent kernel heap as page pointers.\nI:H - XDR helpers such as xdr_buf_pages_zero() kmap and memset through that inflated page_len, writing via out-of-bounds page pointers taken from adjacent slab, a kernel integrity and control-flow hijack primitive.\nA:H - On the scatterlist path PAGE_ALIGN wrapping to 0 hits sg_alloc_table_chained(0) which BUG_ON(!nents) and panics; the huge page_len walk oopses on invalid pages, and an unauthenticated peer can repeat this per request."}]}],"providerMetadata":{"shortName":"Linux","orgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","dateUpdated":"2026-10-19T08:48:24.875Z"},"cpeApplicability":[{"nodes":[{"operator":"OR","negate":false,"cpeMatch":[{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.11","versionEndExcluding":"5.15.221"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.11","versionEndExcluding":"6.1.188"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.11","versionEndExcluding":"6.6.157"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.11","versionEndExcluding":"6.12.109"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.11","versionEndExcluding":"6.18.50"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.11","versionEndExcluding":"7.2.4"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.11","versionEndExcluding":"7.3"}]}]}],"x_generator":{"engine":"bippy-1.2.0"}},"adp":[{"title":"CISA ADP Vulnrichment","metrics":[{"other":{"type":"ssvc","content":{"id":"CVE-2026-89533","role":"CISA Coordinator","options":[{"Exploitation":"none"},{"Automatable":"yes"},{"Technical Impact":"total"}],"version":"2.0.3","timestamp":"2026-10-16T19:23:13.656876Z"}}}],"providerMetadata":{"shortName":"CISA-ADP","orgId":"134c704f-9b21-4f2e-91b3-4a467353bcc0","dateUpdated":"2026-10-16T19:26:41.551Z"}}]}}}