[PATCH] NFS: blocklayout: reject oversized SCSI designators

Jérémy Jean posted 1 patch 1 month ago
fs/nfs/blocklayout/blocklayout.h | 2 +-
fs/nfs/blocklayout/dev.c         | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
[PATCH] NFS: blocklayout: reject oversized SCSI designators
Posted by Jérémy Jean 1 month ago
A SCSI GETDEVICEINFO reply can encode designator_len as 0xffffffff.  The
current signed field turns that into -1, so the size check is bypassed and
the value is converted to SIZE_MAX for xdr_inline_decode() and memcpy().

The attacker model considers a controlled NFSv4.1+ server and a client
already mounted to that server. An OOB read can be triggered in the client
on a file read. KASAN reports:

  BUG: KASAN: out-of-bounds in bl_alloc_deviceid_node+0x616/0x1110
  Read of size 18446744073709551615
  ...
  __asan_memcpy+0x23/0x60
  bl_alloc_deviceid_node+0x616/0x1110
  nfs4_find_get_deviceid+0x565/0x810
  bl_alloc_lseg+0x638/0x12d0
  pnfs_layout_process+0x2b6/0xcf0
  nfs4_proc_layoutget+0x4b3/0xd30


The fix stores the length as u32 and reject oversized values before decoding.
The check is moved up before the call to xdr_inline_decode().

Fixes: d9186c039765 ("nfs/blocklayout: add SCSI layout support")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
---
 fs/nfs/blocklayout/blocklayout.h | 2 +-
 fs/nfs/blocklayout/dev.c         | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index 6da40ca19570..db81ef3f9811 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -84,7 +84,7 @@ struct pnfs_block_volume {
 		struct {
 			enum scsi_code_set		code_set;
 			enum scsi_designator_type	designator_type;
-			int				designator_len;
+			u32				designator_len;
 			u8				designator[256];
 			u64				pr_key;
 		} scsi;
diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c
index 368d20daf67b..1e6141e79f3f 100644
--- a/fs/nfs/blocklayout/dev.c
+++ b/fs/nfs/blocklayout/dev.c
@@ -203,11 +203,11 @@ nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
 		b->scsi.code_set = be32_to_cpup(p++);
 		b->scsi.designator_type = be32_to_cpup(p++);
 		b->scsi.designator_len = be32_to_cpup(p++);
+		if (b->scsi.designator_len > sizeof(b->scsi.designator))
+			return -EIO;
 		p = xdr_inline_decode(xdr, b->scsi.designator_len);
 		if (!p)
 			return -EIO;
-		if (b->scsi.designator_len > 256)
-			return -EIO;
 		memcpy(&b->scsi.designator, p, b->scsi.designator_len);
 		p = xdr_inline_decode(xdr, 8);
 		if (!p)
@@ -345,14 +345,14 @@ bl_validate_designator(struct pnfs_block_volume *v)
 	case PS_DESIGNATOR_T10:
 	case PS_DESIGNATOR_NAME:
 		pr_err("pNFS: unsupported designator "
-			"(code set %d, type %d, len %d.\n",
+			"(code set %d, type %d, len %u.\n",
 			v->scsi.code_set,
 			v->scsi.designator_type,
 			v->scsi.designator_len);
 		return false;
 	default:
 		pr_err("pNFS: invalid designator "
-			"(code set %d, type %d, len %d.\n",
+			"(code set %d, type %d, len %u.\n",
 			v->scsi.code_set,
 			v->scsi.designator_type,
 			v->scsi.designator_len);
-- 
2.47.3