mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 14:34:41 +02:00
smb: client: pin DFS superblock in iterator callback
tcon_super_cb() stores a raw superblock pointer, but __cifs_get_super()
takes its active reference only after iterate_supers_type() has dropped
s_umount and its passive reference. Concurrent DFS automount expiry can
therefore free the superblock before cifs_sb_active() uses it.
A deterministic KASAN test reproduces the race as:
BUG: KASAN: slab-use-after-free in cifs_sb_active+0x77/0x80
The same test passes with this change applied.
Take the active reference in the callback while iterate_supers_type()
still holds s_umount shared. cifs_put_tcp_super() remains the matching
release.
Fixes: bacd704a95 ("cifs: handle prefix paths in reconnect")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
This commit is contained in:
parent
d9d7eeb0ce
commit
d806d5a85d
|
|
@ -891,8 +891,14 @@ static void tcon_super_cb(struct super_block *sb, void *arg)
|
|||
t1->ses->dfs_root_ses == t2->ses->dfs_root_ses) &&
|
||||
t1->ses->server == t2->ses->server &&
|
||||
t2->origin_fullpath &&
|
||||
dfs_src_pathname_equal(t2->origin_fullpath, t1->origin_fullpath))
|
||||
dfs_src_pathname_equal(t2->origin_fullpath, t1->origin_fullpath)) {
|
||||
/*
|
||||
* Take the active reference while iterate_supers_type() still
|
||||
* holds s_umount shared.
|
||||
*/
|
||||
cifs_sb_active(sb);
|
||||
sd->sb = sb;
|
||||
}
|
||||
spin_unlock(&t2->tc_lock);
|
||||
}
|
||||
|
||||
|
|
@ -909,15 +915,8 @@ static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void
|
|||
|
||||
for (; *fs_type; fs_type++) {
|
||||
iterate_supers_type(*fs_type, f, &sd);
|
||||
if (sd.sb) {
|
||||
/*
|
||||
* Grab an active reference in order to prevent automounts (DFS links)
|
||||
* of expiring and then freeing up our cifs superblock pointer while
|
||||
* we're doing failover.
|
||||
*/
|
||||
cifs_sb_active(sd.sb);
|
||||
if (sd.sb)
|
||||
return sd.sb;
|
||||
}
|
||||
}
|
||||
pr_warn_once("%s: could not find dfs superblock\n", __func__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user