]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
smb: client: fix potential cfid UAF in smb2_query_info_compound
authorHenrique Carvalho <henrique.carvalho@suse.com>
Mon, 27 Oct 2025 21:29:19 +0000 (18:29 -0300)
committerSteve French <stfrench@microsoft.com>
Tue, 28 Oct 2025 13:41:36 +0000 (08:41 -0500)
When smb2_query_info_compound() retries, a previously allocated cfid may
have been freed in the first attempt.
Because cfid wasn't reset on replay, later cleanup could act on a stale
pointer, leading to a potential use-after-free.

Reinitialize cfid to NULL under the replay label.

Example trace (trimmed):

refcount_t: underflow; use-after-free.
WARNING: CPU: 1 PID: 11224 at ../lib/refcount.c:28 refcount_warn_saturate+0x9c/0x110
[...]
RIP: 0010:refcount_warn_saturate+0x9c/0x110
[...]
Call Trace:
 <TASK>
 smb2_query_info_compound+0x29c/0x5c0 [cifs f90b72658819bd21c94769b6a652029a07a7172f]
 ? step_into+0x10d/0x690
 ? __legitimize_path+0x28/0x60
 smb2_queryfs+0x6a/0xf0 [cifs f90b72658819bd21c94769b6a652029a07a7172f]
 smb311_queryfs+0x12d/0x140 [cifs f90b72658819bd21c94769b6a652029a07a7172f]
 ? kmem_cache_alloc+0x18a/0x340
 ? getname_flags+0x46/0x1e0
 cifs_statfs+0x9f/0x2b0 [cifs f90b72658819bd21c94769b6a652029a07a7172f]
 statfs_by_dentry+0x67/0x90
 vfs_statfs+0x16/0xd0
 user_statfs+0x54/0xa0
 __do_sys_statfs+0x20/0x50
 do_syscall_64+0x58/0x80

Cc: stable@kernel.org
Fixes: 4f1fffa237692 ("cifs: commands that are retried should have replay flag set")
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
Acked-by: Shyam Prasad N <sprasad@microsoft.com>
Reviewed-by: Enzo Matsumiya <ematsumiya@suse.de>
Signed-off-by: Henrique Carvalho <henrique.carvalho@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb2ops.c

index 0f9130ef2e7d6d9290f32f9b930fba2f231d697b..1e39f2165e427230b595b8b289d98d6d858e3e18 100644 (file)
@@ -2799,11 +2799,12 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
        struct cifs_fid fid;
        int rc;
        __le16 *utf16_path;
-       struct cached_fid *cfid = NULL;
+       struct cached_fid *cfid;
        int retries = 0, cur_sleep = 1;
 
 replay_again:
        /* reinitialize for possible replay */
+       cfid = NULL;
        flags = CIFS_CP_CREATE_CLOSE_OP;
        oplock = SMB2_OPLOCK_LEVEL_NONE;
        server = cifs_pick_channel(ses);