[PATCH] NFS: blocklayout: reject oversized SCSI designators
From: Jérémy Jean
Date: Wed Aug 26 2026 - 04:13:20 EST
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@xxxxxxxxxxxxxxx
Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <Jeremy.Jean@xxxxxxxxxxxxxxxxx>
---
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