[PATCH] NFSv4.1: fix out-of-bounds write from zero back channel ca_maxrequests

Paula <[email protected]>
Newsgroups org.kernel.vger.linux-nfs,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
nfs4_verify_back_channel_attrs() validates the channel attributes a
server returns in a CREATE_SESSION reply before they are used to size
the back channel slot table. Unlike its fore channel sibling
nfs4_verify_fore_channel_attrs(), it never rejects a back channel
ca_maxrequests (rcvd->max_reqs) of zero.

A zero value reaches nfs4_realloc_slot_table(), where
nfs4_reset_slot_table() derives both server_highest_slotid and
max_slotid from max_reqs - 1. The subtraction is unsigned, so zero
underflows to 0xffffffff and is stored as the table's slot-id ceiling.

The attributes are chosen by the server in its CREATE_SESSION response:
a malicious or compromised NFSv4.1 server, on the wire, with no
authentication under sec=sys, and before the mount completes.

With server_highest_slotid and max_slotid at 0xffffffff, the bounds
checks in nfs4_lookup_slot() (slotid <= max_slotid) and validate_seqid()
(csa_slotid > server_highest_slotid) no longer constrain the
server-chosen CB_SEQUENCE csa_slotid. nfs4_lock_slot() then runs
__set_bit(slotid, tbl->used_slots) against the fixed used_slots[] array,
which is only SLOT_TABLE_SZ (16) unsigned longs / 1024 bits. A csa_slotid
of 3584 sets a bit 448 bytes past the array, a slab-out-of-bounds write
into the neighbouring allocation. The slot id is server-controlled, so
the write offset is attacker-chosen and deterministic.

KASAN labels the access below "Read of size 8" because __set_bit() is a
read-modify-write and the sanitizer flags the load; the store is the
actual defect, hence "out-of-bounds write".

  BUG: KASAN: slab-out-of-bounds in nfs4_lock_slot+0x148/0x15c
  Read of size 8 at addr ffff0000c7232bf0 by task NFSv4 callback/235
  Call trace:
   nfs4_lock_slot+0x148/0x15c
   nfs4_try_to_lock_slot+0x74/0xc0
   nfs4_callback_sequence+0x850/0x141c
   nfs4_callback_compound+0x414/0x111c
   nfs_callback_dispatch+0x6c/0xf4
   svc_process_common+0xb3c/0x1ba4
   svc_process_bc+0x400/0x9bc
   svc_recv+0xb5c/0x23fc
   nfs4_callback_svc+0xa8/0x140
   kthread+0x32c/0x3e4
   ret_from_fork+0x10/0x20

  Allocated by task 234:
   __kmalloc_cache_noprof+0x188/0x480
   nfs4_alloc_session+0x44/0x260
   nfs41_init_client+0x18/0x80
   nfs4_init_client+0x120/0x440
   nfs4_set_client+0x310/0x5a0
   nfs4_create_server+0x124/0x234
   nfs4_try_get_tree+0x70/0x240
   vfs_get_tree+0x74/0x2c0

Reachable with CONFIG_NFS_V4_1 whenever the client mounts an NFSv4.1
export from a server the attacker controls or can spoof.

Reject a zero back channel ca_maxrequests in
nfs4_verify_back_channel_attrs(), as nfs4_verify_fore_channel_attrs()
already does, so the underflow never sizes the slot table. The error
propagates through nfs4_verify_channel_attrs() and aborts
nfs4_proc_create_session() before nfs4_update_session() installs the
poisoned ceiling.

Fixes: 5405fc44c337 ("NFSv4.x: Add kernel parameter to control the callback server")
Cc: [email protected]
Assisted-by: Bynario AI
Signed-off-by: Paula <[email protected]>
---
 fs/nfs/nfs4proc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5709c6fea..182078c2e 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -9161,6 +9161,8 @@ static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args
 		return -EINVAL;
 	if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
 		return -EINVAL;
+	if (rcvd->max_reqs == 0)
+		return -EINVAL;
 	if (rcvd->max_ops > sent->max_ops)
 		return -EINVAL;
 	if (rcvd->max_reqs > sent->max_reqs)

base-commit: 3a0dd7ba4f44cdc116d83712f61e7c1a95be3588
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.