From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qt1-f176.google.com (mail-qt1-f176.google.com [209.85.160.176]) (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 4B1D0275AFB for ; Sat, 23 May 2026 01:40:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.176 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779500443; cv=none; b=UHZo6YWU6qhJJlUt60LAw1bid7QuaiDldze9GXNT+qINgwQDJt4nnZiC1NGL0WBdEXc3GWnPgsHDohIwZxn5sLkHIav/7wv+Tnc8JxStEfA3CuU5qXFnp4xE3eUV/L/npQJcBxu6+52/KfCwYaUiWU2OypMUcJ3ohxqyH9+AqKA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779500443; c=relaxed/simple; bh=hnduPY82/gGMnSQk7PIZuYmtQRqZ9KgbG5y9Zo+wlAw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fJH5Fa79T0YaT42/uN7UIwxIYmhakW34uPZYOSwWlVuJlcQzSqsa1nFrHegGkoHNpy1eJugiQ/WXQaYLNQceFX0UAV2dKCL75koP5VlmFx/j5slWLWFVFfGAmfpi6W89gZZH6ad7ENPwQYHL87hEu+grHADcNl4BuKPNGHTvX0s= 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=DCqx65r6; arc=none smtp.client-ip=209.85.160.176 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="DCqx65r6" Received: by mail-qt1-f176.google.com with SMTP id d75a77b69052e-50fb8e9a4edso93985051cf.1 for ; Fri, 22 May 2026 18:40:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779500441; x=1780105241; 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=/6cmfWT4Yx0qceSMPkSgJjcCJUqUmrReUf7axDysEWM=; b=DCqx65r6vGsgdHDLDLDCz99TB0Y0m4QQfonN4pMO1+OVVQY8CZY4Vd2Ts86lyNJ7yo 8RDm4FI2vnFEWM1mKf0cZMV8PNNtwxwRa647pOQ7uISsEEEsokDcjXlsxFpGvY+KVmqJ Q0BpC/0YVM5hzkCOEzBdPaH0neGnYW2QeaekwDrSqOWxLXzXhp6tWFbyaFTvMzxlUK1F zuY8DUSj4PWtTs9H2xKSYsjCKfuOo/bkkeN9C+Z/DHlTrdJ4h14fMGJMH151/ck/oamZ rHSsMzgskxJrRgoav0vNmIcv5tq64Q/fcx9qN8wHqUQsptTEbdwvtJckT4Lseqhhgv1U 6N8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779500441; x=1780105241; 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=/6cmfWT4Yx0qceSMPkSgJjcCJUqUmrReUf7axDysEWM=; b=R5RCjckySIBF/nrN8yc3XiazeFumzOuJTrrTpa1wNNFmxVG0ZVAAYXpA0alqjWls5s cKGZqq5ugVhlriHMjjIbqvoF1OMMuFvClA2v7/xvRDUlirSNamnR5/lEIFBOXbAXnvcc Cl3FkHSjBtLe3fi68PQgBju+e9wU3m6/oeV7XUpD35mcw/6Rd8uzodH0VK+wGFO7VtfG 1d191CnWcSW0X0R77FGJYzOM63V5EGVfUIRxQaYlya4OidCQa16CxHeTYtRcc/aWy2i4 kTZuLQyZZJqvB0Bw5DzG7fwgMTcpoiYYsdp5FDdqUsgZwWYKPJ8eAFDF0q0BBeBcrBlu e8SQ== X-Forwarded-Encrypted: i=1; AFNElJ94Dn+G24q8E/nQJqz82YDis+YUK+QzWUiYVLHwLojnuUTevj2yJpyfu9nKNtiX+cw1Cb/ZHV34BPoQQJ4=@vger.kernel.org X-Gm-Message-State: AOJu0Yy1IGBvAwuKLUFnmu8iAfYJq1K4mfGWMvYZTzOywEXeOYnFUZPQ 1NJfeGl6wHimsYR5cShBW4ERqrMHVQikIc1lUzHP9cuh1MABxnSeQncB X-Gm-Gg: Acq92OEIT/5O1qEjzKj0UjdW7YHPywfyYXCuRGsKNqkbx5Q3iu2tLNLKcTZR4XIgAZl fhfCedrYeLCTVAsE0WtS5hecB99uEylra4q7TmY4+F6fgGTdNmCK7J4pQ1ihYX4jpLB9M4CZbZX Cbc1p5YBgM+XugD/x1r9dAWJdmV7Lp64oFBzJUWPjpw2cKwW/pOYwwqshrZ2yzVOCy6ri2iEAjQ pe4tAjIrxOrSGCR5ey1PbGxnpVQH4aDoNJIADufgkrR65uFDDpusvoaK0RzuH1+1sxE9zHtNKtd jVAas1FMOFzIhbLzRs0nj1FFReQlgwxHIuOuGqaQxjmm3JFw2Wz2jgQmvK2rNGdvCx3BuP83a9Z 33WiDYCRskN8XoQ/eOASKU955b47Mm2MHmqMIfc4HancJZOaTS9cr+ebQ8bwtp6UzaxhamT/U3p 1Dqyon2U4qRsPwjcZa8JpxsuoHzKT6jZcGryH9jXPvhOvHn94cFHENmdTpanhpfNNI/OaDaz/6R NwwBL/Rd81c++2bj7RVOqJXCwgjAoU= X-Received: by 2002:a05:622a:94:b0:50f:be4f:465b with SMTP id d75a77b69052e-516d46455b3mr84987961cf.33.1779500441203; Fri, 22 May 2026 18:40:41 -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 d75a77b69052e-516d8b247c4sm28559031cf.7.2026.05.22.18.40.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 May 2026 18:40:40 -0700 (PDT) From: Michael Bommarito To: Trond Myklebust , Anna Schumaker Cc: Jeff Layton , Tom Haynes , Peng Tao , Kees Cook , Mike Snitzer , Tigran Mkrtchyan , linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org Subject: [PATCH 2/2] NFSv4/flexfile,filelayout: bound multipath DS count in GETDEVICEINFO Date: Fri, 22 May 2026 21:40:33 -0400 Message-ID: <20260523014033.2459677-3-michael.bommarito@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260523014033.2459677-1-michael.bommarito@gmail.com> References: <20260523014033.2459677-1-michael.bommarito@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Both the flexfile and the (legacy) file pNFS layout drivers decode a multipath-DS count from a server-supplied GETDEVICEINFO body and then iterate it via nfs4_decode_mp_ds_addr() without any upper bound. The filelayout driver already caps the outer ds_num against NFS4_PNFS_MAX_MULTI_CNT (== 256) but applies no equivalent cap to the inner mp_count; the flexfile driver applies no cap on either. In addition, both inner loops ignore a NULL return from nfs4_decode_mp_ds_addr(), so once the on-wire data no longer matches a valid netaddr4 encoding the loop is free to consume the trailing bytes of the device_addr opaque as garbage netid + uaddr pairs. A malicious or compromised pNFS metadata server can therefore drive the inner loop indefinitely (up to 2^32 - 1 iterations) against a fixed-size 56-byte body, with each iteration triggering an allocation / kmemdup_nul cycle inside the decoder. Promote NFS4_PNFS_MAX_MULTI_CNT from the filelayout private header to include/linux/nfs4.h so both drivers (and any future pNFS layout driver that decodes a multipath address list) bound the wire-level field consistently. Apply the cap to the inner mp_count in both drivers, matching the existing ds_num check, and bail on the first NULL return so a server that lies about mp_count cannot quietly extend the loop into the trailing layout-body bytes. This is defense-in-depth on top of the companion patch which closes the NULL-deref in nfs4_decode_mp_ds_addr(); either patch alone closes the kernel-panic shape, both together close the latent unbounded-decode class. Cc: stable@vger.kernel.org Fixes: 35124a0994fc ("Cleanup XDR parsing for LAYOUTGET, GETDEVICEINFO") Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito --- fs/nfs/filelayout/filelayout.h | 2 +- fs/nfs/filelayout/filelayoutdev.c | 7 +++++-- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 10 ++++++++-- include/linux/nfs4.h | 3 +++ 4 files changed, 17 insertions(+), 5 deletions(-) With this patch alone the crafted GETDEVICEINFO at multipath_count >= 3 is rejected at the bound check; malformed netaddr in the inner loop bails on the first NULL return. Either this patch or the companion 1/2 closes the panic; both together close the unbounded-decode class. Baseline multipath_count = 1 mount + read completes normally. diff --git a/fs/nfs/filelayout/filelayout.h b/fs/nfs/filelayout/filelayout.h index c7bb5da93307d..03298f2e7cd69 100644 --- a/fs/nfs/filelayout/filelayout.h +++ b/fs/nfs/filelayout/filelayout.h @@ -39,7 +39,7 @@ * RFC 5661 multipath_list4 structures. */ #define NFS4_PNFS_MAX_STRIPE_CNT 4096 -#define NFS4_PNFS_MAX_MULTI_CNT 256 /* 256 fit into a u8 stripe_index */ +/* NFS4_PNFS_MAX_MULTI_CNT now in ; shared with flexfile. */ enum stripetype4 { STRIPE_SPARSE = 1, diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c index 7226989ee4d53..c58c786dcf011 100644 --- a/fs/nfs/filelayout/filelayoutdev.c +++ b/fs/nfs/filelayout/filelayoutdev.c @@ -159,10 +159,13 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, goto out_err_free_deviceid; mp_count = be32_to_cpup(p); /* multipath count */ + if (mp_count > NFS4_PNFS_MAX_MULTI_CNT) + goto out_err_free_deviceid; for (j = 0; j < mp_count; j++) { da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); - if (da) - list_add_tail(&da->da_node, &dsaddrs); + if (!da) + break; + list_add_tail(&da->da_node, &dsaddrs); } if (list_empty(&dsaddrs)) { dprintk("%s: no suitable DS addresses found\n", diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index c40395ae08142..faed05cbe9f1c 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -78,12 +78,18 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, goto out_err_drain_dsaddrs; mp_count = be32_to_cpup(p); dprintk("%s: multipath ds count %d\n", __func__, mp_count); + if (mp_count > NFS4_PNFS_MAX_MULTI_CNT) { + dprintk("%s: multipath count %u greater than supported maximum %d\n", + __func__, mp_count, NFS4_PNFS_MAX_MULTI_CNT); + goto out_err_drain_dsaddrs; + } for (i = 0; i < mp_count; i++) { /* multipath ds */ da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); - if (da) - list_add_tail(&da->da_node, &dsaddrs); + if (!da) + break; + list_add_tail(&da->da_node, &dsaddrs); } if (list_empty(&dsaddrs)) { dprintk("%s: no suitable DS addresses found\n", diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index d87be1f25273a..bfc30baa8159a 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -767,6 +767,9 @@ enum pnfs_block_extent_state { PNFS_BLOCK_NONE_DATA = 3, }; +/* Maximum NFSv4.1 pNFS multipath data-server address count */ +#define NFS4_PNFS_MAX_MULTI_CNT 256 + /* on the wire size of a block layout extent */ #define PNFS_BLOCK_EXTENT_SIZE \ (7 * sizeof(__be32) + NFS4_DEVICEID4_SIZE) -- 2.53.0