diff options
| author | Namjae Jeon <linkinjeon@kernel.org> | 2026-07-22 04:04:19 +0300 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-08-09 21:25:09 +0300 |
| commit | 9be4a66f019ea90bd9deca70511f4f9ffebf5c6f (patch) | |
| tree | c849bf142f5715d17fe2706431c8b025f0fef834 | |
| parent | 213b4568f6e5d5b2c6402bd820f5d9ea3c7a8f91 (diff) | |
| download | linux-9be4a66f019ea90bd9deca70511f4f9ffebf5c6f.tar.xz | |
ksmbd: fix use-after-free in __close_file_table_ids()
[ Upstream commit e7188199eff46a636f3436356f0aae039be6dd66 ]
A ksmbd_file can remain alive after logical close while another session
holds a temporary reference obtained through ksmbd_lookup_fd_inode().
ksmbd_close_fd() currently marks the file closed and drops the idr-owned
reference, but leaves the pointer published in the closing session's idr
until the final reference is dropped.
If the foreign holder performs the final ksmbd_fd_put(), __put_fd_final()
supplies the foreign session's file table to __ksmbd_close_fd(). The object
is then freed without being removed from its owner's idr, and the owner
session later dereferences the stale pointer during file-table teardown.
Remove the volatile id from the owner's idr while ksmbd_close_fd() still
holds that table's lock, and clear volatile_id before dropping
the idr-owned reference. A later foreign final put then only performs
physical destruction and cannot remove the object from the wrong table.
Fixes: 8510a043d334 ("ksmbd: increment reference count of parent fp")
Reported-by: Yunseong Kim <yunseong.kim@est.tech>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
| -rw-r--r-- | fs/smb/server/vfs_cache.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index 0d3341927b48..51e37e89d1aa 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -502,6 +502,8 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id) fp = NULL; else { fp->f_state = FP_CLOSED; + idr_remove(ft->idr, id); + fp->volatile_id = KSMBD_NO_FID; closed = true; if (!atomic_dec_and_test(&fp->refcount)) fp = NULL; |
